summaryrefslogtreecommitdiffstats
path: root/dom/websocket/tests
diff options
context:
space:
mode:
Diffstat (limited to 'dom/websocket/tests')
-rw-r--r--dom/websocket/tests/chrome.toml3
-rw-r--r--dom/websocket/tests/file_bug1384658.html18
-rw-r--r--dom/websocket/tests/file_websocket_basic_wsh.py31
-rw-r--r--dom/websocket/tests/file_websocket_bigBlob_wsh.py11
-rw-r--r--dom/websocket/tests/file_websocket_hello_wsh.py12
-rw-r--r--dom/websocket/tests/file_websocket_http_resource.txt1
-rw-r--r--dom/websocket/tests/file_websocket_permessage_deflate_disabled_wsh.py18
-rw-r--r--dom/websocket/tests/file_websocket_permessage_deflate_params_wsh.py24
-rw-r--r--dom/websocket/tests/file_websocket_permessage_deflate_rejected_wsh.py24
-rw-r--r--dom/websocket/tests/file_websocket_permessage_deflate_wsh.py23
-rw-r--r--dom/websocket/tests/file_websocket_wsh.py171
-rw-r--r--dom/websocket/tests/frame_bug1384658.html13
-rw-r--r--dom/websocket/tests/iframe_websocket_sandbox.html65
-rw-r--r--dom/websocket/tests/iframe_websocket_wss.html35
-rw-r--r--dom/websocket/tests/iframe_webworker_wss.html22
-rw-r--r--dom/websocket/tests/mochitest.toml124
-rw-r--r--dom/websocket/tests/mochitest_http2.toml6
-rw-r--r--dom/websocket/tests/test_bug1081686.html71
-rw-r--r--dom/websocket/tests/test_bug1384658.html54
-rw-r--r--dom/websocket/tests/test_event_listener_leaks.html57
-rw-r--r--dom/websocket/tests/test_websocket1.html42
-rw-r--r--dom/websocket/tests/test_websocket2.html44
-rw-r--r--dom/websocket/tests/test_websocket3.html44
-rw-r--r--dom/websocket/tests/test_websocket4.html42
-rw-r--r--dom/websocket/tests/test_websocket5.html41
-rw-r--r--dom/websocket/tests/test_websocket_basic.html289
-rw-r--r--dom/websocket/tests/test_websocket_bigBlob.html55
-rw-r--r--dom/websocket/tests/test_websocket_frame.html161
-rw-r--r--dom/websocket/tests/test_websocket_hello.html49
-rw-r--r--dom/websocket/tests/test_websocket_http2.html58
-rw-r--r--dom/websocket/tests/test_websocket_longString.html48
-rw-r--r--dom/websocket/tests/test_websocket_mixed_content.html105
-rw-r--r--dom/websocket/tests/test_websocket_mixed_content_blob.html76
-rw-r--r--dom/websocket/tests/test_websocket_mixed_content_opener.html159
-rw-r--r--dom/websocket/tests/test_websocket_no_duplicate_packet.html106
-rw-r--r--dom/websocket/tests/test_websocket_permessage_deflate.html110
-rw-r--r--dom/websocket/tests/test_websocket_sandbox.html34
-rw-r--r--dom/websocket/tests/test_websocket_sharedWorker.html30
-rw-r--r--dom/websocket/tests/test_worker_websocket1.html46
-rw-r--r--dom/websocket/tests/test_worker_websocket2.html46
-rw-r--r--dom/websocket/tests/test_worker_websocket3.html46
-rw-r--r--dom/websocket/tests/test_worker_websocket4.html46
-rw-r--r--dom/websocket/tests/test_worker_websocket5.html46
-rw-r--r--dom/websocket/tests/test_worker_websocket_basic.html57
-rw-r--r--dom/websocket/tests/test_worker_websocket_https.html30
-rw-r--r--dom/websocket/tests/test_worker_websocket_loadgroup.html61
-rw-r--r--dom/websocket/tests/websocket_basic_worker.js48
-rw-r--r--dom/websocket/tests/websocket_helpers.js69
-rw-r--r--dom/websocket/tests/websocket_https_worker.js11
-rw-r--r--dom/websocket/tests/websocket_hybi/file_binary-frames_wsh.py19
-rw-r--r--dom/websocket/tests/websocket_hybi/file_check-binary-messages_wsh.py27
-rw-r--r--dom/websocket/tests/websocket_hybi/mochitest.toml17
-rw-r--r--dom/websocket/tests/websocket_hybi/test_receive-arraybuffer.html97
-rw-r--r--dom/websocket/tests/websocket_hybi/test_receive-blob.html110
-rw-r--r--dom/websocket/tests/websocket_hybi/test_send-arraybuffer.html82
-rw-r--r--dom/websocket/tests/websocket_hybi/test_send-blob.html72
-rw-r--r--dom/websocket/tests/websocket_loadgroup_worker.js26
-rw-r--r--dom/websocket/tests/websocket_sharedWorker.js34
-rw-r--r--dom/websocket/tests/websocket_tests.js1488
-rw-r--r--dom/websocket/tests/websocket_worker1.js19
-rw-r--r--dom/websocket/tests/websocket_worker2.js19
-rw-r--r--dom/websocket/tests/websocket_worker3.js17
-rw-r--r--dom/websocket/tests/websocket_worker4.js19
-rw-r--r--dom/websocket/tests/websocket_worker5.js14
-rw-r--r--dom/websocket/tests/websocket_worker_helpers.js27
-rw-r--r--dom/websocket/tests/websocket_worker_https.html14
-rw-r--r--dom/websocket/tests/window_bug1384658.html19
-rw-r--r--dom/websocket/tests/window_websocket_wss.html65
68 files changed, 4967 insertions, 0 deletions
diff --git a/dom/websocket/tests/chrome.toml b/dom/websocket/tests/chrome.toml
new file mode 100644
index 0000000000..06446e0c06
--- /dev/null
+++ b/dom/websocket/tests/chrome.toml
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+["test_websocket_frame.html"]
diff --git a/dom/websocket/tests/file_bug1384658.html b/dom/websocket/tests/file_bug1384658.html
new file mode 100644
index 0000000000..9db632831e
--- /dev/null
+++ b/dom/websocket/tests/file_bug1384658.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<script>
+ onload = function() {
+ function done(success) {
+ var bc = new BroadcastChannel("test_channel");
+ bc.postMessage({success});
+ bc.close();
+ }
+ try {
+ new WebSocket("ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_basic");
+ done(true); // no hang!
+ } catch (e) {
+ done(false);
+ }
+ }
+</script>
+</html>
diff --git a/dom/websocket/tests/file_websocket_basic_wsh.py b/dom/websocket/tests/file_websocket_basic_wsh.py
new file mode 100644
index 0000000000..050e7ccc10
--- /dev/null
+++ b/dom/websocket/tests/file_websocket_basic_wsh.py
@@ -0,0 +1,31 @@
+from mod_pywebsocket import msgutil
+
+
+def web_socket_do_extra_handshake(request):
+ # must set request.ws_protocol to the selected version from ws_requested_protocols
+ request.ws_protocol = request.ws_requested_protocols[0]
+
+ if request.ws_protocol == "error":
+ raise ValueError("Error")
+ pass
+
+
+def web_socket_transfer_data(request):
+ while True:
+ line = msgutil.receive_message(request)
+ if line == "protocol":
+ msgutil.send_message(request, request.ws_protocol)
+ continue
+
+ if line == "resource":
+ msgutil.send_message(request, request.ws_resource)
+ continue
+
+ if line == "origin":
+ msgutil.send_message(request, request.ws_origin)
+ continue
+
+ msgutil.send_message(request, line)
+
+ if line == "end":
+ return
diff --git a/dom/websocket/tests/file_websocket_bigBlob_wsh.py b/dom/websocket/tests/file_websocket_bigBlob_wsh.py
new file mode 100644
index 0000000000..5ccc85f3a0
--- /dev/null
+++ b/dom/websocket/tests/file_websocket_bigBlob_wsh.py
@@ -0,0 +1,11 @@
+from mod_pywebsocket import msgutil
+
+
+def web_socket_do_extra_handshake(request):
+ pass
+
+
+def web_socket_transfer_data(request):
+ while True:
+ line = msgutil.receive_message(request)
+ msgutil.send_message(request, line, True, True)
diff --git a/dom/websocket/tests/file_websocket_hello_wsh.py b/dom/websocket/tests/file_websocket_hello_wsh.py
new file mode 100644
index 0000000000..5711d2283c
--- /dev/null
+++ b/dom/websocket/tests/file_websocket_hello_wsh.py
@@ -0,0 +1,12 @@
+from mod_pywebsocket import msgutil
+
+
+def web_socket_do_extra_handshake(request):
+ pass
+
+
+def web_socket_transfer_data(request):
+ resp = "Test"
+ if msgutil.receive_message(request) == "data":
+ resp = "Hello world!"
+ msgutil.send_message(request, resp)
diff --git a/dom/websocket/tests/file_websocket_http_resource.txt b/dom/websocket/tests/file_websocket_http_resource.txt
new file mode 100644
index 0000000000..35dc67f08d
--- /dev/null
+++ b/dom/websocket/tests/file_websocket_http_resource.txt
@@ -0,0 +1 @@
+server data
diff --git a/dom/websocket/tests/file_websocket_permessage_deflate_disabled_wsh.py b/dom/websocket/tests/file_websocket_permessage_deflate_disabled_wsh.py
new file mode 100644
index 0000000000..5853f8acd7
--- /dev/null
+++ b/dom/websocket/tests/file_websocket_permessage_deflate_disabled_wsh.py
@@ -0,0 +1,18 @@
+from mod_pywebsocket import common, msgutil
+
+
+def web_socket_do_extra_handshake(request):
+ if request.ws_requested_extensions is not None:
+ for extension_request in request.ws_requested_extensions:
+ if extension_request.name() == "permessage-deflate":
+ raise ValueError("permessage-deflate should not be offered")
+
+
+def web_socket_transfer_data(request):
+ while True:
+ rcvd = msgutil.receive_message(request)
+ opcode = request.ws_stream.get_last_received_opcode()
+ if opcode == common.OPCODE_BINARY:
+ msgutil.send_message(request, rcvd, binary=True)
+ elif opcode == common.OPCODE_TEXT:
+ msgutil.send_message(request, rcvd)
diff --git a/dom/websocket/tests/file_websocket_permessage_deflate_params_wsh.py b/dom/websocket/tests/file_websocket_permessage_deflate_params_wsh.py
new file mode 100644
index 0000000000..e6ea12232f
--- /dev/null
+++ b/dom/websocket/tests/file_websocket_permessage_deflate_params_wsh.py
@@ -0,0 +1,24 @@
+from mod_pywebsocket import common, msgutil
+
+
+def web_socket_do_extra_handshake(request):
+ deflate_found = False
+
+ if request.ws_extension_processors is not None:
+ for extension_processor in request.ws_extension_processors:
+ if extension_processor.name() == "deflate":
+ extension_processor.set_client_no_context_takeover(True)
+ deflate_found = True
+
+ if deflate_found is False:
+ raise ValueError("deflate extension processor not found")
+
+
+def web_socket_transfer_data(request):
+ while True:
+ rcvd = msgutil.receive_message(request)
+ opcode = request.ws_stream.get_last_received_opcode()
+ if opcode == common.OPCODE_BINARY:
+ msgutil.send_message(request, rcvd, binary=True)
+ elif opcode == common.OPCODE_TEXT:
+ msgutil.send_message(request, rcvd)
diff --git a/dom/websocket/tests/file_websocket_permessage_deflate_rejected_wsh.py b/dom/websocket/tests/file_websocket_permessage_deflate_rejected_wsh.py
new file mode 100644
index 0000000000..b67627d67c
--- /dev/null
+++ b/dom/websocket/tests/file_websocket_permessage_deflate_rejected_wsh.py
@@ -0,0 +1,24 @@
+from mod_pywebsocket import common, msgutil
+
+
+def web_socket_do_extra_handshake(request):
+ deflate_removed = False
+
+ if request.ws_extension_processors is not None:
+ for extension_processor in request.ws_extension_processors:
+ if extension_processor.name() == "deflate":
+ request.ws_extension_processors.remove(extension_processor)
+ deflate_removed = True
+
+ if deflate_removed is False:
+ raise ValueError("deflate extension processor not found")
+
+
+def web_socket_transfer_data(request):
+ while True:
+ rcvd = msgutil.receive_message(request)
+ opcode = request.ws_stream.get_last_received_opcode()
+ if opcode == common.OPCODE_BINARY:
+ msgutil.send_message(request, rcvd, binary=True)
+ elif opcode == common.OPCODE_TEXT:
+ msgutil.send_message(request, rcvd)
diff --git a/dom/websocket/tests/file_websocket_permessage_deflate_wsh.py b/dom/websocket/tests/file_websocket_permessage_deflate_wsh.py
new file mode 100644
index 0000000000..c6436c8499
--- /dev/null
+++ b/dom/websocket/tests/file_websocket_permessage_deflate_wsh.py
@@ -0,0 +1,23 @@
+from mod_pywebsocket import common, msgutil
+
+
+def web_socket_do_extra_handshake(request):
+ pmce_offered = False
+
+ if request.ws_requested_extensions is not None:
+ for extension_request in request.ws_requested_extensions:
+ if extension_request.name() == "permessage-deflate":
+ pmce_offered = True
+
+ if pmce_offered is False:
+ raise ValueError("permessage-deflate not offered")
+
+
+def web_socket_transfer_data(request):
+ while True:
+ rcvd = msgutil.receive_message(request)
+ opcode = request.ws_stream.get_last_received_opcode()
+ if opcode == common.OPCODE_BINARY:
+ msgutil.send_message(request, rcvd, binary=True)
+ elif opcode == common.OPCODE_TEXT:
+ msgutil.send_message(request, rcvd)
diff --git a/dom/websocket/tests/file_websocket_wsh.py b/dom/websocket/tests/file_websocket_wsh.py
new file mode 100644
index 0000000000..77dbc3294c
--- /dev/null
+++ b/dom/websocket/tests/file_websocket_wsh.py
@@ -0,0 +1,171 @@
+import time
+
+import six
+from mod_pywebsocket import msgutil
+
+# see the list of tests in test_websocket.html
+
+
+def web_socket_do_extra_handshake(request):
+ # must set request.ws_protocol to the selected version from ws_requested_protocols
+ for x in request.ws_requested_protocols:
+ if x != "test-does-not-exist":
+ request.ws_protocol = x
+ break
+
+ if request.ws_protocol == "test-2.1":
+ time.sleep(3)
+ elif request.ws_protocol == "test-9":
+ time.sleep(3)
+ elif request.ws_protocol == "test-10":
+ time.sleep(3)
+ elif request.ws_protocol == "test-19":
+ raise ValueError("Aborting (test-19)")
+ elif request.ws_protocol == "test-20" or request.ws_protocol == "test-17":
+ time.sleep(3)
+ elif request.ws_protocol == "test-22":
+ # The timeout is 5 seconds
+ time.sleep(13)
+ elif request.ws_protocol == "test-41b":
+ request.sts = "max-age=100"
+ elif request.ws_protocol == "test-49":
+ # subprotocols are compared case-sensitively, so this should fail
+ request.ws_protocol = "teST-49"
+ else:
+ pass
+
+
+# Behave according to recommendation of RFC 6455, section # 5.5.1:
+# "When sending a Close frame in response, the endpoint typically echos the
+# status code it received."
+# - Without this, pywebsocket replies with 1000 to any close code.
+#
+# Note that this function is only called when the client initiates the close
+
+
+def web_socket_passive_closing_handshake(request):
+ if request.ws_close_code == 1005:
+ return None, None
+ return request.ws_close_code, request.ws_close_reason
+
+
+def web_socket_transfer_data(request):
+ if request.ws_protocol == "test-1" or request.ws_protocol == "test-4":
+ msgutil.send_message(request, "server data")
+ msgutil.close_connection(request)
+ elif request.ws_protocol == "test-2.1" or request.ws_protocol == "test-2.2":
+ msgutil.close_connection(request)
+ elif request.ws_protocol == "test-6":
+ resp = "wrong message"
+ if msgutil.receive_message(request) == "1":
+ resp = "2"
+ msgutil.send_message(request, six.ensure_text(resp))
+ resp = "wrong message"
+ if msgutil.receive_message(request) == "3":
+ resp = "4"
+ msgutil.send_message(request, six.ensure_text(resp))
+ resp = "wrong message"
+ if msgutil.receive_message(request) == "5":
+ resp = (
+ b"\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a".decode(
+ "utf-8"
+ )
+ )
+ msgutil.send_message(request, six.ensure_text(resp))
+ msgutil.close_connection(request)
+ elif request.ws_protocol == "test-7":
+ msgutil.send_message(request, "test-7 data")
+ elif request.ws_protocol == "test-10":
+ msgutil.close_connection(request)
+ elif request.ws_protocol == "test-11":
+ resp = "wrong message"
+ if msgutil.receive_message(request) == "client data":
+ resp = "server data"
+ msgutil.send_message(request, six.ensure_text(resp))
+ elif request.ws_protocol == "test-12":
+ msg = msgutil.receive_message(request)
+ if msg == "a\ufffdb":
+ # converted unpaired surrogate in UTF-16 to UTF-8 OK
+ msgutil.send_message(request, "SUCCESS")
+ else:
+ msgutil.send_message(
+ request,
+ "FAIL got '" + msg + "' instead of string with replacement char'",
+ )
+ elif request.ws_protocol == "test-13":
+ # first one binary message containing the byte 0x61 ('a')
+ request.connection.write(b"\xff\x01\x61")
+ # after a bad utf8 message
+ request.connection.write(b"\x01\x61\xff")
+ msgutil.close_connection(request)
+ elif request.ws_protocol == "test-14":
+ msgutil.close_connection(request)
+ msgutil.send_message(request, "server data")
+ elif request.ws_protocol == "test-15":
+ # DISABLED: close_connection hasn't supported 2nd 'abort' argument for a
+ # long time. Passing extra arg was causing exception, which conveniently
+ # caused abort :) but as of pywebsocket v606 raising an exception here no
+ # longer aborts, and there's no obvious way to close TCP connection w/o
+ # sending websocket CLOSE.
+ raise RuntimeError("test-15 should be disabled for now")
+ # msgutil.close_connection(request, True) # OBSOLETE 2nd arg
+ # return
+ elif request.ws_protocol == "test-17" or request.ws_protocol == "test-21":
+ time.sleep(2)
+ resp = "wrong message"
+ if msgutil.receive_message(request) == "client data":
+ resp = "server data"
+ msgutil.send_message(request, six.ensure_text(resp))
+ time.sleep(2)
+ msgutil.close_connection(request)
+ elif request.ws_protocol == "test-20":
+ msgutil.send_message(request, "server data")
+ msgutil.close_connection(request)
+ elif request.ws_protocol == "test-34":
+ request.ws_stream.close_connection(1001, "going away now")
+ elif request.ws_protocol == "test-35a":
+ while not request.client_terminated:
+ msgutil.receive_message(request)
+ global test35code
+ test35code = request.ws_close_code
+ global test35reason
+ test35reason = request.ws_close_reason
+ elif request.ws_protocol == "test-35b":
+ request.ws_stream.close_connection(test35code + 1, test35reason)
+ elif request.ws_protocol == "test-37b":
+ while not request.client_terminated:
+ msgutil.receive_message(request)
+ global test37code
+ test37code = request.ws_close_code
+ global test37reason
+ test37reason = request.ws_close_reason
+ elif request.ws_protocol == "test-37c":
+ request.ws_stream.close_connection(test37code, test37reason)
+ elif request.ws_protocol == "test-42":
+ # Echo back 3 messages
+ msgutil.send_message(request, msgutil.receive_message(request))
+ msgutil.send_message(request, msgutil.receive_message(request))
+ msgutil.send_message(request, msgutil.receive_message(request))
+ elif request.ws_protocol == "test-44":
+ rcv = six.ensure_text(msgutil.receive_message(request))
+ # check we received correct binary msg
+ if len(rcv) == 3 and ord(rcv[0]) == 5 and ord(rcv[1]) == 0 and ord(rcv[2]) == 7:
+ # reply with binary msg 0x04
+ msgutil.send_message(request, b"\x00\x04", True, True)
+ else:
+ msgutil.send_message(request, "incorrect binary msg received!")
+ elif request.ws_protocol == "test-45":
+ rcv = msgutil.receive_message(request)
+ # check we received correct binary msg
+ if six.ensure_text(rcv) == "flob":
+ # send back same blob as binary msg
+ msgutil.send_message(request, rcv, True, True)
+ else:
+ msgutil.send_message(
+ request, "incorrect binary msg received: '" + rcv + "'"
+ )
+ elif request.ws_protocol == "test-46":
+ msgutil.send_message(request, "client must drop this if close was called")
+
+ while not request.client_terminated:
+ msgutil.receive_message(request)
diff --git a/dom/websocket/tests/frame_bug1384658.html b/dom/websocket/tests/frame_bug1384658.html
new file mode 100644
index 0000000000..c13cb17f3a
--- /dev/null
+++ b/dom/websocket/tests/frame_bug1384658.html
@@ -0,0 +1,13 @@
+<html>
+<body>
+ <form action="file_bug1384658.html" method="GET" id="form">
+ <input type='submit' name='y'>
+ <input type='hidden' name='x'>
+ </form>
+ <script>
+onload = function() {
+ document.getElementById("form").submit();
+};
+ </script>
+</body>
+</html>
diff --git a/dom/websocket/tests/iframe_websocket_sandbox.html b/dom/websocket/tests/iframe_websocket_sandbox.html
new file mode 100644
index 0000000000..0e6d1d97bf
--- /dev/null
+++ b/dom/websocket/tests/iframe_websocket_sandbox.html
@@ -0,0 +1,65 @@
+<html><body>
+<iframe id="frame" sandbox="allow-scripts allow-popups"></iframe>
+<script type="application/javascript">
+onmessage = function(e) {
+ parent.postMessage(e.data, '*');
+}
+
+var ifr = document.getElementById('frame');
+
+if (location.search == '?nested') {
+ var url = new URL(location);
+ url.search = "";
+ ifr.src = url.href;
+} else if (location.search == '?popup') {
+ var url = new URL(location);
+ url.search = "?opener";
+
+ ifr.srcdoc = "<html><script>" +
+ "window.open('" + url.href + "', 'foobar');" +
+ "onmessage = function(e) { " +
+ " parent.postMessage(e.data, '*'); " +
+ "}" +
+ "</scr" + "ipt></html>";
+} else if (location.search == '?opener') {
+ try{
+ var socket = new WebSocket('ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_basic');
+ socket.onerror = function(e) {
+ opener.postMessage('WS onerror', '*');
+ close();
+ };
+ socket.onopen = function(event) {
+ opener.postMessage('WS onopen', '*');
+ close();
+ };
+ } catch(e) {
+ if (e.name == 'SecurityError') {
+ opener.postMessage('WS Throws!', '*');
+ } else {
+ opener.postMessage('WS Throws something else!', '*');
+ }
+ close();
+ }
+} else {
+ ifr.srcdoc = `
+ <html><script>
+ try{
+ var socket = new WebSocket('ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_basic');
+ socket.onerror = function(e) {
+ parent.postMessage('WS onerror', '*');
+ };
+ socket.onopen = function(event) {
+ parent.postMessage('WS onopen', '*');
+ };
+ } catch(e) {
+ if (e.name == 'SecurityError') {
+ parent.postMessage('WS Throws!', '*');
+ } else {
+ parent.postMessage('WS Throws something else!', '*');
+ }
+ }
+ </scr`+`ipt>
+ </html>`;
+}
+</script>
+</body></html>
diff --git a/dom/websocket/tests/iframe_websocket_wss.html b/dom/websocket/tests/iframe_websocket_wss.html
new file mode 100644
index 0000000000..817b386624
--- /dev/null
+++ b/dom/websocket/tests/iframe_websocket_wss.html
@@ -0,0 +1,35 @@
+<html><body>
+Creating WebSocket
+<script type="application/javascript">
+onmessage = function(e) {
+ parent.postMessage(e.data, '*');
+}
+
+try{
+ let socket;
+ if (location.search == '?insecure') {
+ socket = new WebSocket('ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello');
+ }
+ else {
+ socket = new WebSocket('wss://example.com/tests/dom/websocket/tests/file_websocket_hello');
+ }
+ socket.onerror = function(e) {
+ parent.postMessage('WS onerror', '*');
+ close();
+ };
+ socket.onopen = function(e) {
+ socket.close();
+ parent.postMessage('WS onopen', '*');
+ close();
+ };
+} catch(e) {
+ if (e.name == 'SecurityError') {
+ parent.postMessage('SecurityError', '*');
+ } else {
+ parent.postMessage('WS Throws something else!', '*');
+ }
+ close();
+}
+
+</script>
+</body></html>
diff --git a/dom/websocket/tests/iframe_webworker_wss.html b/dom/websocket/tests/iframe_webworker_wss.html
new file mode 100644
index 0000000000..a4fb966b7d
--- /dev/null
+++ b/dom/websocket/tests/iframe_webworker_wss.html
@@ -0,0 +1,22 @@
+<html><body>
+Creating WebSocket
+<script type="application/javascript">
+onmessage = function(e) {
+ parent.postMessage(e.data, '*');
+}
+
+try{
+ let worker = new Worker("data:text/javascript,new WebSocket('ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello')");
+ worker.onerror = (e) => {
+ parent.postMessage(e.message, '*');
+ close();
+ };
+ worker.onmessage = (e) => {
+ parent.postMessage(e.message, '*');
+ close();
+ };
+ // catch the security error thrown so it doesn't surface as a duplicate test failure
+} catch(e) {}
+
+</script>
+</body></html>
diff --git a/dom/websocket/tests/mochitest.toml b/dom/websocket/tests/mochitest.toml
new file mode 100644
index 0000000000..3d879abb55
--- /dev/null
+++ b/dom/websocket/tests/mochitest.toml
@@ -0,0 +1,124 @@
+[DEFAULT]
+skip-if = [
+ "http3",
+ "http2",
+]
+support-files = [
+ "!/dom/events/test/event_leak_utils.js",
+ "file_websocket_basic_wsh.py",
+ "file_websocket_hello_wsh.py",
+ "file_websocket_http_resource.txt",
+ "file_websocket_permessage_deflate_wsh.py",
+ "file_websocket_permessage_deflate_disabled_wsh.py",
+ "file_websocket_permessage_deflate_rejected_wsh.py",
+ "file_websocket_permessage_deflate_params_wsh.py",
+ "file_websocket_wsh.py",
+ "websocket_helpers.js",
+ "websocket_tests.js",
+ "websocket_worker_helpers.js",
+]
+
+["test_bug1081686.html"]
+
+["test_bug1384658.html"]
+support-files = [
+ "window_bug1384658.html",
+ "frame_bug1384658.html",
+ "file_bug1384658.html",
+]
+
+["test_event_listener_leaks.html"]
+support-files = ["file_websocket_bigBlob_wsh.py"]
+
+["test_websocket1.html"]
+
+["test_websocket2.html"]
+
+["test_websocket3.html"]
+
+["test_websocket4.html"]
+skip-if = [
+ "os == 'android'", # ssltunnel can't handle WSS scheme
+]
+
+["test_websocket5.html"]
+skip-if = [
+ "os == 'android'", # ssltunnel can't handle WSS scheme
+]
+
+["test_websocket_basic.html"]
+
+["test_websocket_bigBlob.html"]
+support-files = ["file_websocket_bigBlob_wsh.py"]
+
+["test_websocket_hello.html"]
+
+["test_websocket_longString.html"]
+
+["test_websocket_mixed_content.html"]
+scheme = "https"
+support-files = [
+ "iframe_websocket_wss.html",
+ "iframe_webworker_wss.html",
+]
+skip-if = [
+ "os == 'android'", # ssltunnel can't handle WSS scheme
+]
+
+["test_websocket_mixed_content_blob.html"]
+scheme = "https"
+support-files = ["window_websocket_wss.html"]
+skip-if = [
+ "os == 'android'", # ssltunnel can't handle WSS scheme
+]
+
+["test_websocket_mixed_content_opener.html"]
+scheme = "https"
+skip-if = [
+ "os == 'android'", # ssltunnel can't handle WSS scheme
+]
+
+["test_websocket_no_duplicate_packet.html"]
+scheme = "https"
+skip-if = [
+ "os == 'android'", # ssltunnel can't handle WSS scheme
+]
+
+["test_websocket_permessage_deflate.html"]
+
+["test_websocket_sandbox.html"]
+support-files = ["iframe_websocket_sandbox.html"]
+
+["test_websocket_sharedWorker.html"]
+support-files = ["websocket_sharedWorker.js"]
+
+["test_worker_websocket1.html"]
+support-files = ["websocket_worker1.js"]
+
+["test_worker_websocket2.html"]
+support-files = ["websocket_worker2.js"]
+skip-if = ["socketprocess_networking"] # bug 1787044
+
+["test_worker_websocket3.html"]
+support-files = ["websocket_worker3.js"]
+
+["test_worker_websocket4.html"]
+support-files = ["websocket_worker4.js"]
+skip-if = [
+ "os == 'android'", # ssltunnel can't handle WSS scheme
+]
+
+["test_worker_websocket5.html"]
+support-files = ["websocket_worker5.js"]
+
+["test_worker_websocket_basic.html"]
+support-files = ["websocket_basic_worker.js"]
+
+["test_worker_websocket_https.html"]
+support-files = [
+ "websocket_worker_https.html",
+ "websocket_https_worker.js",
+]
+
+["test_worker_websocket_loadgroup.html"]
+support-files = ["websocket_loadgroup_worker.js"]
diff --git a/dom/websocket/tests/mochitest_http2.toml b/dom/websocket/tests/mochitest_http2.toml
new file mode 100644
index 0000000000..952276ff9d
--- /dev/null
+++ b/dom/websocket/tests/mochitest_http2.toml
@@ -0,0 +1,6 @@
+[DEFAULT]
+run-if = ["http2"]
+prefs = ["network.http.http2.websockets=true"]
+
+["test_websocket_http2.html"]
+scheme = "https"
diff --git a/dom/websocket/tests/test_bug1081686.html b/dom/websocket/tests/test_bug1081686.html
new file mode 100644
index 0000000000..debcd97184
--- /dev/null
+++ b/dom/websocket/tests/test_bug1081686.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>bug 1081686</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="testWebSocket()">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var ws;
+
+function forcegc()
+{
+ SpecialPowers.forceGC();
+ SpecialPowers.gc();
+ setTimeout(function()
+ {
+ SpecialPowers.gc();
+ }, 0);
+}
+
+function testWebSocket () {
+ ws = new WebSocket("ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello");
+ ws.onopen = function(e) {
+ ws.send("data");
+ }
+ ws.onclose = function(e) {
+ forcegc();
+ setTimeout(function() {
+ is(ws.readyState, 3, 'WebSocket is closed');
+ is(ws.bufferedAmount, 0, 'WebSocket.bufferedAmount should be empty.');
+ is(ws.binaryType, 'blob', 'WebSocket.binaryType is blob');
+ ws.binaryType = 'arraybuffer';
+ is(ws.binaryType, 'arraybuffer', 'WebSocket.binaryType is arraybuffer');
+ is(ws.url, 'ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello', 'WebSocket.url is correct');
+ ws.close();
+ ws.send('foobar');
+ SimpleTest.finish();
+ }, 1000);
+ }
+
+ ws.onerror = function(e) {
+ ok(false, "onerror called!");
+ SimpleTest.finish();
+ }
+ ws.onmessage = function(e) {
+ is(e.data, "Hello world!", "Wrong data");
+ ws.close();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+
+</script>
+</pre>
+<div>
+
+
+</div>
+
+
+</body>
+</html>
diff --git a/dom/websocket/tests/test_bug1384658.html b/dom/websocket/tests/test_bug1384658.html
new file mode 100644
index 0000000000..dd90a0d5d3
--- /dev/null
+++ b/dom/websocket/tests/test_bug1384658.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1384658
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1384658</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1384658 **/
+
+function test_frameset() {
+ var bc = new BroadcastChannel("test_channel");
+ bc.postMessage("go");
+ bc.onmessage = ev => {
+ ok(ev.data.success, "We didn't hang");
+ bc.close();
+ test_window();
+ };
+}
+
+function test_window() {
+ var win = window.open("http://example.com/tests/dom/websocket/tests/window_bug1384658.html",
+ "_blank", "width=100,height=100");
+ var bc = new BroadcastChannel("test_channel");
+ bc.onmessage = ev => {
+ ok(ev.data.success, "We didn't hang");
+ bc.close();
+ win.close();
+ SimpleTest.finish();
+ };
+}
+
+SimpleTest.waitForExplicitFinish();
+// Use nsICookieService.BEHAVIOR_REJECT_TRACKER to not partition BroadcastChannel
+// by extra first-party domain information.
+SpecialPowers.pushPrefEnv({
+ set: [
+ ["network.cookie.cookieBehavior", 4],
+ // disable third-party storage isolation so the test works as expected
+ ["privacy.partition.always_partition_third_party_non_cookie_storage", false],
+ ["dom.security.https_first", false]
+ ],
+}, test_frameset);
+
+ </script>
+</head>
+<frameset id="frame_set" cols="25%,75%" frameborder="yes" border="5" bordercolor="#008800">
+ <frame id="test_frame" name="test_frame" src="frame_bug1384658.html" marginwidth="20" marginheight="20">
+</frameset>
+</html>
diff --git a/dom/websocket/tests/test_event_listener_leaks.html b/dom/websocket/tests/test_event_listener_leaks.html
new file mode 100644
index 0000000000..9a79fa1354
--- /dev/null
+++ b/dom/websocket/tests/test_event_listener_leaks.html
@@ -0,0 +1,57 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1450358 - Test WebSocket event listener leak conditions</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/dom/events/test/event_leak_utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+// Manipulate WebSocket objects in the frame's context.
+// Its important here that we create a listener callback from
+// the DOM objects back to the frame's global in order to
+// exercise the leak condition.
+async function useWebSocket(contentWindow) {
+ const url = "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_bigBlob";
+ let ws = new contentWindow.WebSocket(url);
+
+ ws.onmessage = _ => {
+ contentWindow.messageCount += 1;
+ };
+
+ contentWindow.openCount = 0;
+ await new Promise((resolve, reject) => {
+ ws.onopen = _ => {
+ contentWindow.openCount += 1;
+ resolve();
+ };
+ ws.onerror = e => {
+ contentWindow.errorCount += 1;
+ reject("websocket error");
+ };
+ });
+
+ is(contentWindow.openCount, 1, "open should be received");
+}
+
+async function runTest() {
+ try {
+ await checkForEventListenerLeaks("WebSocket", useWebSocket);
+ } catch (e) {
+ ok(false, e);
+ } finally {
+ SimpleTest.finish();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+addEventListener("load", runTest, { once: true });
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket1.html b/dom/websocket/tests/test_websocket1.html
new file mode 100644
index 0000000000..1844a67f58
--- /dev/null
+++ b/dom/websocket/tests/test_websocket1.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <script type="text/javascript" src="websocket_tests.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="testWebSocket()">
+<script class="testbody" type="text/javascript">
+
+var tests = [
+ test1, // client tries to connect to a http scheme location;
+ test2, // assure serialization of the connections;
+ test3, // client tries to connect to an non-existent ws server;
+ test4, // client tries to connect using a relative url;
+ test5, // client uses an invalid protocol value;
+ test6, // counter and encoding check;
+ test7, // onmessage event origin property check
+ test8, // client calls close() and the server sends the close frame (with no
+ // code or reason) in acknowledgement;
+ test9, // client closes the connection before the ws connection is established;
+ test10, // client sends a message before the ws connection is established;
+];
+
+function testWebSocket() {
+ doTest();
+}
+
+SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
+ "Expect all sorts of flakiness in this test...");
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+<div id="feedback">
+</div>
+
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket2.html b/dom/websocket/tests/test_websocket2.html
new file mode 100644
index 0000000000..afbbaba62f
--- /dev/null
+++ b/dom/websocket/tests/test_websocket2.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <script type="text/javascript" src="websocket_tests.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="testWebSocket()">
+<script class="testbody" type="text/javascript">
+
+var tests = [
+ test11, // a simple hello echo;
+ test12, // client sends a message containing unpaired surrogates
+ test13, //server sends an invalid message;
+ test14, // server sends the close frame, it doesn't close the tcp connection
+ // and it keeps sending normal ws messages;
+ test15, // server closes the tcp connection, but it doesn't send the close
+ // frame;
+ test16, // client calls close() and tries to send a message;
+ test17, // see bug 572975 - all event listeners set
+ test18, // client tries to connect to an http resource;
+ test19, // server closes the tcp connection before establishing the ws
+ // connection;
+ test20, // see bug 572975 - only on error and onclose event listeners set
+];
+
+function testWebSocket() {
+ doTest();
+}
+
+SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
+ "Expect all sorts of flakiness in this test...");
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+<div id="feedback">
+</div>
+
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket3.html b/dom/websocket/tests/test_websocket3.html
new file mode 100644
index 0000000000..cc2e091fda
--- /dev/null
+++ b/dom/websocket/tests/test_websocket3.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <script type="text/javascript" src="websocket_tests.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="testWebSocket()">
+<script class="testbody" type="text/javascript">
+
+var tests = [
+ test21, // see bug 572975 - same as test 17, but delete strong event listeners
+ // when receiving the message event;
+ test22, // server takes too long to establish the ws connection;
+ test23, // should detect WebSocket on window object;
+ test24, // server rejects sub-protocol string
+ test25, // ctor with valid empty sub-protocol array
+ test26, // ctor with invalid sub-protocol array containing 1 empty element
+ test27, // ctor with invalid sub-protocol array containing an empty element in
+ // list
+ test28, // ctor using valid 1 element sub-protocol array
+ test29, // ctor using all valid 5 element sub-protocol array
+ test30, // ctor using valid 1 element sub-protocol array with element server
+ // will reject
+];
+
+function testWebSocket() {
+ doTest();
+}
+
+SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
+ "Expect all sorts of flakiness in this test...");
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+<div id="feedback">
+</div>
+
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket4.html b/dom/websocket/tests/test_websocket4.html
new file mode 100644
index 0000000000..186a434ab3
--- /dev/null
+++ b/dom/websocket/tests/test_websocket4.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <script type="text/javascript" src="websocket_tests.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="testWebSocket()">
+<script class="testbody" type="text/javascript">
+
+var tests = [
+ test31, // ctor using valid 2 element sub-protocol array with 1 element server
+ // will reject and one server will accept
+ test32, // ctor using invalid sub-protocol array that contains duplicate items
+ test33, // test for sending/receiving custom close code (but no close reason)
+ test34, // test for receiving custom close code and reason
+ test35, // test for sending custom close code and reason
+ test36, // negative test for sending out of range close code
+ test37, // negative test for too long of a close reason
+ test38, // ensure extensions attribute is defined
+ test39, // a basic wss:// connectivity test
+ test40, // negative test for wss:// with no cert
+];
+
+function testWebSocket() {
+ doTest();
+}
+
+SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
+ "Expect all sorts of flakiness in this test...");
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+<div id="feedback">
+</div>
+
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket5.html b/dom/websocket/tests/test_websocket5.html
new file mode 100644
index 0000000000..d86752ed5a
--- /dev/null
+++ b/dom/websocket/tests/test_websocket5.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <script type="text/javascript" src="websocket_tests.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="testWebSocket()">
+<script class="testbody" type="text/javascript">
+
+var tests = [
+ test41, // HSTS
+ test42, // non-char utf-8 sequences
+ test43, // Test setting binaryType attribute
+ test44, // Test sending/receving binary ArrayBuffer
+ test45, // Test sending/receving binary Blob
+ test46, // Test that we don't dispatch incoming msgs once in CLOSING state
+ test47, // Make sure onerror/onclose aren't called during close()
+ test48, // see bug 1227136 - client calls close() from onopen() and waits
+ // until WebSocketChannel::mSocketIn is nulled out on socket thread
+ test49, // Test that we fail if subprotocol returned from server doesn't match
+];
+
+function testWebSocket() {
+ doTest();
+}
+
+SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
+ "Expect all sorts of flakiness in this test...");
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+<div id="feedback">
+</div>
+
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_basic.html b/dom/websocket/tests/test_websocket_basic.html
new file mode 100644
index 0000000000..2ae2e690ac
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_basic.html
@@ -0,0 +1,289 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Basic WebSocket test</title>
+ <script 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 472529</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+const kUrl = "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_basic";
+
+var gTestElement;
+var ws;
+
+function forcegc() {
+ SpecialPowers.forceGC();
+ SpecialPowers.gc();
+}
+
+function testWebSocket() {
+ gTestElement = document.getElementById("test");
+
+ SimpleTest.executeSoon(testWebSocket1);
+}
+
+/**
+ * Sends message keywords, then receives their values.
+ */
+function testWebSocket1() {
+ gTestElement.textContent = "Running testWebSocket1()";
+
+ var results = ["test",
+ "/tests/dom/websocket/tests/file_websocket_basic",
+ "http://mochi.test:8888",
+ "end"];
+
+ ws = new WebSocket(kUrl, "test");
+ is(ws.url, kUrl, "[1] WebSocket.url");
+ ws.onopen = function(e) {
+ const params = ["protocol", "resource", "origin", "end"];
+
+ gTestElement.textContent += "\nSending :";
+ for (var i = 0; i < params.length; ++i) {
+ gTestElement.textContent += " " + params[i];
+ ws.send(params[i]);
+ }
+
+ // Set this before onmessage() is called, so it is displayed once only.
+ gTestElement.textContent += "\nReceived:";
+ };
+ ws.onclose = function(e) {
+ is(results.length, 0, "[1] Number of unreceived messages");
+ ok(e.wasClean, "[1] Connection closed cleanly");
+
+ SimpleTest.executeSoon(testWebSocket2);
+ };
+ ws.onerror = function(e) {
+ ok(false, "[1] onerror() should not have been called!");
+ gTestElement.textContent += "\nonerror() should not have been called!";
+ SimpleTest.executeSoon(SimpleTest.finish);
+ };
+ ws.onmessage = function(e) {
+ is(e.data, results[0], "[1] Received message");
+ gTestElement.textContent += " " + e.data;
+ results.shift();
+ };
+}
+
+/**
+ * Sends 1000+1 test messages, then receives them.
+ */
+function testWebSocket2() {
+ gTestElement.textContent = "Running testWebSocket2()";
+
+ const displayInterval = 100;
+ const testCount = 1000;
+ const testMessage = "test message 2.";
+
+ var messageCount = 0;
+
+ ws = new WebSocket(kUrl, "test");
+ ws.onopen = function(e) {
+ gTestElement.textContent += "\nSending :";
+ for (var i = 1; i <= testCount; ++i) {
+ if (i % displayInterval == 1) {
+ gTestElement.textContent += " " + i;
+ }
+ ws.send(testMessage + i);
+ }
+ gTestElement.textContent += " end";
+ ws.send("end");
+
+ // Set this before onmessage() is called, so it is displayed once only.
+ gTestElement.textContent += "\nReceived:";
+ };
+ ws.onclose = function(e) {
+ is(messageCount, testCount + 1, "[2] Number of received messages");
+ ok(e.wasClean, "[2] Connection closed cleanly");
+
+ SimpleTest.executeSoon(testWebSocket3);
+ };
+ ws.onerror = function(e) {
+ ok(false, "[2] onerror() should not have been called!");
+ gTestElement.textContent += "\nonerror() should not have been called!";
+ SimpleTest.executeSoon(SimpleTest.finish);
+ };
+ ws.onmessage = function(e) {
+ ++messageCount;
+ if (messageCount > testCount)
+ is(e.data, "end", "[2] Received message");
+ else
+ is(e.data, testMessage + messageCount, "[2] Received message");
+ if (messageCount % displayInterval == 1) {
+ gTestElement.textContent += " " + messageCount;
+ }
+ };
+}
+
+/**
+ * Sends testcount+1 test messages, then receives them, calling forcegc() at each step.
+ */
+function testWebSocket3() {
+ gTestElement.textContent = "Running testWebSocket3() [can take a little while]";
+
+ const displayInterval = 10;
+ const testCount = 10;
+ const testMessage = "test message 3.";
+
+ var messageCount = 0;
+
+ ws = new WebSocket(kUrl, "test");
+ // Set this before onopen() is called,
+ // otherwise its display would be delayed by forcegc() calls...
+ gTestElement.textContent += "\nSending :";
+ ws.onopen = function(e) {
+ for (var i = 1; i <= testCount; ++i) {
+ forcegc();
+ if (i % displayInterval == 1) {
+ // Actual display is delayed by forcegc() calls...
+ gTestElement.textContent += " " + i;
+ }
+ ws.send(testMessage + i);
+ }
+ forcegc();
+ gTestElement.textContent += " end";
+ ws.send("end");
+
+ // Set this before onmessage() is called, so it is displayed once only.
+ gTestElement.textContent += "\nReceived:";
+ };
+ ws.onclose = function(e) {
+ is(messageCount, testCount + 1, "[3] Number of received messages");
+ ok(e.wasClean, "[3] Connection closed cleanly");
+
+ SimpleTest.executeSoon(testWebSocket4);
+ };
+ ws.onerror = function(e) {
+ ok(false, "[3] onerror() should not have been called!");
+ gTestElement.textContent += "\nonerror() should not have been called!";
+ SimpleTest.executeSoon(SimpleTest.finish);
+ };
+ ws.onmessage = function(e) {
+ forcegc();
+ ++messageCount;
+ if (messageCount > testCount)
+ is(e.data, "end", "[3] Received message");
+ else
+ is(e.data, testMessage + messageCount, "[3] Received message");
+ if (messageCount % displayInterval == 1) {
+ // Actual display is delayed by forcegc() call(s)...
+ gTestElement.textContent += " " + messageCount;
+ }
+ };
+}
+
+/**
+ * Sends a huge test message, then receives it, then closes the WebSocket from client-side.
+ */
+function testWebSocket4() {
+ gTestElement.textContent = "Running testWebSocket4()";
+
+ // String length = 13 + ((10,000 - 1) * 26) + 11 = 259,998 = almost 254 KiB.
+ const longString = "messageStart " + new Array(10000).join(" -huge WebSocket message- ") + " messageEnd";
+
+ ws = new WebSocket(kUrl, "test");
+ ws.onopen = function(e) {
+ is(this, ws, "[4, onopen()] 'this' should point to the WebSocket.");
+ gTestElement.textContent += "\nSending the huge message";
+ ws.send(longString);
+ };
+ ws.onclose = function(e) {
+ is(this, ws, "[4, onclose()] 'this' should point to the WebSocket.");
+ ok(e.wasClean, "[4] Connection closed cleanly");
+
+ SimpleTest.executeSoon(testWebSocket5);
+ };
+ ws.onerror = function(e) {
+ is(this, ws, "[4, onerror()] 'this' should point to the WebSocket.");
+ ok(false, "[4, onerror()] should not have been called!");
+ gTestElement.textContent += "\nonerror() should not have been called!";
+ SimpleTest.executeSoon(SimpleTest.finish);
+ };
+ ws.onmessage = function(e) {
+ is(this, ws, "[4, onmessage()] 'this' should point to the WebSocket.");
+ // Do not use |is(e.data, longString, "...");| that results in a _very_ long line.
+ is(e.data.length, longString.length, "[4] Length of received message");
+ ok(e.data == longString, "[4] Content of received message");
+ gTestElement.textContent += "\nReceived the huge message";
+ this.close();
+ };
+}
+
+/**
+ * Closes the WebSocket from client-side, then sends a test message that should be buffered.
+ */
+function testWebSocket5() {
+ gTestElement.textContent = "Running testWebSocket5()";
+
+ ws = new WebSocket(kUrl, "test");
+ ws.onopen = function(e) {
+ is(this.bufferedAmount, 0, "[5] Length of empty buffer before closing");
+ this.close();
+ };
+ ws.onclose = function(e) {
+ ok(e.wasClean, "[5] Connection closed cleanly");
+ is(this.bufferedAmount, 0, "[5] Length of empty buffer after closing");
+
+ var msg = "test message to be buffered";
+ this.send(msg);
+ is(this.bufferedAmount, msg.length, "[5] Length of buffered message sent after closing");
+
+ gTestElement.textContent += "\ntestWebSocket5() completed";
+
+ SimpleTest.executeSoon(testWebSocket6);
+ };
+ ws.onerror = function(e) {
+ ok(false, "[5] onerror() should not have been called!");
+ gTestElement.textContent += "\nonerror() should not have been called!";
+ SimpleTest.executeSoon(SimpleTest.finish);
+ };
+}
+
+function testWebSocket6() {
+ gTestElement.textContent = "Running testWebSocket6()";
+
+ var msgReceived = false;
+ ws = new WebSocket(kUrl, "test");
+ ws.onopen = function(e) {
+ gTestElement.textContent += "\nSending ©";
+ ws.send("©");
+ gTestElement.textContent += " end";
+ ws.send("end");
+ };
+ ws.onclose = function(e) {
+ ok(msgReceived, "[6] Number of received messages");
+ ok(e.wasClean, "[6] Connection closed cleanly");
+
+ SimpleTest.executeSoon(SimpleTest.finish);
+ };
+ ws.onerror = function(e) {
+ ok(false, "[6] onerror() should not have been called!");
+ gTestElement.textContent += "\nonerror() should not have been called!";
+ SimpleTest.executeSoon(SimpleTest.finish);
+ };
+
+ ws.onmessage = function(e) {
+ if (msgReceived) {
+ is(e.data, "end", "[6] Received message");
+ } else {
+ gTestElement.textContent += "\nReceived: " + e.data;
+ is(e.data, "©", "[6] Received message");
+ msgReceived = true;
+ }
+ };
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_bigBlob.html b/dom/websocket/tests/test_websocket_bigBlob.html
new file mode 100644
index 0000000000..9db01d6a7f
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_bigBlob.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket test - big blob on content side</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+var ws = CreateTestWS("ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_bigBlob");
+is(ws.readyState, 0, "Initial readyState is 0");
+ws.binaryType = "blob";
+
+ws.onopen = function() {
+ is(ws.readyState, 1, "Open readyState is 1");
+ ws.send(new Blob([new Array(1024*1024).join('123456789ABCDEF')]));
+}
+
+let receivedBlob;
+ws.onmessage = function(e) {
+ ok(e.data instanceof Blob, "We should be receiving a Blob");
+ receivedBlob = e.data;
+ ws.close();
+}
+
+ws.onclose = function(e) {
+ is(ws.readyState, 3, "Close readyState is 3");
+
+ // check blob contents
+ var reader = new FileReader();
+ reader.onload = function(event) {
+ is(reader.result, new Array(1024*1024).join('123456789ABCDEF'), "All data matches");
+ }
+
+ reader.onerror = function(event) {
+ ok(false, "Something bad happen.");
+ }
+
+ reader.onloadend = function(event) {
+ SimpleTest.finish();
+ }
+
+ reader.readAsBinaryString(receivedBlob);
+}
+
+SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
+ "Expect all sorts of flakiness in this test...");
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_frame.html b/dom/websocket/tests/test_websocket_frame.html
new file mode 100644
index 0000000000..6c95419bc2
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_frame.html
@@ -0,0 +1,161 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Basic websocket frame interception test</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+const URI = "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_basic";
+
+var frameReceivedCounter = 0;
+var frameSentCounter = 0;
+var webSocketCreatedCounter = 0;
+var webSocketOpenedCounter = 0;
+var webSocketMessageAvailableCounter = 0;
+var webSocketClosedCounter = 0;
+
+var tests = [
+ { payload: "Hello world!" },
+ { payload: (function() { var buffer = ""; for (var i = 0; i < 120; ++i) buffer += i; return buffer; }()) },
+]
+
+var innerId = window.windowGlobalChild.innerWindowId;
+ok(innerId, "We have a valid innerWindowID: " + innerId);
+
+var service = Cc["@mozilla.org/websocketevent/service;1"]
+ .getService(Ci.nsIWebSocketEventService);
+ok(!!service, "We have the nsIWebSocketEventService");
+
+var listener = {
+ QueryInterface: ChromeUtils.generateQI(["nsIWebSocketEventListener"]),
+
+ webSocketCreated(aWebSocketSerialID, aURI, aProtocols) {
+ info("WebSocketCreated");
+
+ is(aURI, URI, "URI matches");
+ is(aProtocols, "frame", "Protocol matches");
+
+ webSocketCreatedCounter++;
+ },
+
+ webSocketOpened(aWebSocketSerialID, aEffectiveURI, aProtocols, aExtensions, httpChannelId) {
+ info("WebSocketOpened");
+
+ is(aEffectiveURI, URI, "EffectiveURI matches");
+ is(aProtocols, "frame", "Protocol matches");
+ is(aExtensions, "permessage-deflate", "No extensions");
+ ok(httpChannelId > 0, "Channel ID received");
+
+ webSocketOpenedCounter++;
+ },
+
+ webSocketMessageAvailable(aWebSocketSerialID, aData, aMessageType) {
+ info("WebSocketMessageAvailable");
+
+ if (tests.length) {
+ is(aData, tests[0].payload, "Message matches!");
+ is(aMessageType, Ci.nsIWebSocketEventListener.TYPE_STRING, "The type is 'string'");
+
+ webSocketMessageAvailableCounter++;
+
+ tests.shift();
+ if (tests.length) {
+ ws.send(tests[0].payload);
+ } else {
+ ws.send("end");
+ }
+ }
+ },
+
+ webSocketClosed(aWebSocketSerialID, aWasClean,
+ aCode, aReason) {
+ info("WebSocketClosed");
+
+ ok(aWasClean, "The socket is closed in a clean state");
+ is(aCode, 1000, "Exit code 1000");
+ ok(!aReason.length, "No reason");
+
+ webSocketClosedCounter++;
+ checkListener();
+ },
+
+ frameReceived(aWebSocketSerialID, aFrame) {
+ ok(!!aFrame, "We have received a frame");
+
+ if (tests.length) {
+ ok(aFrame.timeStamp, "Checking timeStamp: " + aFrame.timeStamp);
+ is(aFrame.finBit, true, "Checking finBit");
+ is(aFrame.rsvBit1, true, "Checking rsvBit1");
+ is(aFrame.rsvBit2, false, "Checking rsvBit2");
+ is(aFrame.rsvBit3, false, "Checking rsvBit3");
+ is(aFrame.opCode, aFrame.OPCODE_TEXT, "Checking opCode");
+ is(aFrame.maskBit, false, "Checking maskBit");
+ is(aFrame.mask, 0, "Checking mask");
+ is(aFrame.payload, tests[0].payload, "Checking payload: " + aFrame.payload);
+ }
+
+ frameReceivedCounter++;
+ },
+
+ frameSent(aWebSocketSerialID, aFrame) {
+ ok(!!aFrame, "We have sent a frame");
+
+ if (tests.length) {
+ ok(aFrame.timeStamp, "Checking timeStamp: " + aFrame.timeStamp);
+ is(aFrame.finBit, true, "Checking finBit");
+ is(aFrame.rsvBit1, true, "Checking rsvBit1");
+ is(aFrame.rsvBit2, false, "Checking rsvBit2");
+ is(aFrame.rsvBit3, false, "Checking rsvBit3");
+ is(aFrame.opCode, aFrame.OPCODE_TEXT, "Checking opCode");
+ is(aFrame.maskBit, true, "Checking maskBit");
+ ok(!!aFrame.mask, "Checking mask: " + aFrame.mask);
+ is(aFrame.payload, tests[0].payload, "Checking payload: " + aFrame.payload);
+ }
+
+ frameSentCounter++;
+ }
+};
+
+service.addListener(innerId, listener);
+ok(true, "Listener added");
+
+function checkListener() {
+ service.removeListener(innerId, listener);
+
+ ok(frameReceivedCounter, "We received some frames!");
+ ok(frameSentCounter, "We sent some frames!");
+ ok(webSocketCreatedCounter, "We have a create notification");
+ ok(webSocketOpenedCounter, "We have a open notification");
+ ok(webSocketMessageAvailableCounter, "We have a messageAvailable notification");
+ ok(webSocketClosedCounter, "We have a close notification");
+ SimpleTest.finish();
+}
+
+var ws = new WebSocket(URI, "frame");
+ws.onopen = function(e) {
+ info("onopen");
+
+ ws.send(tests[0].payload);
+}
+
+ws.onclose = function(e) {
+ info("onclose");
+}
+
+ws.onmessage = function(e) {
+ info("onmessage");
+ if (tests.length) {
+ is(e.data, tests[0].payload, "Wrong data");
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_hello.html b/dom/websocket/tests/test_websocket_hello.html
new file mode 100644
index 0000000000..8508fba97b
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_hello.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <title>Basic websocket test</title>
+ <script 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"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var ws;
+
+function testWebSocket () {
+ ws = new WebSocket("ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello");
+ ws.onopen = function(e) {
+ ws.send("data");
+ }
+ ws.onclose = function(e) {
+ }
+ ws.onerror = function(e) {
+ ok(false, "onerror called!");
+ SimpleTest.finish();
+ }
+ ws.onmessage = function(e) {
+ is(e.data, "Hello world!", "Wrong data");
+ ws.close();
+ SimpleTest.finish();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<div>
+
+
+</div>
+
+
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_http2.html b/dom/websocket/tests/test_websocket_http2.html
new file mode 100644
index 0000000000..de21604b2e
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_http2.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Basic HTTP/2 WebSocket test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body onload="testWebSocket()">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+const kUrl = "wss://example.com";
+const data = "123456789ABCDEF";
+let ws;
+
+function testWebSocket() {
+ ws = new WebSocket(kUrl, "test");
+
+ ws.onopen = function(e) {
+ ok(true, "onopen is called");
+ ws.send(data);
+ };
+
+ ws.onmessage = function(e) {
+ if (e.data instanceof Blob) {
+ let reader = new FileReader();
+ reader.onload = function(event) {
+ is(data, event.target.result, "data should be the same");
+ ws.close();
+ };
+ reader.readAsText(e.data);
+ } else {
+ is(data, e.data, "data should be the same");
+ ws.close();
+ }
+ };
+
+ ws.onerror = function(e) {
+ ok(false, "onerror() should not have been called!");
+ SimpleTest.executeSoon(SimpleTest.finish);
+ };
+
+ ws.onclose = function(e) {
+ ok(e.wasClean, "ws closed cleanly");
+ SimpleTest.executeSoon(SimpleTest.finish);
+ };
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_longString.html b/dom/websocket/tests/test_websocket_longString.html
new file mode 100644
index 0000000000..78c8e471c7
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_longString.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket test - big blob on content side</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+var ws = new WebSocket("ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_basic", "test");
+is(ws.readyState, 0, "Initial readyState is 0");
+
+const longString = new Array(1024*1024).join('123456789ABCDEF');
+
+ws.onopen = function(e) {
+ is(this, ws, "[onopen()] 'this' should point to the WebSocket.");
+ ws.send(longString);
+};
+
+ws.onclose = function(e) {
+ is(this, ws, "[onclose()] 'this' should point to the WebSocket.");
+ ok(e.wasClean, "Connection closed cleanly");
+
+ SimpleTest.executeSoon(SimpleTest.finish);
+};
+
+ws.onerror = function(e) {
+ is(this, ws, "[onerror()] 'this' should point to the WebSocket.");
+ ok(false, "onerror()] should not have been called!");
+ SimpleTest.executeSoon(SimpleTest.finish);
+};
+
+ws.onmessage = function(e) {
+ is(this, ws, "[onmessage()] 'this' should point to the WebSocket.");
+ // Do not use |is(e.data, longString, "...");| that results in a _very_ long line.
+ is(e.data.length, longString.length, "Length of received message");
+ ok(e.data === longString, "Content of received message");
+ this.close();
+};
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_mixed_content.html b/dom/websocket/tests/test_websocket_mixed_content.html
new file mode 100644
index 0000000000..a4f1d169f2
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_mixed_content.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket mixed content tests - load secure and insecure websockets</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<div id="container"></div>
+<iframe id="frame" sandbox="allow-scripts"></iframe>
+<script class="testbody" type="text/javascript">
+
+let iFrameTests = [testWebSocketSecure, testWebSocketInsecure, testWebSocketInsecureDataURI, testSameOriginSandboxInsecure, testSameOriginSandboxSecure, testCrossOriginSandboxInsecure, testCrossOriginSandboxSecure];
+
+function nextIFrameTest() {
+ if(!iFrameTests.length) {
+ document.getElementById("frame").removeAttribute("src");
+ document.getElementById("frame").remove();
+ SimpleTest.finish();
+ }
+ else {
+ let test = iFrameTests.shift();
+ test();
+ }
+}
+
+function testWebSockets () {
+ nextIFrameTest();
+}
+
+function testWebSocketSecure () {
+ let ws = CreateTestWS("wss://example.com/tests/dom/websocket/tests/file_websocket_hello");
+ ws.onopen = function(e) {
+ ws.send("data");
+ }
+ ws.onmessage = function(e) {
+ is(e.data, "Hello world!", "Wrong data");
+ ws.close();
+ nextIFrameTest();
+ }
+}
+
+// Negative test: this should fail as the page was loaded over https
+function testWebSocketInsecure () {
+ try {
+ let ws = new WebSocket("ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello");
+ ok(false, "Should throw DOMException");
+ } catch (e) {
+ ok(e instanceof DOMException, "DOMException thrown ");
+ nextIFrameTest();
+ }
+}
+
+// Negative test: this should fail as the page was loaded over https
+function testWebSocketInsecureDataURI() {
+ document.getElementById("frame").src = "https://example.com/tests/dom/websocket/tests/iframe_webworker_wss.html";
+ onmessage = function(e) {
+ is(e.data, "SecurityError: The operation is insecure.", "SecurityError received");
+ nextIFrameTest();
+ }
+}
+
+// Negative test: this should fail as the page was loaded over https
+function testSameOriginSandboxInsecure() {
+ document.getElementById("frame").src = "https://example.com/tests/dom/websocket/tests/iframe_websocket_wss.html?insecure";
+ onmessage = function(e) {
+ is(e.data, "SecurityError", "ws://URI cannot be used when loaded over https");
+ nextIFrameTest();
+ }
+}
+
+function testSameOriginSandboxSecure() {
+ document.getElementById("frame").src = "https://example.com/tests/dom/websocket/tests/iframe_websocket_wss.html"
+ onmessage = function(e) {
+ is(e.data, "WS onopen", "wss://URI opened");
+ nextIFrameTest();
+ }
+}
+
+// Negative test: this should fail as the page was loaded over https
+function testCrossOriginSandboxInsecure() {
+ document.getElementById("frame").src = "https://example.org/tests/dom/websocket/tests/iframe_websocket_wss.html?insecure";
+ onmessage = function(e) {
+ is(e.data, "SecurityError", "ws://URI cannot be used when loaded over https");
+ nextIFrameTest();
+ }
+}
+
+function testCrossOriginSandboxSecure() {
+ document.getElementById("frame").src = "https://example.org/tests/dom/websocket/tests/iframe_websocket_wss.html"
+
+ onmessage = function(e) {
+ is(e.data, "WS onopen", "wss://URI opened");
+ nextIFrameTest();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+testWebSockets();
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_mixed_content_blob.html b/dom/websocket/tests/test_websocket_mixed_content_blob.html
new file mode 100644
index 0000000000..160ef4f5de
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_mixed_content_blob.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket mixed content tests - load secure and insecure websockets</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<div id="container"></div>
+<script class="testbody" type="text/javascript">
+
+let testsCompleted = 0;
+const numberOfTestCases = 2;
+
+function markTestCaseComplete() {
+ testsCompleted++;
+
+ if (testsCompleted == numberOfTestCases) {
+ SimpleTest.finish();
+ }
+}
+
+onmessage = (event) => {
+ if (event.data.method === "ws://mochi.test:8888") {
+ is(event.data.result, "SecurityError", "SecurityError should be received from insecure websocket creation in Secure Context.");
+ markTestCaseComplete();
+ }
+ else if (event.data.method === "wss://example.com") {
+ is(event.data.result, "WS onopen", "onopen method should be run from secure websocket creation in Secure Context.");
+ markTestCaseComplete();
+ }
+}
+
+function testWebSocketBlob (method) {
+ let blob = URL.createObjectURL(
+ new Blob(
+ [`<!DOCTYPE html><script>
+ try {
+ let socket = new WebSocket("${method}/tests/dom/websocket/tests/file_websocket_hello");
+ socket.onerror = (e) => {
+ opener.postMessage({result: 'WS onerror', method: '${method}'}, '*');
+ close();
+ };
+ socket.onopen = (e) => {
+ socket.close();
+ opener.postMessage({result: 'WS onopen', method: '${method}'}, '*');
+ close();
+ };
+ }
+ catch(e) {
+ if (e instanceof DOMException) {
+ opener.postMessage({result: 'SecurityError', method: '${method}'}, '*');
+ close();
+ } else {
+ opener.postMessage({result: 'WS Throws something else!', method: '${method}'}, '*');
+ close();
+ }
+ }
+ <\/script>`],
+ {type: 'text/html'}
+ )
+ );
+
+ window.open(blob);
+}
+
+SimpleTest.waitForExplicitFinish();
+testWebSocketBlob("ws://mochi.test:8888");
+testWebSocketBlob("wss://example.com");
+
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_mixed_content_opener.html b/dom/websocket/tests/test_websocket_mixed_content_opener.html
new file mode 100644
index 0000000000..3d2f8d3b3e
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_mixed_content_opener.html
@@ -0,0 +1,159 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket mixed content opener tests - load secure and insecure websockets in secure and insecure iframes through secure and insecure opened windows</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<div id="container"></div>
+<script class="testbody" type="text/javascript">
+function runTest({ name, url, expect, httpsFirst = false }) {
+ return new Promise((resolve) => {
+ SpecialPowers.pushPrefEnv({
+ set: [["dom.security.https_first", httpsFirst]],
+ }).then(() => {
+ let win = window.open(
+ url,
+ "_blank",
+ "location=yes,height=570,width=520,scrollbars=yes,status=yes"
+ );
+ onmessage = function (e) {
+ is(e.data, expect, `${name} - Unexpected message`);
+ win.close();
+ SpecialPowers.flushPrefEnv().then(() => {
+ resolve();
+ });
+ };
+ });
+ });
+}
+
+async function testWebSockets() {
+ await runTest({
+ name: "testSecureWindowWSS",
+ url: "https://example.com/tests/dom/websocket/tests/window_websocket_wss.html",
+ expect: "WS onopen",
+ });
+
+ await runTest({
+ name: "testInsecureWindowWSS",
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html",
+ expect: "WS onopen",
+ });
+
+ // ws://URI cannot be used when loaded over https
+ await runTest({
+ name: "testSecureWindowWS",
+ url: "https://example.com/tests/dom/websocket/tests/window_websocket_wss.html?insecure",
+ expect: "SecurityError",
+ });
+
+ await runTest({
+ name: "testInsecureWindowWS",
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html?insecure",
+ expect: "WS onopen",
+ });
+
+ // ws://URI cannot be used when loaded over https
+ await runTest({
+ name: "testUpgradedWindowWS",
+ httpsFirst: true,
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html?insecure",
+ expect: "SecurityError",
+ });
+
+ await runTest({
+ name: "testSecureWindowSecureIframeWSS",
+ url: "https://example.com/tests/dom/websocket/tests/window_websocket_wss.html?https_iframe_wss",
+ expect: "WS onopen",
+ });
+
+ // ws://URI cannot be used when loaded over https
+ await runTest({
+ name: "testSecureWindowSecureIframeWS",
+ url: "https://example.com/tests/dom/websocket/tests/window_websocket_wss.html?https_iframe_ws",
+ expect: "SecurityError",
+ });
+
+ // http iframe cannot be loaded in secure context (mixed content)
+ await runTest({
+ name: "testSecureWindowInsecureIframeWSS",
+ url: "https://example.com/tests/dom/websocket/tests/window_websocket_wss.html?http_iframe_wss",
+ expect: "Error - iframe not loaded",
+ });
+
+ // http iframe cannot be loaded in secure context (mixed content)
+ await runTest({
+ name: "testSecureWindowInsecureIframeWS",
+ url: "https://example.com/tests/dom/websocket/tests/window_websocket_wss.html?http_iframe_ws",
+ expect: "Error - iframe not loaded",
+ });
+
+ await runTest({
+ name: "testInsecureWindowSecureIframeWSS",
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html?https_iframe_wss",
+ expect: "WS onopen",
+ });
+
+ // ws://URI cannot be used when loaded from an https iframe
+ await runTest({
+ name: "testInsecureWindowSecureIframeWS",
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html?https_iframe_ws",
+ expect: "SecurityError",
+ });
+
+ await runTest({
+ name: "testInsecureWindowInsecureIframeWSS",
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html?http_iframe_wss",
+ expect: "WS onopen",
+ });
+
+ await runTest({
+ name: "testInsecureWindowInsecureIframeWS",
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html?http_iframe_ws",
+ expect: "WS onopen",
+ });
+
+ await runTest({
+ name: "testUpgradedWindowSecureIframeWSS",
+ httpsFirst: true,
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html?https_iframe_wss",
+ expect: "WS onopen",
+ });
+
+ // ws://URI cannot be used when loaded from an https iframe
+ await runTest({
+ name: "testUpgradedWindowSecureIframeWS",
+ httpsFirst: true,
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html?https_iframe_ws",
+ expect: "SecurityError",
+ });
+
+ // http iframe cannot be loaded in secure context (mixed content)
+ await runTest({
+ name: "testUpgradedWindowInsecureIframeWSS",
+ httpsFirst: true,
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html?http_iframe_wss",
+ expect: "Error - iframe not loaded",
+ });
+
+ // http iframe cannot be loaded in secure context (mixed content)
+ await runTest({
+ name: "testUpgradedWindowInsecureIframeWS",
+ httpsFirst: true,
+ url: "http://example.com/tests/dom/websocket/tests/window_websocket_wss.html?http_iframe_ws",
+ expect: "Error - iframe not loaded",
+ });
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+testWebSockets();
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_no_duplicate_packet.html b/dom/websocket/tests/test_websocket_no_duplicate_packet.html
new file mode 100644
index 0000000000..7b2b0fc690
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_no_duplicate_packet.html
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"></meta>
+ <title>WebSocket test - big blob on content side</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="websocket_helpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+// Test steps:
+// 1. Create a websocket and send 8 chunks of 1MB random data.
+// 2. Store the hash of each chunk (1MB of random data).
+// 3. Websocket server returns the same data back.
+// 4. Calculate the hash again and check the hash is the same as the stored one.
+
+function genRandomPayload() {
+ const count = 128;
+ const chunkSize = 64 * 1024;
+ let buffer = new Uint8Array(chunkSize * count);
+ let offset = 0;
+ for (let i = 0; i < count; i++) {
+ let data = new Uint8Array(chunkSize);
+ crypto.getRandomValues(data);
+ buffer.set(data, offset);
+ offset += chunkSize;
+ }
+
+ return buffer;
+}
+
+function genRandomFile() {
+ return new File([genRandomPayload()], "payload.bin", {
+ type: 'application/octet-stream'
+ });
+}
+
+async function toHexString(buffer) {
+ let hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
+ let hashBytes = new Uint8Array(hashBuffer);
+ let toHex = b => b.toString(16).padStart(2, "0");
+ return Array.from(hashBytes, toHex).join("");
+}
+
+let message_count = 0;
+let sentHashArray = [];
+async function sendFile(file, ws) {
+ const oneMiB = 1 * 1024 * 1024;
+
+ let offset = 0;
+ while (offset < file.size) {
+ let blob = file.slice(offset, offset + oneMiB);
+ let buffer = await blob.arrayBuffer();
+ let hash = await toHexString(buffer);
+ sentHashArray.push(hash);
+ ws.send(buffer);
+ offset += blob.size;
+ message_count++;
+ }
+}
+
+var ws = CreateTestWS("wss://example.com/tests/dom/websocket/tests/file_websocket_bigBlob");
+is(ws.readyState, 0, "Initial readyState is 0");
+ws.binaryType = "blob";
+
+ws.onopen = function() {
+ is(ws.readyState, 1, "Open readyState is 1");
+ let file = genRandomFile();
+ sendFile(file, ws);
+}
+
+let receivedBlobs = [];
+ws.onmessage = function(e) {
+ ok(e.data instanceof Blob, "We should be receiving a Blob");
+ receivedBlobs.push(e.data);
+ message_count--;
+ if (message_count == 0) {
+ ws.close();
+ }
+}
+
+async function checkContent() {
+ is(receivedBlobs.length, sentHashArray.length, "length should be the same");
+ for (let index = 0; index < receivedBlobs.length; index++) {
+ let buffer = await receivedBlobs[index].arrayBuffer();
+ let hash = await toHexString(buffer);
+ is(hash, sentHashArray[index], "hash should be equal");
+ }
+}
+
+ws.onclose = function(e) {
+ is(ws.readyState, 3, "Close readyState is 3");
+ checkContent().then(() => {
+ SimpleTest.finish();
+ });
+}
+
+SimpleTest.requestFlakyTimeout("The web socket tests are really fragile, but avoiding timeouts might be hard, since it's testing stuff on the network. " +
+ "Expect all sorts of flakiness in this test...");
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_permessage_deflate.html b/dom/websocket/tests/test_websocket_permessage_deflate.html
new file mode 100644
index 0000000000..ecf66419f2
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_permessage_deflate.html
@@ -0,0 +1,110 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Basic test of permessage compression websocket extension</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="loadDeflate()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=792831">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var ws;
+var textMessage = "This is a text message";
+var binaryMessage = "This is a binary message";
+var testIdx = 0;
+var sendText = true;
+
+tests = [
+ // enable PMCE
+ [ true, true, "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_permessage_deflate" ],
+ // disable PMCE
+ [ false, false, "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_permessage_deflate_disabled" ],
+ // server rejects offered PMCE
+ [ true, false, "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_permessage_deflate_rejected" ],
+ // server returns parameters in the handshake
+ [ true, true, "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_permessage_deflate_params" ]
+]
+
+function ab2str(buf) {
+ return String.fromCharCode.apply(null, new Uint16Array(buf));
+}
+
+function str2ab(str) {
+ var buf = new ArrayBuffer(str.length*2);
+ var bufView = new Uint16Array(buf);
+ for (var i=0, strLen=str.length; i<strLen; i++) {
+ bufView[i] = str.charCodeAt(i);
+ }
+ return buf;
+}
+
+function sendMessage() {
+ if (sendText) {
+ ws.send(textMessage);
+ } else {
+ ws.binaryType = "arraybuffer";
+ ws.send(str2ab(binaryMessage));
+ }
+}
+
+function testDeflate() {
+ ws = new WebSocket(tests[testIdx][2]);
+
+ ws.onopen = function(e) {
+ if (tests[testIdx][1]) {
+ is(ws.extensions, "permessage-deflate", "permessage-deflate not negotiated!");
+ } else {
+ is(ws.extensions, "", "permessage-deflate should not be negotiated!");
+ }
+
+ sendMessage();
+ }
+
+ ws.onclose = function(e) {
+ if (!e.wasClean) {
+ ok(false, "Connection should be closed cleanly!");
+ SimpleTest.finish();
+ }
+ }
+
+ ws.onerror = function(e) {
+ ok(false, "onerror called!");
+ SimpleTest.finish();
+ }
+
+ ws.onmessage = function(e) {
+ if (sendText) {
+ is(e.data, textMessage, "Text message not received successfully!");
+ sendText = false;
+ sendMessage();
+ } else {
+ ok(e.data instanceof ArrayBuffer, "Should receive an arraybuffer!");
+ is(ab2str(e.data), binaryMessage, "Binary message not received successfully!");
+ ws.close();
+
+ sendText = true;
+ testIdx++;
+ if (testIdx < tests.length) {
+ loadDeflate();
+ } else {
+ SimpleTest.finish();
+ }
+ }
+ }
+}
+
+function loadDeflate() {
+ SpecialPowers.pushPrefEnv({"set":[['network.websocket.extensions.permessage-deflate', tests[testIdx][0]]]}, testDeflate);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_sandbox.html b/dom/websocket/tests/test_websocket_sandbox.html
new file mode 100644
index 0000000000..2803186ff0
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_sandbox.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1252751</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<div id="container"></div>
+<iframe id="frame"></iframe>
+<script type="application/javascript">
+var urls = [ "https://example.com/tests/dom/websocket/tests/iframe_websocket_sandbox.html",
+ "https://example.com/tests/dom/websocket/tests/iframe_websocket_sandbox.html?nested",
+ "https://example.com/tests/dom/websocket/tests/iframe_websocket_sandbox.html?popup" ];
+
+onmessage = function(e) {
+ is(e.data, "WS Throws!", "ws://URI cannot be used by a https iframe");
+ runTest();
+}
+
+function runTest() {
+ if (!urls.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ document.getElementById("frame").src = urls.shift();
+}
+
+SimpleTest.waitForExplicitFinish();
+runTest();
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_websocket_sharedWorker.html b/dom/websocket/tests/test_websocket_sharedWorker.html
new file mode 100644
index 0000000000..b79b0a6ced
--- /dev/null
+++ b/dom/websocket/tests/test_websocket_sharedWorker.html
@@ -0,0 +1,30 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for bug 1090183</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<script class="testbody" type="text/javascript">
+
+var sw = new SharedWorker('websocket_sharedWorker.js');
+sw.port.onmessage = function(event) {
+ if (event.data.type == 'finish') {
+ SimpleTest.finish();
+ } else if (event.data.type == 'status') {
+ ok(event.data.status, event.data.msg);
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_worker_websocket1.html b/dom/websocket/tests/test_worker_websocket1.html
new file mode 100644
index 0000000000..71414fbe42
--- /dev/null
+++ b/dom/websocket/tests/test_worker_websocket1.html
@@ -0,0 +1,46 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for WebSocket object in workers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<pre id="feedback"></pre>
+<script class="testbody" type="text/javascript">
+
+ var worker = new Worker("websocket_worker1.js");
+
+ worker.onmessage = function(event) {
+ is(event.target, worker, "event.target should be a worker!");
+
+ if (event.data.type == 'finish') {
+ info("All done!");
+ SimpleTest.finish();
+ } else if (event.data.type == 'status') {
+ ok(event.data.status, event.data.msg);
+ } else if (event.data.type == 'feedback') {
+ info(event.data.msg);
+ document.getElementById('feedback').innerHTML += event.data.msg + "\n";
+ }
+ };
+
+ worker.onerror = function(event) {
+ is(event.target, worker);
+ info("error!");
+ ok(false, "Worker had an error: " + event.data);
+ SimpleTest.finish();
+ };
+
+ worker.postMessage('foobar');
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_worker_websocket2.html b/dom/websocket/tests/test_worker_websocket2.html
new file mode 100644
index 0000000000..d9e16281b9
--- /dev/null
+++ b/dom/websocket/tests/test_worker_websocket2.html
@@ -0,0 +1,46 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for WebSocket object in workers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<pre id="feedback"></pre>
+<script class="testbody" type="text/javascript">
+
+ var worker = new Worker("websocket_worker2.js");
+
+ worker.onmessage = function(event) {
+ is(event.target, worker, "event.target should be a worker!");
+
+ if (event.data.type == 'finish') {
+ info("All done!");
+ SimpleTest.finish();
+ } else if (event.data.type == 'status') {
+ ok(event.data.status, event.data.msg);
+ } else if (event.data.type == 'feedback') {
+ info(event.data.msg);
+ document.getElementById('feedback').innerHTML += event.data.msg + "\n";
+ }
+ };
+
+ worker.onerror = function(event) {
+ is(event.target, worker);
+ info("error!");
+ ok(false, "Worker had an error: " + event.data);
+ SimpleTest.finish();
+ };
+
+ worker.postMessage('foobar');
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_worker_websocket3.html b/dom/websocket/tests/test_worker_websocket3.html
new file mode 100644
index 0000000000..4387192c42
--- /dev/null
+++ b/dom/websocket/tests/test_worker_websocket3.html
@@ -0,0 +1,46 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for WebSocket object in workers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<pre id="feedback"></pre>
+<script class="testbody" type="text/javascript">
+
+ var worker = new Worker("websocket_worker3.js");
+
+ worker.onmessage = function(event) {
+ is(event.target, worker, "event.target should be a worker!");
+
+ if (event.data.type == 'finish') {
+ info("All done!");
+ SimpleTest.finish();
+ } else if (event.data.type == 'status') {
+ ok(event.data.status, event.data.msg);
+ } else if (event.data.type == 'feedback') {
+ info(event.data.msg);
+ document.getElementById('feedback').innerHTML += event.data.msg + "\n";
+ }
+ };
+
+ worker.onerror = function(event) {
+ is(event.target, worker);
+ info("error!");
+ ok(false, "Worker had an error: " + event.data);
+ SimpleTest.finish();
+ };
+
+ worker.postMessage('foobar');
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_worker_websocket4.html b/dom/websocket/tests/test_worker_websocket4.html
new file mode 100644
index 0000000000..5f4c390574
--- /dev/null
+++ b/dom/websocket/tests/test_worker_websocket4.html
@@ -0,0 +1,46 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for WebSocket object in workers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<pre id="feedback"></pre>
+<script class="testbody" type="text/javascript">
+
+ var worker = new Worker("websocket_worker4.js");
+
+ worker.onmessage = function(event) {
+ is(event.target, worker, "event.target should be a worker!");
+
+ if (event.data.type == 'finish') {
+ info("All done!");
+ SimpleTest.finish();
+ } else if (event.data.type == 'status') {
+ ok(event.data.status, event.data.msg);
+ } else if (event.data.type == 'feedback') {
+ info(event.data.msg);
+ document.getElementById('feedback').innerHTML += event.data.msg + "\n";
+ }
+ };
+
+ worker.onerror = function(event) {
+ is(event.target, worker);
+ info("error!");
+ ok(false, "Worker had an error: " + event.data);
+ SimpleTest.finish();
+ };
+
+ worker.postMessage('foobar');
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_worker_websocket5.html b/dom/websocket/tests/test_worker_websocket5.html
new file mode 100644
index 0000000000..0b3450b7b6
--- /dev/null
+++ b/dom/websocket/tests/test_worker_websocket5.html
@@ -0,0 +1,46 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for WebSocket object in workers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<pre id="feedback"></pre>
+<script class="testbody" type="text/javascript">
+
+ var worker = new Worker("websocket_worker5.js");
+
+ worker.onmessage = function(event) {
+ is(event.target, worker, "event.target should be a worker!");
+
+ if (event.data.type == 'finish') {
+ info("All done!");
+ SimpleTest.finish();
+ } else if (event.data.type == 'status') {
+ ok(event.data.status, event.data.msg);
+ } else if (event.data.type == 'feedback') {
+ info(event.data.msg);
+ document.getElementById('feedback').innerHTML += event.data.msg + "\n";
+ }
+ };
+
+ worker.onerror = function(event) {
+ is(event.target, worker);
+ info("error!");
+ ok(false, "Worker had an error: " + event.data);
+ SimpleTest.finish();
+ };
+
+ worker.postMessage('foobar');
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_worker_websocket_basic.html b/dom/websocket/tests/test_worker_websocket_basic.html
new file mode 100644
index 0000000000..39ff1647e7
--- /dev/null
+++ b/dom/websocket/tests/test_worker_websocket_basic.html
@@ -0,0 +1,57 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for WebSocket object in workers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+ var worker = new Worker("websocket_basic_worker.js");
+
+ worker.onmessage = function(event) {
+ is(event.target, worker);
+
+ if (event.data.type == 'finish') {
+ runTest();
+ } else if (event.data.type == 'status') {
+ ok(event.data.status, event.data.msg);
+ }
+ };
+
+ worker.onerror = function(event) {
+ is(event.target, worker);
+ ok(false, "Worker had an error: " + event.data);
+ SimpleTest.finish();
+ };
+
+ var tests = [
+ function() { worker.postMessage(0); },
+ function() { worker.postMessage(1); }
+ ];
+
+ function runTest() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+ }
+
+ runTest();
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_worker_websocket_https.html b/dom/websocket/tests/test_worker_websocket_https.html
new file mode 100644
index 0000000000..9283b9bd09
--- /dev/null
+++ b/dom/websocket/tests/test_worker_websocket_https.html
@@ -0,0 +1,30 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that creating insecure websockets from https workers is not possible</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" language="javascript">
+
+ onmessage = function(event) {
+ is(event.data, "not created", "WebSocket object must not be created");
+ SimpleTest.finish();
+ };
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<iframe src="https://example.com/tests/dom/websocket/tests/websocket_worker_https.html"></iframe>
+</body>
+</html>
diff --git a/dom/websocket/tests/test_worker_websocket_loadgroup.html b/dom/websocket/tests/test_worker_websocket_loadgroup.html
new file mode 100644
index 0000000000..d02b8f149c
--- /dev/null
+++ b/dom/websocket/tests/test_worker_websocket_loadgroup.html
@@ -0,0 +1,61 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for WebSocket object in workers</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+ var worker = new Worker("websocket_loadgroup_worker.js");
+
+ var stopped = false;
+ worker.onmessage = function(e) {
+ if (e.data == 'opened') {
+ stopped = true;
+ window.stop();
+ } else if (e.data == 'closed') {
+ ok(stopped, "Good!");
+ stopped = false;
+ runTest();
+ } else {
+ ok(false, "An error has been received");
+ }
+ };
+
+ worker.onerror = function(event) {
+ is(event.target, worker);
+ ok(false, "Worker had an error: " + event.data);
+ SimpleTest.finish();
+ };
+
+ var tests = [
+ function() { worker.postMessage(0); },
+ function() { worker.postMessage(1); }
+ ];
+
+ function runTest() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+ }
+
+ runTest();
+ SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/websocket/tests/websocket_basic_worker.js b/dom/websocket/tests/websocket_basic_worker.js
new file mode 100644
index 0000000000..089fe3edc4
--- /dev/null
+++ b/dom/websocket/tests/websocket_basic_worker.js
@@ -0,0 +1,48 @@
+onmessage = function (event) {
+ if (event.data != 0) {
+ var worker = new Worker("websocket_basic_worker.js");
+ worker.onmessage = function (e) {
+ postMessage(e.data);
+ };
+
+ worker.postMessage(event.data - 1);
+ return;
+ }
+
+ status = false;
+ try {
+ if (WebSocket instanceof Object) {
+ status = true;
+ }
+ } catch (e) {}
+
+ postMessage({
+ type: "status",
+ status,
+ msg: "WebSocket object:" + WebSocket,
+ });
+
+ var ws = new WebSocket(
+ "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello"
+ );
+ ws.onopen = function (e) {
+ postMessage({ type: "status", status: true, msg: "OnOpen called" });
+ ws.send("data");
+ };
+
+ ws.onclose = function (e) {};
+
+ ws.onerror = function (e) {
+ postMessage({ type: "status", status: false, msg: "onerror called!" });
+ };
+
+ ws.onmessage = function (e) {
+ postMessage({
+ type: "status",
+ status: e.data == "Hello world!",
+ msg: "Wrong data",
+ });
+ ws.close();
+ postMessage({ type: "finish" });
+ };
+};
diff --git a/dom/websocket/tests/websocket_helpers.js b/dom/websocket/tests/websocket_helpers.js
new file mode 100644
index 0000000000..6b988b2fa4
--- /dev/null
+++ b/dom/websocket/tests/websocket_helpers.js
@@ -0,0 +1,69 @@
+var current_test = 0;
+
+function shouldNotOpen(e) {
+ var ws = e.target;
+ ok(false, "onopen shouldn't be called on test " + ws._testNumber + "!");
+}
+
+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) {
+ var ws;
+
+ if (ws_protocol == undefined) {
+ ws = new WebSocket(ws_location);
+ } else {
+ ws = new WebSocket(ws_location, ws_protocol);
+ }
+
+ ws._testNumber = current_test;
+ ok(true, "Created websocket for test " + ws._testNumber + "\n");
+
+ ws.onerror = function (e) {
+ ok(false, "onerror called on test " + e.target._testNumber + "!");
+ };
+
+ return ws;
+}
+
+function forcegc() {
+ SpecialPowers.forceGC();
+ SpecialPowers.gc();
+}
+
+function feedback() {
+ $("feedback").innerHTML =
+ "executing test: " + (current_test + 1) + " of " + tests.length + " tests.";
+}
+
+function finish() {
+ SimpleTest.finish();
+}
+
+function doTest() {
+ if (current_test >= tests.length) {
+ finish();
+ return;
+ }
+
+ feedback();
+ tests[current_test++]().then(doTest);
+}
diff --git a/dom/websocket/tests/websocket_https_worker.js b/dom/websocket/tests/websocket_https_worker.js
new file mode 100644
index 0000000000..e07b0dbec5
--- /dev/null
+++ b/dom/websocket/tests/websocket_https_worker.js
@@ -0,0 +1,11 @@
+onmessage = function () {
+ var wsCreated = true;
+ try {
+ new WebSocket(
+ "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello"
+ );
+ } catch (e) {
+ wsCreated = false;
+ }
+ postMessage(wsCreated ? "created" : "not created");
+};
diff --git a/dom/websocket/tests/websocket_hybi/file_binary-frames_wsh.py b/dom/websocket/tests/websocket_hybi/file_binary-frames_wsh.py
new file mode 100644
index 0000000000..16ace4d3a6
--- /dev/null
+++ b/dom/websocket/tests/websocket_hybi/file_binary-frames_wsh.py
@@ -0,0 +1,19 @@
+import six
+from mod_pywebsocket import common, stream
+
+
+def web_socket_do_extra_handshake(request):
+ pass
+
+
+def web_socket_transfer_data(request):
+ messages_to_send = ["Hello, world!", "", all_distinct_bytes()]
+ for message in messages_to_send:
+ message = six.b(message)
+ # FIXME: Should use better API to send binary messages when pywebsocket supports it.
+ header = stream.create_header(common.OPCODE_BINARY, len(message), 1, 0, 0, 0, 0)
+ request.connection.write(header + message)
+
+
+def all_distinct_bytes():
+ return "".join([chr(i) for i in range(256)])
diff --git a/dom/websocket/tests/websocket_hybi/file_check-binary-messages_wsh.py b/dom/websocket/tests/websocket_hybi/file_check-binary-messages_wsh.py
new file mode 100644
index 0000000000..d72ec1f462
--- /dev/null
+++ b/dom/websocket/tests/websocket_hybi/file_check-binary-messages_wsh.py
@@ -0,0 +1,27 @@
+import six
+from mod_pywebsocket import msgutil
+
+
+def web_socket_do_extra_handshake(request):
+ pass # Always accept.
+
+
+def web_socket_transfer_data(request):
+ expected_messages = ["Hello, world!", "", all_distinct_bytes()]
+
+ for test_number, expected_message in enumerate(expected_messages):
+ expected_message = six.b(expected_message)
+ message = msgutil.receive_message(request)
+ if message == expected_message:
+ msgutil.send_message(request, "PASS: Message #{:d}.".format(test_number))
+ else:
+ msgutil.send_message(
+ request,
+ "FAIL: Message #{:d}: Received unexpected message: {!r}".format(
+ test_number, message
+ ),
+ )
+
+
+def all_distinct_bytes():
+ return "".join([chr(i) for i in range(256)])
diff --git a/dom/websocket/tests/websocket_hybi/mochitest.toml b/dom/websocket/tests/websocket_hybi/mochitest.toml
new file mode 100644
index 0000000000..1b00e0c8b3
--- /dev/null
+++ b/dom/websocket/tests/websocket_hybi/mochitest.toml
@@ -0,0 +1,17 @@
+[DEFAULT]
+skip-if = [
+ "http3",
+ "http2",
+]
+support-files = [
+ "file_binary-frames_wsh.py",
+ "file_check-binary-messages_wsh.py",
+]
+
+["test_receive-arraybuffer.html"]
+
+["test_receive-blob.html"]
+
+["test_send-arraybuffer.html"]
+
+["test_send-blob.html"]
diff --git a/dom/websocket/tests/websocket_hybi/test_receive-arraybuffer.html b/dom/websocket/tests/websocket_hybi/test_receive-arraybuffer.html
new file mode 100644
index 0000000000..6d465b7677
--- /dev/null
+++ b/dom/websocket/tests/websocket_hybi/test_receive-arraybuffer.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+
+<script class="testbody" type="text/javascript">
+
+function debug(msg) {
+ ok(1, msg);
+}
+
+function createArrayBufferContainingHelloWorld()
+{
+ var hello = "Hello, world!";
+ var array = new Uint8Array(hello.length);
+ for (var i = 0; i < hello.length; ++i)
+ array[i] = hello.charCodeAt(i);
+ return array.buffer;
+}
+
+function createEmptyArrayBuffer()
+{
+ return new ArrayBuffer(0);
+}
+
+function createArrayBufferContainingAllDistinctBytes()
+{
+ var array = new Uint8Array(256);
+ for (var i = 0; i < 256; ++i)
+ array[i] = i;
+ return array.buffer;
+}
+
+var ws = new WebSocket("ws://mochi.test:8888/tests/dom/websocket/tests/websocket_hybi/file_binary-frames");
+ws.binaryType = "arraybuffer";
+is(ws.binaryType, "arraybuffer", "should be equal to 'arraybuffer'");
+
+var closeEvent;
+var receivedMessages = [];
+var expectedValues = [createArrayBufferContainingHelloWorld(), createEmptyArrayBuffer(), createArrayBufferContainingAllDistinctBytes()];
+
+ws.onmessage = function(event)
+{
+ receivedMessages.push(event.data);
+};
+
+ws.onclose = function(event)
+{
+ closeEvent = event;
+
+ is(receivedMessages.length, expectedValues.length, "lengths not equal");
+ for (var i = 0; i < expectedValues.length; ++i)
+ check(i);
+ SimpleTest.finish();
+};
+
+var responseType;
+
+function check(index)
+{
+ debug("Checking message #" + index + ".");
+ ok(receivedMessages[index] instanceof ArrayBuffer,
+ "Should receive an arraybuffer!");
+ checkArrayBuffer(index, receivedMessages[index], expectedValues[index]);
+}
+
+var actualArray;
+var expectedArray;
+
+function checkArrayBuffer(testIndex, actual, expected)
+{
+ actualArray = new Uint8Array(actual);
+ expectedArray = new Uint8Array(expected);
+ is(actualArray.length, expectedArray.length, "lengths not equal");
+ // Print only the first mismatched byte in order not to flood console.
+ for (var i = 0; i < expectedArray.length; ++i) {
+ if (actualArray[i] != expectedArray[i]) {
+ ok(false, "Value mismatch: actualArray[" + i + "] = " + actualArray[i] + ", expectedArray[" + i + "] = " + expectedArray[i]);
+ return;
+ }
+ }
+ ok(true, "Passed: Message #" + testIndex + ".");
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/websocket_hybi/test_receive-blob.html b/dom/websocket/tests/websocket_hybi/test_receive-blob.html
new file mode 100644
index 0000000000..5589633a7c
--- /dev/null
+++ b/dom/websocket/tests/websocket_hybi/test_receive-blob.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+
+<script class="testbody" type="text/javascript">
+
+function debug(msg) {
+ ok(true, msg);
+}
+
+function createArrayBufferContainingHelloWorld()
+{
+ var hello = "Hello, world!";
+ var array = new Uint8Array(hello.length);
+ for (var i = 0; i < hello.length; ++i)
+ array[i] = hello.charCodeAt(i);
+ return array.buffer;
+}
+
+function createEmptyArrayBuffer()
+{
+ return new ArrayBuffer(0);
+}
+
+function createArrayBufferContainingAllDistinctBytes()
+{
+ var array = new Uint8Array(256);
+ for (var i = 0; i < 256; ++i)
+ array[i] = i;
+ return array.buffer;
+}
+
+var ws = new WebSocket("ws://mochi.test:8888/tests/dom/websocket/tests/websocket_hybi/file_binary-frames");
+is(ws.binaryType, "blob", "should be 'blob'");
+
+var closeEvent;
+var receivedMessages = [];
+var expectedValues = [createArrayBufferContainingHelloWorld(), createEmptyArrayBuffer(), createArrayBufferContainingAllDistinctBytes()];
+
+ws.onmessage = function(event)
+{
+ receivedMessages.push(event.data);
+};
+
+ws.onclose = function(event)
+{
+ closeEvent = event;
+
+ is(receivedMessages.length, expectedValues.length, "lengths not same");
+ check(0);
+};
+
+var responseType;
+
+function check(index)
+{
+ if (index == expectedValues.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ debug("Checking message #" + index + ".");
+ ok(receivedMessages[index] instanceof Blob,
+ "We should be receiving a Blob");
+ var reader = new FileReader();
+ reader.readAsArrayBuffer(receivedMessages[index]);
+ reader.onload = function(event)
+ {
+ checkArrayBuffer(index, reader.result, expectedValues[index]);
+ check(index + 1);
+ };
+ reader.onerror = function(event)
+ {
+ ok(false, "Failed to read blob: error code = " + reader.error.code);
+ check(index + 1);
+ };
+}
+
+var actualArray;
+var expectedArray;
+
+function checkArrayBuffer(testIndex, actual, expected)
+{
+ actualArray = new Uint8Array(actual);
+ expectedArray = new Uint8Array(expected);
+ is(actualArray.length, expectedArray.length, "lengths not same");
+ // Print only the first mismatched byte in order not to flood console.
+ for (var i = 0; i < expectedArray.length; ++i) {
+ if (actualArray[i] != expectedArray[i]) {
+ ok(false, "Value mismatch: actualArray[" + i + "] = " + actualArray[i] + ", expectedArray[" + i + "] = " + expectedArray[i]);
+ return;
+ }
+ }
+ ok(true, "Passed: Message #" + testIndex + ".");
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/websocket_hybi/test_send-arraybuffer.html b/dom/websocket/tests/websocket_hybi/test_send-arraybuffer.html
new file mode 100644
index 0000000000..6c71ca5415
--- /dev/null
+++ b/dom/websocket/tests/websocket_hybi/test_send-arraybuffer.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+
+<script class="testbody" type="text/javascript">
+
+function debug(msg) {
+ ok(1, msg);
+}
+
+function startsWith(target, prefix)
+{
+ return target.indexOf(prefix) === 0;
+}
+
+function createArrayBufferContainingHelloWorld()
+{
+ var hello = "Hello, world!";
+ var array = new Uint8Array(hello.length);
+ for (var i = 0; i < hello.length; ++i)
+ array[i] = hello.charCodeAt(i);
+ return array.buffer;
+}
+
+function createEmptyArrayBuffer()
+{
+ return new ArrayBuffer(0);
+}
+
+function createArrayBufferContainingAllDistinctBytes()
+{
+ var array = new Uint8Array(256);
+ for (var i = 0; i < 256; ++i)
+ array[i] = i;
+ return array.buffer;
+}
+
+var ws = new WebSocket("ws://mochi.test:8888/tests/dom/websocket/tests/websocket_hybi/file_check-binary-messages");
+var closeEvent;
+
+ws.onopen = function()
+{
+ ok(true, "onopen reached");
+ ws.send(createArrayBufferContainingHelloWorld());
+ ws.send(createEmptyArrayBuffer());
+ ws.send(createArrayBufferContainingAllDistinctBytes());
+};
+
+ws.onmessage = function(event)
+{
+ var message = event.data;
+ if (startsWith(message, "PASS"))
+ ok(true, message);
+ else
+ ok(false, message);
+};
+
+ws.onclose = function(event)
+{
+ ok(event.wasClean, "should have closed cleanly");
+ SimpleTest.finish();
+};
+
+ws.onerror = function(event)
+{
+ ok(false, "onerror should not have been called");
+};
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/websocket_hybi/test_send-blob.html b/dom/websocket/tests/websocket_hybi/test_send-blob.html
new file mode 100644
index 0000000000..6af1e2df03
--- /dev/null
+++ b/dom/websocket/tests/websocket_hybi/test_send-blob.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+
+<script class="testbody" type="text/javascript">
+
+function startsWith(target, prefix)
+{
+ return target.indexOf(prefix) === 0;
+}
+
+function distinctBytes()
+{
+ var array = new Array();
+ for (var i = 0; i < 256; ++i)
+ array[i] = i;
+ // Concatenates chars into a single binary string
+ return String.fromCharCode.apply(null, array);
+}
+
+var filesToCreate = [
+ {name: "hellofile", data: "Hello, world!"},
+ {name: "emptyfile"},
+ {name: "allchars", data: distinctBytes()},
+];
+
+SpecialPowers.createFiles(filesToCreate, function (files) {
+ var ws = new WebSocket("ws://mochi.test:8888/tests/dom/websocket/tests/websocket_hybi/file_check-binary-messages");
+ var closeEvent;
+
+ ws.onopen = function()
+ {
+ ws.send(files[0]);
+ ws.send(files[1]);
+ ws.send(files[2]);
+ };
+
+ ws.onmessage = function(event)
+ {
+ var message = event.data;
+ if (startsWith(message, "PASS"))
+ ok(true, message);
+ else
+ ok(false, message);
+ };
+
+ ws.onclose = function(event)
+ {
+ ok(event.wasClean, "should have closed cleanly");
+ SimpleTest.finish();
+ };
+},
+function (msg) {
+ ok(false, "Failed to create files: " + msg);
+ SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/websocket/tests/websocket_loadgroup_worker.js b/dom/websocket/tests/websocket_loadgroup_worker.js
new file mode 100644
index 0000000000..6de82d1900
--- /dev/null
+++ b/dom/websocket/tests/websocket_loadgroup_worker.js
@@ -0,0 +1,26 @@
+onmessage = function (event) {
+ if (event.data != 0) {
+ var worker = new Worker("websocket_loadgroup_worker.js");
+ worker.onmessage = function (e) {
+ postMessage(e.data);
+ };
+
+ worker.postMessage(event.data - 1);
+ return;
+ }
+
+ var ws = new WebSocket(
+ "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello"
+ );
+ ws.onopen = function (e) {
+ postMessage("opened");
+ };
+
+ ws.onclose = function (e) {
+ postMessage("closed");
+ };
+
+ ws.onerror = function (e) {
+ postMessage("error");
+ };
+};
diff --git a/dom/websocket/tests/websocket_sharedWorker.js b/dom/websocket/tests/websocket_sharedWorker.js
new file mode 100644
index 0000000000..7c832f5c30
--- /dev/null
+++ b/dom/websocket/tests/websocket_sharedWorker.js
@@ -0,0 +1,34 @@
+onconnect = function (evt) {
+ var ws = new WebSocket(
+ "ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello"
+ );
+
+ ws.onopen = function (e) {
+ evt.ports[0].postMessage({
+ type: "status",
+ status: true,
+ msg: "OnOpen called",
+ });
+ ws.send("data");
+ };
+
+ ws.onclose = function (e) {};
+
+ ws.onerror = function (e) {
+ evt.ports[0].postMessage({
+ type: "status",
+ status: false,
+ msg: "onerror called!",
+ });
+ };
+
+ ws.onmessage = function (e) {
+ evt.ports[0].postMessage({
+ type: "status",
+ status: e.data == "Hello world!",
+ msg: "Wrong data",
+ });
+ ws.close();
+ evt.ports[0].postMessage({ type: "finish" });
+ };
+};
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();
+ };
+ });
+}
diff --git a/dom/websocket/tests/websocket_worker1.js b/dom/websocket/tests/websocket_worker1.js
new file mode 100644
index 0000000000..26b37b8e48
--- /dev/null
+++ b/dom/websocket/tests/websocket_worker1.js
@@ -0,0 +1,19 @@
+importScripts("websocket_helpers.js");
+importScripts("websocket_tests.js");
+importScripts("websocket_worker_helpers.js");
+
+var tests = [
+ test1, // client tries to connect to a http scheme location;
+ test2, // assure serialization of the connections;
+ test3, // client tries to connect to an non-existent ws server;
+ test4, // client tries to connect using a relative url;
+ test5, // client uses an invalid protocol value;
+ test6, // counter and encoding check;
+ test7, // onmessage event origin property check
+ test8, // client calls close() and the server sends the close frame (with no
+ // code or reason) in acknowledgement;
+ test9, // client closes the connection before the ws connection is established;
+ test10, // client sends a message before the ws connection is established;
+];
+
+doTest();
diff --git a/dom/websocket/tests/websocket_worker2.js b/dom/websocket/tests/websocket_worker2.js
new file mode 100644
index 0000000000..fbc4591bdb
--- /dev/null
+++ b/dom/websocket/tests/websocket_worker2.js
@@ -0,0 +1,19 @@
+importScripts("websocket_helpers.js");
+importScripts("websocket_tests.js");
+importScripts("websocket_worker_helpers.js");
+
+var tests = [
+ test11, // a simple hello echo;
+ test12, // client sends a message containing unpaired surrogates
+ test13, //server sends an invalid message;
+ test14, // server sends the close frame, it doesn't close the tcp connection
+ // and it keeps sending normal ws messages;
+ test15, // server closes the tcp connection, but it doesn't send the close
+ // frame;
+ test16, // client calls close() and tries to send a message;
+ test18, // client tries to connect to an http resource;
+ test19, // server closes the tcp connection before establishing the ws
+ // connection;
+];
+
+doTest();
diff --git a/dom/websocket/tests/websocket_worker3.js b/dom/websocket/tests/websocket_worker3.js
new file mode 100644
index 0000000000..8fee7f4ca5
--- /dev/null
+++ b/dom/websocket/tests/websocket_worker3.js
@@ -0,0 +1,17 @@
+importScripts("websocket_helpers.js");
+importScripts("websocket_tests.js");
+importScripts("websocket_worker_helpers.js");
+
+var tests = [
+ test24, // server rejects sub-protocol string
+ test25, // ctor with valid empty sub-protocol array
+ test26, // ctor with invalid sub-protocol array containing 1 empty element
+ test27, // ctor with invalid sub-protocol array containing an empty element in
+ // list
+ test28, // ctor using valid 1 element sub-protocol array
+ test29, // ctor using all valid 5 element sub-protocol array
+ test30, // ctor using valid 1 element sub-protocol array with element server
+ // will reject
+];
+
+doTest();
diff --git a/dom/websocket/tests/websocket_worker4.js b/dom/websocket/tests/websocket_worker4.js
new file mode 100644
index 0000000000..3e3408b019
--- /dev/null
+++ b/dom/websocket/tests/websocket_worker4.js
@@ -0,0 +1,19 @@
+importScripts("websocket_helpers.js");
+importScripts("websocket_tests.js");
+importScripts("websocket_worker_helpers.js");
+
+var tests = [
+ test31, // ctor using valid 2 element sub-protocol array with 1 element server
+ // will reject and one server will accept
+ test32, // ctor using invalid sub-protocol array that contains duplicate items
+ test33, // test for sending/receiving custom close code (but no close reason)
+ test34, // test for receiving custom close code and reason
+ test35, // test for sending custom close code and reason
+ test36, // negative test for sending out of range close code
+ test37, // negative test for too long of a close reason
+ test38, // ensure extensions attribute is defined
+ test39, // a basic wss:// connectivity test
+ test40, // negative test for wss:// with no cert
+];
+
+doTest();
diff --git a/dom/websocket/tests/websocket_worker5.js b/dom/websocket/tests/websocket_worker5.js
new file mode 100644
index 0000000000..0ed1bbd486
--- /dev/null
+++ b/dom/websocket/tests/websocket_worker5.js
@@ -0,0 +1,14 @@
+importScripts("websocket_helpers.js");
+importScripts("websocket_tests.js");
+importScripts("websocket_worker_helpers.js");
+
+var tests = [
+ test42, // non-char utf-8 sequences
+ test43, // Test setting binaryType attribute
+ test44, // Test sending/receving binary ArrayBuffer
+ test46, // Test that we don't dispatch incoming msgs once in CLOSING state
+ test47, // Make sure onerror/onclose aren't called during close()
+ test49, // Test that we fail if subprotocol returned from server doesn't match
+];
+
+doTest();
diff --git a/dom/websocket/tests/websocket_worker_helpers.js b/dom/websocket/tests/websocket_worker_helpers.js
new file mode 100644
index 0000000000..e9c55b1009
--- /dev/null
+++ b/dom/websocket/tests/websocket_worker_helpers.js
@@ -0,0 +1,27 @@
+function feedback() {
+ postMessage({
+ type: "feedback",
+ msg:
+ "executing test: " +
+ (current_test + 1) +
+ " of " +
+ tests.length +
+ " tests.",
+ });
+}
+
+function ok(status, msg) {
+ postMessage({ type: "status", status: !!status, msg });
+}
+
+function is(a, b, msg) {
+ ok(a === b, msg);
+}
+
+function isnot(a, b, msg) {
+ ok(a != b, msg);
+}
+
+function finish() {
+ postMessage({ type: "finish" });
+}
diff --git a/dom/websocket/tests/websocket_worker_https.html b/dom/websocket/tests/websocket_worker_https.html
new file mode 100644
index 0000000000..0eb17af65b
--- /dev/null
+++ b/dom/websocket/tests/websocket_worker_https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script>
+ var worker = new Worker("https://example.com/tests/dom/websocket/tests/websocket_https_worker.js");
+
+ worker.onmessage = function(event) {
+ parent.postMessage(event.data, "*");
+ };
+
+ worker.onerror = function(event) {
+ parent.postMessage("error", "*");
+ };
+
+ worker.postMessage("start");
+</script>
diff --git a/dom/websocket/tests/window_bug1384658.html b/dom/websocket/tests/window_bug1384658.html
new file mode 100644
index 0000000000..c2d6e16c8d
--- /dev/null
+++ b/dom/websocket/tests/window_bug1384658.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+ onload = function() {
+ if (window.location.search == "") {
+ window.open("window_bug1384658.html?opened", "_top", "");
+ } else {
+ var iframeURL = "http://mochi.test:8888/tests/dom/websocket/tests/file_bug1384658.html";
+ var iframe = document.createElement("iframe");
+ iframe.src = iframeURL;
+ document.body.appendChild(iframe);
+ }
+ };
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/websocket/tests/window_websocket_wss.html b/dom/websocket/tests/window_websocket_wss.html
new file mode 100644
index 0000000000..391ab74e40
--- /dev/null
+++ b/dom/websocket/tests/window_websocket_wss.html
@@ -0,0 +1,65 @@
+<html><body>
+Creating WebSocket
+<iframe id="frame" sandbox="allow-scripts"></iframe>
+<script type="application/javascript">
+
+function cleanup() {
+ window.document.getElementById("frame").removeAttribute("src");
+ window.document.getElementById("frame").remove();
+}
+
+onmessage = function(e) {
+ cleanup();
+ window.opener.postMessage(e.data, '*');
+}
+
+// Mixed content blocker will prevent loading iframes via http, so in that case pass back the error
+window.document.getElementById("frame").onerror = function(e) {
+ cleanup();
+ window.opener.postMessage("Error - iframe not loaded", '*');
+}
+
+// Load one of the iframe variants?
+if (location.search == '?https_iframe_wss') {
+ window.document.getElementById("frame").src = "https://example.com/tests/dom/websocket/tests/iframe_websocket_wss.html";
+} else if (location.search == '?https_iframe_ws') {
+ window.document.getElementById("frame").src = "https://example.com/tests/dom/websocket/tests/iframe_websocket_wss.html?insecure";
+} else if (location.search == '?http_iframe_wss' || location.search == '?http_iframe_ws') {
+ let iFrameUrl = "http://example.com/tests/dom/websocket/tests/iframe_websocket_wss.html";
+ if (location.search == '?http_iframe_ws') {
+ iFrameUrl += "?insecure";
+ }
+ window.document.getElementById("frame").src = iFrameUrl;
+}
+else {
+ try {
+ let socket;
+ if (location.search == '?insecure') {
+ socket = new WebSocket('ws://mochi.test:8888/tests/dom/websocket/tests/file_websocket_hello');
+ }
+ else {
+ socket = new WebSocket('wss://example.com/tests/dom/websocket/tests/file_websocket_hello');
+ }
+ socket.onerror = function(e) {
+ cleanup();
+ window.opener.postMessage("WS onerror", "*");
+ };
+ socket.onopen = function(event) {
+ socket.close();
+ cleanup();
+ window.opener.postMessage("WS onopen", "*");
+ };
+ }
+ catch(e) {
+ if (e.name == 'SecurityError') {
+ cleanup();
+ window.opener.postMessage("SecurityError", "*");
+ } else {
+ cleanup();
+ window.opener.postMessage("Test Throws", "*");
+ }
+ }
+}
+
+</script>
+</body></html>