test_restrequest.js (26106B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const { RESTRequest } = ChromeUtils.importESModule( 7 "resource://services-common/rest.sys.mjs" 8 ); 9 10 function run_test() { 11 Log.repository.getLogger("Services.Common.RESTRequest").level = 12 Log.Level.Trace; 13 initTestLogging("Trace"); 14 15 run_next_test(); 16 } 17 18 /** 19 * Initializing a RESTRequest with an invalid URI throws 20 * NS_ERROR_MALFORMED_URI. 21 */ 22 add_test(function test_invalid_uri() { 23 do_check_throws(function () { 24 new RESTRequest("an invalid URI"); 25 }, Cr.NS_ERROR_MALFORMED_URI); 26 run_next_test(); 27 }); 28 29 /** 30 * Verify initial values for attributes. 31 */ 32 add_test(function test_attributes() { 33 let uri = "http://foo.com/bar/baz"; 34 let request = new RESTRequest(uri); 35 36 Assert.ok(request.uri instanceof Ci.nsIURI); 37 Assert.equal(request.uri.spec, uri); 38 Assert.equal(request.response, null); 39 Assert.equal(request.status, request.NOT_SENT); 40 let expectedLoadFlags = 41 Ci.nsIRequest.LOAD_BYPASS_CACHE | 42 Ci.nsIRequest.INHIBIT_CACHING | 43 Ci.nsIRequest.LOAD_ANONYMOUS; 44 Assert.equal(request.loadFlags, expectedLoadFlags); 45 46 run_next_test(); 47 }); 48 49 /** 50 * Verify that a proxy auth redirect doesn't break us. This has to be the first 51 * request made in the file! 52 */ 53 add_task(async function test_proxy_auth_redirect() { 54 let pacFetched = false; 55 function pacHandler(metadata, response) { 56 pacFetched = true; 57 let body = 'function FindProxyForURL(url, host) { return "DIRECT"; }'; 58 response.setStatusLine(metadata.httpVersion, 200, "OK"); 59 response.setHeader( 60 "Content-Type", 61 "application/x-ns-proxy-autoconfig", 62 false 63 ); 64 response.bodyOutputStream.write(body, body.length); 65 } 66 67 let fetched = false; 68 function original(metadata, response) { 69 fetched = true; 70 let body = "TADA!"; 71 response.setStatusLine(metadata.httpVersion, 200, "OK"); 72 response.bodyOutputStream.write(body, body.length); 73 } 74 75 let server = httpd_setup({ 76 "/original": original, 77 "/pac3": pacHandler, 78 }); 79 PACSystemSettings.PACURI = server.baseURI + "/pac3"; 80 installFakePAC(); 81 82 let req = new RESTRequest(server.baseURI + "/original"); 83 await req.get(); 84 85 Assert.ok(pacFetched); 86 Assert.ok(fetched); 87 88 Assert.ok(req.response.success); 89 Assert.equal("TADA!", req.response.body); 90 uninstallFakePAC(); 91 await promiseStopServer(server); 92 }); 93 94 /** 95 * Ensure that failures that cause asyncOpen to throw 96 * result in callbacks being invoked. 97 * Bug 826086. 98 */ 99 add_task(async function test_forbidden_port() { 100 let request = new RESTRequest("http://localhost:6000/"); 101 102 await Assert.rejects( 103 request.get(), 104 error => error.result == Cr.NS_ERROR_PORT_ACCESS_NOT_ALLOWED 105 ); 106 }); 107 108 /** 109 * Demonstrate API short-hand: create a request and dispatch it immediately. 110 */ 111 add_task(async function test_simple_get() { 112 let handler = httpd_handler(200, "OK", "Huzzah!"); 113 let server = httpd_setup({ "/resource": handler }); 114 let request = new RESTRequest(server.baseURI + "/resource"); 115 let promiseResponse = request.get(); 116 117 Assert.equal(request.status, request.SENT); 118 Assert.equal(request.method, "GET"); 119 120 let response = await promiseResponse; 121 Assert.equal(response, request.response); 122 123 Assert.equal(request.status, request.COMPLETED); 124 Assert.ok(response.success); 125 Assert.equal(response.status, 200); 126 Assert.equal(response.body, "Huzzah!"); 127 await promiseStopServer(server); 128 }); 129 130 /** 131 * Test HTTP GET with all bells and whistles. 132 */ 133 add_task(async function test_get() { 134 let handler = httpd_handler(200, "OK", "Huzzah!"); 135 let server = httpd_setup({ "/resource": handler }); 136 137 let request = new RESTRequest(server.baseURI + "/resource"); 138 Assert.equal(request.status, request.NOT_SENT); 139 140 let promiseResponse = request.get(); 141 142 Assert.equal(request.status, request.SENT); 143 Assert.equal(request.method, "GET"); 144 145 Assert.ok(!!(request.channel.loadFlags & Ci.nsIRequest.LOAD_BYPASS_CACHE)); 146 Assert.ok(!!(request.channel.loadFlags & Ci.nsIRequest.INHIBIT_CACHING)); 147 148 let response = await promiseResponse; 149 150 Assert.equal(response, request.response); 151 Assert.equal(request.status, request.COMPLETED); 152 Assert.ok(request.response.success); 153 Assert.equal(request.response.status, 200); 154 Assert.equal(request.response.body, "Huzzah!"); 155 Assert.equal(handler.request.method, "GET"); 156 157 await Assert.rejects(request.get(), /Request has already been sent/); 158 159 await promiseStopServer(server); 160 }); 161 162 /** 163 * Test HTTP GET with UTF-8 content, and custom Content-Type. 164 */ 165 add_task(async function test_get_utf8() { 166 let response = "Hello World or Καλημέρα κόσμε or こんにちは 世界 😺"; 167 168 let contentType = "text/plain"; 169 let charset = true; 170 let charsetSuffix = "; charset=UTF-8"; 171 172 let server = httpd_setup({ 173 "/resource": function (req, res) { 174 res.setStatusLine(req.httpVersion, 200, "OK"); 175 res.setHeader( 176 "Content-Type", 177 contentType + (charset ? charsetSuffix : "") 178 ); 179 180 let converter = Cc[ 181 "@mozilla.org/intl/converter-output-stream;1" 182 ].createInstance(Ci.nsIConverterOutputStream); 183 converter.init(res.bodyOutputStream, "UTF-8"); 184 converter.writeString(response); 185 converter.close(); 186 }, 187 }); 188 189 // Check if charset in Content-Type is propertly interpreted. 190 let request1 = new RESTRequest(server.baseURI + "/resource"); 191 await request1.get(); 192 193 Assert.equal(request1.response.status, 200); 194 Assert.equal(request1.response.body, response); 195 Assert.equal( 196 request1.response.headers["content-type"], 197 contentType + charsetSuffix 198 ); 199 200 // Check that we default to UTF-8 if Content-Type doesn't have a charset 201 charset = false; 202 let request2 = new RESTRequest(server.baseURI + "/resource"); 203 await request2.get(); 204 Assert.equal(request2.response.status, 200); 205 Assert.equal(request2.response.body, response); 206 Assert.equal(request2.response.headers["content-type"], contentType); 207 Assert.equal(request2.response.charset, "utf-8"); 208 209 let request3 = new RESTRequest(server.baseURI + "/resource"); 210 211 // With the test server we tend to get onDataAvailable in chunks of 8192 (in 212 // real network requests there doesn't appear to be any pattern to the size of 213 // the data `onDataAvailable` is called with), the smiling cat emoji encodes as 214 // 4 bytes, and so when utf8 encoded, the `"a" + "😺".repeat(2048)` will not be 215 // aligned onto a codepoint. 216 // 217 // Since 8192 isn't guaranteed and could easily change, the following string is 218 // a) very long, and b) misaligned on roughly 3/4 of the bytes, as a safety 219 // measure. 220 response = ("a" + "😺".repeat(2048)).repeat(10); 221 222 await request3.get(); 223 224 Assert.equal(request3.response.status, 200); 225 226 // Make sure it came through ok, despite the misalignment. 227 Assert.equal(request3.response.body, response); 228 229 await promiseStopServer(server); 230 }); 231 232 /** 233 * Test HTTP POST data is encoded as UTF-8 by default. 234 */ 235 add_task(async function test_post_utf8() { 236 // We setup a handler that responds with exactly what it received. 237 // Given we've already tested above that responses are correctly utf-8 238 // decoded we can surmise that the correct response coming back means the 239 // input must also have been encoded. 240 let server = httpd_setup({ 241 "/echo": function (req, res) { 242 res.setStatusLine(req.httpVersion, 200, "OK"); 243 res.setHeader("Content-Type", req.getHeader("content-type")); 244 // Get the body as bytes and write them back without touching them 245 let sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance( 246 Ci.nsIScriptableInputStream 247 ); 248 sis.init(req.bodyInputStream); 249 let body = sis.read(sis.available()); 250 sis.close(); 251 res.write(body); 252 }, 253 }); 254 255 let data = { 256 copyright: "©", 257 // See the comment in test_get_utf8 about this string. 258 long: ("a" + "😺".repeat(2048)).repeat(10), 259 }; 260 let request1 = new RESTRequest(server.baseURI + "/echo"); 261 await request1.post(data); 262 263 Assert.equal(request1.response.status, 200); 264 deepEqual(JSON.parse(request1.response.body), data); 265 Assert.equal( 266 request1.response.headers["content-type"], 267 "application/json; charset=utf-8" 268 ); 269 270 await promiseStopServer(server); 271 }); 272 273 /** 274 * Test more variations of charset handling. 275 */ 276 add_task(async function test_charsets() { 277 let response = "Hello World, I can't speak Russian"; 278 279 let contentType = "text/plain"; 280 let charset = true; 281 let charsetSuffix = "; charset=us-ascii"; 282 283 let server = httpd_setup({ 284 "/resource": function (req, res) { 285 res.setStatusLine(req.httpVersion, 200, "OK"); 286 res.setHeader( 287 "Content-Type", 288 contentType + (charset ? charsetSuffix : "") 289 ); 290 291 let converter = Cc[ 292 "@mozilla.org/intl/converter-output-stream;1" 293 ].createInstance(Ci.nsIConverterOutputStream); 294 converter.init(res.bodyOutputStream, "us-ascii"); 295 converter.writeString(response); 296 converter.close(); 297 }, 298 }); 299 300 // Check that provided charset overrides hint. 301 let request1 = new RESTRequest(server.baseURI + "/resource"); 302 request1.charset = "not-a-charset"; 303 await request1.get(); 304 Assert.equal(request1.response.status, 200); 305 Assert.equal(request1.response.body, response); 306 Assert.equal( 307 request1.response.headers["content-type"], 308 contentType + charsetSuffix 309 ); 310 Assert.equal(request1.response.charset, "us-ascii"); 311 312 // Check that hint is used if Content-Type doesn't have a charset. 313 charset = false; 314 let request2 = new RESTRequest(server.baseURI + "/resource"); 315 request2.charset = "us-ascii"; 316 await request2.get(); 317 318 Assert.equal(request2.response.status, 200); 319 Assert.equal(request2.response.body, response); 320 Assert.equal(request2.response.headers["content-type"], contentType); 321 Assert.equal(request2.response.charset, "us-ascii"); 322 323 await promiseStopServer(server); 324 }); 325 326 /** 327 * Used for testing PATCH/PUT/POST methods. 328 */ 329 async function check_posting_data(method) { 330 let funcName = method.toLowerCase(); 331 let handler = httpd_handler(200, "OK", "Got it!"); 332 let server = httpd_setup({ "/resource": handler }); 333 334 let request = new RESTRequest(server.baseURI + "/resource"); 335 Assert.equal(request.status, request.NOT_SENT); 336 let responsePromise = request[funcName]("Hullo?"); 337 Assert.equal(request.status, request.SENT); 338 Assert.equal(request.method, method); 339 340 let response = await responsePromise; 341 342 Assert.equal(response, request.response); 343 344 Assert.equal(request.status, request.COMPLETED); 345 Assert.ok(request.response.success); 346 Assert.equal(request.response.status, 200); 347 Assert.equal(request.response.body, "Got it!"); 348 349 Assert.equal(handler.request.method, method); 350 Assert.equal(handler.request.body, "Hullo?"); 351 Assert.equal(handler.request.getHeader("Content-Type"), "text/plain"); 352 353 await Assert.rejects( 354 request[funcName]("Hai!"), 355 /Request has already been sent/ 356 ); 357 358 await promiseStopServer(server); 359 } 360 361 /** 362 * Test HTTP PATCH with a simple string argument and default Content-Type. 363 */ 364 add_task(async function test_patch() { 365 await check_posting_data("PATCH"); 366 }); 367 368 /** 369 * Test HTTP PUT with a simple string argument and default Content-Type. 370 */ 371 add_task(async function test_put() { 372 await check_posting_data("PUT"); 373 }); 374 375 /** 376 * Test HTTP POST with a simple string argument and default Content-Type. 377 */ 378 add_task(async function test_post() { 379 await check_posting_data("POST"); 380 }); 381 382 /** 383 * Test HTTP DELETE. 384 */ 385 add_task(async function test_delete() { 386 let handler = httpd_handler(200, "OK", "Got it!"); 387 let server = httpd_setup({ "/resource": handler }); 388 389 let request = new RESTRequest(server.baseURI + "/resource"); 390 Assert.equal(request.status, request.NOT_SENT); 391 let responsePromise = request.delete(); 392 Assert.equal(request.status, request.SENT); 393 Assert.equal(request.method, "DELETE"); 394 395 let response = await responsePromise; 396 Assert.equal(response, request.response); 397 398 Assert.equal(request.status, request.COMPLETED); 399 Assert.ok(request.response.success); 400 Assert.equal(request.response.status, 200); 401 Assert.equal(request.response.body, "Got it!"); 402 Assert.equal(handler.request.method, "DELETE"); 403 404 await Assert.rejects(request.delete(), /Request has already been sent/); 405 406 await promiseStopServer(server); 407 }); 408 409 /** 410 * Test an HTTP response with a non-200 status code. 411 */ 412 add_task(async function test_get_404() { 413 let handler = httpd_handler(404, "Not Found", "Cannae find it!"); 414 let server = httpd_setup({ "/resource": handler }); 415 416 let request = new RESTRequest(server.baseURI + "/resource"); 417 await request.get(); 418 419 Assert.equal(request.status, request.COMPLETED); 420 Assert.ok(!request.response.success); 421 Assert.equal(request.response.status, 404); 422 Assert.equal(request.response.body, "Cannae find it!"); 423 424 await promiseStopServer(server); 425 }); 426 427 /** 428 * The 'data' argument to PUT, if not a string already, is automatically 429 * stringified as JSON. 430 */ 431 add_task(async function test_put_json() { 432 let handler = httpd_handler(200, "OK"); 433 let server = httpd_setup({ "/resource": handler }); 434 435 let sample_data = { 436 some: "sample_data", 437 injson: "format", 438 number: 42, 439 }; 440 let request = new RESTRequest(server.baseURI + "/resource"); 441 await request.put(sample_data); 442 443 Assert.equal(request.status, request.COMPLETED); 444 Assert.ok(request.response.success); 445 Assert.equal(request.response.status, 200); 446 Assert.equal(request.response.body, ""); 447 448 Assert.equal(handler.request.method, "PUT"); 449 Assert.equal(handler.request.body, JSON.stringify(sample_data)); 450 Assert.equal( 451 handler.request.getHeader("Content-Type"), 452 "application/json; charset=utf-8" 453 ); 454 455 await promiseStopServer(server); 456 }); 457 458 /** 459 * The 'data' argument to POST, if not a string already, is automatically 460 * stringified as JSON. 461 */ 462 add_task(async function test_post_json() { 463 let handler = httpd_handler(200, "OK"); 464 let server = httpd_setup({ "/resource": handler }); 465 466 let sample_data = { 467 some: "sample_data", 468 injson: "format", 469 number: 42, 470 }; 471 let request = new RESTRequest(server.baseURI + "/resource"); 472 await request.post(sample_data); 473 474 Assert.equal(request.status, request.COMPLETED); 475 Assert.ok(request.response.success); 476 Assert.equal(request.response.status, 200); 477 Assert.equal(request.response.body, ""); 478 479 Assert.equal(handler.request.method, "POST"); 480 Assert.equal(handler.request.body, JSON.stringify(sample_data)); 481 Assert.equal( 482 handler.request.getHeader("Content-Type"), 483 "application/json; charset=utf-8" 484 ); 485 486 await promiseStopServer(server); 487 }); 488 489 /** 490 * The content-type will be text/plain without a charset if the 'data' argument 491 * to POST is already a string. 492 */ 493 add_task(async function test_post_json() { 494 let handler = httpd_handler(200, "OK"); 495 let server = httpd_setup({ "/resource": handler }); 496 497 let sample_data = "hello"; 498 let request = new RESTRequest(server.baseURI + "/resource"); 499 await request.post(sample_data); 500 Assert.equal(request.status, request.COMPLETED); 501 Assert.ok(request.response.success); 502 Assert.equal(request.response.status, 200); 503 Assert.equal(request.response.body, ""); 504 505 Assert.equal(handler.request.method, "POST"); 506 Assert.equal(handler.request.body, sample_data); 507 Assert.equal(handler.request.getHeader("Content-Type"), "text/plain"); 508 509 await promiseStopServer(server); 510 }); 511 512 /** 513 * HTTP PUT with a custom Content-Type header. 514 */ 515 add_task(async function test_put_override_content_type() { 516 let handler = httpd_handler(200, "OK"); 517 let server = httpd_setup({ "/resource": handler }); 518 519 let request = new RESTRequest(server.baseURI + "/resource"); 520 request.setHeader("Content-Type", "application/lolcat"); 521 await request.put("O HAI!!1!"); 522 523 Assert.equal(request.status, request.COMPLETED); 524 Assert.ok(request.response.success); 525 Assert.equal(request.response.status, 200); 526 Assert.equal(request.response.body, ""); 527 528 Assert.equal(handler.request.method, "PUT"); 529 Assert.equal(handler.request.body, "O HAI!!1!"); 530 Assert.equal(handler.request.getHeader("Content-Type"), "application/lolcat"); 531 532 await promiseStopServer(server); 533 }); 534 535 /** 536 * HTTP POST with a custom Content-Type header. 537 */ 538 add_task(async function test_post_override_content_type() { 539 let handler = httpd_handler(200, "OK"); 540 let server = httpd_setup({ "/resource": handler }); 541 542 let request = new RESTRequest(server.baseURI + "/resource"); 543 request.setHeader("Content-Type", "application/lolcat"); 544 await request.post("O HAI!!1!"); 545 546 Assert.equal(request.status, request.COMPLETED); 547 Assert.ok(request.response.success); 548 Assert.equal(request.response.status, 200); 549 Assert.equal(request.response.body, ""); 550 551 Assert.equal(handler.request.method, "POST"); 552 Assert.equal(handler.request.body, "O HAI!!1!"); 553 Assert.equal(handler.request.getHeader("Content-Type"), "application/lolcat"); 554 555 await promiseStopServer(server); 556 }); 557 558 /** 559 * No special headers are sent by default on a GET request. 560 */ 561 add_task(async function test_get_no_headers() { 562 let handler = httpd_handler(200, "OK"); 563 let server = httpd_setup({ "/resource": handler }); 564 565 let ignore_headers = [ 566 "host", 567 "user-agent", 568 "accept", 569 "accept-language", 570 "accept-encoding", 571 "accept-charset", 572 "keep-alive", 573 "connection", 574 "pragma", 575 "cache-control", 576 "content-length", 577 "sec-fetch-dest", 578 "sec-fetch-mode", 579 "sec-fetch-site", 580 "sec-fetch-user", 581 "priority", 582 ]; 583 let request = new RESTRequest(server.baseURI + "/resource"); 584 await request.get(); 585 586 Assert.equal(request.response.status, 200); 587 Assert.equal(request.response.body, ""); 588 589 let server_headers = handler.request.headers; 590 while (server_headers.hasMoreElements()) { 591 let header = server_headers.getNext().toString(); 592 if (!ignore_headers.includes(header)) { 593 do_throw("Got unexpected header!"); 594 } 595 } 596 597 await promiseStopServer(server); 598 }); 599 600 /** 601 * Client includes default Accept header in API requests 602 */ 603 add_task(async function test_default_accept_headers() { 604 let handler = httpd_handler(200, "OK"); 605 let server = httpd_setup({ "/resource": handler }); 606 607 let request = new RESTRequest(server.baseURI + "/resource"); 608 await request.get(); 609 610 Assert.equal(request.response.status, 200); 611 Assert.equal(request.response.body, ""); 612 613 let accept_header = handler.request.getHeader("accept"); 614 615 Assert.ok(!accept_header.includes("text/html")); 616 Assert.ok(!accept_header.includes("application/xhtml+xml")); 617 Assert.ok(!accept_header.includes("applcation/xml")); 618 619 Assert.ok( 620 accept_header.includes("application/json") || 621 accept_header.includes("application/newlines") 622 ); 623 624 await promiseStopServer(server); 625 }); 626 627 /** 628 * Test changing the URI after having created the request. 629 */ 630 add_task(async function test_changing_uri() { 631 let handler = httpd_handler(200, "OK"); 632 let server = httpd_setup({ "/resource": handler }); 633 634 let request = new RESTRequest("http://localhost:1234/the-wrong-resource"); 635 request.uri = CommonUtils.makeURI(server.baseURI + "/resource"); 636 let response = await request.get(); 637 Assert.equal(response.status, 200); 638 await promiseStopServer(server); 639 }); 640 641 /** 642 * Test setting HTTP request headers. 643 */ 644 add_task(async function test_request_setHeader() { 645 let handler = httpd_handler(200, "OK"); 646 let server = httpd_setup({ "/resource": handler }); 647 648 let request = new RESTRequest(server.baseURI + "/resource"); 649 650 request.setHeader("X-What-Is-Weave", "awesome"); 651 request.setHeader("X-WHAT-is-Weave", "more awesomer"); 652 request.setHeader("Another-Header", "Hello World"); 653 await request.get(); 654 655 Assert.equal(request.response.status, 200); 656 Assert.equal(request.response.body, ""); 657 658 Assert.equal(handler.request.getHeader("X-What-Is-Weave"), "more awesomer"); 659 Assert.equal(handler.request.getHeader("another-header"), "Hello World"); 660 661 await promiseStopServer(server); 662 }); 663 664 /** 665 * Test receiving HTTP response headers. 666 */ 667 add_task(async function test_response_headers() { 668 function handler(request, response) { 669 response.setHeader("X-What-Is-Weave", "awesome"); 670 response.setHeader("Another-Header", "Hello World"); 671 response.setStatusLine(request.httpVersion, 200, "OK"); 672 } 673 let server = httpd_setup({ "/resource": handler }); 674 let request = new RESTRequest(server.baseURI + "/resource"); 675 await request.get(); 676 677 Assert.equal(request.response.status, 200); 678 Assert.equal(request.response.body, ""); 679 680 Assert.equal(request.response.headers["x-what-is-weave"], "awesome"); 681 Assert.equal(request.response.headers["another-header"], "Hello World"); 682 683 await promiseStopServer(server); 684 }); 685 686 /** 687 * The onComplete() handler gets called in case of any network errors 688 * (e.g. NS_ERROR_CONNECTION_REFUSED). 689 */ 690 add_task(async function test_connection_refused() { 691 let request = new RESTRequest("http://localhost:1234/resource"); 692 693 // Fail the test if we resolve, return the error if we reject 694 await Assert.rejects( 695 request.get(), 696 error => 697 error.result == Cr.NS_ERROR_CONNECTION_REFUSED && 698 error.message == "NS_ERROR_CONNECTION_REFUSED" 699 ); 700 701 Assert.equal(request.status, request.COMPLETED); 702 }); 703 704 /** 705 * Abort a request that just sent off. 706 */ 707 add_task(async function test_abort() { 708 function handler() { 709 do_throw("Shouldn't have gotten here!"); 710 } 711 let server = httpd_setup({ "/resource": handler }); 712 713 let request = new RESTRequest(server.baseURI + "/resource"); 714 715 // Aborting a request that hasn't been sent yet is pointless and will throw. 716 do_check_throws(function () { 717 request.abort(); 718 }); 719 720 let responsePromise = request.get(); 721 request.abort(); 722 723 // Aborting an already aborted request is pointless and will throw. 724 do_check_throws(function () { 725 request.abort(); 726 }); 727 728 Assert.equal(request.status, request.ABORTED); 729 730 await Assert.rejects(responsePromise, /NS_BINDING_ABORTED/); 731 732 await promiseStopServer(server); 733 }); 734 735 /** 736 * A non-zero 'timeout' property specifies the amount of seconds to wait after 737 * channel activity until the request is automatically canceled. 738 */ 739 add_task(async function test_timeout() { 740 let server = new HttpServer(); 741 let server_connection; 742 server._handler.handleResponse = function (connection) { 743 // This is a handler that doesn't do anything, just keeps the connection 744 // open, thereby mimicking a timing out connection. We keep a reference to 745 // the open connection for later so it can be properly disposed of. That's 746 // why you really only want to make one HTTP request to this server ever. 747 server_connection = connection; 748 }; 749 server.start(); 750 let identity = server.identity; 751 let uri = 752 identity.primaryScheme + 753 "://" + 754 identity.primaryHost + 755 ":" + 756 identity.primaryPort; 757 758 let request = new RESTRequest(uri + "/resource"); 759 request.timeout = 0.1; // 100 milliseconds 760 761 await Assert.rejects( 762 request.get(), 763 error => error.result == Cr.NS_ERROR_NET_TIMEOUT 764 ); 765 766 Assert.equal(request.status, request.ABORTED); 767 768 // server_connection is undefined on the Android emulator for reasons 769 // unknown. Yet, we still get here. If this test is refactored, we should 770 // investigate the reason why the above callback is behaving differently. 771 if (server_connection) { 772 _("Closing connection."); 773 server_connection.close(); 774 } 775 await promiseStopServer(server); 776 }); 777 778 add_task(async function test_new_channel() { 779 _("Ensure a redirect to a new channel is handled properly."); 780 781 function checkUA(metadata) { 782 let ua = metadata.getHeader("User-Agent"); 783 _("User-Agent is " + ua); 784 Assert.equal("foo bar", ua); 785 } 786 787 let redirectRequested = false; 788 let redirectURL; 789 function redirectHandler(metadata, response) { 790 checkUA(metadata); 791 redirectRequested = true; 792 793 let body = "Redirecting"; 794 response.setStatusLine(metadata.httpVersion, 307, "TEMPORARY REDIRECT"); 795 response.setHeader("Location", redirectURL); 796 response.bodyOutputStream.write(body, body.length); 797 } 798 799 let resourceRequested = false; 800 function resourceHandler(metadata, response) { 801 checkUA(metadata); 802 resourceRequested = true; 803 804 let body = "Test"; 805 response.setHeader("Content-Type", "text/plain"); 806 response.bodyOutputStream.write(body, body.length); 807 } 808 809 let server1 = httpd_setup({ "/redirect": redirectHandler }); 810 let server2 = httpd_setup({ "/resource": resourceHandler }); 811 redirectURL = server2.baseURI + "/resource"; 812 813 let request = new RESTRequest(server1.baseURI + "/redirect"); 814 request.setHeader("User-Agent", "foo bar"); 815 816 // Swizzle in our own fakery, because this redirect is neither 817 // internal nor URI-preserving. RESTRequest's policy is to only 818 // copy headers under certain circumstances. 819 let protoMethod = request.shouldCopyOnRedirect; 820 request.shouldCopyOnRedirect = function wrapped(o, n, f) { 821 // Check the default policy. 822 Assert.ok(!protoMethod.call(this, o, n, f)); 823 return true; 824 }; 825 826 let response = await request.get(); 827 828 Assert.equal(200, response.status); 829 Assert.equal("Test", response.body); 830 Assert.ok(redirectRequested); 831 Assert.ok(resourceRequested); 832 833 await promiseStopServer(server1); 834 await promiseStopServer(server2); 835 }); 836 837 add_task(async function test_not_sending_cookie() { 838 function handler(metadata, response) { 839 let body = "COOKIE!"; 840 response.setStatusLine(metadata.httpVersion, 200, "OK"); 841 response.bodyOutputStream.write(body, body.length); 842 Assert.ok(!metadata.hasHeader("Cookie")); 843 } 844 let server = httpd_setup({ "/test": handler }); 845 846 let uri = CommonUtils.makeURI(server.baseURI); 847 let channel = NetUtil.newChannel({ 848 uri, 849 loadUsingSystemPrincipal: true, 850 contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, 851 }); 852 Services.cookies.setCookieStringFromHttp(uri, "test=test; path=/;", channel); 853 854 let res = new RESTRequest(server.baseURI + "/test"); 855 let response = await res.get(); 856 857 Assert.ok(response.success); 858 Assert.equal("COOKIE!", response.body); 859 860 await promiseStopServer(server); 861 });