gecko/content/base/test/test_websocket.html

1515 lines
38 KiB
HTML

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
<title>WebSocket test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="testWebSocket()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=472529">Mozilla Bug </a>
<p id="display">
<input id="fileList" type="file"></input>
</p>
<div id="content">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/*
* tests:
* 1. client tries to connect to a http scheme location;
* 2. assure serialization of the connections;
* 3. client tries to connect to an non-existent ws server;
* 4. client tries to connect using a relative url;
* 5. client uses an invalid protocol value;
* 6. counter and encoding check;
* 7. onmessage event origin property check
* 8. client calls close() and the server sends the close frame (with no code
* or reason) in acknowledgement;
* 9. client closes the connection before the ws connection is established;
* 10. client sends a message before the ws connection is established;
* 11. a simple hello echo;
* 12. client sends a message containing unpaired surrogates
* 13. server sends an invalid message;
* 14. server sends the close frame, it doesn't close the tcp connection and
* it keeps sending normal ws messages;
* 15. server closes the tcp connection, but it doesn't send the close frame;
* 16. client calls close() and tries to send a message;
* 17. see bug 572975 - all event listeners set
* 18. client tries to connect to an http resource;
* 19. server closes the tcp connection before establishing the ws connection;
* 20. see bug 572975 - only on error and onclose event listeners set
* 21. see bug 572975 - same as test 17, but delete strong event listeners when
* receiving the message event;
* 22. server takes too long to establish the ws connection;
* 23. should detect WebSocket on window object;
* 24. server rejects sub-protocol string
* 25. ctor with valid empty sub-protocol array
* 26. ctor with invalid sub-protocol array containing 1 empty element
* 27. ctor with invalid sub-protocol array containing an empty element in list
* 28. ctor using valid 1 element sub-protocol array
* 29. ctor using all valid 5 element sub-protocol array
* 30. ctor using valid 1 element sub-protocol array with element server will
* reject
* 31. ctor using valid 2 element sub-protocol array with 1 element server
* will reject and one server will accept.
* 32. ctor using invalid sub-protocol array that contains duplicate items
* 33. test for sending/receiving custom close code (but no close reason)
* 34. test for receiving custom close code and reason
* 35. test for sending custom close code and reason
* 36. negative test for sending out of range close code
* 37. negative test for too long of a close reason
* 38. ensure extensions attribute is defined
* 39. a basic wss:// connectivity test
* 40. negative test for wss:// with no cert
* 41. HSTS
* 42. non-char utf-8 sequences
* 43. Test setting binaryType attribute
* 44. Test sending/receving binary ArrayBuffer
* 45. Test sending/receving binary Blob
* 46. Test that we don't dispatch incoming msgs once in CLOSING state
* 47. Make sure onerror/onclose aren't called during close()
*/
var first_test = 1;
var last_test = 47;
// Set this to >1 if you want to run the suite multiple times to probe for
// random orange failures.
// - Do NOT check into mozilla-central with a value != 1.
// - Too large a count will wind up causing tryserver to timeout the test (which
// is ok, but means all testruns will be orange). If I set first_test to >22
// (i.e don't run any of the tests that require waiting) I can get ~250-300
// iterations of the remaining tests w/o a timeout.
var testsuite_iterations = 1;
var current_test = first_test;
var testsuite_iteration = 1;
var test_started = new Array(last_test);
var all_ws = [];
function shouldNotOpen(e)
{
var ws = e.target;
ok(false, "onopen shouldn't be called on test " + ws._testNumber + "!");
}
function shouldNotReceiveCloseEvent(e)
{
var ws = e.target;
var extendedErrorInfo = "";
if (!ws._testNumber) {
extendedErrorInfo += "\nws members:\n";
for (var i in ws) {
extendedErrorInfo += (i + ": " + ws[i] + "\n");
}
extendedErrorInfo += "\ne members:\n";
for (var i in e) {
extendedErrorInfo += (i + ": " + e[i] + "\n");
}
}
// FIXME: see bug 578276. This should be a test failure, but it's too flaky on the tbox.
ok(true, "onclose shouldn't be called on test " + ws._testNumber + "!" + extendedErrorInfo);
}
function shouldCloseCleanly(e)
{
var ws = e.target;
ok(e.wasClean, "the ws connection in test " + ws._testNumber + " should be closed cleanly");
}
function shouldCloseNotCleanly(e)
{
var ws = e.target;
ok(!e.wasClean, "the ws connection in test " + ws._testNumber + " shouldn't be closed cleanly");
}
function ignoreError(e)
{
}
function CreateTestWS(ws_location, ws_protocol, no_increment_test)
{
var ws;
try {
if (ws_protocol == undefined) {
ws = new WebSocket(ws_location);
} else {
ws = new WebSocket(ws_location, ws_protocol);
}
ws._testNumber = current_test;
ws._receivedCloseEvent = false;
ok(true, "Created websocket for test " + ws._testNumber +"\n");
ws.onerror = function(e)
{
ok(false, "onerror called on test " + e.target._testNumber + "!");
};
ws.addEventListener("close", function(e)
{
ws._receivedCloseEvent = true;
}, false);
}
catch (e) {
throw e;
}
finally {
if (!no_increment_test) {
current_test++;
}
}
all_ws.push(ws);
return ws;
}
function forcegc()
{
SpecialPowers.forceGC();
SpecialPowers.gc();
setTimeout(function()
{
SpecialPowers.gc();
}, 1);
}
function doTest(number)
{
if (number > last_test) {
ranAllTests = true;
maybeFinished();
return;
}
if (testsuite_iteration > 1) {
$("feedback").innerHTML = "test suite iteration #" + testsuite_iteration + " of " + testsuite_iterations +
": executing test: " + number + " of " + last_test + " tests.";
} else {
$("feedback").innerHTML = "executing test: " + number + " of " + last_test + " tests.";
}
var fnTest = eval("test" + number + "");
if (test_started[number] === true) {
doTest(number + 1);
return;
}
test_started[number] = true;
fnTest();
}
doTest.timeoutId = null;
function test1()
{
try {
var ws = CreateTestWS("http://mochi.test:8888/tests/content/base/test/file_websocket");
ok(false, "test1 failed");
}
catch (e) {
ok(true, "test1 failed");
}
doTest(2);
}
// this test expects that the serialization list to connect to the proxy
// is empty. Use different domain so we can run this in the background
// and not delay other tests.
var waitTest2Part1 = false;
var waitTest2Part2 = false;
function test2()
{
waitTest2Part1 = true;
waitTest2Part2 = true;
var ws1 = CreateTestWS("ws://sub2.test2.example.com/tests/content/base/test/file_websocket", "test-2.1");
current_test--; // CreateTestWS incremented this
var ws2 = CreateTestWS("ws://sub2.test2.example.com/tests/content/base/test/file_websocket", "test-2.2");
var ws2CanConnect = false;
// the server will delay ws1 for 5 seconds, but the other tests can
// proceed in parallel
doTest(3);
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();
};
}
function test3()
{
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");
ok(e.code == 1006, "test-3 close code should be 1006 but is:" + e.code);
doTest(4);
};
}
function test4()
{
try {
var ws = CreateTestWS("file_websocket");
ok(false, "test-4 failed");
}
catch (e) {
ok(true, "test-4 failed");
}
doTest(5);
}
function test5()
{
try {
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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");
}
current_test--; // CreateTestWS incremented this
try {
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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");
}
current_test--; // CreateTestWS incremented this
try {
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 5");
ok(false, "U+0020 not acceptable in protocol parameter");
}
catch (e) {
ok(true, "U+0020 not acceptable in protocol parameter");
}
doTest(6);
}
function test6()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-6");
var counter = 1;
ws.onopen = function()
{
ws.send(counter);
}
ws.onmessage = function(e)
{
if (counter == 5) {
ok(e.data == "あいうえお", "test-6 counter 5 data ok");
ws.close();
} else {
ok(e.data == counter+1, "bad counter");
counter += 2;
ws.send(counter);
}
}
ws.onclose = function(e)
{
shouldCloseCleanly(e);
doTest(7);
};
}
function test7()
{
var ws = CreateTestWS("ws://sub2.test2.example.org/tests/content/base/test/file_websocket", "test-7");
var gotmsg = false;
ws.onopen = function()
{
ok(true, "test 7 open");
}
ws.onmessage = function(e)
{
ok(true, "test 7 message");
ok(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);
doTest(8);
};
}
function test8()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-8");
ws.onopen = function()
{
ok(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
ok(e.code == 1005, "test-8 close code has wrong value:" + e.code);
ok(e.reason == "", "test-8 close reason has wrong value:" + e.reason);
doTest(9);
};
}
var waitTest9 = false;
function test9()
{
waitTest9 = true;
var ws = CreateTestWS("ws://test2.example.org/tests/content/base/test/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);
waitTest9 = false;
maybeFinished();
};
ws.close();
// the server injects a delay, so proceed with this in the background
doTest(10);
}
var waitTest10 = false;
function test10()
{
waitTest10 = true;
var ws = CreateTestWS("ws://sub1.test1.example.com/tests/content/base/test/file_websocket", "test-10");
ws.onclose = function(e)
{
shouldCloseCleanly(e);
waitTest10 = false;
maybeFinished();
}
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();
}
// proceed with this test in the background
doTest(11);
}
function test11()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-11");
ok(ws.readyState == 0, "create bad readyState in test-11!");
ws.onopen = function()
{
ok(ws.readyState == 1, "open bad readyState in test-11!");
ws.send("client data");
}
ws.onmessage = function(e)
{
ok(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)
{
ok(ws.readyState == 3, "onclose bad readyState in test-11!");
shouldCloseCleanly(e);
ok(e.code == 1000, "test 11 got wrong close code: " + e.code);
ok(e.reason == "Have a nice day", "test 11 got wrong close reason: " + e.reason);
doTest(12);
}
}
function test12()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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)
{
ok(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)
{
ok(ws.readyState == 3, "onclose bad readyState in test-12!");
ok(ws._gotMessage, "didn't receive message!");
shouldCloseCleanly(e);
ok(e.code == 1000, "test 12 got wrong close code: " + e.code);
ok(e.reason == "a\ufffdb", "test 11 didn't get replacement char in close reason: " + e.reason);
doTest(13);
}
}
function test13()
{
// 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/content/base/test/file_websocket", "test-13");
ws._timesCalledOnError = 0;
ws.onerror = function()
{
ws._timesCalledOnError++;
}
ws.onclose = function(e)
{
ok(ws._timesCalledOnError > 0, "no error events");
doTest(14);
}
}
function test14()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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);
// Skip test 15 for now: broken
doTest(16);
};
}
/*
* DISABLED: see comments for test-15 case in file_websocket_wsh.py
*
function test15()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-15");
ws.onclose = function(e)
{
shouldCloseNotCleanly(e);
doTest(16);
};
// termination of the connection might cause an error event if it happens in OPEN
ws.onerror = function()
{
}
}
*/
function test16()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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()
{
doTest(17);
}
}
var status_test17 = "not started";
var waitTest17 = false;
var test17func = function()
{
waitTest17 = true;
var local_ws = new WebSocket("ws://sub1.test2.example.org/tests/content/base/test/file_websocket", "test-17");
local_ws._testNumber = "local17";
local_ws._testNumber = current_test++;
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 " + e.target._testNumber + "!");
};
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();
waitTest17 = false;
maybeFinished();
};
local_ws = null;
window._test17 = null;
forcegc();
// do this in the background
doTest(18);
forcegc();
}
function test17()
{
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.
function test18()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket_http_resource.txt");
ws.onopen = shouldNotOpen;
ws.onerror = ignoreError;
ws.onclose = function(e)
{
shouldCloseNotCleanly(e);
doTest(19);
};
}
function test19()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-19");
ws.onopen = shouldNotOpen;
ws.onerror = ignoreError;
ws.onclose = function(e)
{
shouldCloseNotCleanly(e);
doTest(20);
};
}
var waitTest20 = false;
var test20func = function()
{
waitTest20 = true;
var local_ws = new WebSocket("ws://sub1.test1.example.org/tests/content/base/test/file_websocket", "test-20");
local_ws._testNumber = "local20";
local_ws._testNumber = current_test++;
local_ws.onerror = function()
{
ok(false, "onerror called on test " + e.target._testNumber + "!");
};
local_ws.onclose = function(e)
{
ok(true, "test 20 closed despite gc");
waitTest20 = false;
maybeFinished();
};
local_ws = null;
window._test20 = null;
forcegc();
// let test run in the background
doTest(21);
}
function test20()
{
window._test20 = test20func;
window._test20();
}
var waitTest21 = false;
test21func = function()
{
waitTest21 = true;
var local_ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-21");
local_ws._testNumber = current_test++;
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 " + e.target._testNumber + "!");
};
local_ws.onmessage = function(e)
{
ok(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");
waitTest21 = false;
maybeFinished();
};
local_ws = null;
window._test21 = null;
forcegc();
doTest(22);
}
function test21()
{
window._test21 = test21func;
window._test21();
}
var waitTest22 = false;
function test22()
{
waitTest22 = true;
const pref_open = "network.websocket.timeout.open";
SpecialPowers.setIntPref(pref_open, 5);
var ws = CreateTestWS("ws://sub2.test2.example.org/tests/content/base/test/file_websocket", "test-22");
ws.onopen = shouldNotOpen;
ws.onerror = ignoreError;
ws.onclose = function(e)
{
shouldCloseNotCleanly(e);
waitTest22 = false;
maybeFinished();
};
SpecialPowers.clearUserPref(pref_open);
doTest(23);
}
function test23()
{
current_test++;
is(true, "WebSocket" in window, "WebSocket should be available on window object");
doTest(24);
}
function test24()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-does-not-exist");
ws.onopen = shouldNotOpen;
ws.onclose = function(e)
{
shouldCloseNotCleanly(e);
doTest(25);
};
ws.onerror = function()
{
}
}
function test25()
{
var prots=[];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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)
{
ok(ws.protocol == "", "test25 subprotocol selection");
ok(true, "test 25 protocol array close");
doTest(26);
};
}
function test26()
{
var prots=[""];
try {
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
ok(false, "testing empty element sub protocol array");
}
catch (e) {
ok(true, "testing empty sub element protocol array");
}
doTest(27);
}
function test27()
{
var prots=["test27", ""];
try {
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
ok(false, "testing empty element mixed sub protocol array");
}
catch (e) {
ok(true, "testing empty element mixed sub protocol array");
}
doTest(28);
}
function test28()
{
var prots=["test28"];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
ws.onopen = function(e)
{
ok(true, "test 28 protocol array open");
ws.close();
};
ws.onclose = function(e)
{
ok(ws.protocol == "test28", "test28 subprotocol selection");
ok(true, "test 28 protocol array close");
doTest(29);
};
}
function test29()
{
var prots=["test29a", "test29b"];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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");
doTest(30);
};
}
function test30()
{
var prots=["test-does-not-exist"];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
ws.onopen = shouldNotOpen;
ws.onclose = function(e)
{
shouldCloseNotCleanly(e);
doTest(31);
};
ws.onerror = function()
{
}
}
function test31()
{
var prots=["test-does-not-exist", "test31"];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
ws.onopen = function(e)
{
ok(true, "test 31 protocol array open");
ws.close();
};
ws.onclose = function(e)
{
ok(ws.protocol == "test31", "test31 subprotocol selection");
ok(true, "test 31 protocol array close");
doTest(32);
};
}
function test32()
{
var prots=["test32","test32"];
try {
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
ok(false, "testing duplicated element sub protocol array");
}
catch (e) {
ok(true, "testing duplicated sub element protocol array");
}
doTest(33);
}
function test33()
{
var prots=["test33"];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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);
ok(e.code == 3131, "test 33 got wrong close code: " + e.code);
ok(e.reason === "", "test 33 got wrong close reason: " + e.reason);
doTest(34);
};
}
function test34()
{
var prots=["test-34"];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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");
ok(e.code == 1001, "test 34 custom server code");
ok(e.reason == "going away now", "test 34 custom server reason");
doTest(35);
};
}
function test35()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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");
current_test--; // CreateTestWS for 35a incremented this
var wsb = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-35b");
wsb.onopen = function(e)
{
ok(true, "test 35b open");
wsb.close();
};
wsb.onclose = function(e)
{
ok(true, "test 35b close");
ok(e.wasClean, "test 35b closed cleanly");
ok(e.code == 3501, "test 35 custom server code");
ok(e.reason == "my code", "test 35 custom server reason");
doTest(36);
};
}
}
function test36()
{
var prots=["test-36"];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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 (e) {
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");
doTest(37);
};
}
function test37()
{
var prots=["test-37"];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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 (e) {
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");
current_test--; // CreateTestWS for 37 incremented this
var wsb = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-37b");
wsb.onopen = function(e)
{
// 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 (e) {
ok(true, "testing custom close reason out of range 37b");
wsb.close();
}
}
wsb.onclose = function(e)
{
ok(true, "test 37b close");
ok(e.wasClean, "test 37b closed cleanly");
current_test--; // CreateTestWS for 37 incremented this
var wsc = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-37c");
wsc.onopen = function(e)
{
ok(true, "test 37c open");
wsc.close();
}
wsc.onclose = function(e)
{
ok(e.code != 3101, "test 37c custom server code not present");
ok(e.reason == "", "test 37c custom server reason not present");
doTest(38);
}
}
}
}
function test38()
{
var prots=["test-38"];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", prots);
ws.onopen = function(e)
{
ok(true, "test 38 open");
ok(ws.extensions != undefined, "extensions attribute defined");
// ok(ws.extensions == "deflate-stream", "extensions attribute deflate-stream");
ws.close();
};
ws.onclose = function(e)
{
ok(true, "test 38 close");
doTest(39);
};
}
function test39()
{
var prots=["test-39"];
var ws = CreateTestWS("wss://example.com/tests/content/base/test/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");
ok(status_test39 == "opened", "test 39 did open");
doTest(40);
};
}
function test40()
{
var prots=["test-40"];
var ws = CreateTestWS("wss://nocert.example.com/tests/content/base/test/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");
ok(status_test40 == "started", "test 40 did not open");
doTest(41);
};
}
function test41()
{
var ws = CreateTestWS("ws://example.com/tests/content/base/test/file_websocket", "test-41a", 1);
ws.onopen = function(e)
{
ok(true, "test 41a open");
ok(ws.url == "ws://example.com/tests/content/base/test/file_websocket",
"test 41a initial ws should not be redirected");
ws.close();
};
ws.onclose = function(e)
{
ok(true, "test 41a close");
// establish a hsts policy for example.com
var wsb = CreateTestWS("wss://example.com/tests/content/base/test/file_websocket", "test-41b", 1);
wsb.onopen = function(e)
{
ok(true, "test 41b open");
wsb.close();
}
wsb.onclose = function(e)
{
ok(true, "test 41b close");
// try ws:// again, it should be done over wss:// now due to hsts
var wsc = CreateTestWS("ws://example.com/tests/content/base/test/file_websocket", "test-41c");
wsc.onopen = function(e)
{
ok(true, "test 41c open");
ok(wsc.url == "wss://example.com/tests/content/base/test/file_websocket",
"test 41c ws should be redirected by hsts to wss");
wsc.close();
}
wsc.onclose = function(e)
{
ok(true, "test 41c close");
// clean up the STS state
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
var thehost = ios.newURI("http://example.com", null, null);
var stss = Cc["@mozilla.org/stsservice;1"].getService(Ci.nsIStrictTransportSecurityService);
var loadContext = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsILoadContext);
var flags = 0;
if (loadContext.usePrivateBrowsing)
flags |= Ci.nsISocketProvider.NO_PERMANENT_STORAGE;
stss.removeStsState(thehost, flags);
doTest(42);
}
}
}
}
function test42()
{
// 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/content/base/test/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)
{
ok(e.data == data[index], "bad received message in test-42! index="+index);
index++;
if (index == 3)
ws.close();
}
ws.onclose = function(e)
{
doTest(43);
}
}
function test43()
{
var prots=["test-43"];
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/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");
doTest(44);
};
}
function test44()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-44");
ok(ws.readyState == 0, "bad readyState in test-44!");
ws.binaryType = "arraybuffer";
ws.onopen = function()
{
ok(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)
{
ok(ws.readyState == 3, "onclose bad readyState in test-44!");
shouldCloseCleanly(e);
doTest(45);
}
}
function createDOMFile(fileName, fileData)
{
// enablePrivilege is picky about where it's called? if I put it in global
// scope at start of <script> it doesn't work...
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
// create File in profile dir
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties);
var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
testFile.append(fileName);
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, 0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
// Set filename into DOM <input> field, as if selected by user
var fileList = document.getElementById('fileList');
fileList.value = testFile.path;
// return JS File object, aka Blob
return fileList.files[0];
}
function test45()
{
var blobFile = createDOMFile("testBlobFile", "flob");
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-45");
ok(ws.readyState == 0, "bad readyState in test-45!");
// ws.binaryType = "blob"; // Don't need to specify: blob is the default
ws.onopen = function()
{
ok(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)
{
ok(ws.readyState == 3, "onclose bad readyState in test-45!");
shouldCloseCleanly(e);
// check blob contents
var reader = new FileReader();
reader.onload = function(event)
{
ok(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)
{
doTest(46);
};
reader.readAsBinaryString(test45blob);
}
}
function test46()
{
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-46");
ok(ws.readyState == 0, "create bad readyState in test-46!");
ws.onopen = function()
{
ok(ws.readyState == 1, "open bad readyState in test-46!");
ws.close()
ok(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)
{
ok(ws.readyState == 3, "onclose bad readyState in test-46!");
shouldCloseCleanly(e);
doTest(47);
}
}
function test47()
{
var hasError = false;
var ws = CreateTestWS("ws://another.websocket.server.that.probably.does.not.exist");
ws.onopen = shouldNotOpen;
ws.onerror = function (e)
{
ok(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");
ok(ws.readyState == 3, "test-47: readyState should be CLOSED(3) in onclose: got "
+ ws.readyState);
ok(!ws._withinClose, "onclose() called during close()!");
ok(e.code == 1006, "test-47 close code should be 1006 but is:" + e.code);
doTest(48);
};
// 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;
ok(ws.readyState == 2, "test-47: readyState should be CLOSING(2) after close(): got "
+ ws.readyState);
}
var ranAllTests = false;
function maybeFinished()
{
if (!ranAllTests)
return;
if (waitTest2Part1 || waitTest2Part2 || waitTest9 || waitTest10 ||
waitTest17 || waitTest20 || waitTest21 || waitTest22)
return;
for (i = 0; i < all_ws.length; ++i) {
if (all_ws[i] != shouldNotReceiveCloseEvent &&
!all_ws[i]._receivedCloseEvent) {
ok(false, "didn't called close on test " + all_ws[i]._testNumber + "!");
}
}
if (testsuite_iteration++ < testsuite_iterations) {
// play it again, Sam...
ok(1, "starting testsuite iteration " + testsuite_iteration);
test_started = new Array(last_test);
doTest(current_test = first_test);
} else {
// all done
SimpleTest.finish();
}
}
function testWebSocket ()
{
doTest(first_test);
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<div id="feedback">
</div>
</body>
</html>