diff --git a/XMLHttpRequest/MANIFEST b/XMLHttpRequest/MANIFEST index cd668912acfac2..334be0fd8bdfc8 100644 --- a/XMLHttpRequest/MANIFEST +++ b/XMLHttpRequest/MANIFEST @@ -1,3 +1,13 @@ +support xmlhttprequest-timeout-aborted.js +support xmlhttprequest-timeout-abortedonmain.js +support xmlhttprequest-timeout-overrides.js +support xmlhttprequest-timeout-overridesexpires.js +support xmlhttprequest-timeout-runner.js +support xmlhttprequest-timeout-simple.js +support xmlhttprequest-timeout-synconmain.js +support xmlhttprequest-timeout-synconworker.js +support xmlhttprequest-timeout-twice.js +support xmlhttprequest-timeout.js abort-after-send.htm abort-during-done.htm abort-during-open.htm @@ -80,4 +90,17 @@ xmlhttprequest-basic.htm xmlhttprequest-eventtarget.htm xmlhttprequest-network-error-sync.htm xmlhttprequest-network-error.htm +xmlhttprequest-timeout-aborted.html +xmlhttprequest-timeout-abortedonmain.html +xmlhttprequest-timeout-overrides.html +xmlhttprequest-timeout-overridesexpires.html +xmlhttprequest-timeout-simple.html +xmlhttprequest-timeout-synconmain.html +xmlhttprequest-timeout-twice.html +xmlhttprequest-timeout-worker-aborted.html +xmlhttprequest-timeout-worker-overrides.html +xmlhttprequest-timeout-worker-overridesexpires.html +xmlhttprequest-timeout-worker-simple.html +xmlhttprequest-timeout-worker-synconworker.html +xmlhttprequest-timeout-worker-twice.html xmlhttprequest-unsent.htm diff --git a/XMLHttpRequest/xmlhttprequest-timeout-aborted.html b/XMLHttpRequest/xmlhttprequest-timeout-aborted.html new file mode 100644 index 00000000000000..5983f0925ea1f8 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-aborted.html @@ -0,0 +1,19 @@ + + + + + XHR2 Timeout Property Tests + + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in async cases in document (i.e. non-worker) context.

+
+ + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-aborted.js b/XMLHttpRequest/xmlhttprequest-timeout-aborted.js new file mode 100644 index 00000000000000..4f7fbd0f85368c --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-aborted.js @@ -0,0 +1,6 @@ +if (this.document === undefined) + importScripts("xmlhttprequest-timeout.js"); + +runTestRequests([ new AbortedRequest(false), + new AbortedRequest(true, -1), + new AbortedRequest(true, TIME_NORMAL_LOAD) ]); diff --git a/XMLHttpRequest/xmlhttprequest-timeout-abortedonmain.html b/XMLHttpRequest/xmlhttprequest-timeout-abortedonmain.html new file mode 100644 index 00000000000000..404dfc42db8e47 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-abortedonmain.html @@ -0,0 +1,20 @@ + + + + + XHR2 Timeout Property Tests + + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in async cases in document (i.e. non-worker) context.

+
+ + + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-abortedonmain.js b/XMLHttpRequest/xmlhttprequest-timeout-abortedonmain.js new file mode 100644 index 00000000000000..a9dfc824acf1d1 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-abortedonmain.js @@ -0,0 +1,2 @@ +runTestRequests([ new AbortedRequest(true, 0), + new AbortedRequest(true, TIME_DELAY) ]); diff --git a/XMLHttpRequest/xmlhttprequest-timeout-overrides.html b/XMLHttpRequest/xmlhttprequest-timeout-overrides.html new file mode 100644 index 00000000000000..9bc6eac16b5e7f --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-overrides.html @@ -0,0 +1,20 @@ + + + + + XHR2 Timeout Property Tests + + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in async cases in document (i.e. non-worker) context.

