diff options
Diffstat (limited to 'dom/websocket/tests/websocket_tests.js')
-rw-r--r-- | dom/websocket/tests/websocket_tests.js | 1488 |
1 files changed, 1488 insertions, 0 deletions
diff --git a/dom/websocket/tests/websocket_tests.js b/dom/websocket/tests/websocket_tests.js new file mode 100644 index 0000000000..188daac2f9 --- /dev/null +++ b/dom/websocket/tests/websocket_tests.js @@ -0,0 +1,1488 @@ +// test1: client tries to connect to a http scheme location; +function test1() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "http://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-1" + ); + + ws.onmessage = function () { + ok(true, "created websocket with http scheme"); + }; + + ws.onclose = function (e) { + shouldCloseCleanly(e); + resolve(); + }; + }); +} + +// test2: assure serialization of the connections; +// this test expects that the serialization list to connect to the proxy +// is empty. +function test2() { + return new Promise(function (resolve, reject) { + var waitTest2Part1 = true; + var waitTest2Part2 = true; + + var ws1 = CreateTestWS( + "ws://sub2.test2.example.com/tests/dom/websocket/tests/file_websocket", + "test-2.1" + ); + var ws2 = CreateTestWS( + "ws://sub2.test2.example.com/tests/dom/websocket/tests/file_websocket", + "test-2.2" + ); + + var ws2CanConnect = false; + + function maybeFinished() { + if (!waitTest2Part1 && !waitTest2Part2) { + resolve(); + } + } + + ws1.onopen = function () { + ok(true, "ws1 open in test 2"); + ws2CanConnect = true; + ws1.close(); + }; + + ws1.onclose = function (e) { + waitTest2Part1 = false; + maybeFinished(); + }; + + ws2.onopen = function () { + ok(ws2CanConnect, "shouldn't connect yet in test-2!"); + ws2.close(); + }; + + ws2.onclose = function (e) { + waitTest2Part2 = false; + maybeFinished(); + }; + }); +} + +// test3: client tries to connect to an non-existent ws server; +function test3() { + return new Promise(function (resolve, reject) { + var hasError = false; + var ws = CreateTestWS("ws://this.websocket.server.probably.does.not.exist"); + + ws.onopen = shouldNotOpen; + + ws.onerror = function (e) { + hasError = true; + }; + + ws.onclose = function (e) { + shouldCloseNotCleanly(e); + ok(hasError, "rcvd onerror event"); + is(e.code, 1006, "test-3 close code should be 1006 but is:" + e.code); + resolve(); + }; + }); +} + +// test4: client tries to connect using a relative url; +function test4() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS("file_websocket", "test-4"); + + ws.onmessage = function () { + ok(true, "created websocket with relative scheme"); + }; + + ws.onclose = function (e) { + shouldCloseCleanly(e); + resolve(); + }; + }); +} + +// test5: client uses an invalid protocol value; +function test5() { + return new Promise(function (resolve, reject) { + try { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "" + ); + ok(false, "couldn't accept an empty string in the protocol parameter"); + } catch (e) { + ok(true, "couldn't accept an empty string in the protocol parameter"); + } + + try { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "\n" + ); + ok( + false, + "couldn't accept any not printable ASCII character in the protocol parameter" + ); + } catch (e) { + ok( + true, + "couldn't accept any not printable ASCII character in the protocol parameter" + ); + } + + try { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test 5" + ); + ok(false, "U+0020 not acceptable in protocol parameter"); + } catch (e) { + ok(true, "U+0020 not acceptable in protocol parameter"); + } + + resolve(); + }); +} + +// test6: counter and encoding check; +function test6() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-6" + ); + var counter = 1; + + ws.onopen = function () { + ws.send(counter); + }; + + ws.onmessage = function (e) { + if (counter == 5) { + is(e.data, "あいうえお", "test-6 counter 5 data ok"); + ws.close(); + } else { + is(parseInt(e.data), counter + 1, "bad counter"); + counter += 2; + ws.send(counter); + } + }; + + ws.onclose = function (e) { + shouldCloseCleanly(e); + resolve(); + }; + }); +} + +// test7: onmessage event origin property check +function test7() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://sub2.test2.example.org/tests/dom/websocket/tests/file_websocket", + "test-7" + ); + var gotmsg = false; + + ws.onopen = function () { + ok(true, "test 7 open"); + }; + + ws.onmessage = function (e) { + ok(true, "test 7 message"); + is( + e.origin, + "ws://sub2.test2.example.org", + "onmessage origin set to ws:// host" + ); + gotmsg = true; + ws.close(); + }; + + ws.onclose = function (e) { + ok(gotmsg, "recvd message in test 7 before close"); + shouldCloseCleanly(e); + resolve(); + }; + }); +} + +// test8: client calls close() and the server sends the close frame (with no +// code or reason) in acknowledgement; +function test8() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-8" + ); + + ws.onopen = function () { + is(ws.protocol, "test-8", "test-8 subprotocol selection"); + ws.close(); + }; + + ws.onclose = function (e) { + shouldCloseCleanly(e); + // We called close() with no close code: so pywebsocket will also send no + // close code, which translates to code 1005 + is(e.code, 1005, "test-8 close code has wrong value:" + e.code); + is(e.reason, "", "test-8 close reason has wrong value:" + e.reason); + resolve(); + }; + }); +} + +// test9: client closes the connection before the ws connection is established; +function test9() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://test2.example.org/tests/dom/websocket/tests/file_websocket", + "test-9" + ); + + ws._receivedErrorEvent = false; + + ws.onopen = shouldNotOpen; + + ws.onerror = function (e) { + ws._receivedErrorEvent = true; + }; + + ws.onclose = function (e) { + ok(ws._receivedErrorEvent, "Didn't received the error event in test 9."); + shouldCloseNotCleanly(e); + resolve(); + }; + + ws.close(); + }); +} + +// test10: client sends a message before the ws connection is established; +function test10() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://sub1.test1.example.com/tests/dom/websocket/tests/file_websocket", + "test-10" + ); + + ws.onclose = function (e) { + shouldCloseCleanly(e); + resolve(); + }; + + try { + ws.send("client data"); + ok(false, "Couldn't send data before connecting!"); + } catch (e) { + ok(true, "Couldn't send data before connecting!"); + } + + ws.onopen = function () { + ok(true, "test 10 opened"); + ws.close(); + }; + }); +} + +// test11: a simple hello echo; +function test11() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-11" + ); + is(ws.readyState, 0, "create bad readyState in test-11!"); + + ws.onopen = function () { + is(ws.readyState, 1, "open bad readyState in test-11!"); + ws.send("client data"); + }; + + ws.onmessage = function (e) { + is(e.data, "server data", "bad received message in test-11!"); + ws.close(1000, "Have a nice day"); + + // this ok() is disabled due to a race condition - it state may have + // advanced through 2 (closing) and into 3 (closed) before it is evald + // ok(ws.readyState == 2, "onmessage bad readyState in test-11!"); + }; + + ws.onclose = function (e) { + is(ws.readyState, 3, "onclose bad readyState in test-11!"); + shouldCloseCleanly(e); + is(e.code, 1000, "test 11 got wrong close code: " + e.code); + is( + e.reason, + "Have a nice day", + "test 11 got wrong close reason: " + e.reason + ); + resolve(); + }; + }); +} + +// test12: client sends a message containing unpaired surrogates +function test12() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-12" + ); + + ws.onopen = function () { + try { + // send an unpaired surrogate + ws._gotMessage = false; + ws.send("a\ud800b"); + ok(true, "ok to send an unpaired surrogate"); + } catch (e) { + ok( + false, + "shouldn't fail any more when sending an unpaired surrogate!" + ); + } + }; + + ws.onmessage = function (msg) { + is( + msg.data, + "SUCCESS", + "Unpaired surrogate in UTF-16 not converted in test-12" + ); + ws._gotMessage = true; + // Must support unpaired surrogates in close reason, too + ws.close(1000, "a\ud800b"); + }; + + ws.onclose = function (e) { + is(ws.readyState, 3, "onclose bad readyState in test-12!"); + ok(ws._gotMessage, "didn't receive message!"); + shouldCloseCleanly(e); + is(e.code, 1000, "test 12 got wrong close code: " + e.code); + is( + e.reason, + "a\ufffdb", + "test 11 didn't get replacement char in close reason: " + e.reason + ); + resolve(); + }; + }); +} + +// test13: server sends an invalid message; +function test13() { + return new Promise(function (resolve, reject) { + // previous versions of this test counted the number of protocol errors + // returned, but the protocol stack typically closes down after reporting a + // protocol level error - trying to resync is too dangerous + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-13" + ); + ws._timesCalledOnError = 0; + + ws.onerror = function () { + ws._timesCalledOnError++; + }; + + ws.onclose = function (e) { + ok(ws._timesCalledOnError > 0, "no error events"); + resolve(); + }; + }); +} + +// test14: server sends the close frame, it doesn't close the tcp connection +// and it keeps sending normal ws messages; +function test14() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-14" + ); + + ws.onmessage = function () { + ok( + false, + "shouldn't received message after the server sent the close frame" + ); + }; + + ws.onclose = function (e) { + shouldCloseCleanly(e); + resolve(); + }; + }); +} + +// test15: server closes the tcp connection, but it doesn't send the close +// frame; +function test15() { + return new Promise(function (resolve, reject) { + /* + * DISABLED: see comments for test-15 case in file_websocket_wsh.py + */ + resolve(); + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-15" + ); + ws.onclose = function (e) { + shouldCloseNotCleanly(e); + resolve(); + }; + + // termination of the connection might cause an error event if it happens in OPEN + ws.onerror = function () {}; + }); +} + +// test16: client calls close() and tries to send a message; +function test16() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-16" + ); + + ws.onopen = function () { + ws.close(); + ok( + !ws.send("client data"), + "shouldn't send message after calling close()" + ); + }; + + ws.onmessage = function () { + ok(false, "shouldn't send message after calling close()"); + }; + + ws.onerror = function () {}; + + ws.onclose = function () { + resolve(); + }; + }); +} + +// test17: see bug 572975 - all event listeners set +function test17() { + return new Promise(function (resolve, reject) { + var status_test17 = "not started"; + + var test17func = function () { + var local_ws = new WebSocket( + "ws://sub1.test2.example.org/tests/dom/websocket/tests/file_websocket", + "test-17" + ); + status_test17 = "started"; + + local_ws.onopen = function (e) { + status_test17 = "opened"; + e.target.send("client data"); + forcegc(); + }; + + local_ws.onerror = function () { + ok(false, "onerror called on test " + current_test + "!"); + }; + + local_ws.onmessage = function (e) { + ok(e.data == "server data", "Bad message in test-17"); + status_test17 = "got message"; + forcegc(); + }; + + local_ws.onclose = function (e) { + ok(status_test17 == "got message", "Didn't got message in test-17!"); + shouldCloseCleanly(e); + status_test17 = "closed"; + forcegc(); + resolve(); + }; + + window._test17 = null; + forcegc(); + }; + + window._test17 = test17func; + window._test17(); + }); +} + +// The tests that expects that their websockets neither open nor close MUST +// be in the end of the tests, i.e. HERE, in order to prevent blocking the other +// tests. + +// test18: client tries to connect to an http resource; +function test18() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_http_resource.txt" + ); + ws.onopen = shouldNotOpen; + ws.onerror = ignoreError; + ws.onclose = function (e) { + shouldCloseNotCleanly(e); + resolve(); + }; + }); +} + +// test19: server closes the tcp connection before establishing the ws +// connection; +function test19() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-19" + ); + ws.onopen = shouldNotOpen; + ws.onerror = ignoreError; + ws.onclose = function (e) { + shouldCloseNotCleanly(e); + resolve(); + }; + }); +} + +// test20: see bug 572975 - only on error and onclose event listeners set +function test20() { + return new Promise(function (resolve, reject) { + var test20func = function () { + var local_ws = new WebSocket( + "ws://sub1.test1.example.org/tests/dom/websocket/tests/file_websocket", + "test-20" + ); + + local_ws.onerror = function () { + ok(false, "onerror called on test " + current_test + "!"); + }; + + local_ws.onclose = function (e) { + ok(true, "test 20 closed despite gc"); + resolve(); + }; + + local_ws = null; + window._test20 = null; + forcegc(); + }; + + window._test20 = test20func; + window._test20(); + }); +} + +// test21: see bug 572975 - same as test 17, but delete strong event listeners +// when receiving the message event; +function test21() { + return new Promise(function (resolve, reject) { + var test21func = function () { + var local_ws = new WebSocket( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-21" + ); + var received_message = false; + + local_ws.onopen = function (e) { + e.target.send("client data"); + forcegc(); + e.target.onopen = null; + forcegc(); + }; + + local_ws.onerror = function () { + ok(false, "onerror called on test " + current_test + "!"); + }; + + local_ws.onmessage = function (e) { + is(e.data, "server data", "Bad message in test-21"); + received_message = true; + forcegc(); + e.target.onmessage = null; + forcegc(); + }; + + local_ws.onclose = function (e) { + shouldCloseCleanly(e); + ok(received_message, "close transitioned through onmessage"); + resolve(); + }; + + local_ws = null; + window._test21 = null; + forcegc(); + }; + + window._test21 = test21func; + window._test21(); + }); +} + +// test22: server takes too long to establish the ws connection; +function test22() { + return new Promise(function (resolve, reject) { + const pref_open = "network.websocket.timeout.open"; + SpecialPowers.setIntPref(pref_open, 5); + + var ws = CreateTestWS( + "ws://sub2.test2.example.org/tests/dom/websocket/tests/file_websocket", + "test-22" + ); + + ws.onopen = shouldNotOpen; + ws.onerror = ignoreError; + + ws.onclose = function (e) { + shouldCloseNotCleanly(e); + resolve(); + }; + + SpecialPowers.clearUserPref(pref_open); + }); +} + +// test23: should detect WebSocket on window object; +function test23() { + return new Promise(function (resolve, reject) { + ok("WebSocket" in window, "WebSocket should be available on window object"); + resolve(); + }); +} + +// test24: server rejects sub-protocol string +function test24() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-does-not-exist" + ); + + ws.onopen = shouldNotOpen; + ws.onclose = function (e) { + shouldCloseNotCleanly(e); + resolve(); + }; + + ws.onerror = function () {}; + }); +} + +// test25: ctor with valid empty sub-protocol array +function test25() { + return new Promise(function (resolve, reject) { + var prots = []; + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + // This test errors because the server requires a sub-protocol, but + // the test just wants to ensure that the ctor doesn't generate an + // exception + ws.onerror = ignoreError; + ws.onopen = shouldNotOpen; + + ws.onclose = function (e) { + is(ws.protocol, "", "test25 subprotocol selection"); + ok(true, "test 25 protocol array close"); + resolve(); + }; + }); +} + +// test26: ctor with invalid sub-protocol array containing 1 empty element +function test26() { + return new Promise(function (resolve, reject) { + var prots = [""]; + + try { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + ok(false, "testing empty element sub protocol array"); + } catch (e) { + ok(true, "testing empty sub element protocol array"); + } + + resolve(); + }); +} + +// test27: ctor with invalid sub-protocol array containing an empty element in +// list +function test27() { + return new Promise(function (resolve, reject) { + var prots = ["test27", ""]; + + try { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + ok(false, "testing empty element mixed sub protocol array"); + } catch (e) { + ok(true, "testing empty element mixed sub protocol array"); + } + + resolve(); + }); +} + +// test28: ctor using valid 1 element sub-protocol array +function test28() { + return new Promise(function (resolve, reject) { + var prots = ["test28"]; + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + ws.onopen = function (e) { + ok(true, "test 28 protocol array open"); + ws.close(); + }; + + ws.onclose = function (e) { + is(ws.protocol, "test28", "test28 subprotocol selection"); + ok(true, "test 28 protocol array close"); + resolve(); + }; + }); +} + +// test29: ctor using all valid 5 element sub-protocol array +function test29() { + return new Promise(function (resolve, reject) { + var prots = ["test29a", "test29b"]; + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + ws.onopen = function (e) { + ok(true, "test 29 protocol array open"); + ws.close(); + }; + + ws.onclose = function (e) { + ok(true, "test 29 protocol array close"); + resolve(); + }; + }); +} + +// test30: ctor using valid 1 element sub-protocol array with element server +// will reject +function test30() { + return new Promise(function (resolve, reject) { + var prots = ["test-does-not-exist"]; + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + ws.onopen = shouldNotOpen; + + ws.onclose = function (e) { + shouldCloseNotCleanly(e); + resolve(); + }; + + ws.onerror = function () {}; + }); +} + +// test31: ctor using valid 2 element sub-protocol array with 1 element server +// will reject and one server will accept +function test31() { + return new Promise(function (resolve, reject) { + var prots = ["test-does-not-exist", "test31"]; + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + ws.onopen = function (e) { + ok(true, "test 31 protocol array open"); + ws.close(); + }; + + ws.onclose = function (e) { + is(ws.protocol, "test31", "test31 subprotocol selection"); + ok(true, "test 31 protocol array close"); + resolve(); + }; + }); +} + +// test32: ctor using invalid sub-protocol array that contains duplicate items +function test32() { + return new Promise(function (resolve, reject) { + var prots = ["test32", "test32"]; + + try { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + ok(false, "testing duplicated element sub protocol array"); + } catch (e) { + ok(true, "testing duplicated sub element protocol array"); + } + + resolve(); + }); +} + +// test33: test for sending/receiving custom close code (but no close reason) +function test33() { + return new Promise(function (resolve, reject) { + var prots = ["test33"]; + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + ws.onopen = function (e) { + ok(true, "test 33 open"); + ws.close(3131); // pass code but not reason + }; + + ws.onclose = function (e) { + ok(true, "test 33 close"); + shouldCloseCleanly(e); + is(e.code, 3131, "test 33 got wrong close code: " + e.code); + is(e.reason, "", "test 33 got wrong close reason: " + e.reason); + resolve(); + }; + }); +} + +// test34: test for receiving custom close code and reason +function test34() { + return new Promise(function (resolve, reject) { + var prots = ["test-34"]; + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + ws.onopen = function (e) { + ok(true, "test 34 open"); + ws.close(); + }; + + ws.onclose = function (e) { + ok(true, "test 34 close"); + ok(e.wasClean, "test 34 closed cleanly"); + is(e.code, 1001, "test 34 custom server code"); + is(e.reason, "going away now", "test 34 custom server reason"); + resolve(); + }; + }); +} + +// test35: test for sending custom close code and reason +function test35() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-35a" + ); + + ws.onopen = function (e) { + ok(true, "test 35a open"); + ws.close(3500, "my code"); + }; + + ws.onclose = function (e) { + ok(true, "test 35a close"); + ok(e.wasClean, "test 35a closed cleanly"); + var wsb = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-35b" + ); + + wsb.onopen = function (event) { + ok(true, "test 35b open"); + wsb.close(); + }; + + wsb.onclose = function (event) { + ok(true, "test 35b close"); + ok(event.wasClean, "test 35b closed cleanly"); + is(event.code, 3501, "test 35 custom server code"); + is(event.reason, "my code", "test 35 custom server reason"); + resolve(); + }; + }; + }); +} + +// test36: negative test for sending out of range close code +function test36() { + return new Promise(function (resolve, reject) { + var prots = ["test-36"]; + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + ws.onopen = function (e) { + ok(true, "test 36 open"); + + try { + ws.close(13200); + ok(false, "testing custom close code out of range"); + } catch (ex) { + ok(true, "testing custom close code out of range"); + ws.close(3200); + } + }; + + ws.onclose = function (e) { + ok(true, "test 36 close"); + ok(e.wasClean, "test 36 closed cleanly"); + resolve(); + }; + }); +} + +// test37: negative test for too long of a close reason +function test37() { + return new Promise(function (resolve, reject) { + var prots = ["test-37"]; + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + ws.onopen = function (e) { + ok(true, "test 37 open"); + + try { + ws.close( + 3100, + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123" + ); + ok(false, "testing custom close reason out of range"); + } catch (ex) { + ok(true, "testing custom close reason out of range"); + ws.close( + 3100, + "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012" + ); + } + }; + + ws.onclose = function (e) { + ok(true, "test 37 close"); + ok(e.wasClean, "test 37 closed cleanly"); + + var wsb = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-37b" + ); + + wsb.onopen = function (event) { + // now test that a rejected close code and reason dont persist + ok(true, "test 37b open"); + try { + wsb.close( + 3101, + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123" + ); + ok(false, "testing custom close reason out of range 37b"); + } catch (ex) { + ok(true, "testing custom close reason out of range 37b"); + wsb.close(); + } + }; + + wsb.onclose = function (event) { + ok(true, "test 37b close"); + ok(event.wasClean, "test 37b closed cleanly"); + + var wsc = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-37c" + ); + + wsc.onopen = function (eventInner) { + ok(true, "test 37c open"); + wsc.close(); + }; + + wsc.onclose = function (eventInner) { + isnot( + eventInner.code, + 3101, + "test 37c custom server code not present" + ); + is( + eventInner.reason, + "", + "test 37c custom server reason not present" + ); + resolve(); + }; + }; + }; + }); +} + +// test38: ensure extensions attribute is defined +function test38() { + return new Promise(function (resolve, reject) { + var prots = ["test-38"]; + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + ws.onopen = function (e) { + ok(true, "test 38 open"); + isnot(ws.extensions, undefined, "extensions attribute defined"); + // is(ws.extensions, "deflate-stream", "extensions attribute deflate-stream"); + ws.close(); + }; + + ws.onclose = function (e) { + ok(true, "test 38 close"); + resolve(); + }; + }); +} + +// test39: a basic wss:// connectivity test +function test39() { + return new Promise(function (resolve, reject) { + var prots = ["test-39"]; + + var ws = CreateTestWS( + "wss://example.com/tests/dom/websocket/tests/file_websocket", + prots + ); + status_test39 = "started"; + + ws.onopen = function (e) { + status_test39 = "opened"; + ok(true, "test 39 open"); + ws.close(); + }; + + ws.onclose = function (e) { + ok(true, "test 39 close"); + is(status_test39, "opened", "test 39 did open"); + resolve(); + }; + }); +} + +// test40: negative test for wss:// with no cert +function test40() { + return new Promise(function (resolve, reject) { + var prots = ["test-40"]; + + var ws = CreateTestWS( + "wss://nocert.example.com/tests/dom/websocket/tests/file_websocket", + prots + ); + + status_test40 = "started"; + ws.onerror = ignoreError; + + ws.onopen = function (e) { + status_test40 = "opened"; + ok(false, "test 40 open"); + ws.close(); + }; + + ws.onclose = function (e) { + ok(true, "test 40 close"); + is(status_test40, "started", "test 40 did not open"); + resolve(); + }; + }); +} + +// test41: HSTS +function test41() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://example.com/tests/dom/websocket/tests/file_websocket", + "test-41a", + 1 + ); + + ws.onopen = function (e) { + ok(true, "test 41a open"); + is( + ws.url, + "ws://example.com/tests/dom/websocket/tests/file_websocket", + "test 41a initial ws should not be redirected" + ); + ws.close(); + }; + + ws.onclose = function (e) { + ok(true, "test 41a close"); + + // Since third-party loads can't set HSTS state, this will not set + // HSTS for example.com. + var wsb = CreateTestWS( + "wss://example.com/tests/dom/websocket/tests/file_websocket", + "test-41b", + 1 + ); + + wsb.onopen = function (event) { + ok(true, "test 41b open"); + wsb.close(); + }; + + wsb.onclose = function (event) { + ok(true, "test 41b close"); + + // try ws:// again, it should be done over ws:// again + var wsc = CreateTestWS( + "ws://example.com/tests/dom/websocket/tests/file_websocket", + "test-41c" + ); + + wsc.onopen = function () { + ok(true, "test 41c open"); + is( + wsc.url, + "ws://example.com/tests/dom/websocket/tests/file_websocket", + "test 41c ws should not be redirected by hsts to wss" + ); + wsc.close(); + }; + + wsc.onclose = function () { + ok(true, "test 41c close"); + resolve(); + }; + }; + }; + }); +} + +// test42: non-char utf-8 sequences +function test42() { + return new Promise(function (resolve, reject) { + // test some utf-8 non-characters. They should be allowed in the + // websockets context. Test via round trip echo. + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-42" + ); + var data = ["U+FFFE \ufffe", "U+FFFF \uffff", "U+10FFFF \udbff\udfff"]; + var index = 0; + + ws.onopen = function () { + ws.send(data[0]); + ws.send(data[1]); + ws.send(data[2]); + }; + + ws.onmessage = function (e) { + is( + e.data, + data[index], + "bad received message in test-42! index=" + index + ); + index++; + if (index == 3) { + ws.close(); + } + }; + + ws.onclose = function (e) { + resolve(); + }; + }); +} + +// test43: Test setting binaryType attribute +function test43() { + return new Promise(function (resolve, reject) { + var prots = ["test-43"]; + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + prots + ); + + ws.onopen = function (e) { + ok(true, "test 43 open"); + // Test binaryType setting + ws.binaryType = "arraybuffer"; + ws.binaryType = "blob"; + ws.binaryType = ""; // illegal + is(ws.binaryType, "blob"); + ws.binaryType = "ArrayBuffer"; // illegal + is(ws.binaryType, "blob"); + ws.binaryType = "Blob"; // illegal + is(ws.binaryType, "blob"); + ws.binaryType = "mcfoofluu"; // illegal + is(ws.binaryType, "blob"); + ws.close(); + }; + + ws.onclose = function (e) { + ok(true, "test 43 close"); + resolve(); + }; + }); +} + +// test44: Test sending/receving binary ArrayBuffer +function test44() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-44" + ); + is(ws.readyState, 0, "bad readyState in test-44!"); + ws.binaryType = "arraybuffer"; + + ws.onopen = function () { + is(ws.readyState, 1, "open bad readyState in test-44!"); + var buf = new ArrayBuffer(3); + // create byte view + var view = new Uint8Array(buf); + view[0] = 5; + view[1] = 0; // null byte + view[2] = 7; + ws.send(buf); + }; + + ws.onmessage = function (e) { + ok(e.data instanceof ArrayBuffer, "Should receive an arraybuffer!"); + var view = new Uint8Array(e.data); + ok( + view.length == 2 && view[0] == 0 && view[1] == 4, + "testing Reply arraybuffer" + ); + ws.close(); + }; + + ws.onclose = function (e) { + is(ws.readyState, 3, "onclose bad readyState in test-44!"); + shouldCloseCleanly(e); + resolve(); + }; + }); +} + +// test45: Test sending/receving binary Blob +function test45() { + return new Promise(function (resolve, reject) { + function test45Real(blobFile) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-45" + ); + is(ws.readyState, 0, "bad readyState in test-45!"); + // ws.binaryType = "blob"; // Don't need to specify: blob is the default + + ws.onopen = function () { + is(ws.readyState, 1, "open bad readyState in test-45!"); + ws.send(blobFile); + }; + + var test45blob; + + ws.onmessage = function (e) { + test45blob = e.data; + ok(test45blob instanceof Blob, "We should be receiving a Blob"); + + ws.close(); + }; + + ws.onclose = function (e) { + is(ws.readyState, 3, "onclose bad readyState in test-45!"); + shouldCloseCleanly(e); + + // check blob contents + var reader = new FileReader(); + reader.onload = function (event) { + is( + reader.result, + "flob", + "response should be 'flob': got '" + reader.result + "'" + ); + }; + + reader.onerror = function (event) { + testFailed("Failed to read blob: error code = " + reader.error.code); + }; + + reader.onloadend = function (event) { + resolve(); + }; + + reader.readAsBinaryString(test45blob); + }; + } + + SpecialPowers.createFiles( + [{ name: "testBlobFile", data: "flob" }], + function (files) { + test45Real(files[0]); + }, + function (msg) { + testFailed("Failed to create file for test45: " + msg); + resolve(); + } + ); + }); +} + +// test46: Test that we don't dispatch incoming msgs once in CLOSING state +function test46() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-46" + ); + is(ws.readyState, 0, "create bad readyState in test-46!"); + + ws.onopen = function () { + is(ws.readyState, 1, "open bad readyState in test-46!"); + ws.close(); + is(ws.readyState, 2, "close must set readyState to 2 in test-46!"); + }; + + ws.onmessage = function (e) { + ok(false, "received message after calling close in test-46!"); + }; + + ws.onclose = function (e) { + is(ws.readyState, 3, "onclose bad readyState in test-46!"); + shouldCloseCleanly(e); + resolve(); + }; + }); +} + +// test47: Make sure onerror/onclose aren't called during close() +function test47() { + return new Promise(function (resolve, reject) { + var hasError = false; + var ws = CreateTestWS( + "ws://another.websocket.server.that.probably.does.not.exist" + ); + + ws.onopen = shouldNotOpen; + + ws.onerror = function (e) { + is( + ws.readyState, + 3, + "test-47: readyState should be CLOSED(3) in onerror: got " + + ws.readyState + ); + ok(!ws._withinClose, "onerror() called during close()!"); + hasError = true; + }; + + ws.onclose = function (e) { + shouldCloseNotCleanly(e); + ok(hasError, "test-47: should have called onerror before onclose"); + is( + ws.readyState, + 3, + "test-47: readyState should be CLOSED(3) in onclose: got " + + ws.readyState + ); + ok(!ws._withinClose, "onclose() called during close()!"); + is(e.code, 1006, "test-47 close code should be 1006 but is:" + e.code); + resolve(); + }; + + // Call close before we're connected: throws error + // Make sure we call onerror/onclose asynchronously + ws._withinClose = 1; + ws.close(3333, "Closed before we were open: error"); + ws._withinClose = 0; + is( + ws.readyState, + 2, + "test-47: readyState should be CLOSING(2) after close(): got " + + ws.readyState + ); + }); +} + +// test48: see bug 1227136 - client calls close() from onopen() and waits until +// WebSocketChannel::mSocketIn is nulled out on socket thread. +function test48() { + return new Promise(function (resolve, reject) { + const pref_close = "network.websocket.timeout.close"; + SpecialPowers.setIntPref(pref_close, 1); + + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-48" + ); + + ws.onopen = function () { + ws.close(); + + var date = new Date(); + var curDate = null; + do { + curDate = new Date(); + } while (curDate - date < 1500); + }; + + ws.onclose = function (e) { + ok(true, "ws close in test 48"); + resolve(); + }; + + SpecialPowers.clearUserPref(pref_close); + }); +} + +function test49() { + return new Promise(function (resolve, reject) { + var ws = CreateTestWS( + "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket", + "test-49" + ); + var gotError = 0; + ok(ws.readyState == 0, "create bad readyState in test-49!"); + + ws.onopen = function () { + ok(false, "Connection must fail in test-49"); + }; + + ws.onerror = function (e) { + gotError = 1; + }; + + ws.onclose = function (e) { + ok(gotError, "Should get error in test-49!"); + resolve(); + }; + }); +} |