Backed out changeset 62f7af8fe549 (bug 1843981) for causing valgrind bustage. CLOSED...
[gecko.git] / dom / xhr / tests / test_XHR.js
blob12eb06e4f6ad15f45f1ed197e0064bbb97f065ae
1 "use strict";
2 SimpleTest.waitForExplicitFinish();
4 var gen = runTests();
5 function continueTest() {
6   gen.next();
9 function* runTests() {
10   var expectHttp2Results = location.href.includes("http2");
12   var path = "/tests/dom/xhr/tests/";
14   var passFiles = [
15     ["file_XHR_pass1.xml", "GET", 200, "OK", "text/xml"],
16     ["file_XHR_pass2.txt", "GET", 200, "OK", "text/plain"],
17     ["file_XHR_pass3.txt", "GET", 200, "OK", "text/plain"],
18     ["data:text/xml,%3Cres%3Ehello%3C/res%3E%0A", "GET", 200, "OK", "text/xml"],
19     ["data:text/plain,hello%20pass%0A", "GET", 200, "OK", "text/plain"],
20     ["data:,foo", "GET", 200, "OK", "text/plain;charset=US-ASCII", "foo"],
21     ["data:text/plain;base64,Zm9v", "GET", 200, "OK", "text/plain", "foo"],
22     ["data:text/plain,foo#bar", "GET", 200, "OK", "text/plain", "foo"],
23     ["data:text/plain,foo%23bar", "GET", 200, "OK", "text/plain", "foo#bar"],
24   ];
26   var blob = new Blob(["foo"], { type: "text/plain" });
27   var blobURL = URL.createObjectURL(blob);
29   passFiles.push([blobURL, "GET", 200, "OK", "text/plain", "foo"]);
31   var failFiles = [
32     ["//example.com" + path + "file_XHR_pass1.xml", "GET"],
33     ["ftp://localhost" + path + "file_XHR_pass1.xml", "GET"],
34     ["file_XHR_fail1.txt", "GET"],
35   ];
37   for (i = 0; i < passFiles.length; ++i) {
38     // Function to give our hacked is() a scope
39     (function (oldIs) {
40       function is(actual, expected, message) {
41         oldIs(actual, expected, message + " for " + passFiles[i][0]);
42       }
43       xhr = new XMLHttpRequest();
44       is(xhr.getResponseHeader("Content-Type"), null, "should be null");
45       is(xhr.getAllResponseHeaders(), "", "should be empty string");
46       is(xhr.responseType, "", "wrong initial responseType");
47       xhr.open(passFiles[i][1], passFiles[i][0], false);
48       xhr.send(null);
49       is(xhr.status, passFiles[i][2], "wrong status");
51       // over HTTP2, no status text is received for network requests (but
52       // data/blob URLs default to "200 OK" responses)
53       let expectedStatusText = passFiles[i][3];
54       if (
55         expectHttp2Results &&
56         !passFiles[i][0].startsWith("data:") &&
57         !passFiles[i][0].startsWith("blob:")
58       ) {
59         expectedStatusText = "";
60       }
61       is(xhr.statusText, expectedStatusText, "wrong statusText");
63       is(
64         xhr.getResponseHeader("Content-Type"),
65         passFiles[i][4],
66         "wrong content type"
67       );
68       var headers = xhr.getAllResponseHeaders();
69       ok(
70         /(?:^|\n)Content-Type:\s*([^\r\n]*)\r\n/i.test(headers) &&
71           RegExp.$1 === passFiles[i][4],
72         "wrong response headers"
73       );
74       if (xhr.responseXML) {
75         is(
76           new XMLSerializer().serializeToString(
77             xhr.responseXML.documentElement
78           ),
79           passFiles[i][5] || "<res>hello</res>",
80           "wrong responseXML"
81         );
82         is(
83           xhr.response,
84           passFiles[i][5] || "<res>hello</res>\n",
85           "wrong response"
86         );
87       } else {
88         is(
89           xhr.responseText,
90           passFiles[i][5] || "hello pass\n",
91           "wrong responseText"
92         );
93         is(xhr.response, passFiles[i][5] || "hello pass\n", "wrong response");
94       }
95     })(is);
96   }
98   URL.revokeObjectURL(blobURL);
100   for (i = 0; i < failFiles.length; ++i) {
101     xhr = new XMLHttpRequest();
102     let didthrow = false;
103     try {
104       xhr.open(failFiles[i][1], failFiles[i][0], false);
105       xhr.send(null);
106     } catch (e) {
107       didthrow = true;
108     }
109     if (!didthrow) {
110       is(xhr.status, 301, "wrong status");
111       is(xhr.responseText, "redirect file\n", "wrong response");
112     } else {
113       ok(1, "should have thrown or given incorrect result");
114     }
115   }
117   function checkResponseTextAccessThrows(xhr) {
118     let didthrow = false;
119     try {
120       xhr.responseText;
121     } catch (e) {
122       didthrow = true;
123     }
124     ok(didthrow, "should have thrown when accessing responseText");
125   }
126   function checkResponseXMLAccessThrows(xhr) {
127     let didthrow = false;
128     try {
129       xhr.responseXML;
130     } catch (e) {
131       didthrow = true;
132     }
133     ok(didthrow, "should have thrown when accessing responseXML");
134   }
135   function checkSetResponseType(xhr, type) {
136     let didthrow = false;
137     try {
138       xhr.responseType = type;
139     } catch (e) {
140       didthrow = true;
141     }
142     is(xhr.responseType, type, "responseType should be " + type);
143     ok(!didthrow, "should not have thrown when setting responseType");
144   }
145   function checkSetResponseTypeThrows(xhr, type) {
146     let didthrow = false;
147     try {
148       xhr.responseType = type;
149     } catch (e) {
150       didthrow = true;
151     }
152     ok(didthrow, "should have thrown when setting responseType");
153   }
154   function checkOpenThrows(xhr, method, url, async) {
155     let didthrow = false;
156     try {
157       xhr.open(method, url, async);
158     } catch (e) {
159       didthrow = true;
160     }
161     ok(didthrow, "should have thrown when open is called");
162   }
164   // test if setting responseType before calling open() works
165   xhr = new XMLHttpRequest();
166   checkSetResponseType(xhr, "");
167   checkSetResponseType(xhr, "text");
168   checkSetResponseType(xhr, "document");
169   checkSetResponseType(xhr, "arraybuffer");
170   checkSetResponseType(xhr, "blob");
171   checkSetResponseType(xhr, "json");
172   checkOpenThrows(xhr, "GET", "file_XHR_pass2.txt", false);
174   // test response (sync, responseType is not changeable)
175   xhr = new XMLHttpRequest();
176   xhr.open("GET", "file_XHR_pass2.txt", false);
177   checkSetResponseTypeThrows(xhr, "");
178   checkSetResponseTypeThrows(xhr, "text");
179   checkSetResponseTypeThrows(xhr, "document");
180   checkSetResponseTypeThrows(xhr, "arraybuffer");
181   checkSetResponseTypeThrows(xhr, "blob");
182   checkSetResponseTypeThrows(xhr, "json");
183   xhr.send(null);
184   checkSetResponseTypeThrows(xhr, "document");
185   is(xhr.status, 200, "wrong status");
186   is(xhr.response, "hello pass\n", "wrong response");
188   // test response (responseType='document')
189   xhr = new XMLHttpRequest();
190   xhr.open("GET", "file_XHR_pass1.xml");
191   xhr.responseType = "document";
192   xhr.onloadend = continueTest;
193   xhr.send(null);
194   yield undefined;
195   checkSetResponseTypeThrows(xhr, "document");
196   is(xhr.status, 200, "wrong status");
197   checkResponseTextAccessThrows(xhr);
198   is(
199     new XMLSerializer().serializeToString(xhr.response.documentElement),
200     "<res>hello</res>",
201     "wrong response"
202   );
204   // test response (responseType='text')
205   xhr = new XMLHttpRequest();
206   xhr.open("GET", "file_XHR_pass2.txt");
207   xhr.responseType = "text";
208   xhr.onloadend = continueTest;
209   xhr.send(null);
210   yield undefined;
211   is(xhr.status, 200, "wrong status");
212   checkResponseXMLAccessThrows(xhr);
213   is(xhr.response, "hello pass\n", "wrong response");
215   // test response (responseType='arraybuffer')
216   function arraybuffer_equals_to(ab, s) {
217     is(ab.byteLength, s.length, "wrong arraybuffer byteLength");
219     var u8v = new Uint8Array(ab);
220     is(String.fromCharCode.apply(String, u8v), s, "wrong values");
221   }
223   // with a simple text file
224   xhr = new XMLHttpRequest();
225   xhr.open("GET", "file_XHR_pass2.txt");
226   xhr.responseType = "arraybuffer";
227   xhr.onloadend = continueTest;
228   xhr.send(null);
229   yield undefined;
230   is(xhr.status, 200, "wrong status");
231   checkResponseTextAccessThrows(xhr);
232   checkResponseXMLAccessThrows(xhr);
233   var ab = xhr.response;
234   ok(ab != null, "should have a non-null arraybuffer");
235   arraybuffer_equals_to(ab, "hello pass\n");
237   // test reusing the same XHR (Bug 680816)
238   xhr.open("GET", "file_XHR_binary1.bin");
239   xhr.responseType = "arraybuffer";
240   xhr.onloadend = continueTest;
241   xhr.send(null);
242   yield undefined;
243   is(xhr.status, 200, "wrong status");
244   var ab2 = xhr.response;
245   ok(ab2 != null, "should have a non-null arraybuffer");
246   ok(ab2 != ab, "arraybuffer on XHR reuse should be distinct");
247   arraybuffer_equals_to(ab, "hello pass\n");
248   arraybuffer_equals_to(ab2, "\xaa\xee\0\x03\xff\xff\xff\xff\xbb\xbb\xbb\xbb");
250   // with a binary file
251   xhr = new XMLHttpRequest();
252   xhr.open("GET", "file_XHR_binary1.bin");
253   xhr.responseType = "arraybuffer";
254   xhr.onloadend = continueTest;
255   xhr.send(null);
256   yield undefined;
257   is(xhr.status, 200, "wrong status");
258   checkResponseTextAccessThrows(xhr);
259   checkResponseXMLAccessThrows(xhr);
260   ab = xhr.response;
261   ok(ab != null, "should have a non-null arraybuffer");
262   arraybuffer_equals_to(ab, "\xaa\xee\0\x03\xff\xff\xff\xff\xbb\xbb\xbb\xbb");
263   is(xhr.response, xhr.response, "returns the same ArrayBuffer");
265   // test response (responseType='json')
266   var xhr = new XMLHttpRequest();
267   xhr.open("POST", "responseIdentical.sjs");
268   xhr.responseType = "json";
269   var jsonObjStr = JSON.stringify({ title: "aBook", author: "john" });
270   xhr.onloadend = continueTest;
271   xhr.send(jsonObjStr);
272   yield undefined;
273   is(xhr.status, 200, "wrong status");
274   checkResponseTextAccessThrows(xhr);
275   checkResponseXMLAccessThrows(xhr);
276   is(JSON.stringify(xhr.response), jsonObjStr, "correct result");
277   is(xhr.response, xhr.response, "returning the same object on each access");
279   // with invalid json
280   xhr = new XMLHttpRequest();
281   xhr.open("POST", "responseIdentical.sjs");
282   xhr.responseType = "json";
283   xhr.onloadend = continueTest;
284   xhr.send("{");
285   yield undefined;
286   is(xhr.status, 200, "wrong status");
287   checkResponseTextAccessThrows(xhr);
288   checkResponseXMLAccessThrows(xhr);
289   is(xhr.response, null, "Bad JSON should result in null response.");
290   is(
291     xhr.response,
292     null,
293     "Bad JSON should result in null response even 2nd time."
294   );
296   // Test status/statusText in all readyStates
297   xhr = new XMLHttpRequest();
298   function checkXHRStatus() {
299     if (xhr.readyState == xhr.UNSENT || xhr.readyState == xhr.OPENED) {
300       is(xhr.status, 0, "should be 0 before getting data");
301       is(xhr.statusText, "", "should be empty before getting data");
302     } else {
303       is(xhr.status, 200, "should be 200 when we have data");
304       if (expectHttp2Results) {
305         is(xhr.statusText, "", "should be '' when over HTTP2");
306       } else {
307         is(xhr.statusText, "OK", "should be OK when we have data");
308       }
309     }
310   }
311   checkXHRStatus();
312   xhr.open("GET", "file_XHR_binary1.bin");
313   checkXHRStatus();
314   xhr.responseType = "arraybuffer";
315   xhr.send(null);
316   xhr.onreadystatechange = continueTest;
317   while (xhr.readyState != 4) {
318     checkXHRStatus();
319     yield undefined;
320   }
321   checkXHRStatus();
323   // test response (responseType='blob')
324   // with a simple text file
325   xhr = new XMLHttpRequest();
326   xhr.open("GET", "file_XHR_pass2.txt");
327   xhr.responseType = "blob";
328   xhr.onloadend = continueTest;
329   xhr.send(null);
330   yield undefined;
331   is(xhr.status, 200, "wrong status");
332   checkResponseTextAccessThrows(xhr);
333   checkResponseXMLAccessThrows(xhr);
334   var b = xhr.response;
335   ok(b, "should have a non-null blob");
336   ok(b instanceof Blob, "should be a Blob");
337   ok(!(b instanceof File), "should not be a File");
338   is(b.size, "hello pass\n".length, "wrong blob size");
340   var fr = new FileReader();
341   fr.onload = continueTest;
342   fr.readAsBinaryString(b);
343   yield undefined;
344   is(fr.result, "hello pass\n", "wrong values");
346   // with a binary file
347   xhr = new XMLHttpRequest();
348   xhr.open("GET", "file_XHR_binary1.bin", true);
349   xhr.send(null);
350   xhr.onreadystatechange = continueTest;
351   while (xhr.readyState != 2) {
352     yield undefined;
353   }
355   is(xhr.status, 200, "wrong status");
356   xhr.responseType = "blob";
358   while (xhr.readyState != 4) {
359     yield undefined;
360   }
362   xhr.onreadystatechange = null;
364   b = xhr.response;
365   ok(b != null, "should have a non-null blob");
366   is(b.size, 12, "wrong blob size");
368   fr = new FileReader();
369   fr.readAsBinaryString(b);
370   xhr = null; // kill the XHR object
371   b = null;
372   SpecialPowers.gc();
373   fr.onload = continueTest;
374   yield undefined;
375   is(
376     fr.result,
377     "\xaa\xee\0\x03\xff\xff\xff\xff\xbb\xbb\xbb\xbb",
378     "wrong values"
379   );
381   // with a larger binary file
382   xhr = new XMLHttpRequest();
383   xhr.open("GET", "file_XHR_binary2.bin", true);
384   xhr.responseType = "blob";
385   xhr.send(null);
386   xhr.onreadystatechange = continueTest;
388   while (xhr.readyState != 4) {
389     yield undefined;
390   }
392   xhr.onreadystatechange = null;
394   b = xhr.response;
395   ok(b != null, "should have a non-null blob");
396   is(b.size, 65536, "wrong blob size");
398   fr = new FileReader();
399   fr.readAsArrayBuffer(b);
400   fr.onload = continueTest;
401   xhr = null; // kill the XHR object
402   b = null;
403   SpecialPowers.gc();
404   yield undefined;
406   var u8 = new Uint8Array(fr.result);
407   for (var i = 0; i < 65536; i++) {
408     if (u8[i] !== (i & 255)) {
409       break;
410     }
411   }
412   is(i, 65536, "wrong value at offset " + i);
414   var client = new XMLHttpRequest();
415   client.open("GET", "file_XHR_pass1.xml", true);
416   client.send();
417   client.onreadystatechange = function () {
418     if (client.readyState == 4) {
419       try {
420         is(client.responseXML, null, "responseXML should be null.");
421         is(client.responseText, "", "responseText should be empty string.");
422         is(client.response, "", "response should be empty string.");
423         is(client.status, 0, "status should be 0.");
424         is(client.statusText, "", "statusText should be empty string.");
425         is(
426           client.getAllResponseHeaders(),
427           "",
428           "getAllResponseHeaders() should return empty string."
429         );
430       } catch (ex) {
431         ok(false, "Shouldn't throw! [" + ex + "]");
432       }
433     }
434   };
435   client.abort();
437   SimpleTest.finish();
438 } /* runTests */