follow-redirects 1.14.8 → 1.14.9

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.

Files changed (2) hide show
  1. package/index.js +82 -81
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -336,97 +336,101 @@ RedirectableRequest.prototype._processResponse = function (response) {
336
336
  // the user agent MAY automatically redirect its request to the URI
337
337
  // referenced by the Location field value,
338
338
  // even if the specific status code is not understood.
339
+
340
+ // If the response is not a redirect; return it as-is
339
341
  var location = response.headers.location;
340
- if (location && this._options.followRedirects !== false &&
341
- statusCode >= 300 && statusCode < 400) {
342
- // Abort the current request
343
- abortRequest(this._currentRequest);
344
- // Discard the remainder of the response to avoid waiting for data
345
- response.destroy();
346
-
347
- // RFC7231§6.4: A client SHOULD detect and intervene
348
- // in cyclical redirections (i.e., "infinite" redirection loops).
349
- if (++this._redirectCount > this._options.maxRedirects) {
350
- this.emit("error", new TooManyRedirectsError());
351
- return;
352
- }
342
+ if (!location || this._options.followRedirects === false ||
343
+ statusCode < 300 || statusCode >= 400) {
344
+ response.responseUrl = this._currentUrl;
345
+ response.redirects = this._redirects;
346
+ this.emit("response", response);
353
347
 
354
- // RFC7231§6.4: Automatic redirection needs to done with
355
- // care for methods not known to be safe, []
356
- // RFC7231§6.4.2–3: For historical reasons, a user agent MAY change
357
- // the request method from POST to GET for the subsequent request.
358
- if ((statusCode === 301 || statusCode === 302) && this._options.method === "POST" ||
359
- // RFC7231§6.4.4: The 303 (See Other) status code indicates that
360
- // the server is redirecting the user agent to a different resource […]
361
- // A user agent can perform a retrieval request targeting that URI
362
- // (a GET or HEAD request if using HTTP) […]
363
- (statusCode === 303) && !/^(?:GET|HEAD)$/.test(this._options.method)) {
364
- this._options.method = "GET";
365
- // Drop a possible entity and headers related to it
366
- this._requestBodyBuffers = [];
367
- removeMatchingHeaders(/^content-/i, this._options.headers);
368
- }
348
+ // Clean up
349
+ this._requestBodyBuffers = [];
350
+ return;
351
+ }
369
352
 
370
- // Drop the Host header, as the redirect might lead to a different host
371
- var currentHostHeader = removeMatchingHeaders(/^host$/i, this._options.headers);
353
+ // The response is a redirect, so abort the current request
354
+ abortRequest(this._currentRequest);
355
+ // Discard the remainder of the response to avoid waiting for data
356
+ response.destroy();
372
357
 
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 }));
358
+ // RFC7231§6.4: A client SHOULD detect and intervene
359
+ // in cyclical redirections (i.e., "infinite" redirection loops).
360
+ if (++this._redirectCount > this._options.maxRedirects) {
361
+ this.emit("error", new TooManyRedirectsError());
362
+ return;
363
+ }
378
364
 
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
- }
365
+ // RFC7231§6.4: Automatic redirection needs to done with
366
+ // care for methods not known to be safe, […]
367
+ // RFC7231§6.4.2–3: For historical reasons, a user agent MAY change
368
+ // the request method from POST to GET for the subsequent request.
369
+ if ((statusCode === 301 || statusCode === 302) && this._options.method === "POST" ||
370
+ // RFC7231§6.4.4: The 303 (See Other) status code indicates that
371
+ // the server is redirecting the user agent to a different resource […]
372
+ // A user agent can perform a retrieval request targeting that URI
373
+ // (a GET or HEAD request if using HTTP) […]
374
+ (statusCode === 303) && !/^(?:GET|HEAD)$/.test(this._options.method)) {
375
+ this._options.method = "GET";
376
+ // Drop a possible entity and headers related to it
377
+ this._requestBodyBuffers = [];
378
+ removeMatchingHeaders(/^content-/i, this._options.headers);
379
+ }
388
380
 
