Skip to content

Commit efc39e9

Browse files
authored
Merge pull request #6 from wesgarland/master
Fixed abort/error/loadend event firing, statusCode on error, exceptions
2 parents d0290fa + b9fedb0 commit efc39e9

File tree

2 files changed

+45
-29
lines changed

2 files changed

+45
-29
lines changed

Diff for: lib/XMLHttpRequest.js

+44-28
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ function XMLHttpRequest(opts) {
102102
var sendFlag = false;
103103
// Error flag, used when errors occur or abort is called
104104
var errorFlag = false;
105+
var abortedFlag = false;
105106

106107
// Event listeners
107108
var listeners = {};
@@ -172,10 +173,11 @@ function XMLHttpRequest(opts) {
172173
this.open = function(method, url, async, user, password) {
173174
this.abort();
174175
errorFlag = false;
176+
abortedFlag = false;
175177

176178
// Check for valid request method
177179
if (!isAllowedHttpMethod(method)) {
178-
throw "SecurityError: Request method not allowed";
180+
throw new Error("SecurityError: Request method not allowed");
179181
}
180182

181183
settings = {
@@ -208,16 +210,14 @@ function XMLHttpRequest(opts) {
208210
*/
209211
this.setRequestHeader = function(header, value) {
210212
if (this.readyState != this.OPENED) {
211-
throw "INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN";
212-
return false;
213+
throw new Error("INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN");
213214
}
214215
if (!isAllowedHttpHeader(header)) {
215216
console.warn('Refused to set unsafe header "' + header + '"');
216217
return false;
217218
}
218219
if (sendFlag) {
219-
throw "INVALID_STATE_ERR: send flag is true";
220-
return false;
220+
throw new Error("INVALID_STATE_ERR: send flag is true");
221221
}
222222
headers[header] = value;
223223
return true;
@@ -283,11 +283,11 @@ function XMLHttpRequest(opts) {
283283
*/
284284
this.send = function(data) {
285285
if (this.readyState != this.OPENED) {
286-
throw "INVALID_STATE_ERR: connection must be opened before send() is called";
286+
throw new Error("INVALID_STATE_ERR: connection must be opened before send() is called");
287287
}
288288

289289
if (sendFlag) {
290-
throw "INVALID_STATE_ERR: send has already been called";
290+
throw new Error("INVALID_STATE_ERR: send has already been called");
291291
}
292292

293293
var ssl = false, local = false;
@@ -312,13 +312,13 @@ function XMLHttpRequest(opts) {
312312
break;
313313

314314
default:
315-
throw "Protocol not supported.";
315+
throw new Error("Protocol not supported.");
316316
}
317317

318318
// Load files off the local filesystem (file://)
319319
if (local) {
320320
if (settings.method !== "GET") {
321-
throw "XMLHttpRequest: Only GET method is supported";
321+
throw new Error("XMLHttpRequest: Only GET method is supported");
322322
}
323323

324324
if (settings.async) {
@@ -402,7 +402,6 @@ function XMLHttpRequest(opts) {
402402

403403
// Reset error flag
404404
errorFlag = false;
405-
406405
// Handle async requests
407406
if (settings.async) {
408407
// Use the proper protocol
@@ -545,7 +544,7 @@ function XMLHttpRequest(opts) {
545544
if (self.responseText.match(/^NODE-XMLHTTPREQUEST-ERROR:/)) {
546545
// If the file returned an error, handle it
547546
var errorObj = self.responseText.replace(/^NODE-XMLHTTPREQUEST-ERROR:/, "");
548-
self.handleError(errorObj);
547+
self.handleError(errorObj, 503);
549548
} else {
550549
// If the file returned okay, parse its data and move to the DONE state
551550
self.status = self.responseText.replace(/^NODE-XMLHTTPREQUEST-STATUS:([0-9]*),.*/, "$1");
@@ -557,9 +556,10 @@ function XMLHttpRequest(opts) {
557556

558557
/**
559558
* Called when an error is encountered to deal with it.
559+
* @param status {number} HTTP status code to use rather than the default (0) for XHR errors.
560560
*/
561-
this.handleError = function(error) {
562-
this.status = 503;
561+
this.handleError = function(error, status) {
562+
this.status = +status || 0;
563563
this.statusText = error;
564564
this.responseText = error.stack;
565565
errorFlag = true;
@@ -579,8 +579,7 @@ function XMLHttpRequest(opts) {
579579
this.responseText = "";
580580
this.responseXML = "";
581581

582-
errorFlag = true;
583-
582+
errorFlag = abortedFlag = true
584583
if (this.readyState !== this.UNSENT
585584
&& (this.readyState !== this.OPENED || sendFlag)
586585
&& this.readyState !== this.DONE) {
@@ -619,11 +618,17 @@ function XMLHttpRequest(opts) {
619618
*/
620619
this.dispatchEvent = function(event) {
621620
if (typeof self["on" + event] === "function") {
622-
self["on" + event]();
621+
if (this.readyState === this.DONE)
622+
setImmediate(function() { self["on" + event]() })
623+
else
624+
self["on" + event]()
623625
}
624626
if (event in listeners) {
625-
for (var i = 0, len = listeners[event].length; i < len; i++) {
626-
listeners[event][i].call(self);
627+
for (let i = 0, len = listeners[event].length; i < len; i++) {
628+
if (this.readyState === this.DONE)
629+
setImmediate(function() { listeners[event][i].call(self) })
630+
else
631+
listeners[event][i].call(self)
627632
}
628633
}
629634
};
@@ -634,18 +639,29 @@ function XMLHttpRequest(opts) {
634639
* @param int state New state
635640
*/
636641
var setState = function(state) {
637-
if (self.readyState !== state) {
638-
self.readyState = state;
642+
if ((self.readyState === state) || (self.readyState === self.UNSENT && abortedFlag))
643+
return
639644

640-
if (settings.async || self.readyState < self.OPENED || self.readyState === self.DONE) {
641-
self.dispatchEvent("readystatechange");
642-
}
645+
self.readyState = state;
643646

644-
if (self.readyState === self.DONE && !errorFlag) {
645-
self.dispatchEvent("load");
646-
// @TODO figure out InspectorInstrumentation::didLoadXHR(cookie)
647-
self.dispatchEvent("loadend");
648-
}
647+
if (settings.async || self.readyState < self.OPENED || self.readyState === self.DONE) {
648+
self.dispatchEvent("readystatechange");
649+
}
650+
651+
if (self.readyState === self.DONE) {
652+
let fire
653+
654+
if (abortedFlag)
655+
fire = "abort"
656+
else if (errorFlag)
657+
fire = "error"
658+
else
659+
fire = "load"
660+
661+
self.dispatchEvent(fire)
662+
663+
// @TODO figure out InspectorInstrumentation::didLoadXHR(cookie)
664+
self.dispatchEvent("loadend");
649665
}
650666
};
651667
};

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "xmlhttprequest-ssl",
33
"description": "XMLHttpRequest for Node",
4-
"version": "1.5.5",
4+
"version": "1.5.6",
55
"author": {
66
"name": "Michael de Wit"
77
},

0 commit comments

Comments
 (0)