github.com/jfrog/frogbot@v1.1.1-0.20231221090046-821a26f50338/action/node_modules/@actions/http-client/lib/index.js (about) 1 "use strict"; 2 /* eslint-disable @typescript-eslint/no-explicit-any */ 3 var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 4 if (k2 === undefined) k2 = k; 5 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 6 }) : (function(o, m, k, k2) { 7 if (k2 === undefined) k2 = k; 8 o[k2] = m[k]; 9 })); 10 var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 11 Object.defineProperty(o, "default", { enumerable: true, value: v }); 12 }) : function(o, v) { 13 o["default"] = v; 14 }); 15 var __importStar = (this && this.__importStar) || function (mod) { 16 if (mod && mod.__esModule) return mod; 17 var result = {}; 18 if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 19 __setModuleDefault(result, mod); 20 return result; 21 }; 22 var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 23 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 24 return new (P || (P = Promise))(function (resolve, reject) { 25 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 26 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 27 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 28 step((generator = generator.apply(thisArg, _arguments || [])).next()); 29 }); 30 }; 31 Object.defineProperty(exports, "__esModule", { value: true }); 32 exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0; 33 const http = __importStar(require("http")); 34 const https = __importStar(require("https")); 35 const pm = __importStar(require("./proxy")); 36 const tunnel = __importStar(require("tunnel")); 37 var HttpCodes; 38 (function (HttpCodes) { 39 HttpCodes[HttpCodes["OK"] = 200] = "OK"; 40 HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices"; 41 HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently"; 42 HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved"; 43 HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther"; 44 HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified"; 45 HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy"; 46 HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy"; 47 HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect"; 48 HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect"; 49 HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest"; 50 HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized"; 51 HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired"; 52 HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden"; 53 HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound"; 54 HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed"; 55 HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable"; 56 HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired"; 57 HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout"; 58 HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict"; 59 HttpCodes[HttpCodes["Gone"] = 410] = "Gone"; 60 HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests"; 61 HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError"; 62 HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented"; 63 HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway"; 64 HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable"; 65 HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout"; 66 })(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {})); 67 var Headers; 68 (function (Headers) { 69 Headers["Accept"] = "accept"; 70 Headers["ContentType"] = "content-type"; 71 })(Headers = exports.Headers || (exports.Headers = {})); 72 var MediaTypes; 73 (function (MediaTypes) { 74 MediaTypes["ApplicationJson"] = "application/json"; 75 })(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {})); 76 /** 77 * Returns the proxy URL, depending upon the supplied url and proxy environment variables. 78 * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com 79 */ 80 function getProxyUrl(serverUrl) { 81 const proxyUrl = pm.getProxyUrl(new URL(serverUrl)); 82 return proxyUrl ? proxyUrl.href : ''; 83 } 84 exports.getProxyUrl = getProxyUrl; 85 const HttpRedirectCodes = [ 86 HttpCodes.MovedPermanently, 87 HttpCodes.ResourceMoved, 88 HttpCodes.SeeOther, 89 HttpCodes.TemporaryRedirect, 90 HttpCodes.PermanentRedirect 91 ]; 92 const HttpResponseRetryCodes = [ 93 HttpCodes.BadGateway, 94 HttpCodes.ServiceUnavailable, 95 HttpCodes.GatewayTimeout 96 ]; 97 const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD']; 98 const ExponentialBackoffCeiling = 10; 99 const ExponentialBackoffTimeSlice = 5; 100 class HttpClientError extends Error { 101 constructor(message, statusCode) { 102 super(message); 103 this.name = 'HttpClientError'; 104 this.statusCode = statusCode; 105 Object.setPrototypeOf(this, HttpClientError.prototype); 106 } 107 } 108 exports.HttpClientError = HttpClientError; 109 class HttpClientResponse { 110 constructor(message) { 111 this.message = message; 112 } 113 readBody() { 114 return __awaiter(this, void 0, void 0, function* () { 115 return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { 116 let output = Buffer.alloc(0); 117 this.message.on('data', (chunk) => { 118 output = Buffer.concat([output, chunk]); 119 }); 120 this.message.on('end', () => { 121 resolve(output.toString()); 122 }); 123 })); 124 }); 125 } 126 } 127 exports.HttpClientResponse = HttpClientResponse; 128 function isHttps(requestUrl) { 129 const parsedUrl = new URL(requestUrl); 130 return parsedUrl.protocol === 'https:'; 131 } 132 exports.isHttps = isHttps; 133 class HttpClient { 134 constructor(userAgent, handlers, requestOptions) { 135 this._ignoreSslError = false; 136 this._allowRedirects = true; 137 this._allowRedirectDowngrade = false; 138 this._maxRedirects = 50; 139 this._allowRetries = false; 140 this._maxRetries = 1; 141 this._keepAlive = false; 142 this._disposed = false; 143 this.userAgent = userAgent; 144 this.handlers = handlers || []; 145 this.requestOptions = requestOptions; 146 if (requestOptions) { 147 if (requestOptions.ignoreSslError != null) { 148 this._ignoreSslError = requestOptions.ignoreSslError; 149 } 150 this._socketTimeout = requestOptions.socketTimeout; 151 if (requestOptions.allowRedirects != null) { 152 this._allowRedirects = requestOptions.allowRedirects; 153 } 154 if (requestOptions.allowRedirectDowngrade != null) { 155 this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade; 156 } 157 if (requestOptions.maxRedirects != null) { 158 this._maxRedirects = Math.max(requestOptions.maxRedirects, 0); 159 } 160 if (requestOptions.keepAlive != null) { 161 this._keepAlive = requestOptions.keepAlive; 162 } 163 if (requestOptions.allowRetries != null) { 164 this._allowRetries = requestOptions.allowRetries; 165 } 166 if (requestOptions.maxRetries != null) { 167 this._maxRetries = requestOptions.maxRetries; 168 } 169 } 170 } 171 options(requestUrl, additionalHeaders) { 172 return __awaiter(this, void 0, void 0, function* () { 173 return this.request('OPTIONS', requestUrl, null, additionalHeaders || {}); 174 }); 175 } 176 get(requestUrl, additionalHeaders) { 177 return __awaiter(this, void 0, void 0, function* () { 178 return this.request('GET', requestUrl, null, additionalHeaders || {}); 179 }); 180 } 181 del(requestUrl, additionalHeaders) { 182 return __awaiter(this, void 0, void 0, function* () { 183 return this.request('DELETE', requestUrl, null, additionalHeaders || {}); 184 }); 185 } 186 post(requestUrl, data, additionalHeaders) { 187 return __awaiter(this, void 0, void 0, function* () { 188 return this.request('POST', requestUrl, data, additionalHeaders || {}); 189 }); 190 } 191 patch(requestUrl, data, additionalHeaders) { 192 return __awaiter(this, void 0, void 0, function* () { 193 return this.request('PATCH', requestUrl, data, additionalHeaders || {}); 194 }); 195 } 196 put(requestUrl, data, additionalHeaders) { 197 return __awaiter(this, void 0, void 0, function* () { 198 return this.request('PUT', requestUrl, data, additionalHeaders || {}); 199 }); 200 } 201 head(requestUrl, additionalHeaders) { 202 return __awaiter(this, void 0, void 0, function* () { 203 return this.request('HEAD', requestUrl, null, additionalHeaders || {}); 204 }); 205 } 206 sendStream(verb, requestUrl, stream, additionalHeaders) { 207 return __awaiter(this, void 0, void 0, function* () { 208 return this.request(verb, requestUrl, stream, additionalHeaders); 209 }); 210 } 211 /** 212 * Gets a typed object from an endpoint 213 * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise 214 */ 215 getJson(requestUrl, additionalHeaders = {}) { 216 return __awaiter(this, void 0, void 0, function* () { 217 additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 218 const res = yield this.get(requestUrl, additionalHeaders); 219 return this._processResponse(res, this.requestOptions); 220 }); 221 } 222 postJson(requestUrl, obj, additionalHeaders = {}) { 223 return __awaiter(this, void 0, void 0, function* () { 224 const data = JSON.stringify(obj, null, 2); 225 additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 226 additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); 227 const res = yield this.post(requestUrl, data, additionalHeaders); 228 return this._processResponse(res, this.requestOptions); 229 }); 230 } 231 putJson(requestUrl, obj, additionalHeaders = {}) { 232 return __awaiter(this, void 0, void 0, function* () { 233 const data = JSON.stringify(obj, null, 2); 234 additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 235 additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); 236 const res = yield this.put(requestUrl, data, additionalHeaders); 237 return this._processResponse(res, this.requestOptions); 238 }); 239 } 240 patchJson(requestUrl, obj, additionalHeaders = {}) { 241 return __awaiter(this, void 0, void 0, function* () { 242 const data = JSON.stringify(obj, null, 2); 243 additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 244 additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); 245 const res = yield this.patch(requestUrl, data, additionalHeaders); 246 return this._processResponse(res, this.requestOptions); 247 }); 248 } 249 /** 250 * Makes a raw http request. 251 * All other methods such as get, post, patch, and request ultimately call this. 252 * Prefer get, del, post and patch 253 */ 254 request(verb, requestUrl, data, headers) { 255 return __awaiter(this, void 0, void 0, function* () { 256 if (this._disposed) { 257 throw new Error('Client has already been disposed.'); 258 } 259 const parsedUrl = new URL(requestUrl); 260 let info = this._prepareRequest(verb, parsedUrl, headers); 261 // Only perform retries on reads since writes may not be idempotent. 262 const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb) 263 ? this._maxRetries + 1 264 : 1; 265 let numTries = 0; 266 let response; 267 do { 268 response = yield this.requestRaw(info, data); 269 // Check if it's an authentication challenge 270 if (response && 271 response.message && 272 response.message.statusCode === HttpCodes.Unauthorized) { 273 let authenticationHandler; 274 for (const handler of this.handlers) { 275 if (handler.canHandleAuthentication(response)) { 276 authenticationHandler = handler; 277 break; 278 } 279 } 280 if (authenticationHandler) { 281 return authenticationHandler.handleAuthentication(this, info, data); 282 } 283 else { 284 // We have received an unauthorized response but have no handlers to handle it. 285 // Let the response return to the caller. 286 return response; 287 } 288 } 289 let redirectsRemaining = this._maxRedirects; 290 while (response.message.statusCode && 291 HttpRedirectCodes.includes(response.message.statusCode) && 292 this._allowRedirects && 293 redirectsRemaining > 0) { 294 const redirectUrl = response.message.headers['location']; 295 if (!redirectUrl) { 296 // if there's no location to redirect to, we won't 297 break; 298 } 299 const parsedRedirectUrl = new URL(redirectUrl); 300 if (parsedUrl.protocol === 'https:' && 301 parsedUrl.protocol !== parsedRedirectUrl.protocol && 302 !this._allowRedirectDowngrade) { 303 throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.'); 304 } 305 // we need to finish reading the response before reassigning response 306 // which will leak the open socket. 307 yield response.readBody(); 308 // strip authorization header if redirected to a different hostname 309 if (parsedRedirectUrl.hostname !== parsedUrl.hostname) { 310 for (const header in headers) { 311 // header names are case insensitive 312 if (header.toLowerCase() === 'authorization') { 313 delete headers[header]; 314 } 315 } 316 } 317 // let's make the request with the new redirectUrl 318 info = this._prepareRequest(verb, parsedRedirectUrl, headers); 319 response = yield this.requestRaw(info, data); 320 redirectsRemaining--; 321 } 322 if (!response.message.statusCode || 323 !HttpResponseRetryCodes.includes(response.message.statusCode)) { 324 // If not a retry code, return immediately instead of retrying 325 return response; 326 } 327 numTries += 1; 328 if (numTries < maxTries) { 329 yield response.readBody(); 330 yield this._performExponentialBackoff(numTries); 331 } 332 } while (numTries < maxTries); 333 return response; 334 }); 335 } 336 /** 337 * Needs to be called if keepAlive is set to true in request options. 338 */ 339 dispose() { 340 if (this._agent) { 341 this._agent.destroy(); 342 } 343 this._disposed = true; 344 } 345 /** 346 * Raw request. 347 * @param info 348 * @param data 349 */ 350 requestRaw(info, data) { 351 return __awaiter(this, void 0, void 0, function* () { 352 return new Promise((resolve, reject) => { 353 function callbackForResult(err, res) { 354 if (err) { 355 reject(err); 356 } 357 else if (!res) { 358 // If `err` is not passed, then `res` must be passed. 359 reject(new Error('Unknown error')); 360 } 361 else { 362 resolve(res); 363 } 364 } 365 this.requestRawWithCallback(info, data, callbackForResult); 366 }); 367 }); 368 } 369 /** 370 * Raw request with callback. 371 * @param info 372 * @param data 373 * @param onResult 374 */ 375 requestRawWithCallback(info, data, onResult) { 376 if (typeof data === 'string') { 377 if (!info.options.headers) { 378 info.options.headers = {}; 379 } 380 info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8'); 381 } 382 let callbackCalled = false; 383 function handleResult(err, res) { 384 if (!callbackCalled) { 385 callbackCalled = true; 386 onResult(err, res); 387 } 388 } 389 const req = info.httpModule.request(info.options, (msg) => { 390 const res = new HttpClientResponse(msg); 391 handleResult(undefined, res); 392 }); 393 let socket; 394 req.on('socket', sock => { 395 socket = sock; 396 }); 397 // If we ever get disconnected, we want the socket to timeout eventually 398 req.setTimeout(this._socketTimeout || 3 * 60000, () => { 399 if (socket) { 400 socket.end(); 401 } 402 handleResult(new Error(`Request timeout: ${info.options.path}`)); 403 }); 404 req.on('error', function (err) { 405 // err has statusCode property 406 // res should have headers 407 handleResult(err); 408 }); 409 if (data && typeof data === 'string') { 410 req.write(data, 'utf8'); 411 } 412 if (data && typeof data !== 'string') { 413 data.on('close', function () { 414 req.end(); 415 }); 416 data.pipe(req); 417 } 418 else { 419 req.end(); 420 } 421 } 422 /** 423 * Gets an http agent. This function is useful when you need an http agent that handles 424 * routing through a proxy server - depending upon the url and proxy environment variables. 425 * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com 426 */ 427 getAgent(serverUrl) { 428 const parsedUrl = new URL(serverUrl); 429 return this._getAgent(parsedUrl); 430 } 431 _prepareRequest(method, requestUrl, headers) { 432 const info = {}; 433 info.parsedUrl = requestUrl; 434 const usingSsl = info.parsedUrl.protocol === 'https:'; 435 info.httpModule = usingSsl ? https : http; 436 const defaultPort = usingSsl ? 443 : 80; 437 info.options = {}; 438 info.options.host = info.parsedUrl.hostname; 439 info.options.port = info.parsedUrl.port 440 ? parseInt(info.parsedUrl.port) 441 : defaultPort; 442 info.options.path = 443 (info.parsedUrl.pathname || '') + (info.parsedUrl.search || ''); 444 info.options.method = method; 445 info.options.headers = this._mergeHeaders(headers); 446 if (this.userAgent != null) { 447 info.options.headers['user-agent'] = this.userAgent; 448 } 449 info.options.agent = this._getAgent(info.parsedUrl); 450 // gives handlers an opportunity to participate 451 if (this.handlers) { 452 for (const handler of this.handlers) { 453 handler.prepareRequest(info.options); 454 } 455 } 456 return info; 457 } 458 _mergeHeaders(headers) { 459 if (this.requestOptions && this.requestOptions.headers) { 460 return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers || {})); 461 } 462 return lowercaseKeys(headers || {}); 463 } 464 _getExistingOrDefaultHeader(additionalHeaders, header, _default) { 465 let clientHeader; 466 if (this.requestOptions && this.requestOptions.headers) { 467 clientHeader = lowercaseKeys(this.requestOptions.headers)[header]; 468 } 469 return additionalHeaders[header] || clientHeader || _default; 470 } 471 _getAgent(parsedUrl) { 472 let agent; 473 const proxyUrl = pm.getProxyUrl(parsedUrl); 474 const useProxy = proxyUrl && proxyUrl.hostname; 475 if (this._keepAlive && useProxy) { 476 agent = this._proxyAgent; 477 } 478 if (this._keepAlive && !useProxy) { 479 agent = this._agent; 480 } 481 // if agent is already assigned use that agent. 482 if (agent) { 483 return agent; 484 } 485 const usingSsl = parsedUrl.protocol === 'https:'; 486 let maxSockets = 100; 487 if (this.requestOptions) { 488 maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets; 489 } 490 // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis. 491 if (proxyUrl && proxyUrl.hostname) { 492 const agentOptions = { 493 maxSockets, 494 keepAlive: this._keepAlive, 495 proxy: Object.assign(Object.assign({}, ((proxyUrl.username || proxyUrl.password) && { 496 proxyAuth: `${proxyUrl.username}:${proxyUrl.password}` 497 })), { host: proxyUrl.hostname, port: proxyUrl.port }) 498 }; 499 let tunnelAgent; 500 const overHttps = proxyUrl.protocol === 'https:'; 501 if (usingSsl) { 502 tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp; 503 } 504 else { 505 tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp; 506 } 507 agent = tunnelAgent(agentOptions); 508 this._proxyAgent = agent; 509 } 510 // if reusing agent across request and tunneling agent isn't assigned create a new agent 511 if (this._keepAlive && !agent) { 512 const options = { keepAlive: this._keepAlive, maxSockets }; 513 agent = usingSsl ? new https.Agent(options) : new http.Agent(options); 514 this._agent = agent; 515 } 516 // if not using private agent and tunnel agent isn't setup then use global agent 517 if (!agent) { 518 agent = usingSsl ? https.globalAgent : http.globalAgent; 519 } 520 if (usingSsl && this._ignoreSslError) { 521 // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process 522 // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options 523 // we have to cast it to any and change it directly 524 agent.options = Object.assign(agent.options || {}, { 525 rejectUnauthorized: false 526 }); 527 } 528 return agent; 529 } 530 _performExponentialBackoff(retryNumber) { 531 return __awaiter(this, void 0, void 0, function* () { 532 retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber); 533 const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber); 534 return new Promise(resolve => setTimeout(() => resolve(), ms)); 535 }); 536 } 537 _processResponse(res, options) { 538 return __awaiter(this, void 0, void 0, function* () { 539 return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { 540 const statusCode = res.message.statusCode || 0; 541 const response = { 542 statusCode, 543 result: null, 544 headers: {} 545 }; 546 // not found leads to null obj returned 547 if (statusCode === HttpCodes.NotFound) { 548 resolve(response); 549 } 550 // get the result from the body 551 function dateTimeDeserializer(key, value) { 552 if (typeof value === 'string') { 553 const a = new Date(value); 554 if (!isNaN(a.valueOf())) { 555 return a; 556 } 557 } 558 return value; 559 } 560 let obj; 561 let contents; 562 try { 563 contents = yield res.readBody(); 564 if (contents && contents.length > 0) { 565 if (options && options.deserializeDates) { 566 obj = JSON.parse(contents, dateTimeDeserializer); 567 } 568 else { 569 obj = JSON.parse(contents); 570 } 571 response.result = obj; 572 } 573 response.headers = res.message.headers; 574 } 575 catch (err) { 576 // Invalid resource (contents not json); leaving result obj null 577 } 578 // note that 3xx redirects are handled by the http layer. 579 if (statusCode > 299) { 580 let msg; 581 // if exception/error in body, attempt to get better error 582 if (obj && obj.message) { 583 msg = obj.message; 584 } 585 else if (contents && contents.length > 0) { 586 // it may be the case that the exception is in the body message as string 587 msg = contents; 588 } 589 else { 590 msg = `Failed request: (${statusCode})`; 591 } 592 const err = new HttpClientError(msg, statusCode); 593 err.result = response.result; 594 reject(err); 595 } 596 else { 597 resolve(response); 598 } 599 })); 600 }); 601 } 602 } 603 exports.HttpClient = HttpClient; 604 const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {}); 605 //# sourceMappingURL=index.js.map