src/scripts/utils/http.js
'use strict';
var urlUtils = require('./urlUtils');
var utilities = require('./utilityFunctions');
function HttpRequestError(message) {
this.message = 'HttpRequest Error: ' + (message || '');
}
HttpRequestError.prototype = new Error();
HttpRequestError.prototype.name = "HttpRequest Error";
function HttpRequest(createXhr) {
if (!utilities.isFunction(createXhr)) {
throw new HttpRequestError('Missing XMLHttpRequest factory method');
}
this.createXhr = createXhr;
}
HttpRequest.prototype.run = function (method, url, callback, options) {
sanityCheck(url, callback, options);
var timeout, timeoutId;
var xhr = this.createXhr();
options = options || {};
timeout = utilities.isNumber(options.timeout) ? options.timeout : 0;
xhr.open(method, urlUtils.urlParts(url).href, true);
if (options.headers) {
setHeaders(xhr, options.headers);
}
if (options.withCredentials) {
xhr.withCredentials = true;
}
xhr.onload = function () {
var statusText, response, status;
/**
* The only way to do a secure request on IE8 and IE9 is with the XDomainRequest object. Unfortunately, microsoft is
* so nice that decided that the status property and the 'getAllResponseHeaders' method where not needed so we have to
* fake them. If the request gets done with an XDomainRequest instance, we will assume that there are no headers and
* the status will always be 200. If you don't like it, DO NOT USE ANCIENT BROWSERS!!!
*
* For mor info go to: https://msdn.microsoft.com/en-us/library/cc288060(v=vs.85).aspx
*/
if (!xhr.getAllResponseHeaders) {
xhr.getAllResponseHeaders = function () {
return null;
};
}
if (!xhr.status) {
xhr.status = 200;
}
if (utilities.isDefined(timeoutId)) {
clearTimeout(timeoutId);
timeoutId = undefined;
}
statusText = xhr.statusText || '';
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
response = ('response' in xhr) ? xhr.response : xhr.responseText;
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
status = xhr.status === 1223 ? 204 : xhr.status;
callback(
status,
response,
xhr.getAllResponseHeaders(),
statusText);
};
xhr.onerror = requestError;
xhr.onabort = requestError;
xhr.send();
if (timeout > 0) {
timeoutId = setTimeout(function () {
xhr && xhr.abort();
}, timeout);
}
function sanityCheck(url, callback, options) {
if (!utilities.isString(url) || utilities.isEmptyString(url)) {
throw new HttpRequestError("Invalid url '" + url + "'");
}
if (!utilities.isFunction(callback)) {
throw new HttpRequestError("Invalid handler '" + callback + "' for the http request");
}
if (utilities.isDefined(options) && !utilities.isObject(options)) {
throw new HttpRequestError("Invalid options map '" + options + "'");
}
}
function setHeaders(xhr, headers) {
utilities.forEach(headers, function (value, key) {
if (utilities.isDefined(value)) {
xhr.setRequestHeader(key, value);
}
});
}
function requestError() {
callback(-1, null, null, '');
}
};
HttpRequest.prototype.get = function (url, callback, options) {
this.run('GET', url, processResponse, options);
function processResponse(status, response, headersString, statusText) {
if (isSuccess(status)) {
callback(null, response, status, headersString, statusText);
} else {
callback(new HttpRequestError(statusText), response, status, headersString, statusText);
}
}
function isSuccess(status) {
return 200 <= status && status < 300;
}
};
function createXhr() {
var xhr = new XMLHttpRequest();
if (!("withCredentials" in xhr)) {
// XDomainRequest for IE.
xhr = new XDomainRequest();
}
return xhr;
}
var http = new HttpRequest(createXhr);
module.exports = {
http: http,
HttpRequest: HttpRequest,
HttpRequestError: HttpRequestError,
createXhr: createXhr
};