From 94bc55f572036ba108424eacb80b0a467fb6c2af Mon Sep 17 00:00:00 2001 From: Jacob Wright Date: Fri, 8 Aug 2014 12:47:25 -0600 Subject: [PATCH 01/10] Fixes request headers to conform to spec more closely. I've made the request headers case insensitive for setting and getting by creating a mapping hash to map the insensitive names with the ones used in setting. I've also fixed setRequestHeader to append values to existing ones as per the spec. Because of this I needed to set the defaults on send if they haven't been set previously (user-agent obviously can't because it's in the restricted list). --- lib/XMLHttpRequest.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/XMLHttpRequest.js b/lib/XMLHttpRequest.js index 4b7cab4..8ea63e8 100644 --- a/lib/XMLHttpRequest.js +++ b/lib/XMLHttpRequest.js @@ -40,7 +40,8 @@ exports.XMLHttpRequest = function() { "Accept": "*/*", }; - var headers = defaultHeaders; + var headers = {}; + var headersCase = {}; // These headers are not user setable. // The following are allowed but banned in the spec: @@ -177,7 +178,7 @@ exports.XMLHttpRequest = function() { }; /** - * Sets a header for the request. + * Sets a header for the request or appends the value if one is already set. * * @param string header Header name * @param string value Header value @@ -193,7 +194,9 @@ exports.XMLHttpRequest = function() { if (sendFlag) { throw "INVALID_STATE_ERR: send flag is true"; } - headers[header] = value; + header = headersCase[header.toLowerCase()] || header; + headersCase[header.toLowerCase()] = header; + headers[header] = headers[header] ? headers[header] + ', ' + value : value; }; /** @@ -243,9 +246,8 @@ exports.XMLHttpRequest = function() { * @return string Returns the request header or empty string if not set */ this.getRequestHeader = function(name) { - // @TODO Make this case insensitive - if (typeof name === "string" && headers[name]) { - return headers[name]; + if (typeof name === "string" && headersCase[name.toLowerCase()]) { + return headers[headersCase[name.toLowerCase()]]; } return ""; @@ -325,6 +327,13 @@ exports.XMLHttpRequest = function() { // Add query string if one is used var uri = url.pathname + (url.search ? url.search : ''); + // Set the defaults if they haven't been set + for (var name in defaultHeaders) { + if (!headersCase[name.toLowerCase()]) { + headers[name] = defaultHeaders[name]; + } + } + // Set the Host header or the server may reject the request headers["Host"] = host; if (!((ssl && port === 443) || port === 80)) { From 4610298f2688fcbf001ca494049f8f86f740b19a Mon Sep 17 00:00:00 2001 From: Jacob Wright Date: Fri, 8 Aug 2014 12:54:09 -0600 Subject: [PATCH 02/10] Updates tests to test header changes. --- tests/test-headers.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test-headers.js b/tests/test-headers.js index 76454f1..23a419e 100644 --- a/tests/test-headers.js +++ b/tests/test-headers.js @@ -56,12 +56,16 @@ try { xhr.open("GET", "http://localhost:8000/"); // Valid header xhr.setRequestHeader("X-Test", "Foobar"); + xhr.setRequestHeader("X-Test2", "Foobar1"); + xhr.setRequestHeader("X-Test2", "Foobar2"); // Invalid header xhr.setRequestHeader("Content-Length", 0); // Allowed header outside of specs xhr.setRequestHeader("user-agent", "node-XMLHttpRequest-test"); // Test getRequestHeader assert.equal("Foobar", xhr.getRequestHeader("X-Test")); + assert.equal("Foobar", xhr.getRequestHeader("x-tEST")); + assert.equal("Foobar1, Foobar2", xhr.getRequestHeader("x-test2")); // Test invalid header assert.equal("", xhr.getRequestHeader("Content-Length")); From 5f3750e3d774b4b1cc417b1bb4d4921d69b31f2f Mon Sep 17 00:00:00 2001 From: AWinterman Date: Fri, 7 Nov 2014 11:34:26 -0800 Subject: [PATCH 03/10] throw errors not strings --- lib/XMLHttpRequest.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/XMLHttpRequest.js b/lib/XMLHttpRequest.js index 4b7cab4..c84af40 100644 --- a/lib/XMLHttpRequest.js +++ b/lib/XMLHttpRequest.js @@ -152,7 +152,7 @@ exports.XMLHttpRequest = function() { // Check for valid request method if (!isAllowedHttpMethod(method)) { - throw "SecurityError: Request method not allowed"; + throw new Error("SecurityError: Request method not allowed"); } settings = { @@ -184,14 +184,14 @@ exports.XMLHttpRequest = function() { */ this.setRequestHeader = function(header, value) { if (this.readyState != this.OPENED) { - throw "INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN"; + throw new Error("INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN"); } if (!isAllowedHttpHeader(header)) { console.warn('Refused to set unsafe header "' + header + '"'); return; } if (sendFlag) { - throw "INVALID_STATE_ERR: send flag is true"; + throw new Error("INVALID_STATE_ERR: send flag is true"); } headers[header] = value; }; @@ -258,11 +258,11 @@ exports.XMLHttpRequest = function() { */ this.send = function(data) { if (this.readyState != this.OPENED) { - throw "INVALID_STATE_ERR: connection must be opened before send() is called"; + throw new Error("INVALID_STATE_ERR: connection must be opened before send() is called"); } if (sendFlag) { - throw "INVALID_STATE_ERR: send has already been called"; + throw new Error("INVALID_STATE_ERR: send has already been called"); } var ssl = false, local = false; @@ -287,13 +287,13 @@ exports.XMLHttpRequest = function() { break; default: - throw "Protocol not supported."; + throw new Error("Protocol not supported."); } // Load files off the local filesystem (file://) if (local) { if (settings.method !== "GET") { - throw "XMLHttpRequest: Only GET method is supported"; + throw new Error("XMLHttpRequest: Only GET method is supported"); } if (settings.async) { From 0565aab9ebab79642b3ec6ea27170eb169508ccc Mon Sep 17 00:00:00 2001 From: aaron Date: Sun, 18 Jan 2015 23:56:39 -0800 Subject: [PATCH 04/10] Expose xhr.withCredentials with correct default Fixes #71 Replaces #84 --- lib/XMLHttpRequest.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/XMLHttpRequest.js b/lib/XMLHttpRequest.js index 949fdf9..9e5351c 100644 --- a/lib/XMLHttpRequest.js +++ b/lib/XMLHttpRequest.js @@ -110,6 +110,10 @@ exports.XMLHttpRequest = function() { this.responseXML = ""; this.status = null; this.statusText = null; + + // Whether cross-site Access-Control requests should be made using + // credentials such as cookies or authorization headers + this.withCredentials = false; /** * Private methods @@ -363,7 +367,8 @@ exports.XMLHttpRequest = function() { path: uri, method: settings.method, headers: headers, - agent: false + agent: false, + withCredentials: self.withCredentials }; // Reset error flag @@ -399,7 +404,8 @@ exports.XMLHttpRequest = function() { port: url.port, path: url.path, method: response.statusCode === 303 ? "GET" : settings.method, - headers: headers + headers: headers, + withCredentials: self.withCredentials }; // Issue the new request From ffda60eb522939ffb08321aacec92300d3240fc7 Mon Sep 17 00:00:00 2001 From: Peter deHaan Date: Wed, 20 May 2015 16:22:19 -0700 Subject: [PATCH 05/10] Update license attribute specifying the type and URL is deprecated: https://docs.npmjs.com/files/package.json#license http://npm1k.org/ --- package.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/package.json b/package.json index d6aa638..68af524 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,7 @@ "url": "http://driverdan.com" }, "keywords": ["xhr", "ajax"], - "licenses": [{ - "type": "MIT", - "url": "http://creativecommons.org/licenses/MIT/" - }], + "license": "MIT", "repository": { "type": "git", "url": "git://github.com/driverdan/node-XMLHttpRequest.git" From 94a27f11bce860b280568dd5751a19125b45a3af Mon Sep 17 00:00:00 2001 From: thorn0 Date: Tue, 8 Sep 2015 14:51:39 +0300 Subject: [PATCH 06/10] 1) add events 'error' and 'abort' 2) the status property must return 0 if the error flag is set --- lib/XMLHttpRequest.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/XMLHttpRequest.js b/lib/XMLHttpRequest.js index 949fdf9..1358173 100644 --- a/lib/XMLHttpRequest.js +++ b/lib/XMLHttpRequest.js @@ -509,11 +509,12 @@ exports.XMLHttpRequest = function() { * Called when an error is encountered to deal with it. */ this.handleError = function(error) { - this.status = 503; + this.status = 0; this.statusText = error; this.responseText = error.stack; errorFlag = true; setState(this.DONE); + this.dispatchEvent('error'); }; /** @@ -526,6 +527,7 @@ exports.XMLHttpRequest = function() { } headers = defaultHeaders; + this.status = 0; this.responseText = ""; this.responseXML = ""; @@ -538,6 +540,7 @@ exports.XMLHttpRequest = function() { setState(this.DONE); } this.readyState = this.UNSENT; + this.dispatchEvent('abort'); }; /** From 50be6863810501d61d32fa407d6a0e59054caf98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Pablo=20Ferna=CC=81ndez?= Date: Sun, 20 Sep 2015 12:15:39 +0100 Subject: [PATCH 07/10] Consider null protocol as missing protocol, not an unsupported one. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the URL is just a relative path, as in /blah/bleh, at least in v0.12.7, url.protocol is not set at all, thus, it’s null. --- lib/XMLHttpRequest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/XMLHttpRequest.js b/lib/XMLHttpRequest.js index 949fdf9..2fdbb28 100644 --- a/lib/XMLHttpRequest.js +++ b/lib/XMLHttpRequest.js @@ -284,6 +284,7 @@ exports.XMLHttpRequest = function() { break; case undefined: + case null: case "": host = "localhost"; break; From 86ff70effb6dd529b34650242b9e3b1f0b8b6e86 Mon Sep 17 00:00:00 2001 From: Dan DeFelippi Date: Sun, 11 Oct 2015 15:05:06 -0500 Subject: [PATCH 08/10] v1.8.0 --- README.md | 2 -- package.json | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index b989434..50039f9 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,5 @@ page](https://github.com/driverdan/node-XMLHttpRequest/issues). * Synchronous requests don't set headers properly * Synchronous requests freeze node while waiting for response (But that's what you want, right? Stick with async!). * Some events are missing, such as abort -* getRequestHeader is case-sensitive * Cookies aren't persisted between requests * Missing XML support -* Missing basic auth diff --git a/package.json b/package.json index 68af524..c14434d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "xmlhttprequest", "description": "XMLHttpRequest for Node", - "version": "1.7.0", + "version": "1.8.0", "author": { "name": "Dan DeFelippi", "url": "http://driverdan.com" From 923d98aa201a25a57d61dba924c16e6c0c337f77 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Thu, 13 Oct 2016 19:29:43 +1100 Subject: [PATCH 09/10] Remove redundant require for child_process module --- lib/XMLHttpRequest.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/XMLHttpRequest.js b/lib/XMLHttpRequest.js index 311cedb..5094970 100644 --- a/lib/XMLHttpRequest.js +++ b/lib/XMLHttpRequest.js @@ -12,7 +12,6 @@ */ var Url = require("url"); -var spawn = require("child_process").spawn; var fs = require("fs"); exports.XMLHttpRequest = function() { From 302518055dc4b9e54f639ff924fd9f3b1e252609 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Thu, 13 Oct 2016 20:02:02 +1100 Subject: [PATCH 10/10] Sleep for an order of magnitude less with deasync --- lib/XMLHttpRequest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/XMLHttpRequest.js b/lib/XMLHttpRequest.js index 5094970..80ce0ea 100644 --- a/lib/XMLHttpRequest.js +++ b/lib/XMLHttpRequest.js @@ -473,7 +473,7 @@ exports.XMLHttpRequest = function() { self.dispatchEvent("loadstart"); while(!done) { - require('deasync').sleep(100); + require('deasync').sleep(10); } }