UNPKG

nativescript

Version:

Command-line interface for building NativeScript projects

178 lines • 8.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HttpClient = void 0; const _ = require("lodash"); const os_1 = require("os"); const util = require("util"); const yok_1 = require("./yok"); const axios_1 = require("axios"); const constants_1 = require("./constants"); const tunnel = require("tunnel"); class HttpClient { constructor($logger, $proxyService, $staticConfig) { this.$logger = $logger; this.$proxyService = $proxyService; this.$staticConfig = $staticConfig; } async httpRequest(options, proxySettings) { try { const result = await this.httpRequestCore(options, proxySettings); return { response: result, body: result.body, headers: result.headers, }; } catch (err) { if (err.message === HttpClient.STUCK_REQUEST_ERROR_MESSAGE || err.message === HttpClient.STUCK_RESPONSE_ERROR_MESSAGE) { // Retry the request immediately because there are at least 10 seconds between the two requests. // We have to retry only once the sporadically stuck requests/responses. // We can add exponential backoff retry here if we decide that we need to workaround bigger network issues on the client side. this.$logger.warn("%s Retrying request to %s...", err.message, options.url || options); const retryResult = await this.httpRequestCore(options, proxySettings); return { response: retryResult, body: retryResult.body, headers: retryResult.headers, }; } throw err; } } async httpRequestCore(options, proxySettings) { if (_.isString(options)) { options = { url: options, method: "GET", }; } const cliProxySettings = await this.$proxyService.getCache(); const requestProto = options.proto || "http"; options.headers = options.headers || {}; const headers = options.headers; await this.useProxySettings(proxySettings, cliProxySettings, options, headers, requestProto); if (!headers["User-Agent"]) { if (!this.defaultUserAgent) { //TODO: the user agent client name is also passed explicitly during login and should be kept in sync this.defaultUserAgent = `${this.$staticConfig.USER_AGENT_NAME}/${this.$staticConfig.version} (Node.js ${process.versions.node}; ${process.platform}; ${process.arch})`; this.$logger.trace("User-Agent: %s", this.defaultUserAgent); } headers["User-Agent"] = this.defaultUserAgent; } if (!headers["Accept-Encoding"]) { headers["Accept-Encoding"] = "gzip,deflate"; } this.$logger.trace("httpRequest: %s", util.inspect(options)); let agent; if (cliProxySettings) { agent = tunnel.httpsOverHttp({ proxy: { host: cliProxySettings.hostname, port: parseInt(cliProxySettings.port), }, }); } const result = await (0, axios_1.default)({ url: options.url, headers: options.headers, method: options.method, proxy: false, httpAgent: agent, data: options.body, }).catch((err) => { this.$logger.trace("An error occurred while sending the request:", err); if (err.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx const errorMessage = this.getErrorMessage(err.response.status, null); err.proxyAuthenticationRequired = err.response.status === constants_1.HttpStatusCodes.PROXY_AUTHENTICATION_REQUIRED; err.message = errorMessage || err.message; } else if (err.request) { // The request was made but no response was received // `err.request` is an instance of XMLHttpRequest in the browser and an instance of } else { // Something happened in setting up the request that triggered an Error } throw err; }); if (result) { this.$logger.trace("httpRequest: Done. code = %d", result.status.toString()); return { response: result, body: JSON.stringify(result.data), headers: result.headers, }; } } getErrorMessage(statusCode, body) { if (statusCode === constants_1.HttpStatusCodes.PROXY_AUTHENTICATION_REQUIRED) { const clientNameLowerCase = this.$staticConfig.CLIENT_NAME.toLowerCase(); this.$logger.error(`You can run ${os_1.EOL}\t${clientNameLowerCase} proxy set <url> <username> <password>.${os_1.EOL}In order to supply ${clientNameLowerCase} with the credentials needed.`); return "Your proxy requires authentication."; } else if (statusCode === constants_1.HttpStatusCodes.PAYMENT_REQUIRED) { return "Your subscription has expired."; } else if (statusCode === constants_1.HttpStatusCodes.CONFLICTING_RESOURCE) { return "The request conflicts with the current state of the server."; } else { this.$logger.trace("Request was unsuccessful. Server returned: ", body); try { const err = JSON.parse(body); if (_.isString(err)) { return err; } if (err && err.ExceptionMessage) { return err.ExceptionMessage; } if (err && err.Message) { return err.Message; } } catch (parsingFailed) { this.$logger.trace("Failed to get error from http request: ", parsingFailed); return `The server returned unexpected response: ${body}`; } return body; } } /** * This method respects the proxySettings (or proxyCache) by modifying headers and options passed to http(s) module. * @param {IProxySettings} proxySettings The settings passed for this specific call. * @param {IProxySettings} cliProxySettings The globally set proxy for this CLI. * @param {any}options The object that will be passed to http(s) module. * @param {any} headers Headers of the current request. * @param {string} requestProto The protocol used for the current request - http or https. */ async useProxySettings(proxySettings, cliProxySettings, options, headers, requestProto) { const isLocalRequest = options.host === "localhost" || options.host === "127.0.0.1"; // don't use the proxy for requests to localhost if (!isLocalRequest && (proxySettings || cliProxySettings)) { const proto = (proxySettings && proxySettings.protocol) || cliProxySettings.protocol || "http:"; const host = (proxySettings && proxySettings.hostname) || cliProxySettings.hostname; const port = (proxySettings && proxySettings.port) || cliProxySettings.port; let credentialsPart = ""; if (cliProxySettings.username && cliProxySettings.password) { credentialsPart = `${cliProxySettings.username}:${cliProxySettings.password}@`; } // Note that proto ends with : options.proxy = `${proto}//${credentialsPart}${host}:${port}`; options.rejectUnauthorized = proxySettings ? proxySettings.rejectUnauthorized : cliProxySettings.rejectUnauthorized; this.$logger.trace("Using proxy: %s", options.proxy); } } } exports.HttpClient = HttpClient; HttpClient.STUCK_REQUEST_ERROR_MESSAGE = "The request can't receive any response."; HttpClient.STUCK_RESPONSE_ERROR_MESSAGE = "Can't receive all parts of the response."; yok_1.injector.register("httpClient", HttpClient); //# sourceMappingURL=http-client.js.map