diff options
Diffstat (limited to 'dom/xhr/tests/file_XHRResponseURL.js')
-rw-r--r-- | dom/xhr/tests/file_XHRResponseURL.js | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/dom/xhr/tests/file_XHRResponseURL.js b/dom/xhr/tests/file_XHRResponseURL.js new file mode 100644 index 000000000..7c48201b2 --- /dev/null +++ b/dom/xhr/tests/file_XHRResponseURL.js @@ -0,0 +1,303 @@ +"use strict"; + +// utility functions for worker/window communication + +function isInWorker() { + try { + return !(self instanceof Window); + } catch (e) { + return true; + } +} + +function message(aData) { + if (isInWorker()) { + self.postMessage(aData); + } else { + self.postMessage(aData, "*"); + } +} +message.ping = 0; +message.pong = 0; + +function is(aActual, aExpected, aMessage) { + var obj = { + type: "is", + actual: aActual, + expected: aExpected, + message: aMessage + }; + ++message.ping; + message(obj); +} + +function ok(aBool, aMessage) { + var obj = { + type: "ok", + bool: aBool, + message: aMessage + }; + ++message.ping; + message(obj); +} + +function info(aMessage) { + var obj = { + type: "info", + message: aMessage + }; + ++message.ping; + message(obj); +} + +function request(aURL) { + return new Promise(function (aResolve, aReject) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", aURL); + xhr.addEventListener("load", function () { + xhr.succeeded = true; + aResolve(xhr); + }); + xhr.addEventListener("error", function () { + xhr.succeeded = false; + aResolve(xhr); + }); + xhr.send(); + }); +} + +function createSequentialRequest(aParameters, aTest) { + var sequence = aParameters.reduce(function (aPromise, aParam) { + return aPromise.then(function () { + return request(aParam.requestURL); + }).then(function (aXHR) { + return aTest(aXHR, aParam); + }); + }, Promise.resolve()); + + return sequence; +} + +function testSuccessResponse() { + var blob = new Blob(["data"], {type: "text/plain"}); + var blobURL = URL.createObjectURL(blob); + + var parameters = [ + // tests that start with same-origin request + { + message: "request to same-origin without redirect", + requestURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text", + responseURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text" + }, + { + message: "request to same-origin redirect to same-origin URL", + requestURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text", + responseURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text" + }, + { + message: "request to same-origin redirects several times and finally go to same-origin URL", + requestURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" + encodeURIComponent("http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text"), + responseURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text" + }, + { + message: "request to same-origin redirect to cross-origin URL", + requestURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text", + responseURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text", + }, + { + message: "request to same-origin redirects several times and finally go to cross-origin URL", + requestURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" + encodeURIComponent("http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text"), + responseURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text", + }, + + // tests that start with cross-origin request + { + message: "request to cross-origin without redirect", + requestURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text", + responseURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text" + }, + { + message: "request to cross-origin redirect back to same-origin URL", + requestURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text", + responseURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text" + }, + { + message: "request to cross-origin redirect to the same cross-origin URL", + requestURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text", + responseURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text", + }, + { + message: "request to cross-origin redirect to another cross-origin URL", + requestURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.org/tests/dom/xhr/tests/file_XHRResponseURL.text", + responseURL: "http://example.org/tests/dom/xhr/tests/file_XHRResponseURL.text", + }, + { + message: "request to cross-origin redirects several times and finally go to same-origin URL", + requestURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" + encodeURIComponent("http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text"), + responseURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text", + }, + { + message: "request to cross-origin redirects several times and finally go to the same cross-origin URL", + requestURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" + encodeURIComponent("http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text"), + responseURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text", + }, + { + message: "request to cross-origin redirects several times and finally go to another cross-origin URL", + requestURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" + encodeURIComponent("http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.org/tests/dom/xhr/tests/file_XHRResponseURL.text"), + responseURL: "http://example.org/tests/dom/xhr/tests/file_XHRResponseURL.text", + }, + { + message: "request to cross-origin redirects to another cross-origin and finally go to the other cross-origin URL", + requestURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" + encodeURIComponent("http://example.org/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://test1.example.com/tests/dom/xhr/tests/file_XHRResponseURL.text"), + responseURL: "http://test1.example.com/tests/dom/xhr/tests/file_XHRResponseURL.text", + }, + { + message: "request URL has fragment", + requestURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text#fragment", + responseURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text" + }, + + // tests for non-http(s) URL + { + message: "request to data: URL", + requestURL: "data:text/plain,data", + responseURL: "data:text/plain,data" + }, + { + message: "request to blob: URL", + requestURL: blobURL, + responseURL: blobURL + } + ]; + + var sequence = createSequentialRequest(parameters, function (aXHR, aParam) { + ok(aXHR.succeeded, "assert request succeeded"); + is(aXHR.responseURL, aParam.responseURL, aParam.message); + }); + + sequence.then(function () { + URL.revokeObjectURL(blobURL); + }); + + return sequence; +} + +function testFailedResponse() { + info("test not to leak responseURL for denied cross-origin request"); + var parameters = [ + { + message: "should be empty for denied cross-origin request without redirect", + requestURL: "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL_nocors.text" + }, + { + message: "should be empty for denied cross-origin request with redirect", + requestURL: "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRResponseURL_nocors.text" + } + ]; + + var sequence = createSequentialRequest(parameters, function (aXHR, aParam) { + ok(!aXHR.succeeded, "assert request failed"); + is(aXHR.responseURL, "" , aParam.message); + }); + + return sequence; +} + +function testNotToLeakResponseURLWhileDoingRedirects() { + info("test not to leak responeseURL while doing redirects"); + + if (isInWorker()) { + return testNotToLeakResponseURLWhileDoingRedirectsInWorker(); + } else { + return testNotToLeakResponseURLWhileDoingRedirectsInWindow(); + } +} + +function testNotToLeakResponseURLWhileDoingRedirectsInWindow() { + var xhr = new XMLHttpRequest(); + var requestObserver = { + observe: function (aSubject, aTopic, aData) { + is(xhr.readyState, XMLHttpRequest.OPENED, "assert for XHR state"); + is(xhr.responseURL, "", + "responseURL should return empty string before HEADERS_RECEIVED"); + } + }; + SpecialPowers.addObserver(requestObserver, "specialpowers-http-notify-request", false); + + return new Promise(function (aResolve, aReject) { + xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text"); + xhr.addEventListener("load", function () { + SpecialPowers.removeObserver(requestObserver, "specialpowers-http-notify-request"); + aResolve(); + }); + xhr.addEventListener("error", function () { + ok(false, "unexpected request falilure"); + SpecialPowers.removeObserver(requestObserver, "specialpowers-http-notify-request"); + aResolve(); + }); + xhr.send(); + }); +} + +function testNotToLeakResponseURLWhileDoingRedirectsInWorker() { + var xhr = new XMLHttpRequest(); + var testRedirect = function (e) { + if (e.data === "request" && xhr.readyState === XMLHttpRequest.OPENED) { + is(xhr.responseURL, "", + "responseURL should return empty string before HEADERS_RECEIVED"); + } + }; + + return new Promise(function (aResolve, aReject) { + self.addEventListener("message", testRedirect); + message({type: "redirect_test", status: "start"}); + xhr.open("GET", "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text"); + xhr.addEventListener("load", function () { + self.removeEventListener("message", testRedirect); + message({type: "redirect_test", status: "end"}); + aResolve(); + }); + xhr.addEventListener("error", function (e) { + ok(false, "unexpected request falilure"); + self.removeEventListener("message", testRedirect); + message({type: "redirect_test", status: "end"}); + aResolve(); + }); + xhr.send(); + }); +} + +function waitForAllMessagesProcessed() { + return new Promise(function (aResolve, aReject) { + var id = setInterval(function () { + if (message.ping === message.pong) { + clearInterval(id); + aResolve(); + } + }, 100); + }); +} + + +self.addEventListener("message", function (aEvent) { + if (aEvent.data === "start") { + ok("responseURL" in (new XMLHttpRequest()), + "XMLHttpRequest should have responseURL attribute"); + is((new XMLHttpRequest()).responseURL, "", + "responseURL should be empty string if response's url is null"); + + var promise = testSuccessResponse(); + promise.then(function () { + return testFailedResponse(); + }).then(function () { + return testNotToLeakResponseURLWhileDoingRedirects(); + }).then(function () { + return waitForAllMessagesProcessed(); + }).then(function () { + message("done"); + }); + } + if (aEvent.data === "pong") { + ++message.pong; + } +}); |