websocket_tests.js (38042B)
1 // This file expects websocket_helpers.js to be loaded in the same scope. 2 /* import-globals-from websocket_helpers.js */ 3 4 // test1: client tries to connect to a http scheme location; 5 function test1() { 6 return new Promise(function (resolve) { 7 var ws = CreateTestWS( 8 "http://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 9 "test-1" 10 ); 11 12 ws.onmessage = function () { 13 ok(true, "created websocket with http scheme"); 14 }; 15 16 ws.onclose = function (e) { 17 shouldCloseCleanly(e); 18 resolve(); 19 }; 20 }); 21 } 22 23 // test2: assure serialization of the connections; 24 // this test expects that the serialization list to connect to the proxy 25 // is empty. 26 function test2() { 27 return new Promise(function (resolve) { 28 var waitTest2Part1 = true; 29 var waitTest2Part2 = true; 30 31 var ws1 = CreateTestWS( 32 "ws://sub2.test2.example.com/tests/dom/websocket/tests/file_websocket", 33 "test-2.1" 34 ); 35 var ws2 = CreateTestWS( 36 "ws://sub2.test2.example.com/tests/dom/websocket/tests/file_websocket", 37 "test-2.2" 38 ); 39 40 var ws2CanConnect = false; 41 42 function maybeFinished() { 43 if (!waitTest2Part1 && !waitTest2Part2) { 44 resolve(); 45 } 46 } 47 48 ws1.onopen = function () { 49 ok(true, "ws1 open in test 2"); 50 ws2CanConnect = true; 51 ws1.close(); 52 }; 53 54 ws1.onclose = function () { 55 waitTest2Part1 = false; 56 maybeFinished(); 57 }; 58 59 ws2.onopen = function () { 60 ok(ws2CanConnect, "shouldn't connect yet in test-2!"); 61 ws2.close(); 62 }; 63 64 ws2.onclose = function () { 65 waitTest2Part2 = false; 66 maybeFinished(); 67 }; 68 }); 69 } 70 71 // test3: client tries to connect to an non-existent ws server; 72 function test3() { 73 return new Promise(function (resolve) { 74 var hasError = false; 75 var ws = CreateTestWS("ws://this.websocket.server.probably.does.not.exist"); 76 77 ws.onopen = shouldNotOpen; 78 79 ws.onerror = function () { 80 hasError = true; 81 }; 82 83 ws.onclose = function (e) { 84 shouldCloseNotCleanly(e); 85 ok(hasError, "rcvd onerror event"); 86 is(e.code, 1006, "test-3 close code should be 1006 but is:" + e.code); 87 resolve(); 88 }; 89 }); 90 } 91 92 // test4: client tries to connect using a relative url; 93 function test4() { 94 return new Promise(function (resolve) { 95 var ws = CreateTestWS("file_websocket", "test-4"); 96 97 ws.onmessage = function () { 98 ok(true, "created websocket with relative scheme"); 99 }; 100 101 ws.onclose = function (e) { 102 shouldCloseCleanly(e); 103 resolve(); 104 }; 105 }); 106 } 107 108 // test5: client uses an invalid protocol value; 109 function test5() { 110 return new Promise(function (resolve) { 111 try { 112 CreateTestWS( 113 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 114 "" 115 ); 116 ok(false, "couldn't accept an empty string in the protocol parameter"); 117 } catch (e) { 118 ok(true, "couldn't accept an empty string in the protocol parameter"); 119 } 120 121 try { 122 CreateTestWS( 123 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 124 "\n" 125 ); 126 ok( 127 false, 128 "couldn't accept any not printable ASCII character in the protocol parameter" 129 ); 130 } catch (e) { 131 ok( 132 true, 133 "couldn't accept any not printable ASCII character in the protocol parameter" 134 ); 135 } 136 137 try { 138 CreateTestWS( 139 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 140 "test 5" 141 ); 142 ok(false, "U+0020 not acceptable in protocol parameter"); 143 } catch (e) { 144 ok(true, "U+0020 not acceptable in protocol parameter"); 145 } 146 147 resolve(); 148 }); 149 } 150 151 // test6: counter and encoding check; 152 function test6() { 153 return new Promise(function (resolve) { 154 var ws = CreateTestWS( 155 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 156 "test-6" 157 ); 158 var counter = 1; 159 160 ws.onopen = function () { 161 ws.send(counter); 162 }; 163 164 ws.onmessage = function (e) { 165 if (counter == 5) { 166 is(e.data, "あいうえお", "test-6 counter 5 data ok"); 167 ws.close(); 168 } else { 169 is(parseInt(e.data), counter + 1, "bad counter"); 170 counter += 2; 171 ws.send(counter); 172 } 173 }; 174 175 ws.onclose = function (e) { 176 shouldCloseCleanly(e); 177 resolve(); 178 }; 179 }); 180 } 181 182 // test7: onmessage event origin property check 183 function test7() { 184 return new Promise(function (resolve) { 185 var ws = CreateTestWS( 186 "ws://sub2.test2.example.org/tests/dom/websocket/tests/file_websocket", 187 "test-7" 188 ); 189 var gotmsg = false; 190 191 ws.onopen = function () { 192 ok(true, "test 7 open"); 193 }; 194 195 ws.onmessage = function (e) { 196 ok(true, "test 7 message"); 197 is( 198 e.origin, 199 "ws://sub2.test2.example.org", 200 "onmessage origin set to ws:// host" 201 ); 202 gotmsg = true; 203 ws.close(); 204 }; 205 206 ws.onclose = function (e) { 207 ok(gotmsg, "recvd message in test 7 before close"); 208 shouldCloseCleanly(e); 209 resolve(); 210 }; 211 }); 212 } 213 214 // test8: client calls close() and the server sends the close frame (with no 215 // code or reason) in acknowledgement; 216 function test8() { 217 return new Promise(function (resolve) { 218 var ws = CreateTestWS( 219 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 220 "test-8" 221 ); 222 223 ws.onopen = function () { 224 is(ws.protocol, "test-8", "test-8 subprotocol selection"); 225 ws.close(); 226 }; 227 228 ws.onclose = function (e) { 229 shouldCloseCleanly(e); 230 // We called close() with no close code: so pywebsocket will also send no 231 // close code, which translates to code 1005 232 is(e.code, 1005, "test-8 close code has wrong value:" + e.code); 233 is(e.reason, "", "test-8 close reason has wrong value:" + e.reason); 234 resolve(); 235 }; 236 }); 237 } 238 239 // test9: client closes the connection before the ws connection is established; 240 function test9() { 241 return new Promise(function (resolve) { 242 var ws = CreateTestWS( 243 "ws://test2.example.org/tests/dom/websocket/tests/file_websocket", 244 "test-9" 245 ); 246 247 ws._receivedErrorEvent = false; 248 249 ws.onopen = shouldNotOpen; 250 251 ws.onerror = function () { 252 ws._receivedErrorEvent = true; 253 }; 254 255 ws.onclose = function (e) { 256 ok(ws._receivedErrorEvent, "Didn't received the error event in test 9."); 257 shouldCloseNotCleanly(e); 258 resolve(); 259 }; 260 261 ws.close(); 262 }); 263 } 264 265 // test10: client sends a message before the ws connection is established; 266 function test10() { 267 return new Promise(function (resolve) { 268 var ws = CreateTestWS( 269 "ws://sub1.test1.example.com/tests/dom/websocket/tests/file_websocket", 270 "test-10" 271 ); 272 273 ws.onclose = function (e) { 274 shouldCloseCleanly(e); 275 resolve(); 276 }; 277 278 try { 279 ws.send("client data"); 280 ok(false, "Couldn't send data before connecting!"); 281 } catch (e) { 282 ok(true, "Couldn't send data before connecting!"); 283 } 284 285 ws.onopen = function () { 286 ok(true, "test 10 opened"); 287 ws.close(); 288 }; 289 }); 290 } 291 292 // test11: a simple hello echo; 293 function test11() { 294 return new Promise(function (resolve) { 295 var ws = CreateTestWS( 296 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 297 "test-11" 298 ); 299 is(ws.readyState, 0, "create bad readyState in test-11!"); 300 301 ws.onopen = function () { 302 is(ws.readyState, 1, "open bad readyState in test-11!"); 303 ws.send("client data"); 304 }; 305 306 ws.onmessage = function (e) { 307 is(e.data, "server data", "bad received message in test-11!"); 308 ws.close(1000, "Have a nice day"); 309 310 // this ok() is disabled due to a race condition - it state may have 311 // advanced through 2 (closing) and into 3 (closed) before it is evald 312 // ok(ws.readyState == 2, "onmessage bad readyState in test-11!"); 313 }; 314 315 ws.onclose = function (e) { 316 is(ws.readyState, 3, "onclose bad readyState in test-11!"); 317 shouldCloseCleanly(e); 318 is(e.code, 1000, "test 11 got wrong close code: " + e.code); 319 is( 320 e.reason, 321 "Have a nice day", 322 "test 11 got wrong close reason: " + e.reason 323 ); 324 resolve(); 325 }; 326 }); 327 } 328 329 // test12: client sends a message containing unpaired surrogates 330 function test12() { 331 return new Promise(function (resolve) { 332 var ws = CreateTestWS( 333 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 334 "test-12" 335 ); 336 337 ws.onopen = function () { 338 try { 339 // send an unpaired surrogate 340 ws._gotMessage = false; 341 ws.send("a\ud800b"); 342 ok(true, "ok to send an unpaired surrogate"); 343 } catch (e) { 344 ok( 345 false, 346 "shouldn't fail any more when sending an unpaired surrogate!" 347 ); 348 } 349 }; 350 351 ws.onmessage = function (msg) { 352 is( 353 msg.data, 354 "SUCCESS", 355 "Unpaired surrogate in UTF-16 not converted in test-12" 356 ); 357 ws._gotMessage = true; 358 // Must support unpaired surrogates in close reason, too 359 ws.close(1000, "a\ud800b"); 360 }; 361 362 ws.onclose = function (e) { 363 is(ws.readyState, 3, "onclose bad readyState in test-12!"); 364 ok(ws._gotMessage, "didn't receive message!"); 365 shouldCloseCleanly(e); 366 is(e.code, 1000, "test 12 got wrong close code: " + e.code); 367 is( 368 e.reason, 369 "a\ufffdb", 370 "test 11 didn't get replacement char in close reason: " + e.reason 371 ); 372 resolve(); 373 }; 374 }); 375 } 376 377 // test13: server sends an invalid message; 378 function test13() { 379 return new Promise(function (resolve) { 380 // previous versions of this test counted the number of protocol errors 381 // returned, but the protocol stack typically closes down after reporting a 382 // protocol level error - trying to resync is too dangerous 383 384 var ws = CreateTestWS( 385 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 386 "test-13" 387 ); 388 ws._timesCalledOnError = 0; 389 390 ws.onerror = function () { 391 ws._timesCalledOnError++; 392 }; 393 394 ws.onclose = function () { 395 ok(ws._timesCalledOnError > 0, "no error events"); 396 resolve(); 397 }; 398 }); 399 } 400 401 // test14: server sends the close frame, it doesn't close the tcp connection 402 // and it keeps sending normal ws messages; 403 function test14() { 404 return new Promise(function (resolve) { 405 var ws = CreateTestWS( 406 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 407 "test-14" 408 ); 409 410 ws.onmessage = function () { 411 ok( 412 false, 413 "shouldn't received message after the server sent the close frame" 414 ); 415 }; 416 417 ws.onclose = function (e) { 418 shouldCloseCleanly(e); 419 resolve(); 420 }; 421 }); 422 } 423 424 // test15: server closes the tcp connection, but it doesn't send the close 425 // frame; 426 function test15() { 427 return new Promise(function (resolve) { 428 /* 429 * DISABLED: see comments for test-15 case in file_websocket_wsh.py 430 */ 431 resolve(); 432 433 var ws = CreateTestWS( 434 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 435 "test-15" 436 ); 437 ws.onclose = function (e) { 438 shouldCloseNotCleanly(e); 439 resolve(); 440 }; 441 442 // termination of the connection might cause an error event if it happens in OPEN 443 ws.onerror = function () {}; 444 }); 445 } 446 447 // test16: client calls close() and tries to send a message; 448 function test16() { 449 return new Promise(function (resolve) { 450 var ws = CreateTestWS( 451 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 452 "test-16" 453 ); 454 455 ws.onopen = function () { 456 ws.close(); 457 ok( 458 !ws.send("client data"), 459 "shouldn't send message after calling close()" 460 ); 461 }; 462 463 ws.onmessage = function () { 464 ok(false, "shouldn't send message after calling close()"); 465 }; 466 467 ws.onerror = function () {}; 468 469 ws.onclose = function () { 470 resolve(); 471 }; 472 }); 473 } 474 475 // test17: see bug 572975 - all event listeners set 476 function test17() { 477 return new Promise(function (resolve) { 478 var status_test17 = "not started"; 479 480 var test17func = function () { 481 var local_ws = new WebSocket( 482 "ws://sub1.test2.example.org/tests/dom/websocket/tests/file_websocket", 483 "test-17" 484 ); 485 status_test17 = "started"; 486 487 local_ws.onopen = function (e) { 488 status_test17 = "opened"; 489 e.target.send("client data"); 490 forcegc(); 491 }; 492 493 local_ws.onerror = function () { 494 ok(false, "onerror called on test " + current_test + "!"); 495 }; 496 497 local_ws.onmessage = function (e) { 498 ok(e.data == "server data", "Bad message in test-17"); 499 status_test17 = "got message"; 500 forcegc(); 501 }; 502 503 local_ws.onclose = function (e) { 504 ok(status_test17 == "got message", "Didn't got message in test-17!"); 505 shouldCloseCleanly(e); 506 status_test17 = "closed"; 507 forcegc(); 508 resolve(); 509 }; 510 511 window._test17 = null; 512 forcegc(); 513 }; 514 515 window._test17 = test17func; 516 window._test17(); 517 }); 518 } 519 520 // The tests that expects that their websockets neither open nor close MUST 521 // be in the end of the tests, i.e. HERE, in order to prevent blocking the other 522 // tests. 523 524 // test18: client tries to connect to an http resource; 525 function test18() { 526 return new Promise(function (resolve) { 527 var ws = CreateTestWS( 528 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_http_resource.txt" 529 ); 530 ws.onopen = shouldNotOpen; 531 ws.onerror = ignoreError; 532 ws.onclose = function (e) { 533 shouldCloseNotCleanly(e); 534 resolve(); 535 }; 536 }); 537 } 538 539 // test19: server closes the tcp connection before establishing the ws 540 // connection; 541 function test19() { 542 return new Promise(function (resolve) { 543 var ws = CreateTestWS( 544 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 545 "test-19" 546 ); 547 ws.onopen = shouldNotOpen; 548 ws.onerror = ignoreError; 549 ws.onclose = function (e) { 550 shouldCloseNotCleanly(e); 551 resolve(); 552 }; 553 }); 554 } 555 556 // test20: see bug 572975 - only on error and onclose event listeners set 557 function test20() { 558 return new Promise(function (resolve) { 559 var test20func = function () { 560 var local_ws = new WebSocket( 561 "ws://sub1.test1.example.org/tests/dom/websocket/tests/file_websocket", 562 "test-20" 563 ); 564 565 local_ws.onerror = function () { 566 ok(false, "onerror called on test " + current_test + "!"); 567 }; 568 569 local_ws.onclose = function () { 570 ok(true, "test 20 closed despite gc"); 571 resolve(); 572 }; 573 574 local_ws = null; 575 window._test20 = null; 576 forcegc(); 577 }; 578 579 window._test20 = test20func; 580 window._test20(); 581 }); 582 } 583 584 // test21: see bug 572975 - same as test 17, but delete strong event listeners 585 // when receiving the message event; 586 function test21() { 587 return new Promise(function (resolve) { 588 var test21func = function () { 589 var local_ws = new WebSocket( 590 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 591 "test-21" 592 ); 593 var received_message = false; 594 595 local_ws.onopen = function (e) { 596 e.target.send("client data"); 597 forcegc(); 598 e.target.onopen = null; 599 forcegc(); 600 }; 601 602 local_ws.onerror = function () { 603 ok(false, "onerror called on test " + current_test + "!"); 604 }; 605 606 local_ws.onmessage = function (e) { 607 is(e.data, "server data", "Bad message in test-21"); 608 received_message = true; 609 forcegc(); 610 e.target.onmessage = null; 611 forcegc(); 612 }; 613 614 local_ws.onclose = function (e) { 615 shouldCloseCleanly(e); 616 ok(received_message, "close transitioned through onmessage"); 617 resolve(); 618 }; 619 620 local_ws = null; 621 window._test21 = null; 622 forcegc(); 623 }; 624 625 window._test21 = test21func; 626 window._test21(); 627 }); 628 } 629 630 // test22: server takes too long to establish the ws connection; 631 function test22() { 632 return new Promise(function (resolve) { 633 const pref_open = "network.websocket.timeout.open"; 634 SpecialPowers.setIntPref(pref_open, 5); 635 636 var ws = CreateTestWS( 637 "ws://sub2.test2.example.org/tests/dom/websocket/tests/file_websocket", 638 "test-22" 639 ); 640 641 ws.onopen = shouldNotOpen; 642 ws.onerror = ignoreError; 643 644 ws.onclose = function (e) { 645 shouldCloseNotCleanly(e); 646 resolve(); 647 }; 648 649 SpecialPowers.clearUserPref(pref_open); 650 }); 651 } 652 653 // test23: should detect WebSocket on window object; 654 function test23() { 655 return new Promise(function (resolve) { 656 ok("WebSocket" in window, "WebSocket should be available on window object"); 657 resolve(); 658 }); 659 } 660 661 // test24: server rejects sub-protocol string 662 function test24() { 663 return new Promise(function (resolve) { 664 var ws = CreateTestWS( 665 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 666 "test-does-not-exist" 667 ); 668 669 ws.onopen = shouldNotOpen; 670 ws.onclose = function (e) { 671 shouldCloseNotCleanly(e); 672 resolve(); 673 }; 674 675 ws.onerror = function () {}; 676 }); 677 } 678 679 // test25: ctor with valid empty sub-protocol array 680 function test25() { 681 return new Promise(function (resolve) { 682 var prots = []; 683 684 var ws = CreateTestWS( 685 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 686 prots 687 ); 688 689 // This test errors because the server requires a sub-protocol, but 690 // the test just wants to ensure that the ctor doesn't generate an 691 // exception 692 ws.onerror = ignoreError; 693 ws.onopen = shouldNotOpen; 694 695 ws.onclose = function () { 696 is(ws.protocol, "", "test25 subprotocol selection"); 697 ok(true, "test 25 protocol array close"); 698 resolve(); 699 }; 700 }); 701 } 702 703 // test26: ctor with invalid sub-protocol array containing 1 empty element 704 function test26() { 705 return new Promise(function (resolve) { 706 var prots = [""]; 707 708 try { 709 CreateTestWS( 710 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 711 prots 712 ); 713 ok(false, "testing empty element sub protocol array"); 714 } catch (e) { 715 ok(true, "testing empty sub element protocol array"); 716 } 717 718 resolve(); 719 }); 720 } 721 722 // test27: ctor with invalid sub-protocol array containing an empty element in 723 // list 724 function test27() { 725 return new Promise(function (resolve) { 726 var prots = ["test27", ""]; 727 728 try { 729 CreateTestWS( 730 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 731 prots 732 ); 733 ok(false, "testing empty element mixed sub protocol array"); 734 } catch (e) { 735 ok(true, "testing empty element mixed sub protocol array"); 736 } 737 738 resolve(); 739 }); 740 } 741 742 // test28: ctor using valid 1 element sub-protocol array 743 function test28() { 744 return new Promise(function (resolve) { 745 var prots = ["test28"]; 746 747 var ws = CreateTestWS( 748 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 749 prots 750 ); 751 752 ws.onopen = function () { 753 ok(true, "test 28 protocol array open"); 754 ws.close(); 755 }; 756 757 ws.onclose = function () { 758 is(ws.protocol, "test28", "test28 subprotocol selection"); 759 ok(true, "test 28 protocol array close"); 760 resolve(); 761 }; 762 }); 763 } 764 765 // test29: ctor using all valid 5 element sub-protocol array 766 function test29() { 767 return new Promise(function (resolve) { 768 var prots = ["test29a", "test29b"]; 769 770 var ws = CreateTestWS( 771 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 772 prots 773 ); 774 775 ws.onopen = function () { 776 ok(true, "test 29 protocol array open"); 777 ws.close(); 778 }; 779 780 ws.onclose = function () { 781 ok(true, "test 29 protocol array close"); 782 resolve(); 783 }; 784 }); 785 } 786 787 // test30: ctor using valid 1 element sub-protocol array with element server 788 // will reject 789 function test30() { 790 return new Promise(function (resolve) { 791 var prots = ["test-does-not-exist"]; 792 var ws = CreateTestWS( 793 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 794 prots 795 ); 796 797 ws.onopen = shouldNotOpen; 798 799 ws.onclose = function (e) { 800 shouldCloseNotCleanly(e); 801 resolve(); 802 }; 803 804 ws.onerror = function () {}; 805 }); 806 } 807 808 // test31: ctor using valid 2 element sub-protocol array with 1 element server 809 // will reject and one server will accept 810 function test31() { 811 return new Promise(function (resolve) { 812 var prots = ["test-does-not-exist", "test31"]; 813 var ws = CreateTestWS( 814 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 815 prots 816 ); 817 818 ws.onopen = function () { 819 ok(true, "test 31 protocol array open"); 820 ws.close(); 821 }; 822 823 ws.onclose = function () { 824 is(ws.protocol, "test31", "test31 subprotocol selection"); 825 ok(true, "test 31 protocol array close"); 826 resolve(); 827 }; 828 }); 829 } 830 831 // test32: ctor using invalid sub-protocol array that contains duplicate items 832 function test32() { 833 return new Promise(function (resolve) { 834 var prots = ["test32", "test32"]; 835 836 try { 837 CreateTestWS( 838 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 839 prots 840 ); 841 ok(false, "testing duplicated element sub protocol array"); 842 } catch (e) { 843 ok(true, "testing duplicated sub element protocol array"); 844 } 845 846 resolve(); 847 }); 848 } 849 850 // test33: test for sending/receiving custom close code (but no close reason) 851 function test33() { 852 return new Promise(function (resolve) { 853 var prots = ["test33"]; 854 855 var ws = CreateTestWS( 856 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 857 prots 858 ); 859 860 ws.onopen = function () { 861 ok(true, "test 33 open"); 862 ws.close(3131); // pass code but not reason 863 }; 864 865 ws.onclose = function (e) { 866 ok(true, "test 33 close"); 867 shouldCloseCleanly(e); 868 is(e.code, 3131, "test 33 got wrong close code: " + e.code); 869 is(e.reason, "", "test 33 got wrong close reason: " + e.reason); 870 resolve(); 871 }; 872 }); 873 } 874 875 // test34: test for receiving custom close code and reason 876 function test34() { 877 return new Promise(function (resolve) { 878 var prots = ["test-34"]; 879 880 var ws = CreateTestWS( 881 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 882 prots 883 ); 884 885 ws.onopen = function () { 886 ok(true, "test 34 open"); 887 ws.close(); 888 }; 889 890 ws.onclose = function (e) { 891 ok(true, "test 34 close"); 892 ok(e.wasClean, "test 34 closed cleanly"); 893 is(e.code, 1001, "test 34 custom server code"); 894 is(e.reason, "going away now", "test 34 custom server reason"); 895 resolve(); 896 }; 897 }); 898 } 899 900 // test35: test for sending custom close code and reason 901 function test35() { 902 return new Promise(function (resolve) { 903 var ws = CreateTestWS( 904 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 905 "test-35a" 906 ); 907 908 ws.onopen = function () { 909 ok(true, "test 35a open"); 910 ws.close(3500, "my code"); 911 }; 912 913 ws.onclose = function (e) { 914 ok(true, "test 35a close"); 915 ok(e.wasClean, "test 35a closed cleanly"); 916 var wsb = CreateTestWS( 917 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 918 "test-35b" 919 ); 920 921 wsb.onopen = function () { 922 ok(true, "test 35b open"); 923 wsb.close(); 924 }; 925 926 wsb.onclose = function (event) { 927 ok(true, "test 35b close"); 928 ok(event.wasClean, "test 35b closed cleanly"); 929 is(event.code, 3501, "test 35 custom server code"); 930 is(event.reason, "my code", "test 35 custom server reason"); 931 resolve(); 932 }; 933 }; 934 }); 935 } 936 937 // test36: negative test for sending out of range close code 938 function test36() { 939 return new Promise(function (resolve) { 940 var prots = ["test-36"]; 941 942 var ws = CreateTestWS( 943 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 944 prots 945 ); 946 947 ws.onopen = function () { 948 ok(true, "test 36 open"); 949 950 try { 951 ws.close(13200); 952 ok(false, "testing custom close code out of range"); 953 } catch (ex) { 954 ok(true, "testing custom close code out of range"); 955 ws.close(3200); 956 } 957 }; 958 959 ws.onclose = function (e) { 960 ok(true, "test 36 close"); 961 ok(e.wasClean, "test 36 closed cleanly"); 962 resolve(); 963 }; 964 }); 965 } 966 967 // test37: negative test for too long of a close reason 968 function test37() { 969 return new Promise(function (resolve) { 970 var prots = ["test-37"]; 971 972 var ws = CreateTestWS( 973 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 974 prots 975 ); 976 977 ws.onopen = function () { 978 ok(true, "test 37 open"); 979 980 try { 981 ws.close( 982 3100, 983 "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123" 984 ); 985 ok(false, "testing custom close reason out of range"); 986 } catch (ex) { 987 ok(true, "testing custom close reason out of range"); 988 ws.close( 989 3100, 990 "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012" 991 ); 992 } 993 }; 994 995 ws.onclose = function (e) { 996 ok(true, "test 37 close"); 997 ok(e.wasClean, "test 37 closed cleanly"); 998 999 var wsb = CreateTestWS( 1000 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 1001 "test-37b" 1002 ); 1003 1004 wsb.onopen = function () { 1005 // now test that a rejected close code and reason dont persist 1006 ok(true, "test 37b open"); 1007 try { 1008 wsb.close( 1009 3101, 1010 "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123" 1011 ); 1012 ok(false, "testing custom close reason out of range 37b"); 1013 } catch (ex) { 1014 ok(true, "testing custom close reason out of range 37b"); 1015 wsb.close(); 1016 } 1017 }; 1018 1019 wsb.onclose = function (event) { 1020 ok(true, "test 37b close"); 1021 ok(event.wasClean, "test 37b closed cleanly"); 1022 1023 var wsc = CreateTestWS( 1024 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 1025 "test-37c" 1026 ); 1027 1028 wsc.onopen = function () { 1029 ok(true, "test 37c open"); 1030 wsc.close(); 1031 }; 1032 1033 wsc.onclose = function (eventInner) { 1034 isnot( 1035 eventInner.code, 1036 3101, 1037 "test 37c custom server code not present" 1038 ); 1039 is( 1040 eventInner.reason, 1041 "", 1042 "test 37c custom server reason not present" 1043 ); 1044 resolve(); 1045 }; 1046 }; 1047 }; 1048 }); 1049 } 1050 1051 // test38: ensure extensions attribute is defined 1052 function test38() { 1053 return new Promise(function (resolve) { 1054 var prots = ["test-38"]; 1055 1056 var ws = CreateTestWS( 1057 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 1058 prots 1059 ); 1060 1061 ws.onopen = function () { 1062 ok(true, "test 38 open"); 1063 isnot(ws.extensions, undefined, "extensions attribute defined"); 1064 // is(ws.extensions, "deflate-stream", "extensions attribute deflate-stream"); 1065 ws.close(); 1066 }; 1067 1068 ws.onclose = function () { 1069 ok(true, "test 38 close"); 1070 resolve(); 1071 }; 1072 }); 1073 } 1074 1075 // test39: a basic wss:// connectivity test 1076 function test39() { 1077 return new Promise(function (resolve) { 1078 var prots = ["test-39"]; 1079 1080 var ws = CreateTestWS( 1081 "wss://example.com/tests/dom/websocket/tests/file_websocket", 1082 prots 1083 ); 1084 let status_test39 = "started"; 1085 1086 ws.onopen = function () { 1087 status_test39 = "opened"; 1088 ok(true, "test 39 open"); 1089 ws.close(); 1090 }; 1091 1092 ws.onclose = function () { 1093 ok(true, "test 39 close"); 1094 is(status_test39, "opened", "test 39 did open"); 1095 resolve(); 1096 }; 1097 }); 1098 } 1099 1100 // test40: negative test for wss:// with no cert 1101 function test40() { 1102 return new Promise(function (resolve) { 1103 var prots = ["test-40"]; 1104 1105 var ws = CreateTestWS( 1106 "wss://nocert.example.com/tests/dom/websocket/tests/file_websocket", 1107 prots 1108 ); 1109 1110 let status_test40 = "started"; 1111 ws.onerror = ignoreError; 1112 1113 ws.onopen = function () { 1114 status_test40 = "opened"; 1115 ok(false, "test 40 open"); 1116 ws.close(); 1117 }; 1118 1119 ws.onclose = function () { 1120 ok(true, "test 40 close"); 1121 is(status_test40, "started", "test 40 did not open"); 1122 resolve(); 1123 }; 1124 }); 1125 } 1126 1127 // test41: HSTS 1128 function test41() { 1129 return new Promise(function (resolve) { 1130 var ws = CreateTestWS( 1131 "ws://example.com/tests/dom/websocket/tests/file_websocket", 1132 "test-41a", 1133 1 1134 ); 1135 1136 ws.onopen = function () { 1137 ok(true, "test 41a open"); 1138 is( 1139 ws.url, 1140 "ws://example.com/tests/dom/websocket/tests/file_websocket", 1141 "test 41a initial ws should not be redirected" 1142 ); 1143 ws.close(); 1144 }; 1145 1146 ws.onclose = function () { 1147 ok(true, "test 41a close"); 1148 1149 // Since third-party loads can't set HSTS state, this will not set 1150 // HSTS for example.com. 1151 var wsb = CreateTestWS( 1152 "wss://example.com/tests/dom/websocket/tests/file_websocket", 1153 "test-41b", 1154 1 1155 ); 1156 1157 wsb.onopen = function () { 1158 ok(true, "test 41b open"); 1159 wsb.close(); 1160 }; 1161 1162 wsb.onclose = function () { 1163 ok(true, "test 41b close"); 1164 1165 // try ws:// again, it should be done over ws:// again 1166 var wsc = CreateTestWS( 1167 "ws://example.com/tests/dom/websocket/tests/file_websocket", 1168 "test-41c" 1169 ); 1170 1171 wsc.onopen = function () { 1172 ok(true, "test 41c open"); 1173 is( 1174 wsc.url, 1175 "ws://example.com/tests/dom/websocket/tests/file_websocket", 1176 "test 41c ws should not be redirected by hsts to wss" 1177 ); 1178 wsc.close(); 1179 }; 1180 1181 wsc.onclose = function () { 1182 ok(true, "test 41c close"); 1183 resolve(); 1184 }; 1185 }; 1186 }; 1187 }); 1188 } 1189 1190 // test42: non-char utf-8 sequences 1191 function test42() { 1192 return new Promise(function (resolve) { 1193 // test some utf-8 non-characters. They should be allowed in the 1194 // websockets context. Test via round trip echo. 1195 var ws = CreateTestWS( 1196 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 1197 "test-42" 1198 ); 1199 var data = ["U+FFFE \ufffe", "U+FFFF \uffff", "U+10FFFF \udbff\udfff"]; 1200 var index = 0; 1201 1202 ws.onopen = function () { 1203 ws.send(data[0]); 1204 ws.send(data[1]); 1205 ws.send(data[2]); 1206 }; 1207 1208 ws.onmessage = function (e) { 1209 is( 1210 e.data, 1211 data[index], 1212 "bad received message in test-42! index=" + index 1213 ); 1214 index++; 1215 if (index == 3) { 1216 ws.close(); 1217 } 1218 }; 1219 1220 ws.onclose = function () { 1221 resolve(); 1222 }; 1223 }); 1224 } 1225 1226 // test43: Test setting binaryType attribute 1227 function test43() { 1228 return new Promise(function (resolve) { 1229 var prots = ["test-43"]; 1230 1231 var ws = CreateTestWS( 1232 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 1233 prots 1234 ); 1235 1236 ws.onopen = function () { 1237 ok(true, "test 43 open"); 1238 // Test binaryType setting 1239 ws.binaryType = "arraybuffer"; 1240 ws.binaryType = "blob"; 1241 ws.binaryType = ""; // illegal 1242 is(ws.binaryType, "blob"); 1243 ws.binaryType = "ArrayBuffer"; // illegal 1244 is(ws.binaryType, "blob"); 1245 ws.binaryType = "Blob"; // illegal 1246 is(ws.binaryType, "blob"); 1247 ws.binaryType = "mcfoofluu"; // illegal 1248 is(ws.binaryType, "blob"); 1249 ws.close(); 1250 }; 1251 1252 ws.onclose = function () { 1253 ok(true, "test 43 close"); 1254 resolve(); 1255 }; 1256 }); 1257 } 1258 1259 // test44: Test sending/receving binary ArrayBuffer 1260 function test44() { 1261 return new Promise(function (resolve) { 1262 var ws = CreateTestWS( 1263 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 1264 "test-44" 1265 ); 1266 is(ws.readyState, 0, "bad readyState in test-44!"); 1267 ws.binaryType = "arraybuffer"; 1268 1269 ws.onopen = function () { 1270 is(ws.readyState, 1, "open bad readyState in test-44!"); 1271 var buf = new ArrayBuffer(3); 1272 // create byte view 1273 var view = new Uint8Array(buf); 1274 view[0] = 5; 1275 view[1] = 0; // null byte 1276 view[2] = 7; 1277 ws.send(buf); 1278 }; 1279 1280 ws.onmessage = function (e) { 1281 ok(e.data instanceof ArrayBuffer, "Should receive an arraybuffer!"); 1282 var view = new Uint8Array(e.data); 1283 ok( 1284 view.length == 2 && view[0] == 0 && view[1] == 4, 1285 "testing Reply arraybuffer" 1286 ); 1287 ws.close(); 1288 }; 1289 1290 ws.onclose = function (e) { 1291 is(ws.readyState, 3, "onclose bad readyState in test-44!"); 1292 shouldCloseCleanly(e); 1293 resolve(); 1294 }; 1295 }); 1296 } 1297 1298 // test45: Test sending/receving binary Blob 1299 function test45() { 1300 return new Promise(function (resolve) { 1301 function test45Real(blobFile) { 1302 var ws = CreateTestWS( 1303 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 1304 "test-45" 1305 ); 1306 is(ws.readyState, 0, "bad readyState in test-45!"); 1307 // ws.binaryType = "blob"; // Don't need to specify: blob is the default 1308 1309 ws.onopen = function () { 1310 is(ws.readyState, 1, "open bad readyState in test-45!"); 1311 ws.send(blobFile); 1312 }; 1313 1314 var test45blob; 1315 1316 ws.onmessage = function (e) { 1317 test45blob = e.data; 1318 ok(test45blob instanceof Blob, "We should be receiving a Blob"); 1319 1320 ws.close(); 1321 }; 1322 1323 ws.onclose = function (e) { 1324 is(ws.readyState, 3, "onclose bad readyState in test-45!"); 1325 shouldCloseCleanly(e); 1326 1327 // check blob contents 1328 var reader = new FileReader(); 1329 reader.onload = function () { 1330 is( 1331 reader.result, 1332 "flob", 1333 "response should be 'flob': got '" + reader.result + "'" 1334 ); 1335 }; 1336 1337 reader.onerror = function () { 1338 ok(false, "Failed to read blob: error code = " + reader.error.code); 1339 }; 1340 1341 reader.onloadend = function () { 1342 resolve(); 1343 }; 1344 1345 reader.readAsBinaryString(test45blob); 1346 }; 1347 } 1348 1349 SpecialPowers.createFiles( 1350 [{ name: "testBlobFile", data: "flob" }], 1351 function (files) { 1352 test45Real(files[0]); 1353 }, 1354 function (msg) { 1355 ok(false, "Failed to create file for test45: " + msg); 1356 resolve(); 1357 } 1358 ); 1359 }); 1360 } 1361 1362 // test46: Test that we don't dispatch incoming msgs once in CLOSING state 1363 function test46() { 1364 return new Promise(function (resolve) { 1365 var ws = CreateTestWS( 1366 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 1367 "test-46" 1368 ); 1369 is(ws.readyState, 0, "create bad readyState in test-46!"); 1370 1371 ws.onopen = function () { 1372 is(ws.readyState, 1, "open bad readyState in test-46!"); 1373 ws.close(); 1374 is(ws.readyState, 2, "close must set readyState to 2 in test-46!"); 1375 }; 1376 1377 ws.onmessage = function () { 1378 ok(false, "received message after calling close in test-46!"); 1379 }; 1380 1381 ws.onclose = function (e) { 1382 is(ws.readyState, 3, "onclose bad readyState in test-46!"); 1383 shouldCloseCleanly(e); 1384 resolve(); 1385 }; 1386 }); 1387 } 1388 1389 // test47: Make sure onerror/onclose aren't called during close() 1390 function test47() { 1391 return new Promise(function (resolve) { 1392 var hasError = false; 1393 var ws = CreateTestWS( 1394 "ws://another.websocket.server.that.probably.does.not.exist" 1395 ); 1396 1397 ws.onopen = shouldNotOpen; 1398 1399 ws.onerror = function () { 1400 is( 1401 ws.readyState, 1402 3, 1403 "test-47: readyState should be CLOSED(3) in onerror: got " + 1404 ws.readyState 1405 ); 1406 ok(!ws._withinClose, "onerror() called during close()!"); 1407 hasError = true; 1408 }; 1409 1410 ws.onclose = function (e) { 1411 shouldCloseNotCleanly(e); 1412 ok(hasError, "test-47: should have called onerror before onclose"); 1413 is( 1414 ws.readyState, 1415 3, 1416 "test-47: readyState should be CLOSED(3) in onclose: got " + 1417 ws.readyState 1418 ); 1419 ok(!ws._withinClose, "onclose() called during close()!"); 1420 is(e.code, 1006, "test-47 close code should be 1006 but is:" + e.code); 1421 resolve(); 1422 }; 1423 1424 // Call close before we're connected: throws error 1425 // Make sure we call onerror/onclose asynchronously 1426 ws._withinClose = 1; 1427 ws.close(3333, "Closed before we were open: error"); 1428 ws._withinClose = 0; 1429 is( 1430 ws.readyState, 1431 2, 1432 "test-47: readyState should be CLOSING(2) after close(): got " + 1433 ws.readyState 1434 ); 1435 }); 1436 } 1437 1438 // test48: see bug 1227136 - client calls close() from onopen() and waits until 1439 // WebSocketChannel::mSocketIn is nulled out on socket thread. 1440 function test48() { 1441 return new Promise(function (resolve) { 1442 const pref_close = "network.websocket.timeout.close"; 1443 SpecialPowers.setIntPref(pref_close, 1); 1444 1445 var ws = CreateTestWS( 1446 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 1447 "test-48" 1448 ); 1449 1450 ws.onopen = function () { 1451 ws.close(); 1452 1453 var date = new Date(); 1454 var curDate = null; 1455 do { 1456 curDate = new Date(); 1457 } while (curDate - date < 1500); 1458 }; 1459 1460 ws.onclose = function () { 1461 ok(true, "ws close in test 48"); 1462 resolve(); 1463 }; 1464 1465 SpecialPowers.clearUserPref(pref_close); 1466 }); 1467 } 1468 1469 function test49() { 1470 return new Promise(function (resolve) { 1471 var ws = CreateTestWS( 1472 "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", 1473 "test-49" 1474 ); 1475 var gotError = 0; 1476 ok(ws.readyState == 0, "create bad readyState in test-49!"); 1477 1478 ws.onopen = function () { 1479 ok(false, "Connection must fail in test-49"); 1480 }; 1481 1482 ws.onerror = function () { 1483 gotError = 1; 1484 }; 1485 1486 ws.onclose = function () { 1487 ok(gotError, "Should get error in test-49!"); 1488 resolve(); 1489 }; 1490 }); 1491 }