tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }