"use strict"; var window = require("global/window"); var _extends = require("@babel/runtime/helpers/extends"); var isFunction = require('is-function'); createXHR.httpHandler = require('./http-handler.js'); /** * @license * slighly modified parse-headers 2.0.2 * Copyright (c) 2014 David Björklund * Available under the MIT license * */ var parseHeaders = function parseHeaders(headers) { var result = {}; if (!headers) { return result; } headers.trim().split('\n').forEach(function (row) { var index = row.indexOf(':'); var key = row.slice(0, index).trim().toLowerCase(); var value = row.slice(index + 1).trim(); if (typeof result[key] === 'undefined') { result[key] = value; } else if (Array.isArray(result[key])) { result[key].push(value); } else { result[key] = [result[key], value]; } }); return result; }; module.exports = createXHR; // Allow use of default import syntax in TypeScript module.exports.default = createXHR; createXHR.XMLHttpRequest = window.XMLHttpRequest || noop; createXHR.XDomainRequest = "withCredentials" in new createXHR.XMLHttpRequest() ? createXHR.XMLHttpRequest : window.XDomainRequest; forEachArray(["get", "put", "post", "patch", "head", "delete"], function (method) { createXHR[method === "delete" ? "del" : method] = function (uri, options, callback) { options = initParams(uri, options, callback); options.method = method.toUpperCase(); return _createXHR(options); }; }); function forEachArray(array, iterator) { for (var i = 0; i < array.length; i++) { iterator(array[i]); } } function isEmpty(obj) { for (var i in obj) { if (obj.hasOwnProperty(i)) return false; } return true; } function initParams(uri, options, callback) { var params = uri; if (isFunction(options)) { callback = options; if (typeof uri === "string") { params = { uri: uri }; } } else { params = _extends({}, options, { uri: uri }); } params.callback = callback; return params; } function createXHR(uri, options, callback) { options = initParams(uri, options, callback); return _createXHR(options); } function _createXHR(options) { if (typeof options.callback === "undefined") { throw new Error("callback argument missing"); } var called = false; var callback = function cbOnce(err, response, body) { if (!called) { called = true; options.callback(err, response, body); } }; function readystatechange() { if (xhr.readyState === 4) { setTimeout(loadFunc, 0); } } function getBody() { // Chrome with requestType=blob throws errors arround when even testing access to responseText var body = undefined; if (xhr.response) { body = xhr.response; } else { body = xhr.responseText || getXml(xhr); } if (isJson) { try { body = JSON.parse(body); } catch (e) {} } return body; } function errorFunc(evt) { clearTimeout(timeoutTimer); if (!(evt instanceof Error)) { evt = new Error("" + (evt || "Unknown XMLHttpRequest Error")); } evt.statusCode = 0; return callback(evt, failureResponse); } // will load the data & process the response in a special response object function loadFunc() { if (aborted) return; var status; clearTimeout(timeoutTimer); if (options.useXDR && xhr.status === undefined) { //IE8 CORS GET successful response doesn't have a status field, but body is fine status = 200; } else { status = xhr.status === 1223 ? 204 : xhr.status; } var response = failureResponse; var err = null; if (status !== 0) { response = { body: getBody(), statusCode: status, method: method, headers: {}, url: uri, rawRequest: xhr }; if (xhr.getAllResponseHeaders) { //remember xhr can in fact be XDR for CORS in IE response.headers = parseHeaders(xhr.getAllResponseHeaders()); } } else { err = new Error("Internal XMLHttpRequest Error"); } return callback(err, response, response.body); } var xhr = options.xhr || null; if (!xhr) { if (options.cors || options.useXDR) { xhr = new createXHR.XDomainRequest(); } else { xhr = new createXHR.XMLHttpRequest(); } } var key; var aborted; var uri = xhr.url = options.uri || options.url; var method = xhr.method = options.method || "GET"; var body = options.body || options.data; var headers = xhr.headers = options.headers || {}; var sync = !!options.sync; var isJson = false; var timeoutTimer; var failureResponse = { body: undefined, headers: {}, statusCode: 0, method: method, url: uri, rawRequest: xhr }; if ("json" in options && options.json !== false) { isJson = true; headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json"); //Don't override existing accept header declared by user if (method !== "GET" && method !== "HEAD") { headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json"); //Don't override existing accept header declared by user body = JSON.stringify(options.json === true ? body : options.json); } } xhr.onreadystatechange = readystatechange; xhr.onload = loadFunc; xhr.onerror = errorFunc; // IE9 must have onprogress be set to a unique function. xhr.onprogress = function () {// IE must die }; xhr.onabort = function () { aborted = true; }; xhr.ontimeout = errorFunc; xhr.open(method, uri, !sync, options.username, options.password); //has to be after open if (!sync) { xhr.withCredentials = !!options.withCredentials; } // Cannot set timeout with sync request // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent if (!sync && options.timeout > 0) { timeoutTimer = setTimeout(function () { if (aborted) return; aborted = true; //IE9 may still call readystatechange xhr.abort("timeout"); var e = new Error("XMLHttpRequest timeout"); e.code = "ETIMEDOUT"; errorFunc(e); }, options.timeout); } if (xhr.setRequestHeader) { for (key in headers) { if (headers.hasOwnProperty(key)) { xhr.setRequestHeader(key, headers[key]); } } } else if (options.headers && !isEmpty(options.headers)) { throw new Error("Headers cannot be set on an XDomainRequest object"); } if ("responseType" in options) { xhr.responseType = options.responseType; } if ("beforeSend" in options && typeof options.beforeSend === "function") { options.beforeSend(xhr); } // Microsoft Edge browser sends "undefined" when send is called with undefined value. // XMLHttpRequest spec says to pass null as body to indicate no body // See https://github.com/naugtur/xhr/issues/100. xhr.send(body || null); return xhr; } function getXml(xhr) { // xhr.responseXML will throw Exception "InvalidStateError" or "DOMException" // See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseXML. try { if (xhr.responseType === "document") { return xhr.responseXML; } var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror"; if (xhr.responseType === "" && !firefoxBugTakenEffect) { return xhr.responseXML; } } catch (e) {} return null; } function noop() {}