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