nativescript
Version:
Command-line interface for building NativeScript projects
178 lines • 8.4 kB
JavaScript
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
;