+
+ + + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-overrides.js b/XMLHttpRequest/xmlhttprequest-timeout-overrides.js new file mode 100644 index 00000000000000..995e0755e0bb5a --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-overrides.js @@ -0,0 +1,6 @@ +if (this.document === undefined) + importScripts("xmlhttprequest-timeout.js"); + +runTestRequests([ new RequestTracker(true, "timeout disabled after initially set", TIME_NORMAL_LOAD, TIME_REGULAR_TIMEOUT, 0), + new RequestTracker(true, "timeout overrides load after a delay", TIME_NORMAL_LOAD, TIME_DELAY, TIME_REGULAR_TIMEOUT), + new RequestTracker(true, "timeout enabled after initially disabled", 0, TIME_REGULAR_TIMEOUT, TIME_NORMAL_LOAD) ]); diff --git a/XMLHttpRequest/xmlhttprequest-timeout-overridesexpires.html b/XMLHttpRequest/xmlhttprequest-timeout-overridesexpires.html new file mode 100644 index 00000000000000..7690ef80e1e39a --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-overridesexpires.html @@ -0,0 +1,19 @@ + + + + + XHR2 Timeout Property Tests + + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in async cases in document (i.e. non-worker) context.

+
+ + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-overridesexpires.js b/XMLHttpRequest/xmlhttprequest-timeout-overridesexpires.js new file mode 100644 index 00000000000000..28ce9c33ed3755 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-overridesexpires.js @@ -0,0 +1,6 @@ +if (this.document === undefined) + importScripts("xmlhttprequest-timeout.js"); + +runTestRequests([ new RequestTracker(true, "timeout set to expiring value after load fires", TIME_NORMAL_LOAD, TIME_LATE_TIMEOUT, TIME_DELAY), + new RequestTracker(true, "timeout set to expired value before load fires", TIME_NORMAL_LOAD, TIME_REGULAR_TIMEOUT, TIME_DELAY), + new RequestTracker(true, "timeout set to non-expiring value after timeout fires", TIME_DELAY, TIME_REGULAR_TIMEOUT, TIME_NORMAL_LOAD) ]); diff --git a/XMLHttpRequest/xmlhttprequest-timeout-runner.js b/XMLHttpRequest/xmlhttprequest-timeout-runner.js new file mode 100644 index 00000000000000..b478d0d3bbbd62 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-runner.js @@ -0,0 +1,25 @@ +function testResultCallbackHandler(event) { + if (event.data == "done") { + done(); + return; + } + if (event.data.type == "is") { + test(function() { assert_equals(event.data.got, event.data.expected, event.data.msg); }); + return; + } + if (event.data.type == "ok") { + test(function() { assert_true(event.data.bool, event.data.msg); }); + return; + } +} + +window.addEventListener("message", testResultCallbackHandler); + +// Setting up testharness.js +setup({ explicit_done: true, timeout: 30 * 1000 }); + +// Abort test execution if an individual test case fails. +add_result_callback(function (t) { + if (t.status == t.FAIL) + done(); +}); diff --git a/XMLHttpRequest/xmlhttprequest-timeout-simple.html b/XMLHttpRequest/xmlhttprequest-timeout-simple.html new file mode 100644 index 00000000000000..1ba48204039ca1 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-simple.html @@ -0,0 +1,20 @@ + + + + + XHR2 Timeout Property Tests + + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in async cases in document (i.e. non-worker) context.

+
+ + + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-simple.js b/XMLHttpRequest/xmlhttprequest-timeout-simple.js new file mode 100644 index 00000000000000..0207cf107642f7 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-simple.js @@ -0,0 +1,6 @@ +if (this.document === undefined) + importScripts("xmlhttprequest-timeout.js"); + +runTestRequests([ new RequestTracker(true, "no time out scheduled, load fires normally", 0), + new RequestTracker(true, "load fires normally", TIME_NORMAL_LOAD), + new RequestTracker(true, "timeout hit before load", TIME_REGULAR_TIMEOUT) ]); diff --git a/XMLHttpRequest/xmlhttprequest-timeout-synconmain.html b/XMLHttpRequest/xmlhttprequest-timeout-synconmain.html new file mode 100644 index 00000000000000..94b65b2ac081ce --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-synconmain.html @@ -0,0 +1,20 @@ + + + + + XHR2 Timeout Property Tests + + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in async cases in document (i.e. non-worker) context.

