API Docs for: 1.0.8
Show:

File: client/lib/request.js

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
define(['./hawk', './errors'], function (hawk, ERRORS) {
  'use strict';
  /* global XMLHttpRequest */

  /**
   * @class Request
   * @constructor
   * @param {String} baseUri Base URI
   * @param {Object} xhr XMLHttpRequest constructor
   * @param {Object} [options={}] Options
   *   @param {Number} [options.localtimeOffsetMsec]
   *   Local time offset with the remote auth server's clock
   */
  function Request (baseUri, xhr, options) {
    if (!options) {
      options = {};
    }
    this.baseUri = baseUri;
    this._localtimeOffsetMsec = options.localtimeOffsetMsec;
    this.xhr = xhr || XMLHttpRequest;
    this.timeout = options.timeout || 30 * 1000;
  }

  /**
   * @method send
   * @param {String} path Request path
   * @param {String} method HTTP Method
   * @param {Object} credentials HAWK Headers
   * @param {Object} jsonPayload JSON Payload
   * @param {Object} [options={}] Options
   *   @param {String} [options.retrying]
   *   Flag indicating if the request is a retry
   *   @param {Array} [options.headers]
   *   A set of extra headers to add to the request
   * @return {Promise} A promise that will be fulfilled with JSON `xhr.responseText` of the request
   */
  Request.prototype.send = function request(path, method, credentials, jsonPayload, options) {
    /*eslint complexity: [2, 8] */
    var xhr = new this.xhr();
    var uri = this.baseUri + path;
    var payload = null;
    var self = this;
    options = options || {};

    if (jsonPayload) {
      payload = JSON.stringify(jsonPayload);
    }

    try {
      xhr.open(method, uri);
    } catch (e) {
      return Promise.reject({ error: 'Unknown error', message: e.toString(), errno: 999 });
    }

    return new Promise(function (resolve, reject) {
      xhr.timeout = self.timeout;

      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
          var result = xhr.responseText;
          try {
            result = JSON.parse(xhr.responseText);
          } catch (e) { }

          if (result.errno) {
            // Try to recover from a timeskew error and not already tried
            if (result.errno === ERRORS.INVALID_TIMESTAMP && !options.retrying) {
              var serverTime = result.serverTime;
              self._localtimeOffsetMsec = (serverTime * 1000) - new Date().getTime();

              // add to options that the request is retrying
              options.retrying = true;

              return self.send(path, method, credentials, jsonPayload, options)
                .then(resolve, reject);

            } else {
              return reject(result);
            }
          }

          if (typeof xhr.status === 'undefined' || xhr.status !== 200) {
            if (result.length === 0) {
              return reject({ error: 'Timeout error', errno: 999 });
            } else {
              return reject({ error: 'Unknown error', message: result, errno: 999, code: xhr.status });
            }
          }

          resolve(result);
        }
      };

      // calculate Hawk header if credentials are supplied
      if (credentials) {
        var hawkHeader = hawk.client.header(uri, method, {
                            credentials: credentials,
                            payload: payload,
                            contentType: 'application/json',
                            localtimeOffsetMsec: self._localtimeOffsetMsec || 0
                          });
        xhr.setRequestHeader('authorization', hawkHeader.field);
      }

      xhr.setRequestHeader('Content-Type', 'application/json');

      if (options && options.headers) {
        // set extra headers for this request
        for (var header in options.headers) {
          xhr.setRequestHeader(header, options.headers[header]);
        }
      }

      xhr.send(payload);
    });
  };

  return Request;

});