389
- // Create the redirected request
390
- debug("redirecting to", redirectUrl);
391
- this._isRedirect = true;
392
- var redirectUrlParts = url.parse(redirectUrl);
393
- Object.assign(this._options, redirectUrlParts);
381
+ // Drop the Host header, as the redirect might lead to a different host
382
+ var currentHostHeader = removeMatchingHeaders(/^host$/i, this._options.headers);
394
383
 
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);
399
- }
384
+ // If the redirect is relative, carry over the host of the last request
385
+ var currentUrlParts = url.parse(this._currentUrl);
386
+ var currentHost = currentHostHeader || currentUrlParts.host;
387
+ var currentUrl = /^\w+:/.test(location) ? this._currentUrl :
388
+ url.format(Object.assign(currentUrlParts, { host: currentHost }));
400
389
 
401
- // Evaluate the beforeRedirect callback
402
- if (typeof this._options.beforeRedirect === "function") {
403
- var responseDetails = { headers: response.headers };
404
- try {
405
- this._options.beforeRedirect.call(null, this._options, responseDetails);
406
- }
407
- catch (err) {
408
- this.emit("error", err);
409
- return;
410
- }
411
- this._sanitizeOptions(this._options);
412
- }
390
+ // Determine the URL of the redirection
391
+ var redirectUrl;
392
+ try {
393
+ redirectUrl = url.resolve(currentUrl, location);
394
+ }
395
+ catch (cause) {
396
+ this.emit("error", new RedirectionError(cause));
397
+ return;
398
+ }
399
+
400
+ // Create the redirected request
401
+ debug("redirecting to", redirectUrl);
402
+ this._isRedirect = true;
403
+ var redirectUrlParts = url.parse(redirectUrl);
404
+ Object.assign(this._options, redirectUrlParts);
405
+
406
+ // Drop confidential headers when redirecting to a less secure protocol
407
+ // or to a different domain that is not a superdomain
408
+ if (redirectUrlParts.protocol !== currentUrlParts.protocol &&
409
+ redirectUrlParts.protocol !== "https:" ||
410
+ redirectUrlParts.host !== currentHost &&
411
+ !isSubdomain(redirectUrlParts.host, currentHost)) {
412
+ removeMatchingHeaders(/^(?:authorization|cookie)$/i, this._options.headers);
413
+ }
413
414
 
414
- // Perform the redirected request
415
+ // Evaluate the beforeRedirect callback
416
+ if (typeof this._options.beforeRedirect === "function") {
417
+ var responseDetails = { headers: response.headers };
415
418
  try {
416
- this._performRequest();
419
+ this._options.beforeRedirect.call(null, this._options, responseDetails);
417
420
  }
418
- catch (cause) {
419
- this.emit("error", new RedirectionError(cause));
421
+ catch (err) {
422
+ this.emit("error", err);
423
+ return;
420
424
  }
425
+ this._sanitizeOptions(this._options);
421
426
  }
422
- else {
423
- // The response is not a redirect; return it as-is
424
- response.responseUrl = this._currentUrl;
425
- response.redirects = this._redirects;
426
- this.emit("response", response);
427
427
 
428
- // Clean up
429
- this._requestBodyBuffers = [];
428
+ // Perform the redirected request
429
+ try {
430
+ this._performRequest();
431
+ }
432
+ catch (cause) {
433
+ this.emit("error", new RedirectionError(cause));
430
434
  }
431
435
  };
432
436
 
@@ -560,10 +564,7 @@ function abortRequest(request) {
560
564
  request.abort();
561
565
  }
562
566
 
563
- function isSameOrSubdomain(subdomain, domain) {
564
- if (subdomain === domain) {
565
- return true;
566
- }
567
+ function isSubdomain(subdomain, domain) {
567
568
  const dot = subdomain.length - domain.length - 1;
568
569
  return dot > 0 && subdomain[dot] === "." && subdomain.endsWith(domain);
569
570
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "follow-redirects",
3
- "version": "1.14.8",
3
+ "version": "1.14.9",
4
4
  "description": "HTTP and HTTPS modules that follow redirects.",
5
5
  "license": "MIT",
6
6
  "main": "index.js",