follow-redirects 1.14.4 → 1.14.8
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 +50 -15
- 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,19 +368,34 @@ 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
|
375
|
-
if (redirectUrlParts.
|
376
|
-
|
395
|
+
// Drop confidential headers when redirecting to another scheme:domain
|
396
|
+
if (redirectUrlParts.protocol !== currentUrlParts.protocol ||
|
397
|
+
!isSameOrSubdomain(redirectUrlParts.host, currentHost)) {
|
398
|
+
removeMatchingHeaders(/^(?:authorization|cookie)$/i, this._options.headers);
|
377
399
|
}
|
378
400
|
|
379
401
|
// Evaluate the beforeRedirect callback
|
@@ -394,9 +416,7 @@ RedirectableRequest.prototype._processResponse = function (response) {
|
|
394
416
|
this._performRequest();
|
395
417
|
}
|
396
418
|
catch (cause) {
|
397
|
-
|
398
|
-
error.cause = cause;
|
399
|
-
this.emit("error", error);
|
419
|
+
this.emit("error", new RedirectionError(cause));
|
400
420
|
}
|
401
421
|
}
|
402
422
|
else {
|
@@ -510,13 +530,20 @@ function removeMatchingHeaders(regex, headers) {
|
|
510
530
|
delete headers[header];
|
511
531
|
}
|
512
532
|
}
|
513
|
-
return lastValue
|
533
|
+
return (lastValue === null || typeof lastValue === "undefined") ?
|
534
|
+
undefined : String(lastValue).trim();
|
514
535
|
}
|
515
536
|
|
516
537
|
function createErrorType(code, defaultMessage) {
|
517
|
-
function CustomError(
|
538
|
+
function CustomError(cause) {
|
518
539
|
Error.captureStackTrace(this, this.constructor);
|
519
|
-
|
540
|
+
if (!cause) {
|
541
|
+
this.message = defaultMessage;
|
542
|
+
}
|
543
|
+
else {
|
544
|
+
this.message = defaultMessage + ": " + cause.message;
|
545
|
+
this.cause = cause;
|
546
|
+
}
|
520
547
|
}
|
521
548
|
CustomError.prototype = new Error();
|
522
549
|
CustomError.prototype.constructor = CustomError;
|
@@ -533,6 +560,14 @@ function abortRequest(request) {
|
|
533
560
|
request.abort();
|
534
561
|
}
|
535
562
|
|
563
|
+
function isSameOrSubdomain(subdomain, domain) {
|
564
|
+
if (subdomain === domain) {
|
565
|
+
return true;
|
566
|
+
}
|
567
|
+
const dot = subdomain.length - domain.length - 1;
|
568
|
+
return dot > 0 && subdomain[dot] === "." && subdomain.endsWith(domain);
|
569
|
+
}
|
570
|
+
|
536
571
|
// Exports
|
537
572
|
module.exports = wrap({ http: http, https: https });
|
538
573
|
module.exports.wrap = wrap;
|