+
+ + + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-synconmain.js b/XMLHttpRequest/xmlhttprequest-timeout-synconmain.js new file mode 100644 index 00000000000000..c6c5e985d25740 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-synconmain.js @@ -0,0 +1,2 @@ +runTestRequests([ SyncRequestSettingTimeoutAfterOpen, + SyncRequestSettingTimeoutBeforeOpen ]); diff --git a/XMLHttpRequest/xmlhttprequest-timeout-synconworker.js b/XMLHttpRequest/xmlhttprequest-timeout-synconworker.js new file mode 100644 index 00000000000000..dd2857aeb74c92 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-synconworker.js @@ -0,0 +1,6 @@ +if (this.document === undefined) + importScripts("xmlhttprequest-timeout.js"); + +runTestRequests([ new RequestTracker(false, "no time out scheduled, load fires normally", 0), + new RequestTracker(false, "load fires normally", TIME_NORMAL_LOAD), + new RequestTracker(false, "timeout hit before load", TIME_REGULAR_TIMEOUT) ]); diff --git a/XMLHttpRequest/xmlhttprequest-timeout-twice.html b/XMLHttpRequest/xmlhttprequest-timeout-twice.html new file mode 100644 index 00000000000000..099754c779edd1 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-twice.html @@ -0,0 +1,20 @@ + + + + + XHR2 Timeout Property Tests + + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in async cases in document (i.e. non-worker) context.

+
+ + + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-twice.js b/XMLHttpRequest/xmlhttprequest-timeout-twice.js new file mode 100644 index 00000000000000..0061c7333cfeac --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-twice.js @@ -0,0 +1,6 @@ +if (this.document === undefined) + importScripts("xmlhttprequest-timeout.js"); + +runTestRequests([ new RequestTracker(true, "load fires normally with no timeout set, twice", 0, TIME_REGULAR_TIMEOUT, 0), + new RequestTracker(true, "load fires normally with same timeout set twice", TIME_NORMAL_LOAD, TIME_REGULAR_TIMEOUT, TIME_NORMAL_LOAD), + new RequestTracker(true, "timeout fires normally with same timeout set twice", TIME_REGULAR_TIMEOUT, TIME_DELAY, TIME_REGULAR_TIMEOUT) ]); diff --git a/XMLHttpRequest/xmlhttprequest-timeout-worker-aborted.html b/XMLHttpRequest/xmlhttprequest-timeout-worker-aborted.html new file mode 100644 index 00000000000000..df01a37961bfb4 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-worker-aborted.html @@ -0,0 +1,21 @@ + + + + + XHR2 Timeout Property Tests in Worker + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in in a worker context.

+
+ + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-worker-overrides.html b/XMLHttpRequest/xmlhttprequest-timeout-worker-overrides.html new file mode 100644 index 00000000000000..9146c28dc40a1d --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-worker-overrides.html @@ -0,0 +1,21 @@ + + + + + XHR2 Timeout Property Tests in Worker + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in in a worker context.

+
+ + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-worker-overridesexpires.html b/XMLHttpRequest/xmlhttprequest-timeout-worker-overridesexpires.html new file mode 100644 index 00000000000000..4f3f3d81e65909 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-worker-overridesexpires.html @@ -0,0 +1,21 @@ + + + + + XHR2 Timeout Property Tests in Worker + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in in a worker context.

+
+ + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-worker-simple.html b/XMLHttpRequest/xmlhttprequest-timeout-worker-simple.html new file mode 100644 index 00000000000000..62b1d3890e3f9b --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-worker-simple.html @@ -0,0 +1,22 @@ + + + + + XHR2 Timeout Property Tests in Worker + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in in a worker context.

+
+ + + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-worker-synconworker.html b/XMLHttpRequest/xmlhttprequest-timeout-worker-synconworker.html new file mode 100644 index 00000000000000..15d646c40427bc --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-worker-synconworker.html @@ -0,0 +1,21 @@ + + + + + XHR2 Timeout Property Tests in Worker + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in in a worker context.

+
+ + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout-worker-twice.html b/XMLHttpRequest/xmlhttprequest-timeout-worker-twice.html new file mode 100644 index 00000000000000..fcc1bfd5b429c7 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout-worker-twice.html @@ -0,0 +1,22 @@ + + + + + XHR2 Timeout Property Tests in Worker + + + + + + + +

Description

+

This test validates that the XHR2 timeout property behaves as expected in in a worker context.

