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