follow-redirects 1.14.4 → 1.14.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of follow-redirects might be problematic. Click here for more details.
- package/index.js +44 -14
- package/package.json +1 -1
package/index.js
CHANGED
@@ -18,7 +18,7 @@ events.forEach(function (event) {
|
|
18
18
|
// Error types with codes
|
19
19
|
var RedirectionError = createErrorType(
|
20
20
|
"ERR_FR_REDIRECTION_FAILURE",
|
21
|
-
""
|
21
|
+
"Redirected request failed"
|
22
22
|
);
|
23
23
|
var TooManyRedirectsError = createErrorType(
|
24
24
|
"ERR_FR_TOO_MANY_REDIRECTS",
|
@@ -169,10 +169,16 @@ RedirectableRequest.prototype.setTimeout = function (msecs, callback) {
|
|
169
169
|
|
170
170
|
// Stops a timeout from triggering
|
171
171
|
function clearTimer() {
|
172
|
+
// Clear the timeout
|
172
173
|
if (self._timeout) {
|
173
174
|
clearTimeout(self._timeout);
|
174
175
|
self._timeout = null;
|
175
176
|
}
|
177
|
+
|
178
|
+
// Clean up all attached listeners
|
179
|
+
self.removeListener("abort", clearTimer);
|
180
|
+
self.removeListener("error", clearTimer);
|
181
|
+
self.removeListener("response", clearTimer);
|
176
182
|
if (callback) {
|
177
183
|
self.removeListener("timeout", callback);
|
178
184
|
}
|
@@ -196,8 +202,9 @@ RedirectableRequest.prototype.setTimeout = function (msecs, callback) {
|
|
196
202
|
|
197
203
|
// Clean up on events
|
198
204
|
this.on("socket", destroyOnTimeout);
|
199
|
-
this.
|
200
|
-
this.
|
205
|
+
this.on("abort", clearTimer);
|
206
|
+
this.on("error", clearTimer);
|
207
|
+
this.on("response", clearTimer);
|
201
208
|
|
202
209
|
return this;
|
203
210
|
};
|
@@ -361,18 +368,32 @@ RedirectableRequest.prototype._processResponse = function (response) {
|
|
361
368
|
}
|
362
369
|
|
363
370
|
// Drop the Host header, as the redirect might lead to a different host
|
364
|
-
var
|
365
|
-
|
371
|
+
var currentHostHeader = removeMatchingHeaders(/^host$/i, this._options.headers);
|
372
|
+
|
373
|
+
// If the redirect is relative, carry over the host of the last request
|
374
|
+
var currentUrlParts = url.parse(this._currentUrl);
|
375
|
+
var currentHost = currentHostHeader || currentUrlParts.host;
|
376
|
+
var currentUrl = /^\w+:/.test(location) ? this._currentUrl :
|
377
|
+
url.format(Object.assign(currentUrlParts, { host: currentHost }));
|
378
|
+
|
379
|
+
// Determine the URL of the redirection
|
380
|
+
var redirectUrl;
|
381
|
+
try {
|
382
|
+
redirectUrl = url.resolve(currentUrl, location);
|
383
|
+
}
|
384
|
+
catch (cause) {
|
385
|
+
this.emit("error", new RedirectionError(cause));
|
386
|
+
return;
|
387
|
+
}
|
366
388
|
|
367
389
|
// Create the redirected request
|
368
|
-
var redirectUrl = url.resolve(this._currentUrl, location);
|
369
390
|
debug("redirecting to", redirectUrl);
|
370
391
|
this._isRedirect = true;
|
371
392
|
var redirectUrlParts = url.parse(redirectUrl);
|
372
393
|
Object.assign(this._options, redirectUrlParts);
|
373
394
|
|
374
|
-
// Drop the Authorization header if redirecting to another
|
375
|
-
if (redirectUrlParts.
|
395
|
+
// Drop the Authorization header if redirecting to another domain
|
396
|
+
if (!(redirectUrlParts.host === currentHost || isSubdomainOf(redirectUrlParts.host, currentHost))) {
|
376
397
|
removeMatchingHeaders(/^authorization$/i, this._options.headers);
|
377
398
|
}
|
378
399
|
|
@@ -394,9 +415,7 @@ RedirectableRequest.prototype._processResponse = function (response) {
|
|
394
415
|
this._performRequest();
|
395
416
|
}
|
396
417
|
catch (cause) {
|
397
|
-
|
398
|
-
error.cause = cause;
|
399
|
-
this.emit("error", error);
|
418
|
+
this.emit("error", new RedirectionError(cause));
|
400
419
|
}
|
401
420
|
}
|
402
421
|
else {
|
@@ -506,7 +525,7 @@ function removeMatchingHeaders(regex, headers) {
|
|
506
525
|
var lastValue;
|
507
526
|
for (var header in headers) {
|
508
527
|
if (regex.test(header)) {
|
509
|
-
lastValue = headers[header];
|
528
|
+
lastValue = headers[header].toString().trim();
|
510
529
|
delete headers[header];
|
511
530
|
}
|
512
531
|
}
|
@@ -514,9 +533,15 @@ function removeMatchingHeaders(regex, headers) {
|
|
514
533
|
}
|
515
534
|
|
516
535
|
function createErrorType(code, defaultMessage) {
|
517
|
-
function CustomError(
|
536
|
+
function CustomError(cause) {
|
518
537
|
Error.captureStackTrace(this, this.constructor);
|
519
|
-
|
538
|
+
if (!cause) {
|
539
|
+
this.message = defaultMessage;
|
540
|
+
}
|
541
|
+
else {
|
542
|
+
this.message = defaultMessage + ": " + cause.message;
|
543
|
+
this.cause = cause;
|
544
|
+
}
|
520
545
|
}
|
521
546
|
CustomError.prototype = new Error();
|
522
547
|
CustomError.prototype.constructor = CustomError;
|
@@ -533,6 +558,11 @@ function abortRequest(request) {
|
|
533
558
|
request.abort();
|
534
559
|
}
|
535
560
|
|
561
|
+
function isSubdomainOf(subdomain, domain) {
|
562
|
+
const dot = subdomain.length - domain.length - 1;
|
563
|
+
return dot > 0 && subdomain[dot] === "." && subdomain.endsWith(domain);
|
564
|
+
}
|
565
|
+
|
536
566
|
// Exports
|
537
567
|
module.exports = wrap({ http: http, https: https });
|
538
568
|
module.exports.wrap = wrap;
|