follow-redirects 1.14.3 → 1.14.7
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 +60 -22
- 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",
|
@@ -147,10 +147,8 @@ RedirectableRequest.prototype.removeHeader = function (name) {
|
|
147
147
|
// Global timeout for all underlying requests
|
148
148
|
RedirectableRequest.prototype.setTimeout = function (msecs, callback) {
|
149
149
|
var self = this;
|
150
|
-
if (callback) {
|
151
|
-
this.on("timeout", callback);
|
152
|
-
}
|
153
150
|
|
151
|
+
// Destroys the socket on timeout
|
154
152
|
function destroyOnTimeout(socket) {
|
155
153
|
socket.setTimeout(msecs);
|
156
154
|
socket.removeListener("timeout", socket.destroy);
|
@@ -169,18 +167,32 @@ RedirectableRequest.prototype.setTimeout = function (msecs, callback) {
|
|
169
167
|
destroyOnTimeout(socket);
|
170
168
|
}
|
171
169
|
|
172
|
-
//
|
170
|
+
// Stops a timeout from triggering
|
173
171
|
function clearTimer() {
|
174
|
-
|
172
|
+
// Clear the timeout
|
173
|
+
if (self._timeout) {
|
174
|
+
clearTimeout(self._timeout);
|
175
|
+
self._timeout = null;
|
176
|
+
}
|
177
|
+
|
178
|
+
// Clean up all attached listeners
|
179
|
+
self.removeListener("abort", clearTimer);
|
180
|
+
self.removeListener("error", clearTimer);
|
181
|
+
self.removeListener("response", clearTimer);
|
175
182
|
if (callback) {
|
176
183
|
self.removeListener("timeout", callback);
|
177
184
|
}
|
178
|
-
if (!
|
185
|
+
if (!self.socket) {
|
179
186
|
self._currentRequest.removeListener("socket", startTimer);
|
180
187
|
}
|
181
188
|
}
|
182
189
|
|
183
|
-
//
|
190
|
+
// Attach callback if passed
|
191
|
+
if (callback) {
|
192
|
+
this.on("timeout", callback);
|
193
|
+
}
|
194
|
+
|
195
|
+
// Start the timer if or when the socket is opened
|
184
196
|
if (this.socket) {
|
185
197
|
startTimer(this.socket);
|
186
198
|
}
|
@@ -188,9 +200,11 @@ RedirectableRequest.prototype.setTimeout = function (msecs, callback) {
|
|
188
200
|
this._currentRequest.once("socket", startTimer);
|
189
201
|
}
|
190
202
|
|
203
|
+
// Clean up on events
|
191
204
|
this.on("socket", destroyOnTimeout);
|
192
|
-
this.
|
193
|
-
this.
|
205
|
+
this.on("abort", clearTimer);
|
206
|
+
this.on("error", clearTimer);
|
207
|
+
this.on("response", clearTimer);
|
194
208
|
|
195
209
|
return this;
|
196
210
|
};
|
@@ -354,19 +368,33 @@ RedirectableRequest.prototype._processResponse = function (response) {
|
|
354
368
|
}
|
355
369
|
|
356
370
|
// Drop the Host header, as the redirect might lead to a different host
|
357
|
-
var
|
358
|
-
|
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
|
+
}
|
359
388
|
|
360
389
|
// Create the redirected request
|
361
|
-
var redirectUrl = url.resolve(this._currentUrl, location);
|
362
390
|
debug("redirecting to", redirectUrl);
|
363
391
|
this._isRedirect = true;
|
364
392
|
var redirectUrlParts = url.parse(redirectUrl);
|
365
393
|
Object.assign(this._options, redirectUrlParts);
|
366
394
|
|
367
|
-
// Drop the
|
368
|
-
if (redirectUrlParts.
|
369
|
-
removeMatchingHeaders(/^authorization$/i, this._options.headers);
|
395
|
+
// Drop the confidential headers when redirecting to another domain
|
396
|
+
if (!(redirectUrlParts.host === currentHost || isSubdomainOf(redirectUrlParts.host, currentHost))) {
|
397
|
+
removeMatchingHeaders(/^(?:authorization|cookie)$/i, this._options.headers);
|
370
398
|
}
|
371
399
|
|
372
400
|
// Evaluate the beforeRedirect callback
|
@@ -387,9 +415,7 @@ RedirectableRequest.prototype._processResponse = function (response) {
|
|
387
415
|
this._performRequest();
|
388
416
|
}
|
389
417
|
catch (cause) {
|
390
|
-
|
391
|
-
error.cause = cause;
|
392
|
-
this.emit("error", error);
|
418
|
+
this.emit("error", new RedirectionError(cause));
|
393
419
|
}
|
394
420
|
}
|
395
421
|
else {
|
@@ -503,13 +529,20 @@ function removeMatchingHeaders(regex, headers) {
|
|
503
529
|
delete headers[header];
|
504
530
|
}
|
505
531
|
}
|
506
|
-
return lastValue
|
532
|
+
return (lastValue === null || typeof lastValue === "undefined") ?
|
533
|
+
undefined : String(lastValue).trim();
|
507
534
|
}
|
508
535
|
|
509
536
|
function createErrorType(code, defaultMessage) {
|
510
|
-
function CustomError(
|
537
|
+
function CustomError(cause) {
|
511
538
|
Error.captureStackTrace(this, this.constructor);
|
512
|
-
|
539
|
+
if (!cause) {
|
540
|
+
this.message = defaultMessage;
|
541
|
+
}
|
542
|
+
else {
|
543
|
+
this.message = defaultMessage + ": " + cause.message;
|
544
|
+
this.cause = cause;
|
545
|
+
}
|
513
546
|
}
|
514
547
|
CustomError.prototype = new Error();
|
515
548
|
CustomError.prototype.constructor = CustomError;
|
@@ -526,6 +559,11 @@ function abortRequest(request) {
|
|
526
559
|
request.abort();
|
527
560
|
}
|
528
561
|
|
562
|
+
function isSubdomainOf(subdomain, domain) {
|
563
|
+
const dot = subdomain.length - domain.length - 1;
|
564
|
+
return dot > 0 && subdomain[dot] === "." && subdomain.endsWith(domain);
|
565
|
+
}
|
566
|
+
|
529
567
|
// Exports
|
530
568
|
module.exports = wrap({ http: http, https: https });
|
531
569
|
module.exports.wrap = wrap;
|