Skip to content

Commit 04734a1

Browse files
authored
fix: 🐛 should trigger response event when follow redirect (#361)
1 parent 4e06bbb commit 04734a1

File tree

5 files changed

+102
-41
lines changed

5 files changed

+102
-41
lines changed

lib/urllib.js

Lines changed: 71 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ function requestWithCallback(url, args, callback) {
520520
}
521521
return;
522522
}
523+
523524
var cb = callback;
524525
callback = null;
525526
var headers = {};
@@ -529,49 +530,16 @@ function requestWithCallback(url, args, callback) {
529530
headers = res.headers;
530531
}
531532

532-
// handle digest auth
533-
if (statusCode === 401 && headers['www-authenticate']
534-
&& !options.headers.authorization && args.digestAuth) {
535-
var authenticate = headers['www-authenticate'];
536-
if (authenticate.indexOf('Digest ') >= 0) {
537-
debug('Request#%d %s: got digest auth header WWW-Authenticate: %s', reqId, url, authenticate);
538-
options.headers.authorization = digestAuthHeader(options.method, options.path, authenticate, args.digestAuth);
539-
debug('Request#%d %s: auth with digest header: %s', reqId, url, options.headers.authorization);
540-
if (res.headers['set-cookie']) {
541-
options.headers.cookie = res.headers['set-cookie'].join(';');
542-
}
543-
args.headers = options.headers;
544-
return exports.requestWithCallback(url, args, cb);
545-
}
533+
if (handleDigestAuth(res, cb)) {
534+
return;
546535
}
547536

548-
var requestUseTime = Date.now() - requestStartTime;
549-
if (timing) {
550-
timing.contentDownload = requestUseTime;
551-
}
537+
var response = createCallbackResponse(data, res);
552538

553539
debug('[%sms] done, %s bytes HTTP %s %s %s %s, keepAliveSocket: %s, timing: %j, socketHandledRequests: %s, socketHandledResponses: %s',
554-
requestUseTime, responseSize, statusCode, options.method, options.host, options.path,
540+
response.requestUseTime, responseSize, statusCode, options.method, options.host, options.path,
555541
keepAliveSocket, timing, socketHandledRequests, socketHandledResponses);
556542

557-
var response = {
558-
status: statusCode,
559-
statusCode: statusCode,
560-
statusMessage: statusMessage,
561-
headers: headers,
562-
size: responseSize,
563-
aborted: responseAborted,
564-
rt: requestUseTime,
565-
keepAliveSocket: keepAliveSocket,
566-
data: data,
567-
requestUrls: args.requestUrls,
568-
timing: timing,
569-
remoteAddress: remoteAddress,
570-
remotePort: remotePort,
571-
socketHandledRequests: socketHandledRequests,
572-
socketHandledResponses: socketHandledResponses,
573-
};
574-
575543
if (err) {
576544
var agentStatus = '';
577545
if (agent && typeof agent.getCurrentStatus === 'function') {
@@ -620,6 +588,45 @@ function requestWithCallback(url, args, callback) {
620588

621589
cb(err, data, args.streaming ? res : response);
622590

591+
emitResponseEvent(err, response);
592+
}
593+
594+
function createAndEmitResponseEvent(data, res) {
595+
var response = createCallbackResponse(data, res);
596+
emitResponseEvent(null, response);
597+
}
598+
599+
function createCallbackResponse(data, res) {
600+
var requestUseTime = Date.now() - requestStartTime;
601+
if (timing) {
602+
timing.contentDownload = requestUseTime;
603+
}
604+
605+
var headers = {};
606+
if (res && res.headers) {
607+
headers = res.headers;
608+
}
609+
610+
return {
611+
status: statusCode,
612+
statusCode: statusCode,
613+
statusMessage: statusMessage,
614+
headers: headers,
615+
size: responseSize,
616+
aborted: responseAborted,
617+
rt: requestUseTime,
618+
keepAliveSocket: keepAliveSocket,
619+
data: data,
620+
requestUrls: args.requestUrls,
621+
timing: timing,
622+
remoteAddress: remoteAddress,
623+
remotePort: remotePort,
624+
socketHandledRequests: socketHandledRequests,
625+
socketHandledResponses: socketHandledResponses,
626+
};
627+
}
628+
629+
function emitResponseEvent(err, response) {
623630
if (args.emitter) {
624631
// keep to use the same reqMeta object on request event before
625632
reqMeta.url = parsedUrl.href;
@@ -637,6 +644,30 @@ function requestWithCallback(url, args, callback) {
637644
}
638645
}
639646

647+
function handleDigestAuth(res, cb) {
648+
var headers = {};
649+
if (res && res.headers) {
650+
headers = res.headers;
651+
}
652+
// handle digest auth
653+
if (statusCode === 401 && headers['www-authenticate']
654+
&& !options.headers.authorization && args.digestAuth) {
655+
var authenticate = headers['www-authenticate'];
656+
if (authenticate.indexOf('Digest ') >= 0) {
657+
debug('Request#%d %s: got digest auth header WWW-Authenticate: %s', reqId, url, authenticate);
658+
options.headers.authorization = digestAuthHeader(options.method, options.path, authenticate, args.digestAuth);
659+
debug('Request#%d %s: auth with digest header: %s', reqId, url, options.headers.authorization);
660+
if (res.headers['set-cookie']) {
661+
options.headers.cookie = res.headers['set-cookie'].join(';');
662+
}
663+
args.headers = options.headers;
664+
exports.requestWithCallback(url, args, cb);
665+
return true;
666+
}
667+
}
668+
return false;
669+
}
670+
640671
function handleRedirect(res) {
641672
var err = null;
642673
if (args.followRedirect && statuses.redirect[res.statusCode]) { // handle redirect
@@ -740,6 +771,7 @@ function requestWithCallback(url, args, callback) {
740771
var result = handleRedirect(res);
741772
if (result.redirect) {
742773
res.resume();
774+
createAndEmitResponseEvent(null, res);
743775
return;
744776
}
745777
if (result.error) {
@@ -781,6 +813,7 @@ function requestWithCallback(url, args, callback) {
781813
var result = handleRedirect(res);
782814
if (result.redirect) {
783815
res.resume();
816+
createAndEmitResponseEvent(null, res);
784817
return;
785818
}
786819
if (result.error) {
@@ -874,6 +907,7 @@ function requestWithCallback(url, args, callback) {
874907
return done(result.error, body, res);
875908
}
876909
if (result.redirect) {
910+
createAndEmitResponseEvent(null, res);
877911
return;
878912
}
879913

test/config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module.exports = process.env.CI ? {
55
npmRegistry: 'https://registry.npmjs.com',
66
npmHttpRegistry: 'http://registry.npmjs.com',
77
} : {
8-
npmWeb: 'https://developer.aliyun.com/mirror/npm',
8+
npmWeb: 'https://www.npmjs.com',
99
npmRegistry: 'https://registry.npm.taobao.org',
1010
npmHttpRegistry: 'http://registry.npm.taobao.org',
1111
};

test/files.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ describe('test/files.test.js', function() {
7070
assert(result.headers['content-type'].indexOf('multipart/form-data;') === 0);
7171
assert(res.status === 200);
7272
assert(result.files.file.filename === 'bufferfile0');
73-
assert(result.files.file.mimetype === 'application/octet-stream');
73+
assert(result.files.file.mimetype === 'text/plain');
7474
done();
7575
});
7676
});
@@ -90,7 +90,7 @@ describe('test/files.test.js', function() {
9090
assert(result.files.file1.filename === 'files.test.js');
9191
assert(result.files.file1.mimetype === 'application/javascript');
9292
assert(result.files.file2.filename === 'bufferfile2');
93-
assert(result.files.file2.mimetype === 'application/octet-stream');
93+
assert(result.files.file2.mimetype === 'text/plain');
9494
done();
9595
});
9696
});

test/proxy.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ var isNode012 = /^v0\.12\.\d+$/.test(process.version);
99
var testUrl = process.env.CI ? 'https://registry.npmjs.com' : 'https://registry.npm.taobao.org';
1010

1111
if (!isNode010 && !isNode012) {
12-
describe.only('test/proxy.test.js', function() {
12+
describe('test/proxy.test.js', function() {
1313
var port;
1414
var proxyUrl;
1515
before(function(done) {

test/urllib.test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,6 +1704,33 @@ describe('test/urllib.test.js', function () {
17041704
done();
17051705
});
17061706
});
1707+
1708+
it('should trigger req/res in pair when followRedirect', function (done) {
1709+
done = pedding(5, done);
1710+
var redirected = false;
1711+
urllib.on('request', function (info) {
1712+
info.args.headers = info.args.headers || {};
1713+
info.args.headers['custom-header'] = 'custom-header';
1714+
done();
1715+
});
1716+
urllib.on('response', function (info) {
1717+
if (info.req.options.path === '/302-to-200') {
1718+
redirected = true;
1719+
}
1720+
assert(info.req.options.headers['custom-header'] === 'custom-header');
1721+
assert(redirected);
1722+
done();
1723+
});
1724+
1725+
urllib.request(host + '/302-to-200', {
1726+
followRedirect: true,
1727+
ctx: {
1728+
foo: 'error request'
1729+
}
1730+
}, function () {
1731+
done();
1732+
});
1733+
});
17071734
});
17081735

17091736
describe('charset support', function () {

0 commit comments

Comments
 (0)