diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 047af9119020f..647d421819597 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -13960,8 +13960,9 @@ var assert = __webpack_require__(162); var debug = __webpack_require__(204); // Create handlers that pass events from native requests +var events = ["abort", "aborted", "connect", "error", "socket", "timeout"]; var eventHandlers = Object.create(null); -["abort", "aborted", "connect", "error", "socket", "timeout"].forEach(function (event) { +events.forEach(function (event) { eventHandlers[event] = function (arg1, arg2, arg3) { this._redirectable.emit(event, arg1, arg2, arg3); }; @@ -13970,7 +13971,7 @@ var eventHandlers = Object.create(null); // Error types with codes var RedirectionError = createErrorType( "ERR_FR_REDIRECTION_FAILURE", - "" + "Redirected request failed" ); var TooManyRedirectsError = createErrorType( "ERR_FR_TOO_MANY_REDIRECTS", @@ -14014,6 +14015,11 @@ function RedirectableRequest(options, responseCallback) { } RedirectableRequest.prototype = Object.create(Writable.prototype); +RedirectableRequest.prototype.abort = function () { + abortRequest(this._currentRequest); + this.emit("abort"); +}; + // Writes buffered data to the current native request RedirectableRequest.prototype.write = function (data, encoding, callback) { // Writing is not allowed if end has been called @@ -14093,40 +14099,72 @@ RedirectableRequest.prototype.removeHeader = function (name) { // Global timeout for all underlying requests RedirectableRequest.prototype.setTimeout = function (msecs, callback) { + var self = this; + + // Destroys the socket on timeout + function destroyOnTimeout(socket) { + socket.setTimeout(msecs); + socket.removeListener("timeout", socket.destroy); + socket.addListener("timeout", socket.destroy); + } + + // Sets up a timer to trigger a timeout event + function startTimer(socket) { + if (self._timeout) { + clearTimeout(self._timeout); + } + self._timeout = setTimeout(function () { + self.emit("timeout"); + clearTimer(); + }, msecs); + destroyOnTimeout(socket); + } + + // Stops a timeout from triggering + function clearTimer() { + // Clear the timeout + if (self._timeout) { + clearTimeout(self._timeout); + self._timeout = null; + } + + // Clean up all attached listeners + self.removeListener("abort", clearTimer); + self.removeListener("error", clearTimer); + self.removeListener("response", clearTimer); + if (callback) { + self.removeListener("timeout", callback); + } + if (!self.socket) { + self._currentRequest.removeListener("socket", startTimer); + } + } + + // Attach callback if passed if (callback) { - this.once("timeout", callback); + this.on("timeout", callback); } + // Start the timer if or when the socket is opened if (this.socket) { - startTimer(this, msecs); + startTimer(this.socket); } else { - var self = this; - this._currentRequest.once("socket", function () { - startTimer(self, msecs); - }); + this._currentRequest.once("socket", startTimer); } - this.once("response", clearTimer); - this.once("error", clearTimer); + // Clean up on events + this.on("socket", destroyOnTimeout); + this.on("abort", clearTimer); + this.on("error", clearTimer); + this.on("response", clearTimer); return this; }; -function startTimer(request, msecs) { - clearTimeout(request._timeout); - request._timeout = setTimeout(function () { - request.emit("timeout"); - }, msecs); -} - -function clearTimer() { - clearTimeout(this._timeout); -} - // Proxy all other public ClientRequest methods [ - "abort", "flushHeaders", "getHeader", + "flushHeaders", "getHeader", "setNoDelay", "setSocketKeepAlive", ].forEach(function (method) { RedirectableRequest.prototype[method] = function (a, b) { @@ -14196,11 +14234,8 @@ RedirectableRequest.prototype._performRequest = function () { // Set up event handlers request._redirectable = this; - for (var event in eventHandlers) { - /* istanbul ignore else */ - if (event) { - request.on(event, eventHandlers[event]); - } + for (var e = 0; e < events.length; e++) { + request.on(events[e], eventHandlers[events[e]]); } // End a redirected request @@ -14254,86 +14289,101 @@ RedirectableRequest.prototype._processResponse = function (response) { // the user agent MAY automatically redirect its request to the URI // referenced by the Location field value, // even if the specific status code is not understood. + + // If the response is not a redirect; return it as-is var location = response.headers.location; - if (location && this._options.followRedirects !== false && - statusCode >= 300 && statusCode < 400) { - // Abort the current request - this._currentRequest.removeAllListeners(); - this._currentRequest.on("error", noop); - this._currentRequest.abort(); - // Discard the remainder of the response to avoid waiting for data - response.destroy(); - - // RFC7231§6.4: A client SHOULD detect and intervene - // in cyclical redirections (i.e., "infinite" redirection loops). - if (++this._redirectCount > this._options.maxRedirects) { - this.emit("error", new TooManyRedirectsError()); - return; - } + if (!location || this._options.followRedirects === false || + statusCode < 300 || statusCode >= 400) { + response.responseUrl = this._currentUrl; + response.redirects = this._redirects; + this.emit("response", response); - // RFC7231§6.4: Automatic redirection needs to done with - // care for methods not known to be safe, […] - // RFC7231§6.4.2–3: For historical reasons, a user agent MAY change - // the request method from POST to GET for the subsequent request. - if ((statusCode === 301 || statusCode === 302) && this._options.method === "POST" || - // RFC7231§6.4.4: The 303 (See Other) status code indicates that - // the server is redirecting the user agent to a different resource […] - // A user agent can perform a retrieval request targeting that URI - // (a GET or HEAD request if using HTTP) […] - (statusCode === 303) && !/^(?:GET|HEAD)$/.test(this._options.method)) { - this._options.method = "GET"; - // Drop a possible entity and headers related to it - this._requestBodyBuffers = []; - removeMatchingHeaders(/^content-/i, this._options.headers); - } - - // Drop the Host header, as the redirect might lead to a different host - var previousHostName = removeMatchingHeaders(/^host$/i, this._options.headers) || - url.parse(this._currentUrl).hostname; - - // Create the redirected request - var redirectUrl = url.resolve(this._currentUrl, location); - debug("redirecting to", redirectUrl); - this._isRedirect = true; - var redirectUrlParts = url.parse(redirectUrl); - Object.assign(this._options, redirectUrlParts); - - // Drop the Authorization header if redirecting to another host - if (redirectUrlParts.hostname !== previousHostName) { - removeMatchingHeaders(/^authorization$/i, this._options.headers); - } - - // Evaluate the beforeRedirect callback - if (typeof this._options.beforeRedirect === "function") { - var responseDetails = { headers: response.headers }; - try { - this._options.beforeRedirect.call(null, this._options, responseDetails); - } - catch (err) { - this.emit("error", err); - return; - } - this._sanitizeOptions(this._options); - } + // Clean up + this._requestBodyBuffers = []; + return; + } + + // The response is a redirect, so abort the current request + abortRequest(this._currentRequest); + // Discard the remainder of the response to avoid waiting for data + response.destroy(); + + // RFC7231§6.4: A client SHOULD detect and intervene + // in cyclical redirections (i.e., "infinite" redirection loops). + if (++this._redirectCount > this._options.maxRedirects) { + this.emit("error", new TooManyRedirectsError()); + return; + } + + // RFC7231§6.4: Automatic redirection needs to done with + // care for methods not known to be safe, […] + // RFC7231§6.4.2–3: For historical reasons, a user agent MAY change + // the request method from POST to GET for the subsequent request. + if ((statusCode === 301 || statusCode === 302) && this._options.method === "POST" || + // RFC7231§6.4.4: The 303 (See Other) status code indicates that + // the server is redirecting the user agent to a different resource […] + // A user agent can perform a retrieval request targeting that URI + // (a GET or HEAD request if using HTTP) […] + (statusCode === 303) && !/^(?:GET|HEAD)$/.test(this._options.method)) { + this._options.method = "GET"; + // Drop a possible entity and headers related to it + this._requestBodyBuffers = []; + removeMatchingHeaders(/^content-/i, this._options.headers); + } + + // Drop the Host header, as the redirect might lead to a different host + var currentHostHeader = removeMatchingHeaders(/^host$/i, this._options.headers); + + // If the redirect is relative, carry over the host of the last request + var currentUrlParts = url.parse(this._currentUrl); + var currentHost = currentHostHeader || currentUrlParts.host; + var currentUrl = /^\w+:/.test(location) ? this._currentUrl : + url.format(Object.assign(currentUrlParts, { host: currentHost })); + + // Determine the URL of the redirection + var redirectUrl; + try { + redirectUrl = url.resolve(currentUrl, location); + } + catch (cause) { + this.emit("error", new RedirectionError(cause)); + return; + } + + // Create the redirected request + debug("redirecting to", redirectUrl); + this._isRedirect = true; + var redirectUrlParts = url.parse(redirectUrl); + Object.assign(this._options, redirectUrlParts); - // Perform the redirected request + // 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)) { + removeMatchingHeaders(/^(?:authorization|cookie)$/i, this._options.headers); + } + + // Evaluate the beforeRedirect callback + if (typeof this._options.beforeRedirect === "function") { + var responseDetails = { headers: response.headers }; try { - this._performRequest(); + this._options.beforeRedirect.call(null, this._options, responseDetails); } - catch (cause) { - var error = new RedirectionError("Redirected request failed: " + cause.message); - error.cause = cause; - this.emit("error", error); + catch (err) { + this.emit("error", err); + return; } + this._sanitizeOptions(this._options); } - else { - // The response is not a redirect; return it as-is - response.responseUrl = this._currentUrl; - response.redirects = this._redirects; - this.emit("response", response); - // Clean up - this._requestBodyBuffers = []; + // Perform the redirected request + try { + this._performRequest(); + } + catch (cause) { + this.emit("error", new RedirectionError(cause)); } }; @@ -14353,7 +14403,7 @@ function wrap(protocols) { var wrappedProtocol = exports[scheme] = Object.create(nativeProtocol); // Executes a request, following redirects - wrappedProtocol.request = function (input, options, callback) { + function request(input, options, callback) { // Parse parameters if (typeof input === "string") { var urlStr = input; @@ -14388,14 +14438,20 @@ function wrap(protocols) { assert.equal(options.protocol, protocol, "protocol mismatch"); debug("options", options); return new RedirectableRequest(options, callback); - }; + } // Executes a GET request, following redirects - wrappedProtocol.get = function (input, options, callback) { - var request = wrappedProtocol.request(input, options, callback); - request.end(); - return request; - }; + function get(input, options, callback) { + var wrappedRequest = wrappedProtocol.request(input, options, callback); + wrappedRequest.end(); + return wrappedRequest; + } + + // Expose the properties on the wrapped protocol + Object.defineProperties(wrappedProtocol, { + request: { value: request, configurable: true, enumerable: true, writable: true }, + get: { value: get, configurable: true, enumerable: true, writable: true }, + }); }); return exports; } @@ -14431,13 +14487,20 @@ function removeMatchingHeaders(regex, headers) { delete headers[header]; } } - return lastValue; + return (lastValue === null || typeof lastValue === "undefined") ? + undefined : String(lastValue).trim(); } function createErrorType(code, defaultMessage) { - function CustomError(message) { + function CustomError(cause) { Error.captureStackTrace(this, this.constructor); - this.message = message || defaultMessage; + if (!cause) { + this.message = defaultMessage; + } + else { + this.message = defaultMessage + ": " + cause.message; + this.cause = cause; + } } CustomError.prototype = new Error(); CustomError.prototype.constructor = CustomError; @@ -14446,6 +14509,19 @@ function createErrorType(code, defaultMessage) { return CustomError; } +function abortRequest(request) { + for (var e = 0; e < events.length; e++) { + request.removeListener(events[e], eventHandlers[events[e]]); + } + request.on("error", noop); + request.abort(); +} + +function isSubdomain(subdomain, domain) { + const dot = subdomain.length - domain.length - 1; + return dot > 0 && subdomain[dot] === "." && subdomain.endsWith(domain); +} + // Exports module.exports = wrap({ http: http, https: https }); module.exports.wrap = wrap; @@ -14462,14 +14538,20 @@ module.exports = require("url"); /***/ (function(module, exports, __webpack_require__) { var debug; -try { - /* eslint global-require: off */ - debug = __webpack_require__(205)("follow-redirects"); -} -catch (error) { - debug = function () { /* */ }; -} -module.exports = debug; + +module.exports = function () { + if (!debug) { + try { + /* eslint global-require: off */ + debug = __webpack_require__(205)("follow-redirects"); + } + catch (error) { /* */ } + if (typeof debug !== "function") { + debug = function () { /* */ }; + } + } + debug.apply(null, arguments); +}; /***/ }), diff --git a/yarn.lock b/yarn.lock index 42b7f23176a81..8d38bbfbf2bea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15348,20 +15348,10 @@ follow-redirects@1.12.1: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.12.1.tgz#de54a6205311b93d60398ebc01cf7015682312b6" integrity sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg== -follow-redirects@^1.0.0, follow-redirects@^1.10.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" - integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== - -follow-redirects@^1.14.4: - version "1.14.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.6.tgz#8cfb281bbc035b3c067d6cd975b0f6ade6e855cd" - integrity sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A== - -follow-redirects@^1.14.7: - version "1.14.8" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" - integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== +follow-redirects@^1.0.0, follow-redirects@^1.10.0, follow-redirects@^1.14.4, follow-redirects@^1.14.7: + version "1.14.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" + integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== font-awesome@4.7.0: version "4.7.0" @@ -29567,9 +29557,9 @@ url-parse-lax@^3.0.0: prepend-http "^2.0.0" url-parse@^1.4.3, url-parse@^1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" - integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== + version "1.5.9" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.9.tgz#05ff26484a0b5e4040ac64dcee4177223d74675e" + integrity sha512-HpOvhKBvre8wYez+QhHcYiVvVmeF6DVnuSOOPhe3cTum3BnqHhvKaZm8FU5yTiOu/Jut2ZpB2rA/SbBA1JIGlQ== dependencies: querystringify "^2.1.1" requires-port "^1.0.0"