+
+ + + + diff --git a/XMLHttpRequest/xmlhttprequest-timeout.js b/XMLHttpRequest/xmlhttprequest-timeout.js new file mode 100644 index 00000000000000..263afb36659506 --- /dev/null +++ b/XMLHttpRequest/xmlhttprequest-timeout.js @@ -0,0 +1,322 @@ +/* Test adapted from Alex Vincent's XHR2 timeout tests, written for Mozilla. + https://hg.mozilla.org/mozilla-central/file/tip/content/base/test/ + Released into the public domain or under BSD, according to + https://bugzilla.mozilla.org/show_bug.cgi?id=525816#c86 +*/ + +/* Notes: + - All times are expressed in milliseconds in this test suite. + - Test harness code is at the end of this file. + - We generate only one request at a time, to avoid overloading the HTTP + request handlers. + */ + +var TIME_NORMAL_LOAD = 1000; +var TIME_LATE_TIMEOUT = 800; +var TIME_XHR_LOAD = 600; +var TIME_REGULAR_TIMEOUT = 400; +var TIME_SYNC_TIMEOUT = 200; +var TIME_DELAY = 200; + +/* + * This should point to a resource that responds with a text/plain resource after a delay of TIME_XHR_LOAD milliseconds. + */ +var STALLED_REQUEST_URL = "resources/delay.php?ms=" + (TIME_XHR_LOAD * 1000); + +var inWorker = false; +try { + inWorker = !(self instanceof Window); +} catch (e) { + inWorker = true; +} + +function message(obj) { + if (inWorker) + self.postMessage(obj); + else + self.postMessage(obj, "*"); +} + +function is(got, expected, msg) { + var obj = {}; + obj.type = "is"; + obj.got = got; + obj.expected = expected; + obj.msg = msg; + + message(obj); +} + +function ok(bool, msg) { + var obj = {}; + obj.type = "ok"; + obj.bool = bool; + obj.msg = msg; + + message(obj); +} + +/** + * Generate and track results from a XMLHttpRequest with regards to timeouts. + * + * @param {String} id The test description. + * @param {Number} timeLimit The initial setting for the request timeout. + * @param {Number} resetAfter (Optional) The time after sending the request, to + * reset the timeout. + * @param {Number} resetTo (Optional) The delay to reset the timeout to. + * + * @note The actual testing takes place in handleEvent(event). + * The requests are generated in startXHR(). + * + * @note If resetAfter and resetTo are omitted, only the initial timeout setting + * applies. + * + * @constructor + * @implements DOMEventListener + */ +function RequestTracker(async, id, timeLimit /*[, resetAfter, resetTo]*/) { + this.async = async; + this.id = id; + this.timeLimit = timeLimit; + + if (arguments.length > 3) { + this.mustReset = true; + this.resetAfter = arguments[3]; + this.resetTo = arguments[4]; + } + + this.hasFired = false; +} +RequestTracker.prototype = { + /** + * Start the XMLHttpRequest! + */ + startXHR: function() { + var req = new XMLHttpRequest(); + this.request = req; + req.open("GET", STALLED_REQUEST_URL, this.async); + var me = this; + function handleEvent(e) { return me.handleEvent(e); }; + req.onerror = handleEvent; + req.onload = handleEvent; + req.onabort = handleEvent; + req.ontimeout = handleEvent; + + req.timeout = this.timeLimit; + + if (this.mustReset) { + var resetTo = this.resetTo; + self.setTimeout(function() { + req.timeout = resetTo; + }, this.resetAfter); + } + + try { + req.send(null); + } + catch (e) { + // Synchronous case in workers. + ok(!this.async && this.timeLimit < TIME_XHR_LOAD && e.name == "TimeoutError", "Unexpected error: " + e); + TestCounter.testComplete(); + } + }, + + /** + * Get a message describing this test. + * + * @returns {String} The test description. + */ + getMessage: function() { + var rv = this.id + ", "; + if (this.mustReset) { + rv += "original timeout at " + this.timeLimit + ", "; + rv += "reset at " + this.resetAfter + " to " + this.resetTo; + } + else { + rv += "timeout scheduled at " + this.timeLimit; + } + return rv; + }, + + /** + * Check the event received, and if it's the right (and only) one we get. + * + * @param {DOMProgressEvent} evt An event of type "load" or "timeout". + */ + handleEvent: function(evt) { + if (this.hasFired) { + ok(false, "Only one event should fire: " + this.getMessage()); + return; + } + this.hasFired = true; + + var type = evt.type, expectedType; + // The XHR responds after TIME_XHR_LOAD milliseconds with a load event. + var timeLimit = this.mustReset && (this.resetAfter < Math.min(TIME_XHR_LOAD, this.timeLimit)) ? + this.resetTo : + this.timeLimit; + if ((timeLimit == 0) || (timeLimit >= TIME_XHR_LOAD)) { + expectedType = "load"; + } + else { + expectedType = "timeout"; + } + is(type, expectedType, this.getMessage()); + TestCounter.testComplete(); + } +}; + +/** + * Generate and track XMLHttpRequests which will have abort() called on. + * + * @param shouldAbort {Boolean} True if we should call abort at all. + * @param abortDelay {Number} The time in ms to wait before calling abort(). + */ +function AbortedRequest(shouldAbort, abortDelay) { + this.shouldAbort = shouldAbort; + this.abortDelay = abortDelay; + this.hasFired = false; +} +AbortedRequest.prototype = { + /** + * Start the XMLHttpRequest! + */ + startXHR: function() { + var req = new XMLHttpRequest(); + this.request = req; + req.open("GET", STALLED_REQUEST_URL); + var _this = this; + function handleEvent(e) { return _this.handleEvent(e); }; + req.onerror = handleEvent; + req.onload = handleEvent; + req.onabort = handleEvent; + req.ontimeout = handleEvent; + + req.timeout = TIME_REGULAR_TIMEOUT; + + function abortReq() { + req.abort(); + } + + if (!this.shouldAbort) { + self.setTimeout(function() { + try { + _this.noEventsFired(); + } + catch (e) { + ok(false, "Unexpected error: " + e); + TestCounter.testComplete(); + } + }, TIME_NORMAL_LOAD); + } + else { + // Abort events can only be triggered on sent requests. + req.send(); + if (this.abortDelay == -1) { + abortReq(); + } + else { + self.setTimeout(abortReq, this.abortDelay); + } + } + }, + + /** + * Ensure that no events fired at all, especially not our timeout event. + */ + noEventsFired: function() { + ok(!this.hasFired, "No events should fire for an unsent, unaborted request"); + // We're done; if timeout hasn't fired by now, it never will. + TestCounter.testComplete(); + }, + + /** + * Get a message describing this test. + * + * @returns {String} The test description. + */ + getMessage: function() { + return "time to abort is " + this.abortDelay + ", timeout set at " + TIME_REGULAR_TIMEOUT; + }, + + /** + * Check the event received, and if it's the right (and only) one we get. + * + * WebKit fires abort events even for DONE and UNSENT states, which is + * discussed in http://webkit.org/b/98404 + * That's why we chose to accept secondary "abort" events in this test. + * + * @param {DOMProgressEvent} evt An event of type "load" or "timeout". + */ + handleEvent: function(evt) { + if (this.hasFired && evt.type != "abort") { + ok(false, "Only abort event should fire: " + this.getMessage()); + return; + } + + var expectedEvent = (this.abortDelay >= TIME_REGULAR_TIMEOUT && !this.hasFired) ? "timeout" : "abort"; + this.hasFired = true; + is(evt.type, expectedEvent, this.getMessage()); + TestCounter.testComplete(); + } +}; + +var SyncRequestSettingTimeoutAfterOpen = { + startXHR: function() { + var pass = false; + var req = new XMLHttpRequest(); + req.open("GET", STALLED_REQUEST_URL, false); + try { + req.timeout = TIME_SYNC_TIMEOUT; + } + catch (e) { + pass = true; + } + ok(pass, "Synchronous XHR must not allow a timeout to be set"); + TestCounter.testComplete(); + } +}; + +var SyncRequestSettingTimeoutBeforeOpen = { + startXHR: function() { + var pass = false; + var req = new XMLHttpRequest(); + req.timeout = TIME_SYNC_TIMEOUT; + try { + req.open("GET", STALLED_REQUEST_URL, false); + } + catch (e) { + pass = true; + } + ok(pass, "Synchronous XHR must not allow a timeout to be set"); + TestCounter.testComplete(); + } +}; + +var TestRequests = []; + +// This code controls moving from one test to another. +var TestCounter = { + testComplete: function() { + // Allow for the possibility there are other events coming. + self.setTimeout(function() { + TestCounter.next(); + }, TIME_NORMAL_LOAD); + }, + + next: function() { + var test = TestRequests.shift(); + + if (test) { + test.startXHR(); + } + else { + message("done"); + } + } +}; + +function runTestRequests(testRequests) { + TestRequests = testRequests; + TestCounter.next(); +}