Comparing version 1.17.0 to 2.0.0
183
index.js
@@ -0,10 +1,6 @@ | ||
"use strict"; | ||
var window = require("global/window") | ||
var once = require("once") | ||
var parseHeaders = require('parse-headers') | ||
var parseHeaders = require("parse-headers") | ||
var messages = { | ||
"0": "Internal XMLHttpRequest Error", | ||
"4": "4xx Client Error", | ||
"5": "5xx Server Error" | ||
} | ||
@@ -17,2 +13,72 @@ var XHR = window.XMLHttpRequest || noop | ||
function createXHR(options, callback) { | ||
function readystatechange() { | ||
if (xhr.readyState === 4) { | ||
loadFunc() | ||
} | ||
} | ||
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 if (xhr.responseType === "text" || !xhr.responseType) { | ||
body = xhr.responseText || xhr.responseXML | ||
} | ||
if (isJson) { | ||
try { | ||
body = JSON.parse(body) | ||
} catch (e) {} | ||
} | ||
return body | ||
} | ||
var failureResponse = { | ||
body: undefined, | ||
headers: {}, | ||
statusCode: 0, | ||
method: method, | ||
url: uri, | ||
rawRequest: xhr | ||
} | ||
function errorFunc(evt) { | ||
clearTimeout(timeoutTimer) | ||
if(! evt instanceof Error){ | ||
evt = new Error(""+evt) | ||
} | ||
evt.statusCode = 0 | ||
callback(evt, failureResponse) | ||
} | ||
// will load the data & process the response in a special response object | ||
function loadFunc() { | ||
clearTimeout(timeoutTimer) | ||
var 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") | ||
} | ||
callback(err, response, response.body) | ||
} | ||
if (typeof options === "string") { | ||
@@ -35,2 +101,3 @@ options = { uri: options } | ||
var key | ||
var uri = xhr.url = options.uri || options.url | ||
@@ -42,8 +109,7 @@ var method = xhr.method = options.method || "GET" | ||
var isJson = false | ||
var key | ||
var load = options.response ? loadResponse : loadXhr | ||
var timeoutTimer | ||
if ("json" in options) { | ||
isJson = true | ||
headers["Accept"] = "application/json" | ||
headers["Accept"] || (headers["Accept"] = "application/json") //Don't override existing accept header declared by user | ||
if (method !== "GET" && method !== "HEAD") { | ||
@@ -56,4 +122,4 @@ headers["Content-Type"] = "application/json" | ||
xhr.onreadystatechange = readystatechange | ||
xhr.onload = load | ||
xhr.onerror = error | ||
xhr.onload = loadFunc | ||
xhr.onerror = errorFunc | ||
// IE9 must have onprogress be set to a unique function. | ||
@@ -63,13 +129,14 @@ xhr.onprogress = function () { | ||
} | ||
// hate IE | ||
xhr.ontimeout = noop | ||
xhr.ontimeout = errorFunc | ||
xhr.open(method, uri, !sync) | ||
//backward compatibility | ||
if (options.withCredentials || (options.cors && options.withCredentials !== false)) { | ||
xhr.withCredentials = true | ||
} | ||
//has to be after open | ||
xhr.withCredentials = !!options.withCredentials | ||
// Cannot set timeout with sync request | ||
if (!sync) { | ||
xhr.timeout = "timeout" in options ? options.timeout : 5000 | ||
// 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(){ | ||
xhr.abort("timeout"); | ||
}, options.timeout+2 ); | ||
} | ||
@@ -101,79 +168,3 @@ | ||
function readystatechange() { | ||
if (xhr.readyState === 4) { | ||
load() | ||
} | ||
} | ||
function getBody() { | ||
// Chrome with requestType=blob throws errors arround when even testing access to responseText | ||
var body = null | ||
if (xhr.response) { | ||
body = xhr.response | ||
} else if (xhr.responseType === 'text' || !xhr.responseType) { | ||
body = xhr.responseText || xhr.responseXML | ||
} | ||
if (isJson) { | ||
try { | ||
body = JSON.parse(body) | ||
} catch (e) {} | ||
} | ||
return body | ||
} | ||
function getStatusCode() { | ||
return xhr.status === 1223 ? 204 : xhr.status | ||
} | ||
// if we're getting a none-ok statusCode, build & return an error | ||
function errorFromStatusCode(status) { | ||
var error = null | ||
if (status === 0 || (status >= 400 && status < 600)) { | ||
var message = (typeof body === "string" ? body : false) || | ||
messages[String(status).charAt(0)] | ||
error = new Error(message) | ||
error.statusCode = status | ||
} | ||
return error | ||
} | ||
// will load the data & process the response in a special response object | ||
function loadResponse() { | ||
var status = getStatusCode() | ||
var error = errorFromStatusCode(status) | ||
var response = { | ||
body: getBody(), | ||
statusCode: status, | ||
statusText: xhr.statusText, | ||
raw: xhr | ||
} | ||
if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE | ||
response.headers = parseHeaders(xhr.getAllResponseHeaders()) | ||
} else { | ||
response.headers = {} | ||
} | ||
callback(error, response, response.body) | ||
} | ||
// will load the data and add some response properties to the source xhr | ||
// and then respond with that | ||
function loadXhr() { | ||
var status = getStatusCode() | ||
var error = errorFromStatusCode(status) | ||
xhr.status = xhr.statusCode = status | ||
xhr.body = getBody() | ||
xhr.headers = parseHeaders(xhr.getAllResponseHeaders()) | ||
callback(error, xhr, xhr.body) | ||
} | ||
function error(evt) { | ||
callback(evt, xhr) | ||
} | ||
} | ||
@@ -180,0 +171,0 @@ |
{ | ||
"name": "xhr", | ||
"version": "1.17.0", | ||
"version": "2.0.0", | ||
"description": "small xhr abstraction", | ||
@@ -45,19 +45,3 @@ "keywords": [ | ||
"browser": "run-browser test/index.js" | ||
}, | ||
"testling": { | ||
"files": "test/*.js", | ||
"browsers": [ | ||
"ie/8..latest", | ||
"firefox/17..latest", | ||
"firefox/nightly", | ||
"chrome/22..latest", | ||
"chrome/canary", | ||
"opera/12..latest", | ||
"opera/next", | ||
"safari/5.1..latest", | ||
"ipad/6.0..latest", | ||
"iphone/6.0..latest", | ||
"android-browser/4.2..latest" | ||
] | ||
} | ||
} |
@@ -5,3 +5,3 @@ # xhr | ||
[![browser support](https://ci.testling.com/raynos/xhr.png)](https://ci.testling.com/Raynos/xhr) | ||
Browser support: IE8+ and everything else. | ||
@@ -20,4 +20,3 @@ ## Example | ||
}, function (err, resp, body) { | ||
// resp === xhr | ||
// check resp.body or resp.statusCode | ||
// check resp.statusCode | ||
}) | ||
@@ -39,4 +38,3 @@ ``` | ||
json: Object?, | ||
withCredentials: Boolean?, | ||
response: Boolean? | ||
withCredentials: Boolean? | ||
} | ||
@@ -50,10 +48,24 @@ xhr := (XhrOptions, Callback<Response>) => Request | ||
Your callback will be called once with the arguments | ||
( [`Error`][5], `response` , `body` ) where the response is depending on | ||
`options.response` and body will be either | ||
[`xhr.response`][6], [`xhr.responseText`][7] or | ||
( [`Error`][5], `response` , `body` ) where the response is an object: | ||
```js | ||
{ | ||
body: Object||String, | ||
statusCode: Number, | ||
method: String, | ||
headers: {}, | ||
url: String, | ||
rawRequest: xhr | ||
} | ||
``` | ||
- `body`: HTTP response body - [`xhr.response`][6], [`xhr.responseText`][7] or | ||
[`xhr.responseXML`][8] depending on the request type. | ||
- `rawRequest`: Original [`XMLHttpRequest`][3] instance | ||
or [`XDomainRequest`][4] instance (if on IE8/IE9 && | ||
`options.useXDR` is set to `true`) | ||
- `headers`: A collection of headers where keys are header names converted to lowercase | ||
Your callback will be called with an [`Error`][5] if the | ||
resulting status of the request is either `0`, `4xx` or `5xx` | ||
Your callback will be called with an [`Error`][5] if there is an error in the browser that prevents sending the request. | ||
A HTTP 500 response is not going to cause an error to be returned. | ||
If `options` is a string then it's a short hand for | ||
@@ -67,8 +79,2 @@ `{ method: "GET", uri: string }` | ||
### `options.response` | ||
Specify the format of the response. Defaults to return the xhr/xdr-object | ||
with body, headers and status-properties added. When set to `true` a special response | ||
object is returned that includes parsed response headers, status and body. | ||
`options.response` must be set to `true` for IE8 support. | ||
### `options.useXDR` | ||
@@ -106,4 +112,3 @@ | ||
A numeric timeout to use for this xhr request. Defaults to 5 | ||
seconds. Ignored when `options.sync` is true. | ||
Number of miliseconds to wait for response. Defaults to 0 (no timeout). Ignored when `options.sync` is true. | ||
@@ -123,5 +128,2 @@ ### `options.json` | ||
For backward-compatibility defaults to true | ||
when deprecated `options.cors` is also true. | ||
A wildcard `*` cannot be used in the `Access-Control-Allow-Origin` header when `withCredentials` is true. | ||
@@ -128,0 +130,0 @@ The header needs to specify your origin explicitly or browser will abort the request. |
@@ -6,6 +6,4 @@ var window = require("global/window") | ||
test("constructs and calls callback without throwing", function(assert) { | ||
xhr({ | ||
response: !!window.XDomainRequest //currently, IE8 will fail if this is not set to true, as documented | ||
}, function (err, resp, body) { | ||
test("constructs and calls callback without throwing", function (assert) { | ||
xhr({}, function (err, resp, body) { | ||
assert.ok(true, "got here") | ||
@@ -16,9 +14,15 @@ assert.end() | ||
test("can GET current page", function(assert) { | ||
test("can GET a url", function (assert) { | ||
xhr({ | ||
headers: {accept: "text/html"}, | ||
uri: window.location.href, | ||
response: !!window.XDomainRequest | ||
headers: { | ||
accept: "text/html" | ||
}, | ||
uri: "http://reqr.es/api/stuff" | ||
}, function (err, resp, body) { | ||
assert.ifError(err, "no err") | ||
assert.equal(resp.statusCode, 200) | ||
assert.equal(typeof resp.rawRequest, "object") | ||
assert.equal(resp.headers['content-type'].indexOf('application/json'), 0) | ||
assert.notEqual(resp.body.length, 0) | ||
assert.notEqual(body.length, 0) | ||
assert.end() | ||
@@ -28,14 +32,12 @@ }) | ||
test("can GET current page with response option = true", function(assert) { | ||
test("Returns http error responses like npm's request", function (assert) { | ||
xhr({ | ||
headers: {accept: "text/html"}, | ||
uri: window.location.href, | ||
response: true | ||
headers: { | ||
accept: "text/html" | ||
}, | ||
uri: "http://reqr.es/api/stuff/23" | ||
}, function (err, resp, body) { | ||
assert.ifError(err, "no err") | ||
assert.equal(resp.statusCode, 200) | ||
assert.equal(resp.statusText, 'OK') | ||
assert.equal(resp.headers['content-type'].indexOf('text/html'), 0) //can be 'text/html; charset=UTF-8' in IE8 particularly | ||
assert.notEqual(resp.body.length, 0) | ||
assert.notEqual(body.length, 0) | ||
assert.equal(resp.statusCode, 404) | ||
assert.equal(typeof resp.rawRequest, "object") | ||
assert.end() | ||
@@ -45,24 +47,30 @@ }) | ||
test("withCredentials option", function(assert) { | ||
if(!window.XDomainRequest){ | ||
test("Times out to an error ", function (assert) { | ||
xhr({ | ||
headers: { | ||
accept: "text/html" | ||
}, | ||
timeout: 1000, | ||
uri: "http://reqr.es/api/stuff?delay=10" | ||
}, function (err, resp, body) { | ||
assert.ok(err instanceof Error, "should return error") | ||
assert.equal(resp.statusCode, 0) | ||
assert.end() | ||
}) | ||
}) | ||
test("withCredentials option", function (assert) { | ||
if (!window.XDomainRequest) { | ||
var req = xhr({}, function () {}) | ||
assert.ok( | ||
!req.withCredentials, | ||
"withCredentials not true when nothing set in options" | ||
assert.ok(!req.withCredentials, | ||
"withCredentials not true" | ||
) | ||
req = xhr({ | ||
cors: true | ||
withCredentials: true | ||
}, function () {}) | ||
assert.ok( | ||
req.withCredentials, | ||
"withCredentials set to true when cors is true in options" | ||
"withCredentials set to true" | ||
) | ||
req = xhr({ | ||
cors: true, | ||
withCredentials: false | ||
}, function () {}) | ||
assert.ok( | ||
!req.withCredentials, | ||
"withCredentials set to false when set to false in options" | ||
) | ||
} else { | ||
@@ -77,34 +85,25 @@ assert.ok( | ||
test("XDR usage (run on IE8 or 9)", function(assert) { | ||
test("XDR usage (run on IE8 or 9)", function (assert) { | ||
var req = xhr({ | ||
useXDR: true, | ||
response:true, | ||
uri: window.location.href, | ||
}, function () {}) | ||
assert.ok( | ||
!window.XDomainRequest || window.XDomainRequest === req.constructor, | ||
assert.ok(!window.XDomainRequest || window.XDomainRequest === req.constructor, | ||
"Uses XDR when told to" | ||
) | ||
req = xhr({ | ||
cors: true, | ||
uri: window.location.href, | ||
}, function () {}) | ||
assert.ok( | ||
!window.XDomainRequest || window.XDomainRequest === req.constructor, | ||
"Uses XDR with deprecated option cors" | ||
) | ||
if(!!window.XDomainRequest){ | ||
assert.throws(function(){ | ||
if (!!window.XDomainRequest) { | ||
assert.throws(function () { | ||
xhr({ | ||
useXDR: true, | ||
uri: window.location.href, | ||
headers:{"foo":"bar"} | ||
headers: { | ||
"foo": "bar" | ||
} | ||
}, function () {}) | ||
},true,"Throws when trying to send headers with XDR") | ||
}, true, "Throws when trying to send headers with XDR") | ||
} | ||
assert.end() | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
138
14924
228
1