diff options
Diffstat (limited to '')
61 files changed, 4370 insertions, 0 deletions
diff --git a/dom/websocket/tests/.eslintrc.js b/dom/websocket/tests/.eslintrc.js new file mode 100644 index 0000000000..721e0938af --- /dev/null +++ b/dom/websocket/tests/.eslintrc.js @@ -0,0 +1,5 @@ +"use strict"; + +module.exports = { + extends: ["plugin:mozilla/mochitest-test", "plugin:mozilla/chrome-test"], +}; diff --git a/dom/websocket/tests/chrome.ini b/dom/websocket/tests/chrome.ini new file mode 100644 index 0000000000..b781f62e6e --- /dev/null +++ b/dom/websocket/tests/chrome.ini @@ -0,0 +1,4 @@ +[DEFAULT] +skip-if = os == 'android' + +[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..c588ebc77c --- /dev/null +++ b/dom/websocket/tests/file_websocket_permessage_deflate_disabled_wsh.py @@ -0,0 +1,19 @@ +from mod_pywebsocket import msgutil +from mod_pywebsocket import common + + +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..8387569645 --- /dev/null +++ b/dom/websocket/tests/file_websocket_permessage_deflate_params_wsh.py @@ -0,0 +1,25 @@ +from mod_pywebsocket import msgutil +from mod_pywebsocket import common + + +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..e0a99467f3 --- /dev/null +++ b/dom/websocket/tests/file_websocket_permessage_deflate_rejected_wsh.py @@ -0,0 +1,25 @@ +from mod_pywebsocket import msgutil +from mod_pywebsocket import common + + +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..8075829481 --- /dev/null +++ b/dom/websocket/tests/file_websocket_permessage_deflate_wsh.py @@ -0,0 +1,24 @@ +from mod_pywebsocket import msgutil +from mod_pywebsocket import common + + +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..b9301276c0 --- /dev/null +++ b/dom/websocket/tests/file_websocket_wsh.py @@ -0,0 +1,164 @@ +from mod_pywebsocket import msgutil + +import time +import struct + +# 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-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, resp.decode("utf-8")) + resp = "wrong message" + if msgutil.receive_message(request) == "3": + resp = "4" + msgutil.send_message(request, resp.decode("utf-8")) + resp = "wrong message" + if msgutil.receive_message(request) == "5": + resp = "あいうえお" + msgutil.send_message(request, resp.decode("utf-8")) + 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, resp.decode("utf-8")) + elif request.ws_protocol == "test-12": + msg = msgutil.receive_message(request) + if msg == u"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("\xff\x01\x61") + # after a bad utf8 message + request.connection.write("\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, resp.decode("utf-8")) + 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 = 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, struct.pack("cc", chr(0), chr(4)), 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 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/mochitest.ini b/dom/websocket/tests/mochitest.ini new file mode 100644 index 0000000000..7e66cbefeb --- /dev/null +++ b/dom/websocket/tests/mochitest.ini @@ -0,0 +1,55 @@ +[DEFAULT] +skip-if = toolkit == 'android' # bug 982828 +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 +skip-if = (os == "win" && processor == "aarch64") #bug 1535784 +[test_websocket1.html] +[test_websocket2.html] +[test_websocket3.html] +[test_websocket4.html] +[test_websocket5.html] +[test_websocket_basic.html] +[test_websocket_hello.html] +[test_websocket_permessage_deflate.html] +[test_webSocket_sandbox.html] +support-files = iframe_webSocket_sandbox.html +[test_worker_websocket1.html] +support-files = websocket_worker1.js +[test_worker_websocket2.html] +support-files = websocket_worker2.js +[test_worker_websocket3.html] +support-files = websocket_worker3.js +[test_worker_websocket4.html] +support-files = websocket_worker4.js +[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 +[test_webSocket_sharedWorker.html] +support-files = webSocket_sharedWorker.js +[test_websocket_bigBlob.html] +support-files = file_websocket_bigBlob_wsh.py +[test_webSocket_longString.html] +[test_webSocket_no_duplicate_packet.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..c90e4c8bdf --- /dev/null +++ b/dom/websocket/tests/test_bug1384658.html @@ -0,0 +1,49 @@ +<!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]], +}, 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_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_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_sandbox.html b/dom/websocket/tests/test_webSocket_sandbox.html new file mode 100644 index 0000000000..363afcfe21 --- /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..9e5c5bbafd --- /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_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..26910246e4 --- /dev/null +++ b/dom/websocket/tests/test_websocket_frame.html @@ -0,0 +1,163 @@ +<!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; + +ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); + +var tests = [ + { payload: "Hello world!" }, + { payload: (function() { var buffer = ""; for (var i = 0; i < 120; ++i) buffer += i; return buffer; }()) }, +] + +var innerId = window.top.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_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_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_sharedWorker.js b/dom/websocket/tests/webSocket_sharedWorker.js new file mode 100644 index 0000000000..8943ce2ac3 --- /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_basic_worker.js b/dom/websocket/tests/websocket_basic_worker.js new file mode 100644 index 0000000000..d1d263afcc --- /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..18f9f5a835 --- /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..6d7fd8376e --- /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..830367e846 --- /dev/null +++ b/dom/websocket/tests/websocket_hybi/file_binary-frames_wsh.py @@ -0,0 +1,18 @@ +from mod_pywebsocket import common +from mod_pywebsocket import 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: + # 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..1d5bc49dfa --- /dev/null +++ b/dom/websocket/tests/websocket_hybi/file_check-binary-messages_wsh.py @@ -0,0 +1,25 @@ +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): + message = msgutil.receive_message(request) + if type(message) == str and 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.ini b/dom/websocket/tests/websocket_hybi/mochitest.ini new file mode 100644 index 0000000000..21d61c8c86 --- /dev/null +++ b/dom/websocket/tests/websocket_hybi/mochitest.ini @@ -0,0 +1,13 @@ +[DEFAULT] +support-files = + file_binary-frames_wsh.py + file_check-binary-messages_wsh.py + +[test_receive-arraybuffer.html] +skip-if = toolkit == 'android' +[test_receive-blob.html] +skip-if = toolkit == 'android' +[test_send-arraybuffer.html] +skip-if = toolkit == 'android' +[test_send-blob.html] +skip-if = toolkit == 'android' 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..f97cd4c5f2 --- /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_tests.js b/dom/websocket/tests/websocket_tests.js new file mode 100644 index 0000000000..53561785b6 --- /dev/null +++ b/dom/websocket/tests/websocket_tests.js @@ -0,0 +1,1493 @@ +// test1: client tries to connect to a http scheme location; +function test1() { + return new Promise(function(resolve, reject) { + try { + var ws = CreateTestWS( + "http://mochi.test:8888/tests/dom/websocket/tests/file_websocket" + ); + ok(false, "test1 failed"); + } catch (e) { + ok(true, "test1 failed"); + } + + 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) { + try { + var ws = CreateTestWS("file_websocket"); + ok(false, "test-4 failed"); + } catch (e) { + ok(true, "test-4 failed"); + } + + 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"); + + // establish a hsts policy 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 wss:// now due to hsts + 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, + "wss://example.com/tests/dom/websocket/tests/file_websocket", + "test 41c ws should be redirected by hsts to wss" + ); + wsc.close(); + }; + + wsc.onclose = function() { + ok(true, "test 41c close"); + + // clean up the STS state + const Ci = SpecialPowers.Ci; + var loadContext = SpecialPowers.wrap(window).docShell.QueryInterface( + Ci.nsILoadContext + ); + var flags = 0; + if (loadContext.usePrivateBrowsing) { + flags |= Ci.nsISocketProvider.NO_PERMANENT_STORAGE; + } + SpecialPowers.cleanUpSTSData("http://example.com", flags); + 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> |