follow-redirects
Advanced tools
Comparing version 1.15.3 to 1.15.4
188
index.js
@@ -9,2 +9,25 @@ var url = require("url"); | ||
// Whether to use the native URL object or the legacy url module | ||
var useNativeURL = false; | ||
try { | ||
assert(new URL()); | ||
} | ||
catch (error) { | ||
useNativeURL = error.code === "ERR_INVALID_URL"; | ||
} | ||
// URL fields to preserve in copy operations | ||
var preservedUrlFields = [ | ||
"auth", | ||
"host", | ||
"hostname", | ||
"href", | ||
"path", | ||
"pathname", | ||
"port", | ||
"protocol", | ||
"query", | ||
"search", | ||
]; | ||
// Create handlers that pass events from native requests | ||
@@ -19,2 +42,3 @@ var events = ["abort", "aborted", "connect", "error", "socket", "timeout"]; | ||
// Error types with codes | ||
var InvalidUrlError = createErrorType( | ||
@@ -25,3 +49,2 @@ "ERR_INVALID_URL", | ||
); | ||
// Error types with codes | ||
var RedirectionError = createErrorType( | ||
@@ -33,3 +56,4 @@ "ERR_FR_REDIRECTION_FAILURE", | ||
"ERR_FR_TOO_MANY_REDIRECTS", | ||
"Maximum number of redirects exceeded" | ||
"Maximum number of redirects exceeded", | ||
RedirectionError | ||
); | ||
@@ -69,3 +93,9 @@ var MaxBodyLengthExceededError = createErrorType( | ||
this._onNativeResponse = function (response) { | ||
self._processResponse(response); | ||
try { | ||
self._processResponse(response); | ||
} | ||
catch (cause) { | ||
self.emit("error", cause instanceof RedirectionError ? | ||
cause : new RedirectionError({ cause: cause })); | ||
} | ||
}; | ||
@@ -288,4 +318,3 @@ | ||
if (!nativeProtocol) { | ||
this.emit("error", new TypeError("Unsupported protocol " + protocol)); | ||
return; | ||
throw new TypeError("Unsupported protocol " + protocol); | ||
} | ||
@@ -389,4 +418,3 @@ | ||
if (++this._redirectCount > this._options.maxRedirects) { | ||
this.emit("error", new TooManyRedirectsError()); | ||
return; | ||
throw new TooManyRedirectsError(); | ||
} | ||
@@ -425,3 +453,3 @@ | ||
// If the redirect is relative, carry over the host of the last request | ||
var currentUrlParts = url.parse(this._currentUrl); | ||
var currentUrlParts = parseUrl(this._currentUrl); | ||
var currentHost = currentHostHeader || currentUrlParts.host; | ||
@@ -431,24 +459,14 @@ var currentUrl = /^\w+:/.test(location) ? this._currentUrl : | ||
// Determine the URL of the redirection | ||
var redirectUrl; | ||
try { | ||
redirectUrl = url.resolve(currentUrl, location); | ||
} | ||
catch (cause) { | ||
this.emit("error", new RedirectionError({ cause: cause })); | ||
return; | ||
} | ||
// Create the redirected request | ||
debug("redirecting to", redirectUrl); | ||
var redirectUrl = resolveUrl(location, currentUrl); | ||
debug("redirecting to", redirectUrl.href); | ||
this._isRedirect = true; | ||
var redirectUrlParts = url.parse(redirectUrl); | ||
Object.assign(this._options, redirectUrlParts); | ||
spreadUrlObject(redirectUrl, this._options); | ||
// Drop confidential headers when redirecting to a less secure protocol | ||
// or to a different domain that is not a superdomain | ||
if (redirectUrlParts.protocol !== currentUrlParts.protocol && | ||
redirectUrlParts.protocol !== "https:" || | ||
redirectUrlParts.host !== currentHost && | ||
!isSubdomain(redirectUrlParts.host, currentHost)) { | ||
if (redirectUrl.protocol !== currentUrlParts.protocol && | ||
redirectUrl.protocol !== "https:" || | ||
redirectUrl.host !== currentHost && | ||
!isSubdomain(redirectUrl.host, currentHost)) { | ||
removeMatchingHeaders(/^(?:authorization|cookie)$/i, this._options.headers); | ||
@@ -468,9 +486,3 @@ } | ||
}; | ||
try { | ||
beforeRedirect(this._options, responseDetails, requestDetails); | ||
} | ||
catch (err) { | ||
this.emit("error", err); | ||
return; | ||
} | ||
beforeRedirect(this._options, responseDetails, requestDetails); | ||
this._sanitizeOptions(this._options); | ||
@@ -480,8 +492,3 @@ } | ||
// Perform the redirected request | ||
try { | ||
this._performRequest(); | ||
} | ||
catch (cause) { | ||
this.emit("error", new RedirectionError({ cause: cause })); | ||
} | ||
this._performRequest(); | ||
}; | ||
@@ -506,23 +513,12 @@ | ||
function request(input, options, callback) { | ||
// Parse parameters | ||
if (isString(input)) { | ||
var parsed; | ||
try { | ||
parsed = urlToOptions(new URL(input)); | ||
} | ||
catch (err) { | ||
/* istanbul ignore next */ | ||
parsed = url.parse(input); | ||
} | ||
if (!isString(parsed.protocol)) { | ||
throw new InvalidUrlError({ input }); | ||
} | ||
input = parsed; | ||
// Parse parameters, ensuring that input is an object | ||
if (isURL(input)) { | ||
input = spreadUrlObject(input); | ||
} | ||
else if (URL && (input instanceof URL)) { | ||
input = urlToOptions(input); | ||
else if (isString(input)) { | ||
input = spreadUrlObject(parseUrl(input)); | ||
} | ||
else { | ||
callback = options; | ||
options = input; | ||
options = validateUrl(input); | ||
input = { protocol: protocol }; | ||
@@ -566,25 +562,55 @@ } | ||
/* istanbul ignore next */ | ||
function noop() { /* empty */ } | ||
// from https://github.com/nodejs/node/blob/master/lib/internal/url.js | ||
function urlToOptions(urlObject) { | ||
var options = { | ||
protocol: urlObject.protocol, | ||
hostname: urlObject.hostname.startsWith("[") ? | ||
/* istanbul ignore next */ | ||
urlObject.hostname.slice(1, -1) : | ||
urlObject.hostname, | ||
hash: urlObject.hash, | ||
search: urlObject.search, | ||
pathname: urlObject.pathname, | ||
path: urlObject.pathname + urlObject.search, | ||
href: urlObject.href, | ||
}; | ||
if (urlObject.port !== "") { | ||
options.port = Number(urlObject.port); | ||
function parseUrl(input) { | ||
var parsed; | ||
/* istanbul ignore else */ | ||
if (useNativeURL) { | ||
parsed = new URL(input); | ||
} | ||
return options; | ||
else { | ||
// Ensure the URL is valid and absolute | ||
parsed = validateUrl(url.parse(input)); | ||
if (!isString(parsed.protocol)) { | ||
throw new InvalidUrlError({ input }); | ||
} | ||
} | ||
return parsed; | ||
} | ||
function resolveUrl(relative, base) { | ||
/* istanbul ignore next */ | ||
return useNativeURL ? new URL(relative, base) : parseUrl(url.resolve(base, relative)); | ||
} | ||
function validateUrl(input) { | ||
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) { | ||
throw new InvalidUrlError({ input: input.href || input }); | ||
} | ||
if (/^\[/.test(input.host) && !/^\[[:0-9a-f]+\](:\d+)?$/i.test(input.host)) { | ||
throw new InvalidUrlError({ input: input.href || input }); | ||
} | ||
return input; | ||
} | ||
function spreadUrlObject(urlObject, target) { | ||
var spread = target || {}; | ||
for (var key of preservedUrlFields) { | ||
spread[key] = urlObject[key]; | ||
} | ||
// Fix IPv6 hostname | ||
if (spread.hostname.startsWith("[")) { | ||
spread.hostname = spread.hostname.slice(1, -1); | ||
} | ||
// Ensure port is a number | ||
if (spread.port !== "") { | ||
spread.port = Number(spread.port); | ||
} | ||
// Concatenate path | ||
spread.path = spread.search ? spread.pathname + spread.search : spread.pathname; | ||
return spread; | ||
} | ||
function removeMatchingHeaders(regex, headers) { | ||
@@ -613,4 +639,12 @@ var lastValue; | ||
CustomError.prototype = new (baseClass || Error)(); | ||
CustomError.prototype.constructor = CustomError; | ||
CustomError.prototype.name = "Error [" + code + "]"; | ||
Object.defineProperties(CustomError.prototype, { | ||
constructor: { | ||
value: CustomError, | ||
enumerable: false, | ||
}, | ||
name: { | ||
value: "Error [" + code + "]", | ||
enumerable: false, | ||
}, | ||
}); | ||
return CustomError; | ||
@@ -645,4 +679,8 @@ } | ||
function isURL(value) { | ||
return URL && value instanceof URL; | ||
} | ||
// Exports | ||
module.exports = wrap({ http: http, https: https }); | ||
module.exports.wrap = wrap; |
{ | ||
"name": "follow-redirects", | ||
"version": "1.15.3", | ||
"version": "1.15.4", | ||
"description": "HTTP and HTTPS modules that follow redirects.", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
29352
611