Backed out changeset 62f7af8fe549 (bug 1843981) for causing valgrind bustage. CLOSED...
[gecko.git] / dom / xhr / tests / file_XHRResponseURL.js
blob1ab1694bfa5b3e1e2306687639f87fc9db80b517
1 "use strict";
3 // utility functions for worker/window communication
5 function isInWorker() {
6   try {
7     return !(self instanceof Window);
8   } catch (e) {
9     return true;
10   }
13 function message(aData) {
14   if (isInWorker()) {
15     self.postMessage(aData);
16   } else {
17     self.postMessage(aData, "*");
18   }
20 message.ping = 0;
21 message.pong = 0;
23 function is(aActual, aExpected, aMessage) {
24   var obj = {
25     type: "is",
26     actual: aActual,
27     expected: aExpected,
28     message: aMessage,
29   };
30   ++message.ping;
31   message(obj);
34 function ok(aBool, aMessage) {
35   var obj = {
36     type: "ok",
37     bool: aBool,
38     message: aMessage,
39   };
40   ++message.ping;
41   message(obj);
44 function info(aMessage) {
45   var obj = {
46     type: "info",
47     message: aMessage,
48   };
49   ++message.ping;
50   message(obj);
53 function request(aURL) {
54   return new Promise(function (aResolve, aReject) {
55     var xhr = new XMLHttpRequest();
56     xhr.open("GET", aURL);
57     xhr.addEventListener("load", function () {
58       xhr.succeeded = true;
59       aResolve(xhr);
60     });
61     xhr.addEventListener("error", function () {
62       xhr.succeeded = false;
63       aResolve(xhr);
64     });
65     xhr.send();
66   });
69 function createSequentialRequest(aParameters, aTest) {
70   var sequence = aParameters.reduce(function (aPromise, aParam) {
71     return aPromise
72       .then(function () {
73         return request(aParam.requestURL);
74       })
75       .then(function (aXHR) {
76         return aTest(aXHR, aParam);
77       });
78   }, Promise.resolve());
80   return sequence;
83 function testSuccessResponse() {
84   var blob = new Blob(["data"], { type: "text/plain" });
85   var blobURL = URL.createObjectURL(blob);
87   var parameters = [
88     // tests that start with same-origin request
89     {
90       message: "request to same-origin without redirect",
91       requestURL:
92         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text",
93       responseURL:
94         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text",
95     },
96     {
97       message: "request to same-origin redirect to same-origin URL",
98       requestURL:
99         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text",
100       responseURL:
101         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text",
102     },
103     {
104       message:
105         "request to same-origin redirects several times and finally go to same-origin URL",
106       requestURL:
107         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" +
108         encodeURIComponent(
109           "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text"
110         ),
111       responseURL:
112         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text",
113     },
114     {
115       message: "request to same-origin redirect to cross-origin URL",
116       requestURL:
117         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text",
118       responseURL:
119         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text",
120     },
121     {
122       message:
123         "request to same-origin redirects several times and finally go to cross-origin URL",
124       requestURL:
125         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" +
126         encodeURIComponent(
127           "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text"
128         ),
129       responseURL:
130         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text",
131     },
133     // tests that start with cross-origin request
134     {
135       message: "request to cross-origin without redirect",
136       requestURL:
137         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text",
138       responseURL:
139         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text",
140     },
141     {
142       message: "request to cross-origin redirect back to same-origin URL",
143       requestURL:
144         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text",
145       responseURL:
146         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text",
147     },
148     {
149       message: "request to cross-origin redirect to the same cross-origin URL",
150       requestURL:
151         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text",
152       responseURL:
153         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text",
154     },
155     {
156       message: "request to cross-origin redirect to another cross-origin URL",
157       requestURL:
158         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.org/tests/dom/xhr/tests/file_XHRResponseURL.text",
159       responseURL:
160         "http://example.org/tests/dom/xhr/tests/file_XHRResponseURL.text",
161     },
162     {
163       message:
164         "request to cross-origin redirects several times and finally go to same-origin URL",
165       requestURL:
166         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" +
167         encodeURIComponent(
168           "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text"
169         ),
170       responseURL:
171         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text",
172     },
173     {
174       message:
175         "request to cross-origin redirects several times and finally go to the same cross-origin URL",
176       requestURL:
177         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" +
178         encodeURIComponent(
179           "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text"
180         ),
181       responseURL:
182         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.text",
183     },
184     {
185       message:
186         "request to cross-origin redirects several times and finally go to another cross-origin URL",
187       requestURL:
188         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" +
189         encodeURIComponent(
190           "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.org/tests/dom/xhr/tests/file_XHRResponseURL.text"
191         ),
192       responseURL:
193         "http://example.org/tests/dom/xhr/tests/file_XHRResponseURL.text",
194     },
195     {
196       message:
197         "request to cross-origin redirects to another cross-origin and finally go to the other cross-origin URL",
198       requestURL:
199         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=" +
200         encodeURIComponent(
201           "http://example.org/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://test1.example.com/tests/dom/xhr/tests/file_XHRResponseURL.text"
202         ),
203       responseURL:
204         "http://test1.example.com/tests/dom/xhr/tests/file_XHRResponseURL.text",
205     },
206     {
207       message: "request URL has fragment",
208       requestURL:
209         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text#fragment",
210       responseURL:
211         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text",
212     },
214     // tests for non-http(s) URL
215     {
216       message: "request to data: URL",
217       requestURL: "data:text/plain,data",
218       responseURL: "data:text/plain,data",
219     },
220     {
221       message: "request to blob: URL",
222       requestURL: blobURL,
223       responseURL: blobURL,
224     },
225   ];
227   var sequence = createSequentialRequest(parameters, function (aXHR, aParam) {
228     ok(aXHR.succeeded, "assert request succeeded");
229     is(aXHR.responseURL, aParam.responseURL, aParam.message);
230   });
232   sequence.then(function () {
233     URL.revokeObjectURL(blobURL);
234   });
236   return sequence;
239 function testFailedResponse() {
240   info("test not to leak responseURL for denied cross-origin request");
241   var parameters = [
242     {
243       message:
244         "should be empty for denied cross-origin request without redirect",
245       requestURL:
246         "http://example.com/tests/dom/xhr/tests/file_XHRResponseURL_nocors.text",
247     },
248     {
249       message: "should be empty for denied cross-origin request with redirect",
250       requestURL:
251         "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://example.com/tests/dom/xhr/tests/file_XHRResponseURL_nocors.text",
252     },
253   ];
255   var sequence = createSequentialRequest(parameters, function (aXHR, aParam) {
256     ok(!aXHR.succeeded, "assert request failed");
257     is(aXHR.responseURL, "", aParam.message);
258   });
260   return sequence;
263 function testNotToLeakResponseURLWhileDoingRedirects() {
264   info("test not to leak responeseURL while doing redirects");
266   if (isInWorker()) {
267     return testNotToLeakResponseURLWhileDoingRedirectsInWorker();
268   }
269   return testNotToLeakResponseURLWhileDoingRedirectsInWindow();
272 function testNotToLeakResponseURLWhileDoingRedirectsInWindow() {
273   var xhr = new XMLHttpRequest();
274   var requestObserver = {
275     observe(aSubject, aTopic, aData) {
276       is(xhr.readyState, XMLHttpRequest.OPENED, "assert for XHR state");
277       is(
278         xhr.responseURL,
279         "",
280         "responseURL should return empty string before HEADERS_RECEIVED"
281       );
282     },
283   };
284   SpecialPowers.addObserver(
285     requestObserver,
286     "specialpowers-http-notify-request"
287   );
289   return new Promise(function (aResolve, aReject) {
290     xhr.open(
291       "GET",
292       "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text"
293     );
294     xhr.addEventListener("load", function () {
295       SpecialPowers.removeObserver(
296         requestObserver,
297         "specialpowers-http-notify-request"
298       );
299       aResolve();
300     });
301     xhr.addEventListener("error", function () {
302       ok(false, "unexpected request falilure");
303       SpecialPowers.removeObserver(
304         requestObserver,
305         "specialpowers-http-notify-request"
306       );
307       aResolve();
308     });
309     xhr.send();
310   });
313 function testNotToLeakResponseURLWhileDoingRedirectsInWorker() {
314   var xhr = new XMLHttpRequest();
315   var testRedirect = function (e) {
316     if (e.data === "request" && xhr.readyState === XMLHttpRequest.OPENED) {
317       is(
318         xhr.responseURL,
319         "",
320         "responseURL should return empty string before HEADERS_RECEIVED"
321       );
322     }
323   };
325   return new Promise(function (aResolve, aReject) {
326     self.addEventListener("message", testRedirect);
327     message({ type: "redirect_test", status: "start" });
328     xhr.open(
329       "GET",
330       "http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.sjs?url=http://mochi.test:8888/tests/dom/xhr/tests/file_XHRResponseURL.text"
331     );
332     xhr.addEventListener("load", function () {
333       self.removeEventListener("message", testRedirect);
334       message({ type: "redirect_test", status: "end" });
335       aResolve();
336     });
337     xhr.addEventListener("error", function (e) {
338       ok(false, "unexpected request falilure");
339       self.removeEventListener("message", testRedirect);
340       message({ type: "redirect_test", status: "end" });
341       aResolve();
342     });
343     xhr.send();
344   });
347 function waitForAllMessagesProcessed() {
348   return new Promise(function (aResolve, aReject) {
349     var id = setInterval(function () {
350       if (message.ping === message.pong) {
351         clearInterval(id);
352         aResolve();
353       }
354     }, 100);
355   });
358 self.addEventListener("message", function (aEvent) {
359   if (aEvent.data === "start") {
360     ok(
361       "responseURL" in new XMLHttpRequest(),
362       "XMLHttpRequest should have responseURL attribute"
363     );
364     is(
365       new XMLHttpRequest().responseURL,
366       "",
367       "responseURL should be empty string if response's url is null"
368     );
370     var promise = testSuccessResponse();
371     promise
372       .then(function () {
373         return testFailedResponse();
374       })
375       .then(function () {
376         return testNotToLeakResponseURLWhileDoingRedirects();
377       })
378       .then(function () {
379         return waitForAllMessagesProcessed();
380       })
381       .then(function () {
382         message("done");
383       });
384   }
385   if (aEvent.data === "pong") {
386     ++message.pong;
387   }