diff options
Diffstat (limited to 'testing/web-platform/tests/websockets')
254 files changed, 6376 insertions, 0 deletions
diff --git a/testing/web-platform/tests/websockets/Close-1000-reason.any.js b/testing/web-platform/tests/websockets/Close-1000-reason.any.js new file mode 100644 index 0000000000..79ad6a0418 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-1000-reason.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close(1000, reason) - readyState should be in CLOSED state and wasClean is TRUE - Connection should be closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.close(1000, "Clean Close"); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be opened"); + assert_equals(wsocket.readyState, 3, "readyState should be 3(CLOSED)"); + assert_equals(evt.wasClean, true, "wasClean should be TRUE"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-1000-verify-code.any.js b/testing/web-platform/tests/websockets/Close-1000-verify-code.any.js new file mode 100644 index 0000000000..c3a9274caa --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-1000-verify-code.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close(1000, reason) - event.code == 1000 and event.reason = 'Clean Close'"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.close(1000, "Clean Close"); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(evt.code, 1000, "CloseEvent.code should be 1000"); + assert_equals(evt.reason, "Clean Close", "CloseEvent.reason should be the same as the reason sent in close"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-1000.any.js b/testing/web-platform/tests/websockets/Close-1000.any.js new file mode 100644 index 0000000000..2f535ba21a --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-1000.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close(1000) - readyState should be in CLOSED state and wasClean is TRUE - Connection should be closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.close(1000); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be opened"); + assert_equals(wsocket.readyState, 3, "readyState should be 3(CLOSED)"); + assert_equals(evt.wasClean, true, "wasClean should be TRUE"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-1005-verify-code.any.js b/testing/web-platform/tests/websockets/Close-1005-verify-code.any.js new file mode 100644 index 0000000000..28f84c8003 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-1005-verify-code.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close() - return close code is 1005 - Connection should be closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.close(); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(evt.code, 1005, "CloseEvent.code should be 1005"); + assert_equals(evt.reason, "", "CloseEvent.reason should be empty"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-1005.any.js b/testing/web-platform/tests/websockets/Close-1005.any.js new file mode 100644 index 0000000000..5055e283f3 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-1005.any.js @@ -0,0 +1,18 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close(1005) - see '7.1.5. The WebSocket Connection Close Code' in http://www.ietf.org/rfc/rfc6455.txt"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + assert_throws_dom("INVALID_ACCESS_ERR", function() { + wsocket.close(1005, "1005 - reserved code") + }); + test.done(); +}), true); + +wsocket.addEventListener('close', test.unreached_func('close event should not fire'), true); diff --git a/testing/web-platform/tests/websockets/Close-2999-reason.any.js b/testing/web-platform/tests/websockets/Close-2999-reason.any.js new file mode 100644 index 0000000000..6336c7db4f --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-2999-reason.any.js @@ -0,0 +1,17 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close(2999, reason) - INVALID_ACCESS_ERR is thrown"); + +var wsocket = CreateWebSocket(false, false); + +wsocket.addEventListener('open', test.step_func(function(evt) { + assert_throws_dom("INVALID_ACCESS_ERR", function() { + wsocket.close(2999, "Close not in range 3000-4999") + }); + test.done(); +}), true); + +wsocket.addEventListener('close', test.unreached_func('close event should not fire'), true); diff --git a/testing/web-platform/tests/websockets/Close-3000-reason.any.js b/testing/web-platform/tests/websockets/Close-3000-reason.any.js new file mode 100644 index 0000000000..8e34ce7c05 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-3000-reason.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close(3000, reason) - readyState should be in CLOSED state and wasClean is TRUE - Connection should be closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.close(3000, "Clean Close with code - 3000"); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(wsocket.readyState, 3, "readyState should be 3(CLOSED)"); + assert_equals(evt.wasClean, true, "wasClean should be TRUE"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-3000-verify-code.any.js b/testing/web-platform/tests/websockets/Close-3000-verify-code.any.js new file mode 100644 index 0000000000..a6703dec16 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-3000-verify-code.any.js @@ -0,0 +1,20 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close(3000, reason) - verify return code is 3000 - Connection should be closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.close(3000, "Clean Close"); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(evt.code, 3000, "CloseEvent.code should be 3000"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-4999-reason.any.js b/testing/web-platform/tests/websockets/Close-4999-reason.any.js new file mode 100644 index 0000000000..8c2a1c9ad9 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-4999-reason.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close(4999, reason) - readyState should be in CLOSED state and wasClean is TRUE - Connection should be closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.close(3000, "Clean Close with code - 4999"); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(wsocket.readyState, 3, "readyState should be 3(CLOSED)"); + assert_equals(evt.wasClean, true, "wasClean should be TRUE"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-Reason-124Bytes.any.js b/testing/web-platform/tests/websockets/Close-Reason-124Bytes.any.js new file mode 100644 index 0000000000..063b12be16 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-Reason-124Bytes.any.js @@ -0,0 +1,20 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Create WebSocket - Close the Connection - close(code, 'reason more than 123 bytes') - SYNTAX_ERR is thrown"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + var reason = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123"; + assert_equals(reason.length, 124); + assert_throws_dom("SYNTAX_ERR", function() { + wsocket.close(1000, reason) + }); + test.done(); +}), true); + +wsocket.addEventListener('close', test.unreached_func('close event should not fire'), true); diff --git a/testing/web-platform/tests/websockets/Close-delayed.any.js b/testing/web-platform/tests/websockets/Close-delayed.any.js new file mode 100644 index 0000000000..9e0a60cc6a --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-delayed.any.js @@ -0,0 +1,27 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close should not emit until handshake completes - Connection should be closed"); + +var wsocket = new WebSocket(`${SCHEME_DOMAIN_PORT}/delayed-passive-close`); +var startTime; +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + startTime = performance.now(); + wsocket.close(); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + const elapsed = performance.now() - startTime; + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(wsocket.readyState, 3, "readyState should be 3(CLOSED)"); + assert_equals(evt.wasClean, true, "wasClean should be TRUE"); + const jitterAllowance = 100; + assert_greater_than_equal(elapsed, 1000 - jitterAllowance, + 'one second should have elapsed') + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-onlyReason.any.js b/testing/web-platform/tests/websockets/Close-onlyReason.any.js new file mode 100644 index 0000000000..243eb05e73 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-onlyReason.any.js @@ -0,0 +1,17 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close(only reason) - INVALID_ACCESS_ERR is thrown"); + +var wsocket = CreateWebSocket(false, false); + +wsocket.addEventListener('open', test.step_func(function(evt) { + assert_throws_dom("INVALID_ACCESS_ERR", function() { + wsocket.close("Close with only reason") + }); + test.done(); +}), true); + +wsocket.addEventListener('close', test.unreached_func('close event should not fire'), true); diff --git a/testing/web-platform/tests/websockets/Close-readyState-Closed.any.js b/testing/web-platform/tests/websockets/Close-readyState-Closed.any.js new file mode 100644 index 0000000000..6c7b5f1132 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-readyState-Closed.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - readyState should be in CLOSED state and wasClean is TRUE - Connection should be closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.close(); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(wsocket.readyState, 3, "readyState should be 3(CLOSED)"); + assert_equals(evt.wasClean, true, "wasClean should be TRUE"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-readyState-Closing.any.js b/testing/web-platform/tests/websockets/Close-readyState-Closing.any.js new file mode 100644 index 0000000000..221130b8f7 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-readyState-Closing.any.js @@ -0,0 +1,20 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - readyState should be in CLOSING state just before onclose is called"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + isOpenCalled = true; + wsocket.close(); + assert_equals(wsocket.readyState, 2, "readyState should be 2(CLOSING)"); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, 'open must be called'); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-reason-unpaired-surrogates.any.js b/testing/web-platform/tests/websockets/Close-reason-unpaired-surrogates.any.js new file mode 100644 index 0000000000..e5a71d2735 --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-reason-unpaired-surrogates.any.js @@ -0,0 +1,22 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Close the Connection - close(reason with unpaired surrogates) - connection should get closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var replacementChar = "\uFFFD"; +var reason = "\uD807"; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.close(1000, reason); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be opened"); + assert_equals(evt.reason, replacementChar, "reason replaced with replacement character"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-server-initiated-close.any.js b/testing/web-platform/tests/websockets/Close-server-initiated-close.any.js new file mode 100644 index 0000000000..82fd457e1e --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-server-initiated-close.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Create WebSocket - Server initiated Close - Client sends back a CLOSE - readyState should be in CLOSED state and wasClean is TRUE - Connection should be closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.send("Goodbye"); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(wsocket.readyState, 3, "readyState should be 3(CLOSED)"); + assert_equals(evt.wasClean, true, "wasClean should be TRUE"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Close-undefined.any.js b/testing/web-platform/tests/websockets/Close-undefined.any.js new file mode 100644 index 0000000000..e24ef0c3db --- /dev/null +++ b/testing/web-platform/tests/websockets/Close-undefined.any.js @@ -0,0 +1,19 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test(); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + isOpenCalled = true; + wsocket.close(undefined); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, 'open event must fire'); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Create-asciiSep-protocol-string.any.js b/testing/web-platform/tests/websockets/Create-asciiSep-protocol-string.any.js new file mode 100644 index 0000000000..d0102ce533 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-asciiSep-protocol-string.any.js @@ -0,0 +1,12 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +test(function() { + var asciiWithSep = "/echo"; + var wsocket; + assert_throws_dom("SYNTAX_ERR", function() { + wsocket = CreateWebSocketWithAsciiSep(asciiWithSep) + }); +}, "Create WebSocket - Pass a valid URL and a protocol string with an ascii separator character - SYNTAX_ERR is thrown") diff --git a/testing/web-platform/tests/websockets/Create-blocked-port.any.js b/testing/web-platform/tests/websockets/Create-blocked-port.any.js new file mode 100644 index 0000000000..2962312ff5 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-blocked-port.any.js @@ -0,0 +1,97 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +async_test(t => { + const ws = CreateWebSocketWithBlockedPort(__PORT) + ws.onerror = t.unreached_func() + ws.onopen = t.step_func_done() +}, 'Basic check'); +// list of bad ports according to +// https://fetch.spec.whatwg.org/#port-blocking +[ + 1, // tcpmux + 7, // echo + 9, // discard + 11, // systat + 13, // daytime + 15, // netstat + 17, // qotd + 19, // chargen + 20, // ftp-data + 21, // ftp + 22, // ssh + 23, // telnet + 25, // smtp + 37, // time + 42, // name + 43, // nicname + 53, // domain + 69, // tftp + 77, // priv-rjs + 79, // finger + 87, // ttylink + 95, // supdup + 101, // hostriame + 102, // iso-tsap + 103, // gppitnp + 104, // acr-nema + 109, // pop2 + 110, // pop3 + 111, // sunrpc + 113, // auth + 115, // sftp + 117, // uucp-path + 119, // nntp + 123, // ntp + 135, // loc-srv / epmap + 137, // netbios-ns + 139, // netbios-ssn + 143, // imap2 + 179, // bgp + 389, // ldap + 427, // afp (alternate) + 465, // smtp (alternate) + 512, // print / exec + 513, // login + 514, // shell + 515, // printer + 526, // tempo + 530, // courier + 531, // chat + 532, // netnews + 540, // uucp + 548, // afp + 554, // rtsp + 556, // remotefs + 563, // nntp+ssl + 587, // smtp (outgoing) + 601, // syslog-conn + 636, // ldap+ssl + 989, // ftps-data + 990, // ftps + 993, // ldap+ssl + 995, // pop3+ssl + 1719, // h323gatestat + 1720, // h323hostcall + 1723, // pptp + 2049, // nfs + 3659, // apple-sasl + 4045, // lockd + 6000, // x11 + 6566, // sane-port + 6665, // irc (alternate) + 6666, // irc (alternate) + 6667, // irc (default) + 6668, // irc (alternate) + 6669, // irc (alternate) + 6697, // irc+tls + 10080, // amanda +].forEach(blockedPort => { + async_test(t => { + const ws = CreateWebSocketWithBlockedPort(blockedPort) + ws.onerror = t.step_func_done() + ws.onopen = t.unreached_func() + }, "WebSocket blocked port test " + blockedPort) +}) diff --git a/testing/web-platform/tests/websockets/Create-extensions-empty.any.js b/testing/web-platform/tests/websockets/Create-extensions-empty.any.js new file mode 100644 index 0000000000..98a7d65ab5 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-extensions-empty.any.js @@ -0,0 +1,20 @@ +// META: timeout=long +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Create WebSocket - wsocket.extensions should be set to '' after connection is established - Connection should be closed"); + +var wsocket = new WebSocket(SCHEME_DOMAIN_PORT + "/handshake_no_extensions"); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func_done(function(evt) { + wsocket.close(); + isOpenCalled = true; + assert_equals(wsocket.extensions, "", "extensions should be empty"); +}), true); + +wsocket.addEventListener('close', test.step_func_done(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be closed"); +}), true); diff --git a/testing/web-platform/tests/websockets/Create-http-urls.any.js b/testing/web-platform/tests/websockets/Create-http-urls.any.js new file mode 100644 index 0000000000..17590fc43e --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-http-urls.any.js @@ -0,0 +1,19 @@ +test(() => { + const url = new URL ("/", location); + url.protocol = "http"; + const httpURL = url.href; + url.protocol = "https"; + const httpsURL = url.href; + url.protocol = "ws"; + const wsURL = url.href; + url.protocol = "wss"; + const wssURL = url.href; + + let ws = new WebSocket(httpURL); + assert_equals(ws.url, wsURL); + ws.close(); + + ws = new WebSocket(httpsURL); + assert_equals(ws.url, wssURL); + ws.close(); +}, "WebSocket: ensure both HTTP schemes are supported"); diff --git a/testing/web-platform/tests/websockets/Create-invalid-urls.any.js b/testing/web-platform/tests/websockets/Create-invalid-urls.any.js new file mode 100644 index 0000000000..73c9fadab9 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-invalid-urls.any.js @@ -0,0 +1,14 @@ +[ + "ws://foo bar.com/", + "wss://foo bar.com/", + "ftp://"+location.host+"/", + "mailto:example@example.org", + "about:blank", + location.origin + "/#", + location.origin + "/#test", + "#test" +].forEach(input => { + test(() => { + assert_throws_dom("SyntaxError", () => new WebSocket(input)); + }, `new WebSocket("${input}") should throw a "SyntaxError" DOMException`); +}); diff --git a/testing/web-platform/tests/websockets/Create-non-absolute-url.any.js b/testing/web-platform/tests/websockets/Create-non-absolute-url.any.js new file mode 100644 index 0000000000..5a7b1794d0 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-non-absolute-url.any.js @@ -0,0 +1,14 @@ +[ + "test", + "?", + null, + 123, +].forEach(input => { + test(() => { + const url = new URL(input, location); + url.protocol = "ws"; + const ws = new WebSocket(input); + assert_equals(ws.url, url.href); + ws.close(); + }, `Create WebSocket - Pass a non absolute URL: ${input}`); +}); diff --git a/testing/web-platform/tests/websockets/Create-nonAscii-protocol-string.any.js b/testing/web-platform/tests/websockets/Create-nonAscii-protocol-string.any.js new file mode 100644 index 0000000000..fda926a9d5 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-nonAscii-protocol-string.any.js @@ -0,0 +1,12 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +test(function() { + var nonAsciiProtocol = "\u0080echo"; + var wsocket; + assert_throws_dom("SYNTAX_ERR", function() { + wsocket = CreateWebSocketNonAsciiProtocol(nonAsciiProtocol) + }); +}, "Create WebSocket - Pass a valid URL and a protocol string with non-ascii values - SYNTAX_ERR is thrown") diff --git a/testing/web-platform/tests/websockets/Create-on-worker-shutdown.any.js b/testing/web-platform/tests/websockets/Create-on-worker-shutdown.any.js new file mode 100644 index 0000000000..218bf7cf19 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-on-worker-shutdown.any.js @@ -0,0 +1,26 @@ +async_test(t => { + function workerCode() { + close(); + var ws = new WebSocket(self.location.origin.replace('http', 'ws')); + var data = { + originalState: ws.readyState, + afterCloseState: null + }; + + ws.close(); + + data.afterCloseState = ws.readyState; + postMessage(data); + } + + var workerBlob = new Blob([workerCode.toString() + ";workerCode();"], { + type: "application/javascript" + }); + + var w = new Worker(URL.createObjectURL(workerBlob)); + w.onmessage = t.step_func(function(e) { + assert_equals(e.data.originalState, WebSocket.CONNECTING, "WebSocket created on worker shutdown is in connecting state."); + assert_equals(e.data.afterCloseState, WebSocket.CLOSING, "Closed WebSocket created on worker shutdown is in closing state."); + t.done(); + }); +}, 'WebSocket created after a worker self.close()'); diff --git a/testing/web-platform/tests/websockets/Create-protocol-with-space.any.js b/testing/web-platform/tests/websockets/Create-protocol-with-space.any.js new file mode 100644 index 0000000000..a85d4e5df9 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-protocol-with-space.any.js @@ -0,0 +1,11 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +test(function() { + var wsocket; + assert_throws_dom("SYNTAX_ERR", function() { + wsocket = CreateWebSocketWithSpaceInProtocol("ec ho") + }); +}, "Create WebSocket - Pass a valid URL and a protocol string with a space in it - SYNTAX_ERR is thrown") diff --git a/testing/web-platform/tests/websockets/Create-protocols-repeated-case-insensitive.any.js b/testing/web-platform/tests/websockets/Create-protocols-repeated-case-insensitive.any.js new file mode 100644 index 0000000000..1a508e87d3 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-protocols-repeated-case-insensitive.any.js @@ -0,0 +1,11 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +test(function() { + var wsocket; + assert_throws_dom("SYNTAX_ERR", function() { + wsocket = CreateWebSocketWithRepeatedProtocolsCaseInsensitive() + }); +}, "Create WebSocket - Pass a valid URL and an array of protocol strings with repeated values but different case - SYNTAX_ERR is thrown") diff --git a/testing/web-platform/tests/websockets/Create-protocols-repeated.any.js b/testing/web-platform/tests/websockets/Create-protocols-repeated.any.js new file mode 100644 index 0000000000..2f12a47f96 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-protocols-repeated.any.js @@ -0,0 +1,11 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +test(function() { + var wsocket; + assert_throws_dom("SYNTAX_ERR", function() { + wsocket = CreateWebSocketWithRepeatedProtocols() + }); +}, "Create WebSocket - Pass a valid URL and an array of protocol strings with repeated values - SYNTAX_ERR is thrown") diff --git a/testing/web-platform/tests/websockets/Create-url-with-space.any.js b/testing/web-platform/tests/websockets/Create-url-with-space.any.js new file mode 100644 index 0000000000..f2bea5b9d9 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-url-with-space.any.js @@ -0,0 +1,12 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +test(function() { + var wsocket; + var spaceUrl = "web platform.test"; + assert_throws_dom("SYNTAX_ERR", function() { + wsocket = CreateWebSocketWithSpaceInUrl(spaceUrl) + }); +}, "Create WebSocket - Pass a URL with a space - SYNTAX_ERR should be thrown") diff --git a/testing/web-platform/tests/websockets/Create-url-with-windows-1252-encoding.html b/testing/web-platform/tests/websockets/Create-url-with-windows-1252-encoding.html new file mode 100644 index 0000000000..6596b5e1a0 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-url-with-windows-1252-encoding.html @@ -0,0 +1,20 @@ +<!doctype html> +<meta charset=windows-1252> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +test(() => { + const url = new URL("/", location); + url.protocol = "ws"; + const input = "?\u20AC"; + const expected = url.href + "?%E2%82%AC"; + + let ws = new WebSocket(url.href + input); + assert_equals(ws.url, expected); + ws.close(); + + ws = new WebSocket("/" + input); + assert_equals(ws.url, expected); + ws.close(); +}, "URL's percent-encoding is always in UTF-8 for WebSocket"); +</script> diff --git a/testing/web-platform/tests/websockets/Create-valid-url-array-protocols.any.js b/testing/web-platform/tests/websockets/Create-valid-url-array-protocols.any.js new file mode 100644 index 0000000000..fe71fd7ca2 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-valid-url-array-protocols.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Create WebSocket - Pass a valid URL and array of protocol strings - Connection should be closed"); + +var wsocket = CreateWebSocket(false, true); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + assert_equals(wsocket.readyState, 1, "readyState should be 1(OPEN)"); + wsocket.close(); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Create-valid-url-binaryType-blob.any.js b/testing/web-platform/tests/websockets/Create-valid-url-binaryType-blob.any.js new file mode 100644 index 0000000000..7840ff314f --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-valid-url-binaryType-blob.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Create WebSocket - wsocket.binaryType should be set to 'blob' after connection is established - Connection should be closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + assert_equals(wsocket.binaryType, "blob", "binaryType should be set to Blob"); + wsocket.close(); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Create-valid-url-protocol-empty.any.js b/testing/web-platform/tests/websockets/Create-valid-url-protocol-empty.any.js new file mode 100644 index 0000000000..f18a9d8908 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-valid-url-protocol-empty.any.js @@ -0,0 +1,10 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +test(function() { + var wsocket = CreateWebSocket(true, false); + assert_equals(wsocket.protocol, "", "protocol should be empty"); + wsocket.close(); +}, "Create WebSocket - wsocket.protocol should be empty before connection is established") diff --git a/testing/web-platform/tests/websockets/Create-valid-url-protocol-setCorrectly.any.js b/testing/web-platform/tests/websockets/Create-valid-url-protocol-setCorrectly.any.js new file mode 100644 index 0000000000..c5d06ac84c --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-valid-url-protocol-setCorrectly.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Create WebSocket - Pass a valid URL and protocol string - Connection should be closed"); + +var wsocket = CreateWebSocket(true, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + assert_equals(wsocket.protocol, "echo", "protocol should be set to echo"); + wsocket.close(); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Create-valid-url-protocol-string.any.js b/testing/web-platform/tests/websockets/Create-valid-url-protocol-string.any.js new file mode 100644 index 0000000000..10e928d333 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-valid-url-protocol-string.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - Pass a valid URL and protocol string - Connection should be closed"); + +var wsocket = CreateWebSocket(true, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + assert_equals(wsocket.readyState, 1, "readyState should be 1(OPEN)"); + wsocket.close(); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Create-valid-url-protocol.any.js b/testing/web-platform/tests/websockets/Create-valid-url-protocol.any.js new file mode 100644 index 0000000000..37b5a0e886 --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-valid-url-protocol.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Create WebSocket - Pass a valid URL and a protocol string - Connection should be closed"); + +var wsocket = CreateWebSocket(true, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + assert_equals(wsocket.readyState, 1, "readyState should be 1(OPEN)"); + wsocket.close(); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Create-valid-url.any.js b/testing/web-platform/tests/websockets/Create-valid-url.any.js new file mode 100644 index 0000000000..1df995fb8b --- /dev/null +++ b/testing/web-platform/tests/websockets/Create-valid-url.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Create WebSocket - Pass a valid URL - Connection should be closed"); + +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + assert_equals(wsocket.readyState, 1, "readyState should be 1(OPEN)"); + wsocket.close(); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/META.yml b/testing/web-platform/tests/websockets/META.yml new file mode 100644 index 0000000000..77a6bff0bf --- /dev/null +++ b/testing/web-platform/tests/websockets/META.yml @@ -0,0 +1,5 @@ +spec: https://websockets.spec.whatwg.org/ +suggested_reviewers: + - jdm + - ricea + - yutakahirano diff --git a/testing/web-platform/tests/websockets/README.md b/testing/web-platform/tests/websockets/README.md new file mode 100644 index 0000000000..ea35c702ae --- /dev/null +++ b/testing/web-platform/tests/websockets/README.md @@ -0,0 +1 @@ +Tests for the [WebSockets Standard](https://websockets.spec.whatwg.org/). diff --git a/testing/web-platform/tests/websockets/Send-0byte-data.any.js b/testing/web-platform/tests/websockets/Send-0byte-data.any.js new file mode 100644 index 0000000000..4176de411c --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-0byte-data.any.js @@ -0,0 +1,30 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Send 0 byte data on a WebSocket - Connection should be closed"); + +var data = ""; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.send(data); + assert_equals(data.length, wsocket.bufferedAmount); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + assert_equals(evt.data, data); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-65K-data.any.js b/testing/web-platform/tests/websockets/Send-65K-data.any.js new file mode 100644 index 0000000000..20e5ba7c94 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-65K-data.any.js @@ -0,0 +1,33 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send 65K data on a WebSocket - Connection should be closed"); + +var data = ""; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + for (var i = 0; i < 65000; i++) { + data = data + "c"; + } + wsocket.send(data); + assert_equals(data.length, wsocket.bufferedAmount); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + assert_equals(evt.data, data); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-before-open.any.js b/testing/web-platform/tests/websockets/Send-before-open.any.js new file mode 100644 index 0000000000..4fdbf71c6f --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-before-open.any.js @@ -0,0 +1,11 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +test(function() { + var wsocket = CreateWebSocket(false, false); + assert_throws_dom("INVALID_STATE_ERR", function() { + wsocket.send("Message to send") + }); +}, "Send data on a WebSocket before connection is opened - INVALID_STATE_ERR is returned") diff --git a/testing/web-platform/tests/websockets/Send-binary-65K-arraybuffer.any.js b/testing/web-platform/tests/websockets/Send-binary-65K-arraybuffer.any.js new file mode 100644 index 0000000000..6bee660bb3 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-65K-arraybuffer.any.js @@ -0,0 +1,33 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send 65K binary data on a WebSocket - ArrayBuffer - Connection should be closed"); + +var data = ""; +var datasize = 65000; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + wsocket.send(data); + assert_equals(datasize, wsocket.bufferedAmount); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + assert_equals(evt.data.byteLength, datasize); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-arraybuffer.any.js b/testing/web-platform/tests/websockets/Send-binary-arraybuffer.any.js new file mode 100644 index 0000000000..0b34e0cfc9 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-arraybuffer.any.js @@ -0,0 +1,33 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send binary data on a WebSocket - ArrayBuffer - Connection should be closed"); + +var data = ""; +var datasize = 15; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + wsocket.send(data); + assert_equals(datasize, wsocket.bufferedAmount); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + assert_equals(evt.data.byteLength, datasize); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-arraybufferview-float32.any.js b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-float32.any.js new file mode 100644 index 0000000000..47ee5b1170 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-float32.any.js @@ -0,0 +1,40 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send binary data on a WebSocket - ArrayBufferView - Float32Array - Connection should be closed"); + +var data = ""; +var datasize = 8; +var view; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + view = new Float32Array(data); + for (var i = 0; i < 2; i++) { + view[i] = i; + } + wsocket.send(view); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + var resultView = new Float32Array(evt.data); + for (var i = 0; i < resultView.length; i++) { + assert_equals(resultView[i], view[i], "ArrayBufferView returned is the same"); + } + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-arraybufferview-float64.any.js b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-float64.any.js new file mode 100644 index 0000000000..78bcb13d43 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-float64.any.js @@ -0,0 +1,40 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send binary data on a WebSocket - ArrayBufferView - Float64Array - Connection should be closed"); + +var data = ""; +var datasize = 8; +var view; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + view = new Float64Array(data); + for (var i = 0; i < 1; i++) { + view[i] = i; + } + wsocket.send(view); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + var resultView = new Float64Array(evt.data); + for (var i = 0; i < resultView.length; i++) { + assert_equals(resultView[i], view[i], "ArrayBufferView returned is the same"); + } + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-arraybufferview-int16-offset.any.js b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-int16-offset.any.js new file mode 100644 index 0000000000..3dd64552b0 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-int16-offset.any.js @@ -0,0 +1,40 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send binary data on a WebSocket - ArrayBufferView - Int16Array with offset - Connection should be closed"); + +var data = ""; +var datasize = 8; +var view; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + view = new Int16Array(data, 2); + for (var i = 0; i < 4; i++) { + view[i] = i; + } + wsocket.send(view); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + var resultView = new Int16Array(evt.data); + for (var i = 0; i < resultView.length; i++) { + assert_equals(resultView[i], view[i], "ArrayBufferView returned is the same"); + } + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-arraybufferview-int32.any.js b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-int32.any.js new file mode 100644 index 0000000000..853ba39b4b --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-int32.any.js @@ -0,0 +1,40 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send binary data on a WebSocket - ArrayBufferView - Int32Array - Connection should be closed"); + +var data = ""; +var datasize = 8; +var view; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + view = new Int32Array(data); + for (var i = 0; i < 2; i++) { + view[i] = i; + } + wsocket.send(view); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + var resultView = new Int32Array(evt.data); + for (var i = 0; i < resultView.length; i++) { + assert_equals(resultView[i], view[i], "ArrayBufferView returned is the same"); + } + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-arraybufferview-int8.any.js b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-int8.any.js new file mode 100644 index 0000000000..aa90020bba --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-int8.any.js @@ -0,0 +1,40 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Send binary data on a WebSocket - ArrayBufferView - Int8Array - Connection should be closed"); + +var data = ""; +var datasize = 8; +var int8View; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + int8View = new Int8Array(data); + for (var i = 0; i < 8; i++) { + int8View[i] = i; + } + wsocket.send(int8View); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + var resultView = new Int8Array(evt.data); + for (var i = 0; i < resultView.length; i++) { + assert_equals(resultView[i], int8View[i], "ArrayBufferView returned is the same"); + } + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint16-offset-length.any.js b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint16-offset-length.any.js new file mode 100644 index 0000000000..a3c1f326a5 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint16-offset-length.any.js @@ -0,0 +1,40 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send binary data on a WebSocket - ArrayBufferView - Uint16Array with offset and length - Connection should be closed"); + +var data = ""; +var datasize = 8; +var view; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + view = new Uint16Array(data, 2, 2); + for (var i = 0; i < 4; i++) { + view[i] = i; + } + wsocket.send(view); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + var resultView = new Uint16Array(evt.data); + for (var i = 0; i < resultView.length; i++) { + assert_equals(resultView[i], view[i], "ArrayBufferView returned is the same"); + } + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint32-offset.any.js b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint32-offset.any.js new file mode 100644 index 0000000000..fede995450 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint32-offset.any.js @@ -0,0 +1,40 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send binary data on a WebSocket - ArrayBufferView - Uint32Array with offset - Connection should be closed"); + +var data = ""; +var datasize = 8; +var view; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + view = new Uint32Array(data, 0); + for (var i = 0; i < 2; i++) { + view[i] = i; + } + wsocket.send(view); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + var resultView = new Uint32Array(evt.data); + for (var i = 0; i < resultView.length; i++) { + assert_equals(resultView[i], view[i], "ArrayBufferView returned is the same"); + } + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint8-offset-length.any.js b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint8-offset-length.any.js new file mode 100644 index 0000000000..de3ae00f27 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint8-offset-length.any.js @@ -0,0 +1,40 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send binary data on a WebSocket - ArrayBufferView - Uint8Array with offset and length - Connection should be closed"); + +var data = ""; +var datasize = 8; +var view; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + view = new Uint8Array(data, 2, 4); + for (var i = 0; i < 8; i++) { + view[i] = i; + } + wsocket.send(view); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + var resultView = new Uint8Array(evt.data); + for (var i = 0; i < resultView.length; i++) { + assert_equals(resultView[i], view[i], "ArrayBufferView returned is the same"); + } + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint8-offset.any.js b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint8-offset.any.js new file mode 100644 index 0000000000..089174b384 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-arraybufferview-uint8-offset.any.js @@ -0,0 +1,40 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send binary data on a WebSocket - ArrayBufferView - Uint8Array with offset - Connection should be closed"); + +var data = ""; +var datasize = 8; +var view; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + view = new Uint8Array(data, 2); + for (var i = 0; i < 8; i++) { + view[i] = i; + } + wsocket.send(view); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + var resultView = new Uint8Array(evt.data); + for (var i = 0; i < resultView.length; i++) { + assert_equals(resultView[i], view[i], "ArrayBufferView returned is the same"); + } + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received") + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-binary-blob.any.js b/testing/web-platform/tests/websockets/Send-binary-blob.any.js new file mode 100644 index 0000000000..5131b716b4 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-binary-blob.any.js @@ -0,0 +1,36 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send binary data on a WebSocket - Blob - Connection should be closed"); + +var data = ""; +var datasize = 65000; +var isOpenCalled = false; +var isMessageCalled = false; + +var wsocket = CreateWebSocket(false, false); + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.binaryType = "blob"; + for (var i = 0; i < datasize; i++) + data += String.fromCharCode(0); + data = new Blob([data]); + isOpenCalled = true; + wsocket.send(data); +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + assert_true(evt.data instanceof Blob); + assert_equals(evt.data.size, datasize); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received"); + assert_true(evt.wasClean, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-data.any.js b/testing/web-platform/tests/websockets/Send-data.any.js new file mode 100644 index 0000000000..a606ada310 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-data.any.js @@ -0,0 +1,30 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Send data on a WebSocket - Connection should be closed"); + +var data = "Message to send"; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.send(data); + assert_equals(data.length, wsocket.bufferedAmount); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + assert_equals(evt.data, data); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isMessageCalled, "message should be received"); + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-data.worker.js b/testing/web-platform/tests/websockets/Send-data.worker.js new file mode 100644 index 0000000000..5a8bdd5fa3 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-data.worker.js @@ -0,0 +1,26 @@ +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +importScripts("/resources/testharness.js"); +importScripts('constants.sub.js') + +var data = "test data"; + +async_test(function(t) { + + var wsocket = CreateWebSocket(false, false); + + wsocket.addEventListener('open', function (e) { + wsocket.send(data) + }, true) + + wsocket.addEventListener('message', t.step_func_done(function(e) { + assert_equals(e.data, data); + }), true); + + wsocket.addEventListener('close', t.unreached_func('the close event should not fire'), true); + +}, "Send data on a WebSocket in a Worker") + +done(); diff --git a/testing/web-platform/tests/websockets/Send-null.any.js b/testing/web-platform/tests/websockets/Send-null.any.js new file mode 100644 index 0000000000..e621bb892b --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-null.any.js @@ -0,0 +1,32 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send null data on a WebSocket - Connection should be closed"); + +var data = null; +var nullReturned = false; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.send(data); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + if ("null" == evt.data || "" == evt.data) + nullReturned = true; + assert_true(nullReturned); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-paired-surrogates.any.js b/testing/web-platform/tests/websockets/Send-paired-surrogates.any.js new file mode 100644 index 0000000000..51e4fb965e --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-paired-surrogates.any.js @@ -0,0 +1,30 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send paired surrogates data on a WebSocket - Connection should be closed"); + +var data = "\uD801\uDC07"; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.send(data); + assert_equals(data.length * 2, wsocket.bufferedAmount); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + assert_equals(evt.data, data); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-unicode-data.any.js b/testing/web-platform/tests/websockets/Send-unicode-data.any.js new file mode 100644 index 0000000000..a3556b26ab --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-unicode-data.any.js @@ -0,0 +1,30 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +var test = async_test("Send unicode data on a WebSocket - Connection should be closed"); + +var data = "¥¥¥¥¥¥"; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.send(data); + assert_equals(data.length * 2, wsocket.bufferedAmount); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + assert_equals(evt.data, data); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/Send-unpaired-surrogates.any.js b/testing/web-platform/tests/websockets/Send-unpaired-surrogates.any.js new file mode 100644 index 0000000000..cbbcc6ebf6 --- /dev/null +++ b/testing/web-platform/tests/websockets/Send-unpaired-surrogates.any.js @@ -0,0 +1,30 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Send unpaired surrogates on a WebSocket - Connection should be closed"); + +var data = "\uD807"; +var replacementChar = "\uFFFD"; +var wsocket = CreateWebSocket(false, false); +var isOpenCalled = false; +var isMessageCalled = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + wsocket.send(data); + isOpenCalled = true; +}), true); + +wsocket.addEventListener('message', test.step_func(function(evt) { + isMessageCalled = true; + assert_equals(evt.data, replacementChar); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(isOpenCalled, "WebSocket connection should be open"); + assert_true(isMessageCalled, "message should be received"); + assert_equals(evt.wasClean, true, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js b/testing/web-platform/tests/websockets/back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js new file mode 100644 index 0000000000..f6ee5edeaa --- /dev/null +++ b/testing/web-platform/tests/websockets/back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js @@ -0,0 +1,31 @@ +// META: title=Testing BFCache support for page with closed WebSocket connection and "Cache-Control: no-store" header. +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: script=resources/websockets-test-helpers.sub.js + +'use strict'; + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ { headers: [['Cache-Control', 'no-store']] }, + /*options=*/ { features: 'noopener' } + ); + // Make sure that we only run the remaining of the test when page with + // "Cache-Control: no-store" header is eligible for BFCache. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ true); + + await openThenCloseWebSocket(rc1); + // The page should not be eligible for BFCache because of the usage + // of WebSocket. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredFromBFCache(rc1, [ + 'WebSocketSticky', + 'MainResourceHasCacheControlNoStore' + ]); +}); diff --git a/testing/web-platform/tests/websockets/back-forward-cache-with-closed-websocket-connection.window.js b/testing/web-platform/tests/websockets/back-forward-cache-with-closed-websocket-connection.window.js new file mode 100644 index 0000000000..30b8e63a2c --- /dev/null +++ b/testing/web-platform/tests/websockets/back-forward-cache-with-closed-websocket-connection.window.js @@ -0,0 +1,20 @@ +// META: title=Testing BFCache support for page with closed WebSocket connection. +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: script=resources/websockets-test-helpers.sub.js + +'use strict'; + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ { features: 'noopener' }); + await openThenCloseWebSocket(rc1); + // The page should be eligible for BFCache because the WebSocket connection has been closed. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ true); +}); diff --git a/testing/web-platform/tests/websockets/back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js b/testing/web-platform/tests/websockets/back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js new file mode 100644 index 0000000000..f37a04af91 --- /dev/null +++ b/testing/web-platform/tests/websockets/back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js @@ -0,0 +1,32 @@ +// META: title=Testing BFCache support for page with open WebSocket connection and "Cache-Control: no-store" header. +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: script=resources/websockets-test-helpers.sub.js + +'use strict'; + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ { headers: [['Cache-Control', 'no-store']] }, + /*options=*/ { features: 'noopener' } + ); + // Make sure that we only run the remaining of the test when page with + // "Cache-Control: no-store" header is eligible for BFCache. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ true); + + await openWebSocket(rc1); + // The page should not be eligible for BFCache because of the usage + // of WebSocket. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredFromBFCache(rc1, [ + 'WebSocket', + 'WebSocketSticky', + 'MainResourceHasCacheControlNoStore' + ]); +}); diff --git a/testing/web-platform/tests/websockets/back-forward-cache-with-open-websocket-connection.window.js b/testing/web-platform/tests/websockets/back-forward-cache-with-open-websocket-connection.window.js new file mode 100644 index 0000000000..6c48a57010 --- /dev/null +++ b/testing/web-platform/tests/websockets/back-forward-cache-with-open-websocket-connection.window.js @@ -0,0 +1,21 @@ +// META: title=Testing BFCache support for page with open WebSocket connection. +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/websockets/constants.sub.js +// META: script=resources/websockets-test-helpers.sub.js + +'use strict'; + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*config=*/ null, /*options=*/ { features: 'noopener' }); + await openWebSocket(rc1); + // The page should not be eligible for BFCache because of open WebSocket connection. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ false); + await assertNotRestoredFromBFCache(rc1, ['websocket']); +}); diff --git a/testing/web-platform/tests/websockets/basic-auth.any.js b/testing/web-platform/tests/websockets/basic-auth.any.js new file mode 100644 index 0000000000..9fbdc5d5ce --- /dev/null +++ b/testing/web-platform/tests/websockets/basic-auth.any.js @@ -0,0 +1,17 @@ +// META: global=window,worker +// META: script=constants.sub.js +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +async_test(t => { + const url = __SCHEME + '://' + 'foo:bar@' + __SERVER__NAME + ':' + __PORT + '/basic_auth'; + const ws = new WebSocket(url); + ws.onopen = () => { + ws.onclose = ws.onerror = null; + ws.close(); + t.done(); + }; + ws.onerror = ws.onclose = t.unreached_func('open should succeed'); +}, 'HTTP basic authentication should work with WebSockets'); + +done(); diff --git a/testing/web-platform/tests/websockets/binary/001.html b/testing/web-platform/tests/websockets/binary/001.html new file mode 100644 index 0000000000..077bf79def --- /dev/null +++ b/testing/web-platform/tests/websockets/binary/001.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>WebSockets: Send/Receive blob, blob size less than network array buffer</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT + '/echo'); + var data = ""; + var datasize = 10; + ws.onopen = t.step_func(function(e) { + ws.binaryType = "blob"; + data = new ArrayBuffer(datasize); + ws.send(data); + }) + ws.onmessage = t.step_func(function(e) { + assert_true(e.data instanceof Blob); + assert_equals(e.data.size, datasize); + t.done(); + }) + ws.onclose = t.unreached_func('close event should not fire'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/binary/002.html b/testing/web-platform/tests/websockets/binary/002.html new file mode 100644 index 0000000000..558777694b --- /dev/null +++ b/testing/web-platform/tests/websockets/binary/002.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>WebSockets: Send/Receive blob, blob size greater than network array buffer</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var data = ""; + var datasize = 100000; + ws.onopen = t.step_func(function(e) { + ws.binaryType = "blob"; + data = new ArrayBuffer(datasize); + ws.send(data); + }); + ws.onmessage = t.step_func(function(e) { + assert_true(e.data instanceof Blob); + assert_equals(e.data.size, datasize); + t.done(); + }); + ws.onclose = t.unreached_func('close event should not fire'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/binary/004.html b/testing/web-platform/tests/websockets/binary/004.html new file mode 100644 index 0000000000..8ca4e923ea --- /dev/null +++ b/testing/web-platform/tests/websockets/binary/004.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>WebSockets: Send/Receive ArrayBuffer, size greater than network array buffer</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var data = ""; + var datasize = 100000; + ws.onopen = t.step_func(function(e) { + ws.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + ws.send(data); + }) + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data.byteLength, datasize); + t.done(); + }) + ws.onclose = t.unreached_func('close event should not fire'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/binary/005.html b/testing/web-platform/tests/websockets/binary/005.html new file mode 100644 index 0000000000..e89f4c0e83 --- /dev/null +++ b/testing/web-platform/tests/websockets/binary/005.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>WebSockets: Send/Receive ArrayBuffer, size less than network array buffer</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var data = ""; + var datasize = 10; + ws.onopen = t.step_func(function(e) { + ws.binaryType = "arraybuffer"; + data = new ArrayBuffer(datasize); + ws.send(data); + }); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data.byteLength, datasize); + t.done(); + }); + ws.onclose = t.unreached_func('close event should not fire'); + }); +</script> diff --git a/testing/web-platform/tests/websockets/binaryType-wrong-value.any.js b/testing/web-platform/tests/websockets/binaryType-wrong-value.any.js new file mode 100644 index 0000000000..683fb47bed --- /dev/null +++ b/testing/web-platform/tests/websockets/binaryType-wrong-value.any.js @@ -0,0 +1,23 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +var test = async_test("Create WebSocket - set binaryType to something other than blob or arraybuffer - SYNTAX_ERR is returned - Connection should be closed"); + +let wsocket = CreateWebSocket(false, false); +let opened = false; + +wsocket.addEventListener('open', test.step_func(function(evt) { + opened = true; + assert_equals(wsocket.binaryType, "blob"); + wsocket.binaryType = "notBlobOrArrayBuffer"; + assert_equals(wsocket.binaryType, "blob"); + wsocket.close(); +}), true); + +wsocket.addEventListener('close', test.step_func(function(evt) { + assert_true(opened, "connection should be opened"); + assert_true(evt.wasClean, "wasClean should be true"); + test.done(); +}), true); diff --git a/testing/web-platform/tests/websockets/bufferedAmount-unchanged-by-sync-xhr.any.js b/testing/web-platform/tests/websockets/bufferedAmount-unchanged-by-sync-xhr.any.js new file mode 100644 index 0000000000..c15536d767 --- /dev/null +++ b/testing/web-platform/tests/websockets/bufferedAmount-unchanged-by-sync-xhr.any.js @@ -0,0 +1,25 @@ +// META: script=constants.sub.js +// META: global=window,dedicatedworker,sharedworker +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +async_test(t => { + const ws = CreateWebSocket(false, false); + ws.onopen = t.step_func(() => { + ws.onclose = ws.onerror = null; + assert_equals(ws.bufferedAmount, 0); + ws.send('hello'); + assert_equals(ws.bufferedAmount, 5); + // Stop execution for 1s with a sync XHR. + const xhr = new XMLHttpRequest(); + xhr.open('GET', '/common/blank.html?pipe=trickle(d1)', false); + xhr.send(); + assert_equals(ws.bufferedAmount, 5); + ws.close(); + t.done(); + }); + ws.onerror = ws.onclose = t.unreached_func('open should succeed'); +}, 'bufferedAmount should not be updated during a sync XHR'); + +done(); diff --git a/testing/web-platform/tests/websockets/close-invalid.any.js b/testing/web-platform/tests/websockets/close-invalid.any.js new file mode 100644 index 0000000000..c964c8391d --- /dev/null +++ b/testing/web-platform/tests/websockets/close-invalid.any.js @@ -0,0 +1,21 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +[ + [0, "0"], + [500, "500"], + [NaN, "NaN"], + ["string", "String"], + [null, "null"], + [0x10000 + 1000, "2**16+1000"], +].forEach(function(t) { + test(function() { + var ws = CreateWebSocket(false, false); + assert_throws_dom("InvalidAccessError", function() { + ws.close(t[0]); + }); + ws.onerror = this.unreached_func(); + }, t[1] + " on a websocket"); +}); diff --git a/testing/web-platform/tests/websockets/closing-handshake/002.html b/testing/web-platform/tests/websockets/closing-handshake/002.html new file mode 100644 index 0000000000..8d1e43b6de --- /dev/null +++ b/testing/web-platform/tests/websockets/closing-handshake/002.html @@ -0,0 +1,23 @@ +<!doctype html> +<title>WebSockets: server sends closing handshake</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo_exit'); + ws.onmessage = ws.onerror = t.unreached_func(); + ws.onopen = t.step_func(function(e) { + ws.send('Goodbye'); + }) + ws.onclose = t.step_func(function(e) { + assert_equals(e.wasClean, true, 'e.wasClean'); + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }); +}); +</script> diff --git a/testing/web-platform/tests/websockets/closing-handshake/003.html b/testing/web-platform/tests/websockets/closing-handshake/003.html new file mode 100644 index 0000000000..43e1603d34 --- /dev/null +++ b/testing/web-platform/tests/websockets/closing-handshake/003.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>WebSockets: client sends closing handshake</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT + '/echo'); + ws.onmessage = ws.onerror = t.unreached_func(); + ws.onopen = t.step_func(function(e) { + ws.close(); + }); + ws.onclose = t.step_func(function(e) { + assert_equals(e.code, 1005, 'e.code'); + assert_equals(e.wasClean, true, 'e.wasClean'); + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }); +}); +</script> diff --git a/testing/web-platform/tests/websockets/closing-handshake/004.html b/testing/web-platform/tests/websockets/closing-handshake/004.html new file mode 100644 index 0000000000..96411ea639 --- /dev/null +++ b/testing/web-platform/tests/websockets/closing-handshake/004.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>WebSockets: data after closing handshake</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo_close_data'); + ws.onmessage = ws.onerror = t.unreached_func(); + + ws.onopen = t.step_func(function(e) { + ws.send('Goodbye'); + }) + + ws.onclose = t.step_func(function(e) { + assert_equals(e.wasClean, true); + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }) +}); +</script> diff --git a/testing/web-platform/tests/websockets/constants.sub.js b/testing/web-platform/tests/websockets/constants.sub.js new file mode 100644 index 0000000000..fd3c3b84b9 --- /dev/null +++ b/testing/web-platform/tests/websockets/constants.sub.js @@ -0,0 +1,94 @@ +const __SERVER__NAME = "{{host}}"; +const __PATH = "echo"; + +let __SCHEME; +let __PORT; +if (url_has_flag('h2')) { + __SCHEME = 'wss'; + __PORT = "{{ports[h2][0]}}"; +} else if (url_has_variant('wss') || location.protocol === 'https:') { + __SCHEME = 'wss'; + __PORT = "{{ports[wss][0]}}"; +} else { + __SCHEME = 'ws'; + __PORT = "{{ports[ws][0]}}"; +} + +const SCHEME_DOMAIN_PORT = __SCHEME + '://' + __SERVER__NAME + ':' + __PORT; + +function url_has_variant(variant) { + const params = new URLSearchParams(location.search); + return params.get(variant) === ""; +} + +function url_has_flag(flag) { + const params = new URLSearchParams(location.search); + return params.getAll("wpt_flags").indexOf(flag) !== -1; +} + +function IsWebSocket() { + if (!self.WebSocket) { + assert_true(false, "Browser does not support WebSocket"); + } +} + +function CreateWebSocketNonAsciiProtocol(nonAsciiProtocol) { + IsWebSocket(); + const url = SCHEME_DOMAIN_PORT + "/" + __PATH; + return new WebSocket(url, nonAsciiProtocol); +} + +function CreateWebSocketWithAsciiSep(asciiWithSep) { + IsWebSocket(); + const url = SCHEME_DOMAIN_PORT + "/" + __PATH; + return new WebSocket(url, asciiWithSep); +} + +function CreateWebSocketWithBlockedPort(blockedPort) { + IsWebSocket(); + const url = __SCHEME + "://" + __SERVER__NAME + ":" + blockedPort + "/" + __PATH; + return new WebSocket(url); +} + +function CreateWebSocketWithSpaceInUrl(urlWithSpace) { + IsWebSocket(); + const url = __SCHEME + "://" + urlWithSpace + ":" + __PORT + "/" + __PATH; + return new WebSocket(url); +} + +function CreateWebSocketWithSpaceInProtocol(protocolWithSpace) { + IsWebSocket(); + const url = SCHEME_DOMAIN_PORT + "/" + __PATH; + return new WebSocket(url, protocolWithSpace); +} + +function CreateWebSocketWithRepeatedProtocols() { + IsWebSocket(); + const url = SCHEME_DOMAIN_PORT + "/" + __PATH; + return new WebSocket(url, ["echo", "echo"]); +} + +function CreateWebSocketWithRepeatedProtocolsCaseInsensitive() { + IsWebSocket(); + const url = SCHEME_DOMAIN_PORT + "/" + __PATH; + wsocket = new WebSocket(url, ["echo", "eCho"]); +} + +function CreateInsecureWebSocket() { + IsWebSocket(); + const url = `ws://${__SERVER__NAME}:{{ports[ws][0]}}/${__PATH}`; + return new WebSocket(url); +} + +function CreateWebSocket(isProtocol, isProtocols) { + IsWebSocket(); + const url = SCHEME_DOMAIN_PORT + "/" + __PATH; + + if (isProtocol) { + return new WebSocket(url, "echo"); + } + if (isProtocols) { + return new WebSocket(url, ["echo", "chat"]); + } + return new WebSocket(url); +} diff --git a/testing/web-platform/tests/websockets/constructor.any.js b/testing/web-platform/tests/websockets/constructor.any.js new file mode 100644 index 0000000000..0cef2065f6 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor.any.js @@ -0,0 +1,10 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT + "/" + __PATH, + "echo", "Stray argument") + assert_true(ws instanceof WebSocket, "Expected a WebSocket instance.") +}, "Calling the WebSocket constructor with too many arguments should not throw.") diff --git a/testing/web-platform/tests/websockets/constructor/001.html b/testing/web-platform/tests/websockets/constructor/001.html new file mode 100644 index 0000000000..13493e3430 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/001.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>WebSockets: new WebSocket() with no args</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +test(function() { + assert_throws_js(TypeError, function(){new WebSocket()}); +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/004.html b/testing/web-platform/tests/websockets/constructor/004.html new file mode 100644 index 0000000000..814321089b --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/004.html @@ -0,0 +1,36 @@ +<!doctype html> +<title>WebSockets: new WebSocket(url, invalid protocol)</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +// empty string +test(function() { + assert_throws_dom("SyntaxError", function() { + new WebSocket(SCHEME_DOMAIN_PORT + '/empty-message', "") + }) +}); + +// chars below U+0020 except U+0000; U+0000 is tested in a separate test +for (var i = 1; i < 0x20; ++i) { + test(function() { + assert_throws_dom("SyntaxError", function() { + new WebSocket(SCHEME_DOMAIN_PORT + '/empty-message', + "a"+String.fromCharCode(i)+"b") + }, 'char code '+i); + }) +} +// some chars above U+007E +for (var i = 0x7F; i < 0x100; ++i) { + test(function() { + assert_throws_dom("SyntaxError", function() { + new WebSocket(SCHEME_DOMAIN_PORT + '/empty-message', + "a"+String.fromCharCode(i)+"b") + }, 'char code '+i); + }) +} +</script> diff --git a/testing/web-platform/tests/websockets/constructor/005.html b/testing/web-platform/tests/websockets/constructor/005.html new file mode 100644 index 0000000000..9d467def3f --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/005.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>WebSockets: return value</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +test(function() { + assert_true(new WebSocket(SCHEME_DOMAIN_PORT + '/empty-message') instanceof WebSocket); +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/006.html b/testing/web-platform/tests/websockets/constructor/006.html new file mode 100644 index 0000000000..59875830da --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/006.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>WebSockets: converting first arguments</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var a = document.createElement('a'); + a.href = SCHEME_DOMAIN_PORT+'/echo'; + var ws = new WebSocket(a); // should stringify arguments; <a> stringifies to its .href + assert_equals(ws.url, a.href); + ws.onopen = t.step_func(function(e) { + ws.send('test'); + }); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, 'test'); + ws.onclose = t.step_func(function(e) { + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }); + ws.close(); + }); + ws.onerror = ws.onclose = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/007.html b/testing/web-platform/tests/websockets/constructor/007.html new file mode 100644 index 0000000000..e126d1aa0f --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/007.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>WebSockets: new WebSocket(url, null char)</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +test(function() { + assert_throws_dom("SyntaxError", function() { + new WebSocket(SCHEME_DOMAIN_PORT + '/empty-message', + 'a' + String.fromCharCode(0) + 'b') + }) +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/008.html b/testing/web-platform/tests/websockets/constructor/008.html new file mode 100644 index 0000000000..e10c652134 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/008.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>WebSockets: new WebSocket(url with not blocked port)</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +//Pass condition is to not throw +test(function(){new WebSocket('ws://example.invalid:80/')}); +test(function(){new WebSocket('ws://example.invalid:443/')}); +test(function(){new WebSocket('wss://example.invalid:80/')}); +test(function(){new WebSocket('wss://example.invalid:443/')}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/009.html b/testing/web-platform/tests/websockets/constructor/009.html new file mode 100644 index 0000000000..f8123c2c86 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/009.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>WebSockets: protocol</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/protocol', 'foobar'); + + ws.onmessage = t.step_func(function(e) { + assert_equals(ws.protocol, 'foobar'); + ws.onclose = t.step_func(function(e) { + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }) + ws.close(); + }) + ws.onerror = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/010.html b/testing/web-platform/tests/websockets/constructor/010.html new file mode 100644 index 0000000000..e5bc6ecc36 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/010.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>WebSockets: protocol in response but no requested protocol</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/handshake_protocol'); + ws.onopen = ws.onmessage = ws.onclose = t.step_func(e => assert_unreached(e.type)); + ws.onerror = t.step_func(function(e) { + ws.onclose = t.step_func(function(e) { + assert_false(e.wasClean, 'e.wasClean should be false'); + assert_equals(e.code, 1006, 'e.code should be 1006'); + t.done(); + }); + }) +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/011.html b/testing/web-platform/tests/websockets/constructor/011.html new file mode 100644 index 0000000000..33b09dbaf8 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/011.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>WebSockets: protocol mismatch</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + // Sub-protocol matching is case-sensitive. + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/handshake_protocol', 'FOOBAR'); + var gotOpen = false; + var gotError = false; + ws.onopen = t.step_func(function(e) { + gotOpen = true; + }); + ws.onerror = t.step_func(function(e) { + gotError = true; + }); + ws.onclose = t.step_func(function(e) { + assert_false(gotOpen, 'got open'); + assert_true(gotError, 'got error'); + t.done(); + }); +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/012.html b/testing/web-platform/tests/websockets/constructor/012.html new file mode 100644 index 0000000000..ba2b6b2df0 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/012.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>WebSockets: no protocol in response</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/handshake_no_protocol', 'foobar'); + ws.onclose = t.step_func(function(e) { + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }) + ws.onmessage = t.unreached_func(); +}); +</script> + diff --git a/testing/web-platform/tests/websockets/constructor/013.html b/testing/web-platform/tests/websockets/constructor/013.html new file mode 100644 index 0000000000..d599fde528 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/013.html @@ -0,0 +1,42 @@ +<!doctype html> +<title>WebSockets: multiple WebSocket objects</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + // test that the events are fired as they should when opening 25 websockets and + // sending a message on each and then closing when getting the message back + var ws = []; + var events = 0; + for (var i = 0; i < 25; ++i) { + ws[i] = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws[i].id = i; + ws[i].onopen = t.step_func(function(e) { + events++; + this.send(this.id); + this.onopen = t.step_func(function() {assert_unreached()}); + }, ws[i]); + ws[i].onmessage = t.step_func(function(e) { + events++; + assert_equals(e.data, ''+this.id); + this.close(); + this.onmessage = t.step_func(function() {assert_unreached()}); + }, ws[i]); + ws[i].onclose = t.step_func(function(e) { + events++; + if (events == 75) { + t.done(); + } + this.onclose = t.step_func(function() {assert_unreached()}); + }, ws[i]); + ws[i].onerror = t.step_func(function() {assert_unreached()}); + } +}); +</script> + diff --git a/testing/web-platform/tests/websockets/constructor/014.html b/testing/web-platform/tests/websockets/constructor/014.html new file mode 100644 index 0000000000..afa0dac4c1 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/014.html @@ -0,0 +1,39 @@ +<!doctype html> +<title>WebSockets: serialize establish a connection</title> +<meta name="timeout" content="long"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> + +async_test(function(t) { + var ws = []; + var events = 0; + var prevDate; + var date; + for (var i = 0; i < 2; ++i) { + ws[i] = new WebSocket(SCHEME_DOMAIN_PORT+'/handshake_sleep_2'); + ws[i].id = i; + ws[i].onopen = t.step_func(function(e) { + events++; + date = new Date(); + if (prevDate) { + assert_greater_than(date - prevDate, 1000); + } + prevDate = date; + this.onopen = t.step_func(function() {assert_unreached()}); + }.bind(ws[i])) + ws[i].onclose = t.step_func(function() { + events++; + if (events == 4) { + t.done(); + } + this.onclose = t.step_func(function() {assert_unreached()}); + }.bind(ws[i])); + ws[i].onerror = ws[i].onmessage = t.step_func(function() {assert_unreached()}); + } +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/016.html b/testing/web-platform/tests/websockets/constructor/016.html new file mode 100644 index 0000000000..18605056dd --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/016.html @@ -0,0 +1,20 @@ +<!doctype html> +<meta charset=windows-1252> +<title>WebSockets: non-ascii URL in query, document encoding windows-1252</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo-query_v13?åäö'); + ws.onclose = t.step_func(function() {assert_unreached()}); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, '%C3%A5%C3%A4%C3%B6'); + t.done(); + }); +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/017.html b/testing/web-platform/tests/websockets/constructor/017.html new file mode 100644 index 0000000000..e1795b175e --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/017.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>WebSockets: too few slashes after ws: and wss:</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +var tests = [ + [__SCHEME + ':', __PORT], + [__SCHEME + ':/', __PORT], +]; +//Pass condition is to not throw +for (var i = 0; i < tests.length; ++i) { + test(function(){new WebSocket(tests[i][0] + location.hostname + ':' + tests[i][1] + '/echo')}, tests[i][0]); +} +</script> diff --git a/testing/web-platform/tests/websockets/constructor/018.html b/testing/web-platform/tests/websockets/constructor/018.html new file mode 100644 index 0000000000..71f7376496 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/018.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>WebSockets: NULL char in url</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo-query?x\u0000y\u0000'); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, 'x%00y'); + ws.close(); + t.done(); + }) + ws.onclose = ws.onerror = t.step_func(function(e) {assert_unreached(e.type)}); +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/019.html b/testing/web-platform/tests/websockets/constructor/019.html new file mode 100644 index 0000000000..8fbb1cbfff --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/019.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>WebSockets: uppercase 'WS:'</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var scheme = SCHEME_DOMAIN_PORT.split('://')[0]; + var domain = SCHEME_DOMAIN_PORT.split('://')[1]; + var ws = new WebSocket(scheme.toUpperCase()+'://'+domain+'/echo'); + ws.onopen = t.step_func(function(e) { + ws.close(); + t.done(); + }) + ws.onclose = ws.onerror = ws.onmessage = t.step_func(function() {assert_unreached()}); +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/020.html b/testing/web-platform/tests/websockets/constructor/020.html new file mode 100644 index 0000000000..e4d61f366e --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/020.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>WebSockets: uppercase host</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var scheme = SCHEME_DOMAIN_PORT.split('://')[0]; + var domain = SCHEME_DOMAIN_PORT.split('://')[1]; + var ws = new WebSocket(scheme+'://'+domain.toUpperCase()+'/echo'); + ws.onopen = t.step_func(function(e) { + ws.close(); + t.done(); + }); + ws.onclose = ws.onerror = ws.onmessage = t.step_func(function() {assert_unreached()}); +}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/021.html b/testing/web-platform/tests/websockets/constructor/021.html new file mode 100644 index 0000000000..d3854feeb4 --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/021.html @@ -0,0 +1,12 @@ +<!doctype html> +<title>WebSockets: Same sub protocol twice</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +test(function() {assert_throws_dom("SyntaxError", function(){new WebSocket("ws://certo2.oslo.osa/protocol_array",["foobar, foobar"])})}); +</script> diff --git a/testing/web-platform/tests/websockets/constructor/022.html b/testing/web-platform/tests/websockets/constructor/022.html new file mode 100644 index 0000000000..fd53c0f29a --- /dev/null +++ b/testing/web-platform/tests/websockets/constructor/022.html @@ -0,0 +1,23 @@ +<!doctype html> +<title>WebSockets: protocol array</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/protocol_array',['foobar','foobar2']); + ws.onmessage = t.step_func(function(e) { + assert_equals(ws.protocol, 'foobar'); + ws.onclose = t.step_func(function(e) { + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }); + ws.close(); + }); + ws.onerror = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/cookies/001.html b/testing/web-platform/tests/websockets/cookies/001.html new file mode 100644 index 0000000000..abec94e4b1 --- /dev/null +++ b/testing/web-platform/tests/websockets/cookies/001.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>WebSockets: Cookie in request</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss&wpt_flags=https"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +var cookie_id = ((new Date())-0) + '.' + Math.random(); +async_test(function(t) { + if (window.WebSocket) { + document.cookie = 'ws_test_'+cookie_id+'=test; Path=/'; + } + t.add_cleanup(function() { + // remove cookie + document.cookie = 'ws_test_'+cookie_id+'=; Path=/; Expires=Sun, 06 Nov 1994 08:49:37 GMT'; + }); + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo-cookie'); + ws.onmessage = t.step_func(function(e) { + assert_regexp_match(e.data, new RegExp('ws_test_'+cookie_id+'=test')); + ws.close(); + t.done(); + }); + ws.onerror = ws.onclose = t.step_func(function(e) {assert_unreached(e.type)}); +}); +</script> diff --git a/testing/web-platform/tests/websockets/cookies/002.html b/testing/web-platform/tests/websockets/cookies/002.html new file mode 100644 index 0000000000..758ce473a9 --- /dev/null +++ b/testing/web-platform/tests/websockets/cookies/002.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>WebSockets: Set-Cookie in response</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss&wpt_flags=https"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +var cookie_id = ((new Date())-0) + '.' + Math.random(); +async_test(function(t) { + t.add_cleanup(function() { + // remove cookie + document.cookie = 'ws_test_'+cookie_id+'=; Path=/; Expires=Sun, 06 Nov 1994 08:49:37 GMT'; + }); + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/set-cookie?'+cookie_id); + ws.onopen = t.step_func(function(e) { + assert_regexp_match(document.cookie, new RegExp('ws_test_'+cookie_id+'=test')); + ws.close(); + ws.onclose = null; + t.done(); + }); + ws.onerror = ws.onclose = t.step_func(function(e) {assert_unreached(e.type)}); +}); +</script> diff --git a/testing/web-platform/tests/websockets/cookies/003.html b/testing/web-platform/tests/websockets/cookies/003.html new file mode 100644 index 0000000000..9f770aef22 --- /dev/null +++ b/testing/web-platform/tests/websockets/cookies/003.html @@ -0,0 +1,34 @@ +<!doctype html> +<title>WebSockets: sending HttpOnly cookies in ws request</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss&wpt_flags=https"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +setup({explicit_done:true}) +var cookie_id = ((new Date())-0) + '.' + Math.random(); + +var t = async_test(function(t) { + var iframe = document.createElement('iframe'); + t.add_cleanup(function() { + // remove cookie + iframe.src = 'support/set-cookie.py?'+encodeURIComponent('ws_test_'+cookie_id+'=; Path=/; HttpOnly; Expires=Sun, 06 Nov 1994 08:49:37 GMT'); + iframe.onload = done; + }); + iframe.src = 'support/set-cookie.py?'+encodeURIComponent('ws_test_'+cookie_id+'=test; Path=/; HttpOnly'); + iframe.onload = t.step_func(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo-cookie'); + ws.onmessage = t.step_func(function(e) { + ws.close(); + ws.onclose = null; + assert_regexp_match(e.data, new RegExp('ws_test_'+cookie_id+'=test')); + t.done(); + }); + ws.onerror = ws.onclose = t.step_func(function(e) {assert_unreached(e.type)}); + }); + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/websockets/cookies/004.html b/testing/web-platform/tests/websockets/cookies/004.html new file mode 100644 index 0000000000..523dabaf63 --- /dev/null +++ b/testing/web-platform/tests/websockets/cookies/004.html @@ -0,0 +1,31 @@ +<!doctype html> +<title>WebSockets: setting HttpOnly cookies in ws response, checking document.cookie</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss&wpt_flags=https"> +<div id=log></div> +<script> +setup({explicit_done:true}) +var cookie_id = ((new Date())-0) + '.' + Math.random(); + +var t = async_test(function(t) { + var iframe = document.createElement('iframe'); + t.add_cleanup(function() { + // remove cookie + iframe.src = 'support/set-cookie.py?'+encodeURIComponent('ws_test_'+cookie_id+'=; Path=/; HttpOnly; Expires=Sun, 06 Nov 1994 08:49:37 GMT'); + iframe.onload = done; + }); + var url = SCHEME_DOMAIN_PORT+'/set-cookie_http?'+cookie_id; + var ws = new WebSocket(url); + ws.onopen = t.step_func(function(e) { + ws.close(); + ws.onclose = null; + assert_false(new RegExp('ws_test_'+cookie_id+'=test').test(document.cookie)); + t.done(); + }); + ws.onerror = ws.onclose = t.step_func(function(e) {assert_unreached(e.type)}); + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/websockets/cookies/005.html b/testing/web-platform/tests/websockets/cookies/005.html new file mode 100644 index 0000000000..f3e334c1df --- /dev/null +++ b/testing/web-platform/tests/websockets/cookies/005.html @@ -0,0 +1,35 @@ +<!doctype html> +<title>WebSockets: setting HttpOnly cookies in ws response, checking ws request</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss&wpt_flags=https"> +<div id=log></div> +<script> +setup({explicit_done:true}) +var cookie_id = ((new Date())-0) + '.' + Math.random(); + +var t = async_test(function(t) { + var iframe = document.createElement('iframe'); + t.add_cleanup(function() { + // remove cookie + iframe.src = 'support/set-cookie.py?'+encodeURIComponent('ws_test_'+cookie_id+'=; Path=/; HttpOnly; Expires=Sun, 06 Nov 1994 08:49:37 GMT'); + iframe.onload = done; + }); + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/set-cookie_http?'+cookie_id); + ws.onopen = t.step_func(function(e) { + var ws2 = new WebSocket(SCHEME_DOMAIN_PORT+'/echo-cookie'); + ws2.onmessage = t.step_func(function(e) { + ws.close(); + ws.onclose = null; + ws2.close(); + assert_regexp_match(e.data, new RegExp('ws_test_'+cookie_id+'=test')); + t.done(); + }); + }); + ws.onerror = ws.onclose = t.step_func(function(e) {assert_unreached(e.type)}); + document.body.appendChild(iframe); +}) +</script> diff --git a/testing/web-platform/tests/websockets/cookies/006.html b/testing/web-platform/tests/websockets/cookies/006.html new file mode 100644 index 0000000000..6e12bfac6c --- /dev/null +++ b/testing/web-platform/tests/websockets/cookies/006.html @@ -0,0 +1,35 @@ +<!doctype html> +<title>WebSockets: setting Secure cookie with document.cookie, checking ws request</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss&wpt_flags=https"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +var cookie_id = ((new Date())-0) + '.' + Math.random(); +async_test(function(t) { + if (window.WebSocket) { + document.cookie = 'ws_test_'+cookie_id+'=test; Path=/; Secure'; + } + t.add_cleanup(function() { + // remove cookie + document.cookie = 'ws_test_'+cookie_id+'=; Path=/; Secure; Expires=Sun, 06 Nov 1994 08:49:37 GMT'; + }); + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo-cookie'); + ws.onmessage = t.step_func(function(e) { + ws.close(); + var cookie_was_seen = e.data.indexOf('ws_test_'+cookie_id+'=test') != -1; + if (SCHEME_DOMAIN_PORT.substr(0,3) == 'wss') { + assert_true(cookie_was_seen, + 'cookie should have been visible to wss'); + } else { + assert_false(cookie_was_seen, + 'cookie should not have been visible to ws'); + } + t.done(); + }) + ws.onerror = ws.onclose = t.step_func(function(e) {assert_unreached(e.type)}); +}); +</script> diff --git a/testing/web-platform/tests/websockets/cookies/007.html b/testing/web-platform/tests/websockets/cookies/007.html new file mode 100644 index 0000000000..3e69bfc09d --- /dev/null +++ b/testing/web-platform/tests/websockets/cookies/007.html @@ -0,0 +1,36 @@ +<!doctype html> +<title>WebSockets: when to process set-cookie fields in ws response</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss&wpt_flags=https"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +var cookie_id = ((new Date())-0) + '.' + Math.random(); +async_test(function(t) { + t.add_cleanup(function() { + // remove cookie + document.cookie = 'ws_test_'+cookie_id+'; Path=/; Expires=Sun, 06 Nov 1994 08:49:37 GMT'; + }); + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/set-cookie?'+cookie_id); + ws.onopen = t.step_func(function(e) { + ws.close(); + ws.onclose = null; + assert_regexp_match(document.cookie, new RegExp('ws_test_'+cookie_id+'=test')); + t.done(); + }); + ws.onerror = ws.onclose = t.step_func(function() {assert_unreached()}); + + // sleep for 2 seconds with sync xhr + var sleep = new XMLHttpRequest(); + sleep.open('GET', '/common/blank.html?pipe=trickle(d2)', false); + sleep.send(null); + + if (new RegExp('ws_test_'+cookie_id+'=test').test(document.cookie)) { + assert_unreached('cookie was set during script execution'); + } +}); +</script> diff --git a/testing/web-platform/tests/websockets/cookies/support/set-cookie.py b/testing/web-platform/tests/websockets/cookies/support/set-cookie.py new file mode 100644 index 0000000000..71cd8bca60 --- /dev/null +++ b/testing/web-platform/tests/websockets/cookies/support/set-cookie.py @@ -0,0 +1,7 @@ +from urllib.parse import unquote + +from wptserve.utils import isomorphic_encode + +def main(request, response): + response.headers.set(b'Set-Cookie', isomorphic_encode(unquote(request.url_parts.query))) + return [(b"Content-Type", b"text/plain")], b"" diff --git a/testing/web-platform/tests/websockets/cookies/support/websocket-cookies-helper.sub.js b/testing/web-platform/tests/websockets/cookies/support/websocket-cookies-helper.sub.js new file mode 100644 index 0000000000..a7fae2551e --- /dev/null +++ b/testing/web-platform/tests/websockets/cookies/support/websocket-cookies-helper.sub.js @@ -0,0 +1,57 @@ +// Set up global variables. +(_ => { + var HOST = '{{host}}'; + var CROSS_ORIGIN_HOST = '{{hosts[alt][]}}'; + var WSS_PORT = ':{{ports[wss][0]}}'; + var HTTPS_PORT = ':{{ports[https][0]}}'; + + window.WSS_ORIGIN = 'wss://' + HOST + WSS_PORT; + window.WSS_CROSS_SITE_ORIGIN = 'wss://' + CROSS_ORIGIN_HOST + WSS_PORT; + window.HTTPS_ORIGIN = 'https://' + HOST + HTTPS_PORT; + window.HTTPS_CROSS_SITE_ORIGIN = 'https://' + CROSS_ORIGIN_HOST + HTTPS_PORT; +})(); + +// Sets a cookie with each SameSite option. +function setSameSiteCookies(origin, value) { + return new Promise(resolve => { + const ws = new WebSocket(origin + '/set-cookies-samesite?value=' + value); + ws.onopen = () => { + ws.close(); + }; + ws.onclose = resolve; + }); +} + +// Clears cookies set by setSameSiteCookies(). +function clearSameSiteCookies(origin) { + return new Promise(resolve => { + const ws = new WebSocket(origin + '/set-cookies-samesite?clear'); + ws.onopen = () => ws.close(); + ws.onclose = resolve; + }); +} + +// Gets value of Cookie header sent in request. +function connectAndGetRequestCookiesFrom(origin) { + return new Promise((resolve, reject) => { + var ws = new WebSocket(origin + '/echo-cookie'); + ws.onmessage = evt => { + var cookies = evt.data + resolve(cookies); + ws.onerror = undefined; + ws.onclose = undefined; + }; + ws.onerror = () => reject('Unexpected error event'); + ws.onclose = evt => reject('Unexpected close event: ' + JSON.stringify(evt)); + }); +} + +// Assert that a given cookie is or is not present in the string |cookies|. +function assertCookie(cookies, name, value, present) { + var assertion = present ? assert_true : assert_false; + var description = name + '=' + value + ' cookie is' + + (present ? ' ' : ' not ') + 'present.'; + var re = new RegExp('(?:^|; )' + name + '=' + value + '(?:$|;)'); + assertion(re.test(cookies), description); +} + diff --git a/testing/web-platform/tests/websockets/cookies/third-party-cookie-accepted.https.html b/testing/web-platform/tests/websockets/cookies/third-party-cookie-accepted.https.html new file mode 100644 index 0000000000..208d297016 --- /dev/null +++ b/testing/web-platform/tests/websockets/cookies/third-party-cookie-accepted.https.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<meta charset="utf-8"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/websocket-cookies-helper.sub.js"></script> +<script> +promise_test(() => { + var value = '' + Math.random(); + var origin = WSS_CROSS_SITE_ORIGIN; + return setSameSiteCookies(origin, value).then( + () => { return connectAndGetRequestCookiesFrom(origin); } + ).then( + cookies => { + assert_not_equals(cookies, '(none)', 'request should contain cookies.'); + // SameSite cookies are blocked. + assertCookie(cookies, 'samesite-unspecified', value, false /* present */); + assertCookie(cookies, 'samesite-lax', value, false /* present */); + assertCookie(cookies, 'samesite-strict', value, false /* present */); + // SameSite=None third-party cookie is not blocked. + assertCookie(cookies, 'samesite-none', value, true /* present */); + return clearSameSiteCookies(origin); + } + ); +}, 'Test that third-party cookies are accepted for WebSockets.'); +</script> diff --git a/testing/web-platform/tests/websockets/eventhandlers.any.js b/testing/web-platform/tests/websockets/eventhandlers.any.js new file mode 100644 index 0000000000..f596328b92 --- /dev/null +++ b/testing/web-platform/tests/websockets/eventhandlers.any.js @@ -0,0 +1,15 @@ +// META: script=constants.sub.js +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +function testEventHandler(name) { + test(function() { + var ws = CreateWebSocket(true, false); + assert_equals(ws["on" + name], null); + ws["on" + name] = function() {}; + ws["on" + name] = 2; + assert_equals(ws["on" + name], null); + }, "Event handler for " + name + " should have [TreatNonCallableAsNull]") +} +["open", "error", "close", "message"].forEach(testEventHandler); diff --git a/testing/web-platform/tests/websockets/extended-payload-length.html b/testing/web-platform/tests/websockets/extended-payload-length.html new file mode 100644 index 0000000000..92e3802c35 --- /dev/null +++ b/testing/web-platform/tests/websockets/extended-payload-length.html @@ -0,0 +1,72 @@ +<!doctype html> +<title>WebSockets : Boundary-value tests for the 'Extended payload length' field in RFC6455 section5.2 'Base Framing Protocol'</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var datasize = 125; + var data = null; + ws.onopen = t.step_func(function(e) { + data = new Array(datasize + 1).join('a'); + ws.send(data); + }); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, data); + t.done(); + }); + ws.onclose = t.unreached_func('close event should not fire'); +}, "Application data is 125 byte which means any 'Extended payload length' field isn't used at all."); + +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var datasize = 126; + var data = null; + ws.onopen = t.step_func(function(e) { + data = new Array(datasize + 1).join('a'); + ws.send(data); + }); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, data); + t.done(); + }); + ws.onclose = t.unreached_func('close event should not fire'); +}, "Application data is 126 byte which starts to use the 16 bit 'Extended payload length' field."); + +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var datasize = 0xFFFF; + var data = null; + ws.onopen = t.step_func(function(e) { + data = new Array(datasize + 1).join('a'); + ws.send(data); + }); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, data); + t.done(); + }); + ws.onclose = t.unreached_func('close event should not fire'); +}, "Application data is 0xFFFF byte which means the upper bound of the 16 bit 'Extended payload length' field."); + +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var datasize = 0xFFFF + 1; + var data = null; + ws.onopen = t.step_func(function(e) { + data = new Array(datasize + 1).join('a'); + ws.send(data); + }); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, data); + t.done(); + }); + ws.onclose = t.unreached_func('close event should not fire'); +}, "Application data is (0xFFFF + 1) byte which starts to use the 64 bit 'Extended payload length' field"); + +</script> diff --git a/testing/web-platform/tests/websockets/handlers/basic_auth_wsh.py b/testing/web-platform/tests/websockets/handlers/basic_auth_wsh.py new file mode 100755 index 0000000000..72e920a1d8 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/basic_auth_wsh.py @@ -0,0 +1,26 @@ +#!/usr/bin/python + +"""A WebSocket handler that enforces basic HTTP authentication. Username is +'foo' and password is 'bar'.""" + + +from mod_pywebsocket.handshake import AbortedByUserException + + +def web_socket_do_extra_handshake(request): + authorization = request.headers_in.get('authorization') + if authorization is None or authorization != 'Basic Zm9vOmJhcg==': + if request.protocol == "HTTP/2": + request.status = 401 + request.headers_out["Content-Length"] = "0" + request.headers_out['www-authenticate'] = 'Basic realm="camelot"' + else: + request.connection.write(b'HTTP/1.1 401 Unauthorized\x0d\x0a' + b'Content-Length: 0\x0d\x0a' + b'WWW-Authenticate: Basic realm="camelot"\x0d\x0a' + b'\x0d\x0a') + raise AbortedByUserException('Abort the connection') + + +def web_socket_transfer_data(request): + pass diff --git a/testing/web-platform/tests/websockets/handlers/delayed-passive-close_wsh.py b/testing/web-platform/tests/websockets/handlers/delayed-passive-close_wsh.py new file mode 100755 index 0000000000..7d55b88ecc --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/delayed-passive-close_wsh.py @@ -0,0 +1,27 @@ +#!/usr/bin/python +from mod_pywebsocket import common +import time + +def web_socket_do_extra_handshake(request): + pass + + +def web_socket_transfer_data(request): + # Wait for the close frame to arrive. + request.ws_stream.receive_message() + + +def web_socket_passive_closing_handshake(request): + # Echo close status code and reason + code, reason = request.ws_close_code, request.ws_close_reason + + # No status received is a reserved pseudo code representing an empty code, + # so echo back an empty code in this case. + if code == common.STATUS_NO_STATUS_RECEIVED: + code = None + + # The browser may error the connection if the closing handshake takes too + # long, but hopefully no browser will have a timeout this short. + time.sleep(1) + + return code, reason diff --git a/testing/web-platform/tests/websockets/handlers/echo-cookie_wsh.py b/testing/web-platform/tests/websockets/handlers/echo-cookie_wsh.py new file mode 100755 index 0000000000..98620b6552 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/echo-cookie_wsh.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +from mod_pywebsocket import msgutil + +def web_socket_do_extra_handshake(request): + request.ws_cookie = request.headers_in.get('cookie') + +def web_socket_transfer_data(request): + if request.ws_cookie is not None: + msgutil.send_message(request, request.ws_cookie) + else: + msgutil.send_message(request, '(none)') diff --git a/testing/web-platform/tests/websockets/handlers/echo-query_v13_wsh.py b/testing/web-platform/tests/websockets/handlers/echo-query_v13_wsh.py new file mode 100755 index 0000000000..d670e6e660 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/echo-query_v13_wsh.py @@ -0,0 +1,11 @@ +#!/usr/bin/python + +from mod_pywebsocket import msgutil + +def web_socket_do_extra_handshake(request): + pass + +def web_socket_transfer_data(request): + while True: + msgutil.send_message(request, request.unparsed_uri.split('?')[1] or '') + return diff --git a/testing/web-platform/tests/websockets/handlers/echo-query_wsh.py b/testing/web-platform/tests/websockets/handlers/echo-query_wsh.py new file mode 100755 index 0000000000..3921913495 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/echo-query_wsh.py @@ -0,0 +1,9 @@ +#!/usr/bin/python + +from mod_pywebsocket import msgutil + +def web_socket_do_extra_handshake(request): + pass # Always accept. + +def web_socket_transfer_data(request): + msgutil.send_message(request, request.unparsed_uri.split('?', 1)[1] or '') diff --git a/testing/web-platform/tests/websockets/handlers/echo_close_data_wsh.py b/testing/web-platform/tests/websockets/handlers/echo_close_data_wsh.py new file mode 100755 index 0000000000..31ffcbb849 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/echo_close_data_wsh.py @@ -0,0 +1,20 @@ +#!/usr/bin/python + +_GOODBYE_MESSAGE = u'Goodbye' + +def web_socket_do_extra_handshake(request): + # This example handler accepts any request. See origin_check_wsh.py for how + # to reject access from untrusted scripts based on origin value. + + pass # Always accept. + + +def web_socket_transfer_data(request): + while True: + line = request.ws_stream.receive_message() + if line is None: + return + if isinstance(line, str): + if line == _GOODBYE_MESSAGE: + return + request.ws_stream.send_message(line, binary=False) diff --git a/testing/web-platform/tests/websockets/handlers/echo_exit_wsh.py b/testing/web-platform/tests/websockets/handlers/echo_exit_wsh.py new file mode 100755 index 0000000000..8f6f7f854e --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/echo_exit_wsh.py @@ -0,0 +1,19 @@ +#!/usr/bin/python + +_GOODBYE_MESSAGE = u'Goodbye' + +def web_socket_do_extra_handshake(request): + # This example handler accepts any request. See origin_check_wsh.py for how + # to reject access from untrusted scripts based on origin value. + + pass # Always accept. + + +def web_socket_transfer_data(request): + while True: + line = request.ws_stream.receive_message() + if line is None: + return + if isinstance(line, str): + if line == _GOODBYE_MESSAGE: + return diff --git a/testing/web-platform/tests/websockets/handlers/echo_raw_wsh.py b/testing/web-platform/tests/websockets/handlers/echo_raw_wsh.py new file mode 100755 index 0000000000..e1fc26608f --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/echo_raw_wsh.py @@ -0,0 +1,16 @@ +#!/usr/bin/python + +from mod_pywebsocket import msgutil + + +def web_socket_do_extra_handshake(request): + pass # Always accept. + +def web_socket_transfer_data(request): + while True: + line = msgutil.receive_message(request) + if line == b'exit': + return + + if line is not None: + request.connection.write(line) diff --git a/testing/web-platform/tests/websockets/handlers/echo_wsh.py b/testing/web-platform/tests/websockets/handlers/echo_wsh.py new file mode 100755 index 0000000000..7367b70af1 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/echo_wsh.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +from mod_pywebsocket import common + +_GOODBYE_MESSAGE = u'Goodbye' + +def web_socket_do_extra_handshake(request): + # This example handler accepts any request. See origin_check_wsh.py for how + # to reject access from untrusted scripts based on origin value. + if request.ws_requested_protocols: + if "echo" in request.ws_requested_protocols: + request.ws_protocol = "echo" + + +def web_socket_transfer_data(request): + while True: + line = request.ws_stream.receive_message() + if line is None: + return + if isinstance(line, str): + request.ws_stream.send_message(line, binary=False) + if line == _GOODBYE_MESSAGE: + return + else: + request.ws_stream.send_message(line, binary=True) + +def web_socket_passive_closing_handshake(request): + # Echo close status code and reason + code, reason = request.ws_close_code, request.ws_close_reason + + # No status received is a reserved pseudo code representing an empty code, + # so echo back an empty code in this case. + if code == common.STATUS_NO_STATUS_RECEIVED: + code = None + + return code, reason diff --git a/testing/web-platform/tests/websockets/handlers/empty-message_wsh.py b/testing/web-platform/tests/websockets/handlers/empty-message_wsh.py new file mode 100755 index 0000000000..0eb107f0b1 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/empty-message_wsh.py @@ -0,0 +1,13 @@ +#!/usr/bin/python + +from mod_pywebsocket import msgutil + +def web_socket_do_extra_handshake(request): + pass # Always accept. + +def web_socket_transfer_data(request): + line = msgutil.receive_message(request) + if line == "": + msgutil.send_message(request, 'pass') + else: + msgutil.send_message(request, 'fail') diff --git a/testing/web-platform/tests/websockets/handlers/handshake_no_extensions_wsh.py b/testing/web-platform/tests/websockets/handlers/handshake_no_extensions_wsh.py new file mode 100755 index 0000000000..0d0f0a8b73 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/handshake_no_extensions_wsh.py @@ -0,0 +1,9 @@ +#!/usr/bin/python + + +def web_socket_do_extra_handshake(request): + request.ws_extension_processors = [] + + +def web_socket_transfer_data(request): + pass diff --git a/testing/web-platform/tests/websockets/handlers/handshake_no_protocol_wsh.py b/testing/web-platform/tests/websockets/handlers/handshake_no_protocol_wsh.py new file mode 100755 index 0000000000..ffc2ae80ef --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/handshake_no_protocol_wsh.py @@ -0,0 +1,8 @@ +#!/usr/bin/python + +def web_socket_do_extra_handshake(request): + # Trick pywebsocket into believing no subprotocol was requested. + request.ws_requested_protocols = None + +def web_socket_transfer_data(request): + pass diff --git a/testing/web-platform/tests/websockets/handlers/handshake_protocol_wsh.py b/testing/web-platform/tests/websockets/handlers/handshake_protocol_wsh.py new file mode 100755 index 0000000000..2ca20c052d --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/handshake_protocol_wsh.py @@ -0,0 +1,7 @@ +#!/usr/bin/python + +def web_socket_do_extra_handshake(request): + request.ws_protocol = 'foobar' + +def web_socket_transfer_data(request): + pass
\ No newline at end of file diff --git a/testing/web-platform/tests/websockets/handlers/handshake_sleep_2_wsh.py b/testing/web-platform/tests/websockets/handlers/handshake_sleep_2_wsh.py new file mode 100755 index 0000000000..78de7c7659 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/handshake_sleep_2_wsh.py @@ -0,0 +1,9 @@ +#!/usr/bin/python + +import time + +def web_socket_do_extra_handshake(request): + time.sleep(2) + +def web_socket_transfer_data(request): + pass diff --git a/testing/web-platform/tests/websockets/handlers/invalid_wsh.py b/testing/web-platform/tests/websockets/handlers/invalid_wsh.py new file mode 100755 index 0000000000..4bfc3ce4e7 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/invalid_wsh.py @@ -0,0 +1,8 @@ +#!/usr/bin/python + +def web_socket_do_extra_handshake(request): + request.connection.write(b"FOO BAR BAZ\r\n\r\n") + + +def web_socket_transfer_data(request): + pass diff --git a/testing/web-platform/tests/websockets/handlers/msg_channel_wsh.py b/testing/web-platform/tests/websockets/handlers/msg_channel_wsh.py new file mode 100644 index 0000000000..7a66646f2b --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/msg_channel_wsh.py @@ -0,0 +1,234 @@ +#!/usr/bin/python +import json +import logging +import urllib +import threading +import traceback +from queue import Empty + +from mod_pywebsocket import stream, msgutil +from wptserve import stash as stashmod + +logger = logging.getLogger() + +address, authkey = stashmod.load_env_config() +stash = stashmod.Stash("msg_channel", address=address, authkey=authkey) + +# Backend for websocket based channels. +# +# Each socket connection has a uuid identifying the channel and a +# direction which is either "read" or "write". There can be only 1 +# "read" channel per uuid, but multiple "write" channels +# (i.e. multiple producer, single consumer). +# +# The websocket connection URL contains the uuid and the direction as +# named query parameters. +# +# Channels are backed by a queue which is stored in the stash (one +# queue per uuid). +# +# The representation of a queue in the stash is a tuple (queue, +# has_reader, writer_count). The first field is the queue itself, the +# latter are effectively reference counts for reader channels (which +# is zero or one, represented by a bool) and writer channels. Once +# both counts drop to zero the queue can be deleted. +# +# Entries on the queue itself are formed of (command, data) pairs. The +# command can be either "close", signalling the socket is closing and +# the reference count on the channel should be decremented, or +# "message", which indicates a message. + + +def log(uuid, msg, level="debug"): + msg = f"{uuid}: {msg}" + getattr(logger, level)(msg) + + +def web_socket_do_extra_handshake(request): + return + + +def web_socket_transfer_data(request): + """Handle opening a websocket connection.""" + + uuid, direction = parse_request(request) + log(uuid, f"Got web_socket_transfer_data {direction}") + + # Get or create the relevant queue from the stash and update the refcount + with stash.lock: + value = stash.take(uuid) + if value is None: + queue = stash.get_queue() + if direction == "read": + has_reader = True + writer_count = 0 + else: + has_reader = False + writer_count = 1 + else: + queue, has_reader, writer_count = value + if direction == "read": + if has_reader: + raise ValueError("Tried to start multiple readers for the same queue") + has_reader = True + else: + writer_count += 1 + + stash.put(uuid, (queue, has_reader, writer_count)) + + if direction == "read": + run_read(request, uuid, queue) + elif direction == "write": + run_write(request, uuid, queue) + + log(uuid, f"transfer_data loop exited {direction}") + close_channel(uuid, direction) + + +def web_socket_passive_closing_handshake(request): + """Handle a client initiated close. + + When the client closes a reader, put a message in the message + queue indicating the close. For a writer we don't need special + handling here because receive_message in run_read will return an + empty message in this case, so that loop will exit on its own. + """ + uuid, direction = parse_request(request) + log(uuid, f"Got web_socket_passive_closing_handshake {direction}") + + if direction == "read": + with stash.lock: + data = stash.take(uuid) + stash.put(uuid, data) + if data is not None: + queue = data[0] + queue.put(("close", None)) + + return request.ws_close_code, request.ws_close_reason + + +def parse_request(request): + query = request.unparsed_uri.split('?')[1] + GET = dict(urllib.parse.parse_qsl(query)) + uuid = GET["uuid"] + direction = GET["direction"] + return uuid, direction + + +def wait_for_close(request, uuid, queue): + """Listen for messages on the socket for a read connection to a channel.""" + closed = False + while not closed: + try: + msg = request.ws_stream.receive_message() + if msg is None: + break + try: + cmd, data = json.loads(msg) + except ValueError: + cmd = None + if cmd == "close": + closed = True + log(uuid, "Got client initiated close") + else: + log(uuid, f"Unexpected message on read socket {msg}", "warning") + except Exception: + if not (request.server_terminated or request.client_terminated): + log(uuid, f"Got exception in wait_for_close\n{traceback.format_exc()}") + closed = True + + if not request.server_terminated: + queue.put(("close", None)) + + +def run_read(request, uuid, queue): + """Main loop for a read-type connection. + + This mostly just listens on the queue for new messages of the + form (message, data). Supported messages are: + message - Send `data` on the WebSocket + close - Close the reader queue + + In addition there's a thread that listens for messages on the + socket itself. Typically this socket shouldn't recieve any + messages, but it can recieve an explicit "close" message, + indicating the socket should be disconnected. + """ + + close_thread = threading.Thread(target=wait_for_close, args=(request, uuid, queue), daemon=True) + close_thread.start() + + while True: + try: + data = queue.get(True, 1) + except Empty: + if request.server_terminated or request.client_terminated: + break + else: + cmd, body = data + log(uuid, f"queue.get ({cmd}, {body})") + if cmd == "close": + break + if cmd == "message": + msgutil.send_message(request, json.dumps(body)) + else: + log(uuid, f"Unknown queue command {cmd}", level="warning") + + +def run_write(request, uuid, queue): + """Main loop for a write-type connection. + + Messages coming over the socket have the format (command, data). + The recognised commands are: + message - Send the message `data` over the channel. + disconnectReader - Close the reader connection for this channel. + delete - Force-delete the entire channel and the underlying queue. + """ + while True: + msg = request.ws_stream.receive_message() + if msg is None: + break + cmd, body = json.loads(msg) + if cmd == "disconnectReader": + queue.put(("close", None)) + elif cmd == "message": + log(uuid, f"queue.put ({cmd}, {body})") + queue.put((cmd, body)) + elif cmd == "delete": + close_channel(uuid, None) + + +def close_channel(uuid, direction): + """Update the channel state in the stash when closing a connection + + This updates the stash entry, including refcounts, once a + connection to a channel is closed. + + Params: + uuid - the UUID of the channel being closed. + direction - "read" if a read connection was closed, "write" if a + write connection was closed, None to remove the + underlying queue from the stash entirely. + + """ + log(uuid, f"Got close_channel {direction}") + with stash.lock: + data = stash.take(uuid) + if data is None: + log(uuid, "Message queue already deleted") + return + if direction is None: + # Return without replacing the channel in the stash + log(uuid, "Force deleting message queue") + return + queue, has_reader, writer_count = data + if direction == "read": + has_reader = False + else: + writer_count -= 1 + + if has_reader or writer_count > 0 or not queue.empty(): + log(uuid, f"Updating refcount {has_reader}, {writer_count}") + stash.put(uuid, (queue, has_reader, writer_count)) + else: + log(uuid, "Deleting message queue") diff --git a/testing/web-platform/tests/websockets/handlers/origin_wsh.py b/testing/web-platform/tests/websockets/handlers/origin_wsh.py new file mode 100755 index 0000000000..ce5f3a7f6a --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/origin_wsh.py @@ -0,0 +1,11 @@ +#!/usr/bin/python + +from mod_pywebsocket import msgutil + + +def web_socket_do_extra_handshake(request): + pass # Always accept. + + +def web_socket_transfer_data(request): + msgutil.send_message(request, request.ws_origin) diff --git a/testing/web-platform/tests/websockets/handlers/protocol_array_wsh.py b/testing/web-platform/tests/websockets/handlers/protocol_array_wsh.py new file mode 100755 index 0000000000..be24ee01fd --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/protocol_array_wsh.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +from mod_pywebsocket import msgutil + +def web_socket_do_extra_handshake(request): + line = request.headers_in.get('sec-websocket-protocol') + request.ws_protocol = line.split(',', 1)[0] + +#pass + +def web_socket_transfer_data(request): + while True: + msgutil.send_message(request, request.ws_protocol) + return diff --git a/testing/web-platform/tests/websockets/handlers/protocol_wsh.py b/testing/web-platform/tests/websockets/handlers/protocol_wsh.py new file mode 100755 index 0000000000..10bdf33205 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/protocol_wsh.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +from mod_pywebsocket import msgutil + +def web_socket_do_extra_handshake(request): + request.ws_protocol = request.headers_in.get('sec-websocket-protocol') +#pass + +def web_socket_transfer_data(request): + while True: + msgutil.send_message(request, request.ws_protocol) + return diff --git a/testing/web-platform/tests/websockets/handlers/receive-backpressure_wsh.py b/testing/web-platform/tests/websockets/handlers/receive-backpressure_wsh.py new file mode 100755 index 0000000000..9c2e4709fd --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/receive-backpressure_wsh.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +import time + + +def web_socket_do_extra_handshake(request): + # Turn off permessage-deflate, otherwise it shrinks our 8MB buffer to 8KB. + request.ws_extension_processors = [] + + +def web_socket_transfer_data(request): + # Wait two seconds to cause backpressure. + time.sleep(2); + request.ws_stream.receive_message() diff --git a/testing/web-platform/tests/websockets/handlers/receive-many-with-backpressure_wsh.py b/testing/web-platform/tests/websockets/handlers/receive-many-with-backpressure_wsh.py new file mode 100644 index 0000000000..8e35beebdf --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/receive-many-with-backpressure_wsh.py @@ -0,0 +1,23 @@ +# Sleep to build backpressure, receive messages, and send back their length. +# Used by send-many-64K-messages-with-backpressure.any.js. + + +import time + + +def web_socket_do_extra_handshake(request): + # Compression will interfere with backpressure, so disable the + # permessage-delate extension. + request.ws_extension_processors = [] + + +def web_socket_transfer_data(request): + while True: + # Don't read the message immediately, so backpressure can build. + time.sleep(0.1) + line = request.ws_stream.receive_message() + if line is None: + return + # Send back the size of the message as acknowledgement that it was + # received. + request.ws_stream.send_message(str(len(line)), binary=False) diff --git a/testing/web-platform/tests/websockets/handlers/referrer_wsh.py b/testing/web-platform/tests/websockets/handlers/referrer_wsh.py new file mode 100755 index 0000000000..9df652dc3c --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/referrer_wsh.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +from mod_pywebsocket import msgutil + +def web_socket_do_extra_handshake(request): + pass + +def web_socket_transfer_data(request): + referrer = request.headers_in.get("referer") + if referrer is None: + referrer = "MISSING AS PER FETCH" + msgutil.send_message(request, referrer) diff --git a/testing/web-platform/tests/websockets/handlers/send-backpressure_wsh.py b/testing/web-platform/tests/websockets/handlers/send-backpressure_wsh.py new file mode 100755 index 0000000000..d3288d0e85 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/send-backpressure_wsh.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +import time + +# The amount of internal buffering a WebSocket connection has is not +# standardised, and varies depending upon the OS. Setting this number too small +# will result in false negatives, as the entire message gets buffered. Setting +# this number too large will result in false positives, when it takes more than +# 2 seconds to transmit the message anyway. This number was arrived at by +# trial-and-error. +MESSAGE_SIZE = 1024 * 1024 + +# With Windows 10 and Python 3, the OS will buffer an entire message in memory +# and return from send() immediately, even if it is very large. To work around +# this problem, send multiple messages. +MESSAGE_COUNT = 16 + + +def web_socket_do_extra_handshake(request): + # Turn off permessage-deflate, otherwise it shrinks our big message to a + # tiny message. + request.ws_extension_processors = [] + + +def web_socket_transfer_data(request): + # Send empty message to fill the ReadableStream queue + request.ws_stream.send_message(b'', binary=True) + + # TODO(ricea@chromium.org): Use time.perf_counter() when migration to python + # 3 is complete. time.time() can go backwards. + start_time = time.time() + + # The large messages that will be blocked by backpressure. + for i in range(MESSAGE_COUNT): + request.ws_stream.send_message(b' ' * MESSAGE_SIZE, binary=True) + + # Report the time taken to send the large message. + request.ws_stream.send_message(str(time.time() - start_time), + binary=False) diff --git a/testing/web-platform/tests/websockets/handlers/set-cookie-secure_wsh.py b/testing/web-platform/tests/websockets/handlers/set-cookie-secure_wsh.py new file mode 100755 index 0000000000..052a882084 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/set-cookie-secure_wsh.py @@ -0,0 +1,11 @@ +#!/usr/bin/python +import urllib + + +def web_socket_do_extra_handshake(request): + url_parts = urllib.parse.urlsplit(request.uri) + request.extra_headers.append(('Set-Cookie', 'ws_test_'+(url_parts.query or '')+'=test; Secure; Path=/')) + +def web_socket_transfer_data(request): + # Expect close() from user agent. + request.ws_stream.receive_message() diff --git a/testing/web-platform/tests/websockets/handlers/set-cookie_http_wsh.py b/testing/web-platform/tests/websockets/handlers/set-cookie_http_wsh.py new file mode 100755 index 0000000000..5331091964 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/set-cookie_http_wsh.py @@ -0,0 +1,11 @@ +#!/usr/bin/python + +import urllib + +def web_socket_do_extra_handshake(request): + url_parts = urllib.parse.urlsplit(request.uri) + request.extra_headers.append(('Set-Cookie', 'ws_test_'+(url_parts.query or '')+'=test; Path=/; HttpOnly\x0D\x0ASec-WebSocket-Origin: '+request.ws_origin)) + +def web_socket_transfer_data(request): + # Expect close from user agent. + request.ws_stream.receive_message() diff --git a/testing/web-platform/tests/websockets/handlers/set-cookie_wsh.py b/testing/web-platform/tests/websockets/handlers/set-cookie_wsh.py new file mode 100755 index 0000000000..5fe3ad9c57 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/set-cookie_wsh.py @@ -0,0 +1,11 @@ +#!/usr/bin/python +import urllib + + +def web_socket_do_extra_handshake(request): + url_parts = urllib.parse.urlsplit(request.uri) + request.extra_headers.append(('Set-Cookie', 'ws_test_'+(url_parts.query or '')+'=test; Path=/')) + +def web_socket_transfer_data(request): + # Expect close from user agent. + request.ws_stream.receive_message() diff --git a/testing/web-platform/tests/websockets/handlers/set-cookies-samesite_wsh.py b/testing/web-platform/tests/websockets/handlers/set-cookies-samesite_wsh.py new file mode 100644 index 0000000000..59f0a4a598 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/set-cookies-samesite_wsh.py @@ -0,0 +1,25 @@ +import urllib + + +def web_socket_do_extra_handshake(request): + url_parts = urllib.parse.urlsplit(request.uri) + max_age = "" + if "clear" in url_parts.query: + max_age = "; Max-Age=0" + value = "1" + if "value" in url_parts.query: + value = urllib.parse.parse_qs(url_parts.query)["value"][0] + cookies = [ + "samesite-unspecified={}; Path=/".format(value) + max_age, + "samesite-lax={}; Path=/; SameSite=Lax".format(value) + max_age, + "samesite-strict={}; Path=/; SameSite=Strict".format(value) + max_age, + # SameSite=None cookies must be Secure. + "samesite-none={}; Path=/; SameSite=None; Secure".format(value) + max_age + ] + for cookie in cookies: + request.extra_headers.append(("Set-Cookie", cookie)) + + +def web_socket_transfer_data(request): + # Expect close() from user agent. + request.ws_stream.receive_message() diff --git a/testing/web-platform/tests/websockets/handlers/simple_handshake_wsh.py b/testing/web-platform/tests/websockets/handlers/simple_handshake_wsh.py new file mode 100755 index 0000000000..ad466877fe --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/simple_handshake_wsh.py @@ -0,0 +1,35 @@ +#!/usr/bin/python + +from mod_pywebsocket import common, stream +from mod_pywebsocket.handshake import AbortedByUserException, hybi + + +def web_socket_do_extra_handshake(request): + # Send simple response header. This test implements the handshake manually, + # so that we can send the header in the same packet as the close frame. + msg = (b'HTTP/1.1 101 Switching Protocols:\x0D\x0A' + b'Connection: Upgrade\x0D\x0A' + b'Upgrade: WebSocket\x0D\x0A' + b'Set-Cookie: ws_test=test\x0D\x0A' + b'Sec-WebSocket-Origin: %s\x0D\x0A' + b'Sec-WebSocket-Accept: %s\x0D\x0A\x0D\x0A') % (request.ws_origin.encode( + 'UTF-8'), hybi.compute_accept_from_unicode(request.headers_in.get(common.SEC_WEBSOCKET_KEY_HEADER))) + # Create a clean close frame. + close_body = stream.create_closing_handshake_body(1001, 'PASS') + close_frame = stream.create_close_frame(close_body) + # Concatenate the header and the close frame and write them to the socket. + request.connection.write(msg + close_frame) + # Wait for the responding close frame from the user agent. It's not possible + # to use the stream methods at this point because the stream hasn't been + # established from pywebsocket's point of view. Instead just read the + # correct number of bytes. + # Warning: reading the wrong number of bytes here will make the test + # flaky. + MASK_LENGTH = 4 + request.connection.read(len(close_frame) + MASK_LENGTH) + # Close the socket without pywebsocket sending its own handshake response. + raise AbortedByUserException('Abort the connection') + + +def web_socket_transfer_data(request): + pass diff --git a/testing/web-platform/tests/websockets/handlers/sleep_10_v13_wsh.py b/testing/web-platform/tests/websockets/handlers/sleep_10_v13_wsh.py new file mode 100755 index 0000000000..bdef2f2afd --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/sleep_10_v13_wsh.py @@ -0,0 +1,15 @@ +#!/usr/bin/python + +import sys, urllib, time +from mod_pywebsocket import msgutil + +def web_socket_do_extra_handshake(request): + time.sleep(10) + return + +def web_socket_transfer_data(request): + while True: + line = msgutil.receive_message(request) + if line == 'Goodbye': + return + request.ws_stream.send_message(line, binary=False) diff --git a/testing/web-platform/tests/websockets/handlers/stash_responder_blocking_wsh.py b/testing/web-platform/tests/websockets/handlers/stash_responder_blocking_wsh.py new file mode 100755 index 0000000000..10ecdfe0da --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/stash_responder_blocking_wsh.py @@ -0,0 +1,45 @@ +#!/usr/bin/python +import json +import threading +import wptserve.stash +from mod_pywebsocket import msgutil + +address, authkey = wptserve.stash.load_env_config() +path = "/stash_responder_blocking" +stash = wptserve.stash.Stash(path, address=address, authkey=authkey) +cv = threading.Condition() + +def handle_set(key, value): + with cv: + stash.put(key, value) + cv.notify_all() + +def handle_get(key): + with cv: + while True: + value = stash.take(key) + if value is not None: + return value + cv.wait() + +def web_socket_do_extra_handshake(request): + pass + +def web_socket_transfer_data(request): + line = request.ws_stream.receive_message() + + query = json.loads(line) + action = query["action"] + key = query["key"] + + if action == "set": + value = query["value"] + handle_set(key, value) + response = {} + elif action == "get": + value = handle_get(key) + response = {"value": value} + else: + response = {} + + msgutil.send_message(request, json.dumps(response)) diff --git a/testing/web-platform/tests/websockets/handlers/stash_responder_wsh.py b/testing/web-platform/tests/websockets/handlers/stash_responder_wsh.py new file mode 100755 index 0000000000..d18ad3bc96 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/stash_responder_wsh.py @@ -0,0 +1,45 @@ +#!/usr/bin/python +import json +import urllib +from mod_pywebsocket import msgutil +from wptserve import stash + +address, authkey = stash.load_env_config() +stash = stash.Stash("/stash_responder", address=address, authkey=authkey) + +def web_socket_do_extra_handshake(request): + return + +def web_socket_transfer_data(request): + while True: + line = request.ws_stream.receive_message() + if line == "echo": + query = request.unparsed_uri.split('?')[1] + GET = dict(urllib.parse.parse_qsl(query)) + + # TODO(kristijanburnik): This code should be reused from + # /mixed-content/generic/expect.py or implemented more generally + # for other tests. + path = GET.get("path", request.unparsed_uri.split('?')[0]) + key = GET["key"] + action = GET["action"] + + if action == "put": + value = GET["value"] + stash.take(key=key, path=path) + stash.put(key=key, value=value, path=path) + response_data = json.dumps({"status": "success", "result": key}) + elif action == "purge": + value = stash.take(key=key, path=path) + response_data = json.dumps({"status": "success", "result": value}) + elif action == "take": + value = stash.take(key=key, path=path) + if value is None: + status = "allowed" + else: + status = "blocked" + response_data = json.dumps({"status": status, "result": value}) + + msgutil.send_message(request, response_data) + + return diff --git a/testing/web-platform/tests/websockets/handlers/wrong_accept_key_wsh.py b/testing/web-platform/tests/websockets/handlers/wrong_accept_key_wsh.py new file mode 100755 index 0000000000..43240e1afb --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/wrong_accept_key_wsh.py @@ -0,0 +1,19 @@ +#!/usr/bin/python + +import sys, urllib, time + + +def web_socket_do_extra_handshake(request): + msg = (b'HTTP/1.1 101 Switching Protocols:\x0D\x0A' + b'Connection: Upgrade\x0D\x0A' + b'Upgrade: WebSocket\x0D\x0A' + b'Sec-WebSocket-Origin: %s\x0D\x0A' + b'Sec-WebSocket-Accept: thisisawrongacceptkey\x0D\x0A\x0D\x0A') % request.ws_origin.encode('UTF-8') + request.connection.write(msg) + return + + +def web_socket_transfer_data(request): + while True: + request.ws_stream.send_message('test', binary=False) + return diff --git a/testing/web-platform/tests/websockets/idlharness.any.js b/testing/web-platform/tests/websockets/idlharness.any.js new file mode 100644 index 0000000000..653cc36d21 --- /dev/null +++ b/testing/web-platform/tests/websockets/idlharness.any.js @@ -0,0 +1,17 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +// https://websockets.spec.whatwg.org/ + +"use strict"; + +idl_test( + ['websockets'], + ['html', 'dom'], + idl_array => { + idl_array.add_objects({ + WebSocket: ['new WebSocket("ws://invalid")'], + CloseEvent: ['new CloseEvent("close")'], + }); + } +); diff --git a/testing/web-platform/tests/websockets/interfaces/CloseEvent/clean-close.html b/testing/web-platform/tests/websockets/interfaces/CloseEvent/clean-close.html new file mode 100644 index 0000000000..8614028fd0 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/CloseEvent/clean-close.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>WebSockets: wasClean, true</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + ws.send('Test'); + }); + ws.onmessage = t.step_func(function(e) { + ws.close(); + }); + ws.onclose = t.step_func(function(e) { + assert_equals(e.wasClean,true); + t.done(); + }); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/CloseEvent/constructor.html b/testing/web-platform/tests/websockets/interfaces/CloseEvent/constructor.html new file mode 100644 index 0000000000..1ed86bdf8f --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/CloseEvent/constructor.html @@ -0,0 +1,35 @@ +<!doctype html> +<meta charset=utf-8> +<title>CloseEvent: constructor</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var event = new CloseEvent("foo"); + assert_true(event instanceof CloseEvent, "should be a CloseEvent"); + assert_equals(event.type, "foo"); + assert_false(event.bubbles, "bubbles"); + assert_false(event.cancelable, "cancelable"); + assert_false(event.wasClean, "wasClean"); + assert_equals(event.code, 0); + assert_equals(event.reason, ""); +}, "new CloseEvent() without dictionary"); + +test(function() { + var event = new CloseEvent("foo", { + bubbles: true, + cancelable: true, + wasClean: true, + code: 7, + reason: "x", + }); + assert_true(event instanceof CloseEvent, "should be a CloseEvent"); + assert_equals(event.type, "foo"); + assert_true(event.bubbles, "bubbles"); + assert_true(event.cancelable, "cancelable"); + assert_true(event.wasClean, "wasClean"); + assert_equals(event.code, 7); + assert_equals(event.reason, "x"); +}, "new CloseEvent() with dictionary"); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/CloseEvent/historical.html b/testing/web-platform/tests/websockets/interfaces/CloseEvent/historical.html new file mode 100644 index 0000000000..24528a86fb --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/CloseEvent/historical.html @@ -0,0 +1,12 @@ +<!doctype html> +<meta charset=utf-8> +<title>CloseEvent: historical initialization</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + assert_false("initCloseEvent" in CloseEvent.prototype); + assert_false("initCloseEvent" in new CloseEvent('close')); +}, "initCloseEvent"); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html new file mode 100644 index 0000000000..5d2bfd076c --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html @@ -0,0 +1,27 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: bufferedAmount for ArrayBuffer</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var datasize = 10; + ws.onopen = t.step_func(function(e) { + ws.binaryType = "arraybuffer"; + var data = new ArrayBuffer(datasize); + ws.send(data); + assert_equals(ws.bufferedAmount, data.byteLength); + }) + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data.byteLength, datasize); + t.done(); + }) + ws.onclose = t.unreached_func('close event should not fire'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html new file mode 100644 index 0000000000..d0028dae0f --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html @@ -0,0 +1,28 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: bufferedAmount for blob</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var datasize = 10; + ws.onopen = t.step_func(function(e) { + ws.binaryType = "blob"; + var data = new ArrayBuffer(datasize); + ws.send(data); + assert_equals(ws.bufferedAmount, data.byteLength); + }); + ws.onmessage = t.step_func(function(e) { + assert_true(e.data instanceof Blob); + assert_equals(e.data.size, datasize); + t.done(); + }); + ws.onclose = t.unreached_func('close event should not fire'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html new file mode 100644 index 0000000000..ea6e70cfcf --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: defineProperty getter for bufferedAmount</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(){ + Object.defineProperty(WebSocket.prototype, 'bufferedAmount', { + get: function() { return 'foo'; } + }); + var ws = new WebSocket('ws://example.invalid/'); + assert_equals(ws.bufferedAmount, 'foo'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-setter.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-setter.html new file mode 100644 index 0000000000..8f0fa5c806 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-setter.html @@ -0,0 +1,20 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: defineProperty setter for bufferedAmount</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + window.setter_ran = false; + Object.defineProperty(WebSocket.prototype, 'bufferedAmount', { + set: function(v) { window[v] = true; } + }); + var ws = new WebSocket('ws://example.invalid/'); + ws.bufferedAmount = 'setter_ran'; + assert_true(setter_ran); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-deleting.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-deleting.html new file mode 100644 index 0000000000..1d99636bf0 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-deleting.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: delete bufferedAmount</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + assert_equals(ws.bufferedAmount, 0, 'after creation'); + ws.close(); + delete ws.bufferedAmount; + assert_equals(ws.bufferedAmount, 0, + 'after attempt to delete ws.bufferedAmount'); + delete WebSocket.prototype.bufferedAmount; + assert_equals(ws.bufferedAmount, undefined, + 'after attempt to delete WebSocket.prototype.bufferedAmount'); +}); +</script> + diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-getting.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-getting.html new file mode 100644 index 0000000000..92bcea6082 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-getting.html @@ -0,0 +1,54 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: bufferedAmount after send()ing</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t){ + // bufferedAmount should increase sync in the send() method and decrease between + // events in the event loop (so never while script is running). + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + ws.send('x'); + assert_equals(ws.bufferedAmount, 1, 'bufferedAmount after sent "x"'); + ws.send('\u00E5'); + assert_equals(ws.bufferedAmount, 1+2, 'bufferedAmount after sent "x", "\u00E5"'); + ws.send('\u5336'); + assert_equals(ws.bufferedAmount, 1+2+3, 'bufferedAmount after sent "x", "\u00E5", "\u5336"'); + ws.send('\uD801\uDC7E'); + assert_equals(ws.bufferedAmount, 1+2+3+4, 'bufferedAmount after sent "x", "\u00E5", "\u5336", "\uD801\uDC7E"'); + }) + var i = 0; + ws.onmessage = t.step_func(function(e) { + i++; + switch(i) { + case 1: + assert_equals(e.data, 'x'); + assert_true(ws.bufferedAmount < 2+3+4 + 1, 'bufferedAmount after received "x"'); + break; + case 2: + assert_equals(e.data, '\u00E5'); + assert_true(ws.bufferedAmount < 3+4 + 1, 'bufferedAmount after received "x", "\u00E5"'); + break; + case 3: + assert_equals(e.data, '\u5336'); + assert_true(ws.bufferedAmount < 4 + 1, 'bufferedAmount after received "x", "\u00E5", "\u5336"'); + break; + case 4: + assert_equals(e.data, '\uD801\uDC7E'); + assert_equals(ws.bufferedAmount, 0, 'bufferedAmount after received "x", "\u00E5", "\u5336", "\uD801\uDC7E"'); + t.done(); + break; + default: + assert_unreached(i); + } + }) + ws.onerror = ws.onclose = t.step_func(function() {assert_unreached()}); +}); +</script> + diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-initial.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-initial.html new file mode 100644 index 0000000000..be37b6dea0 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-initial.html @@ -0,0 +1,15 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: getting bufferedAmount</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_equals(ws.bufferedAmount, 0); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-large.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-large.html new file mode 100644 index 0000000000..18c5482535 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-large.html @@ -0,0 +1,29 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: bufferedAmount for 65K data</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var data = ""; + ws.onopen = t.step_func(function(e) { + for (var i = 0; i < 65000; i++) { + data = data + "x"; + } + ws.send(data); + assert_equals(data.length, ws.bufferedAmount); + }); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, data); + t.done(); + }) + ws.onclose = t.unreached_func('close event should not fire'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-readonly.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-readonly.html new file mode 100644 index 0000000000..152da696e1 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-readonly.html @@ -0,0 +1,16 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: setting bufferedAmount</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + ws.bufferedAmount = 5; + assert_equals(ws.bufferedAmount, 0); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-unicode.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-unicode.html new file mode 100644 index 0000000000..ab01f3c790 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-unicode.html @@ -0,0 +1,25 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: bufferedAmount for unicode data</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var data = "¥¥¥¥¥¥"; + ws.onopen = t.step_func(function(e) { + ws.send(data); + assert_equals(data.length * 2, ws.bufferedAmount); + }); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, data); + t.done(); + }); + ws.onclose = t.unreached_func('close event should not fire'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-basic.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-basic.html new file mode 100644 index 0000000000..b646ca4167 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-basic.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>WebSockets: close()</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + ws.onclose = t.step_func(function(e) { + assert_equals(e instanceof CloseEvent, true, 'e instanceof CloseEvent'); + assert_equals(e.wasClean, false, 'e.wasClean'); + e.wasClean = true; + assert_equals(e.wasClean, false, 'e.wasClean = true'); + delete e.wasClean; + assert_equals(e.wasClean, false, 'delete e.wasClean'); + delete CloseEvent.prototype.wasClean; + assert_equals(e.wasClean, undefined, 'delete CloseEvent.prototype.wasClean'); + t.done(); + }); + ws.close(); + assert_equals(ws.readyState, ws.CLOSING); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-connecting-async.any.js b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-connecting-async.any.js new file mode 100644 index 0000000000..88005520b0 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-connecting-async.any.js @@ -0,0 +1,31 @@ +// META: script=../../../constants.sub.js +// META: variant=?default +// META: variant=?wpt_flags=h2 +// META: variant=?wss + +async_test(t => { + const ws = new WebSocket(SCHEME_DOMAIN_PORT + '/handshake_sleep_2'); + let closeMethodReturned = false; + let errorEventSeen = false; + let closeEventSeen = false; + ws.onerror = t.step_func(() => { + assert_true(closeMethodReturned, 'ws.close() should have returned'); + assert_false(errorEventSeen, 'error event should only fire once'); + errorEventSeen = true; + assert_false(closeEventSeen, 'error event should come before close event'); + }); + ws.onclose = t.step_func_done(() => { + assert_true(closeMethodReturned, 'ws.close() should have returned'); + assert_true(errorEventSeen, 'error event should have fired'); + assert_false(closeEventSeen, 'close event should only fire once'); + closeEventSeen = true; + assert_equals(ws.readyState, WebSocket.CLOSED, + 'readyState should be CLOSED'); + }); + assert_equals(ws.readyState, WebSocket.CONNECTING, + 'readyState should be CONNECTING'); + ws.close(); + closeMethodReturned = true; + assert_equals(ws.readyState, WebSocket.CLOSING, + 'readyState should be CLOSING'); +}, 'close event should be fired asynchronously when WebSocket is connecting'); diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-connecting.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-connecting.html new file mode 100644 index 0000000000..de038ca09f --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-connecting.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>WebSockets: close() when connecting</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/sleep_10_v13'); + t.step_timeout(function() { + assert_equals(ws.readyState, ws.CONNECTING); + ws.close(); + assert_equals(ws.readyState, ws.CLOSING); + ws.onclose = t.step_func(function(e) { + assert_equals(ws.readyState, ws.CLOSED); + assert_equals(e.wasClean, false); + t.done(); + }); + }, 1000); + ws.onopen = ws.onclose = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-multiple.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-multiple.html new file mode 100644 index 0000000000..e440d80179 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-multiple.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>WebSockets: close() several times</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var i = 0; +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + ws.onclose = t.step_func(function(e) { + i++; + }); + ws.close(); + ws.close(); + ws.close(); + var f = t.step_func(function() { + if (i < 1) { + t.step_timeout(f, 500); + return; + } + assert_equals(i, 1); + t.done() + }); + t.step_timeout(f, 500); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-nested.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-nested.html new file mode 100644 index 0000000000..74b8fa0c48 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-nested.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>WebSockets: close() in close event handler</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + var i = 0; + ws.onclose = t.step_func(function(e) { + i++; + if (i == 1) { + assert_equals(ws.readyState, ws.CLOSED); + ws.close(); + assert_equals(ws.readyState, ws.CLOSED); + } + t.step_timeout(function() { + assert_equals(i, 1); + t.done(); + }, 50); + }); + ws.close(); + assert_equals(ws.readyState, ws.CLOSING); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-replace.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-replace.html new file mode 100644 index 0000000000..e9d2364794 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-replace.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>WebSockets: replacing close</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + ws.close = 5; + assert_equals(ws.close, 5); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-return.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-return.html new file mode 100644 index 0000000000..e74c9b076d --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/close/close-return.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>WebSockets: close() return value</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_equals(ws.close(), undefined); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/001.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/001.html new file mode 100644 index 0000000000..7d79bf5d7b --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/001.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>WebSockets: getting constants on constructor</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var constants = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; +for (var i = 0; i < constants.length; ++i) { + test(function(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_equals(WebSocket[constants[i]], i, 'WebSocket.'+constants[i]); + }, "Constants on constructors " + constants[i]); +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/002.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/002.html new file mode 100644 index 0000000000..6810bc6c29 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/002.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>WebSockets: setting constants</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +// this test is testing WebIDL stuff +var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); +var constants = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; +for (var i = 0; i < constants.length; ++i) { + test(function() { + WebSocket[constants[i]] = 5; // should be ignored, has { ReadOnly } + WebSocket.prototype[constants[i]] = 5; // should be ignored, has { ReadOnly } + ws[constants[i]] = 5; // should be ignored, { ReadOnly } is inherited from prototype + assert_equals(WebSocket[constants[i]], i, 'WebSocket.'+constants[i]); + assert_equals(WebSocket.prototype[constants[i]], i, 'WebSocket.prototype.'+constants[i]); + assert_equals(ws[constants[i]], i, 'ws.'+constants[i]); + }, "Readonly constants " + constants[i]); +}; +</script> + diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/003.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/003.html new file mode 100644 index 0000000000..4a86af8b1c --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/003.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>WebSockets: deleting constants</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var constants = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; +for (var i = 0; i < constants.length; ++i) { + test(function(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + delete WebSocket[constants[i]]; // should be ignored, has { DontDelete } + delete WebSocket.prototype[constants[i]]; // should be ignored, has { DontDelete } + delete ws[constants[i]]; // should be ignored, there is no such property on the object + assert_equals(WebSocket[constants[i]], i, 'WebSocket.'+constants[i]); + assert_equals(WebSocket.prototype[constants[i]], i, 'WebSocket.prototype.'+constants[i]); + assert_equals(ws[constants[i]], i, 'ws.'+constants[i]); + }) +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/004.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/004.html new file mode 100644 index 0000000000..2ca3830b72 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/004.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>WebSockets: getting constants on prototype and object</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var constants = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; +for (var i = 0; i < constants.length; ++i) { + test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_equals(WebSocket.prototype[constants[i]], i); + }, 'WebSocket.prototype.'+constants[i]); + test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_equals(ws[constants[i]], i); + }, 'ws.'+constants[i]); +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/005.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/005.html new file mode 100644 index 0000000000..26d5b24d2c --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/005.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>WebSockets: defineProperty getter for constants</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var constants = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; +for (var i = 0; i < constants.length; ++i) { + test(function() { + assert_throws_js(TypeError, function() { + Object.defineProperty(WebSocket.prototype, constants[i], { + get: function() { return 'foo'; } + }); + }); + }, "defineProperty getter " + constants[i]); +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/006.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/006.html new file mode 100644 index 0000000000..78126c86f5 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/constants/006.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>WebSockets: defineProperty setter for constants</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var constants = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; +for (var i = 0; i < constants.length; ++i) { + test(function() { + assert_throws_js(TypeError, function(){ + Object.defineProperty(WebSocket.prototype, constants[i], { + set: function() { return 'foo'; } + }); + }); + }, "defineProperty setter " + constants[i]) +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/001.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/001.html new file mode 100644 index 0000000000..88dcf9e424 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/001.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>WebSockets: getting on*</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +var events = ['open', 'message', 'error', 'close']; +for (var i = 0; i < events.length; ++i) { + test(function(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_equals(ws['on'+events[i]], null, 'on'+events[i]); + }); +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/002.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/002.html new file mode 100644 index 0000000000..481730800c --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/002.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>WebSockets: setting on*</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +var events = ['open', 'message', 'error', 'close']; +for (var i = 0; i < events.length; ++i) { + test(function(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + var foo = function () {}; + ws['on'+events[i]] = foo; + assert_equals(ws['on'+events[i]], foo); + }); +} +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/003.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/003.html new file mode 100644 index 0000000000..a5373ecded --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/003.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>WebSockets: listening for events with onopen</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + var foo = t.step_func(function (e) { + if (e.detail == 5) + t.done(); + }) + ws.onopen = foo; + var ev = document.createEvent('UIEvents'); + ev.initUIEvent('open', false, false, window, 5); + ws.dispatchEvent(ev); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/004.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/004.html new file mode 100644 index 0000000000..9c5144cefa --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/004.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>WebSockets: members of EventTarget</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_equals(typeof ws.addEventListener, 'function'); + assert_equals(typeof ws.removeEventListener, 'function'); + assert_equals(typeof ws.dispatchEvent, 'function'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/006.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/006.html new file mode 100644 index 0000000000..de2f55694d --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/006.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>WebSockets: 'on*' in ws</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_equals('onopen' in ws, true, 'onopen'); + assert_equals('onmessage' in ws, true, 'onmessage'); + assert_equals('onerror' in ws, true, 'onerror'); + assert_equals('onclose' in ws, true, 'onclose'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/007.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/007.html new file mode 100644 index 0000000000..0fe7241ecf --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/007.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>WebSockets: listening for events with onmessage</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + var foo = t.step_func(function (e) { + if (e.detail == 5) + t.done(); + }) + ws.onmessage = foo; + var ev = document.createEvent('UIEvents'); + ev.initUIEvent('message', false, false, window, 5); + ws.dispatchEvent(ev); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/008.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/008.html new file mode 100644 index 0000000000..066eb0922e --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/008.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>WebSockets: listening for events with onerror</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + var run = false; + var foo = t.step_func(function (e) { + run = true; + assert_equals(e.detail, 5) + }); + ws.onerror = foo; + var ev = document.createEvent('UIEvents'); + ev.initUIEvent('error', false, false, window, 5); + ws.dispatchEvent(ev); + assert_true(run); + t.done(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/009.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/009.html new file mode 100644 index 0000000000..b9e56e2fbd --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/009.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>WebSockets: listening for events with onclose</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + var foo = t.step_func(function (e) { + if (e.detail == 5) + t.done(); + }); + ws.onclose = foo; + var ev = document.createEvent('UIEvents'); + ev.initUIEvent('close', false, false, window, 5); + ws.dispatchEvent(ev); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/010.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/010.html new file mode 100644 index 0000000000..360e7d9bd2 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/010.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>WebSockets: setting event handlers to undefined</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var events = ['onclose', 'onopen', 'onerror', 'onmessage']; +for (var i = 0; i < events.length; ++i) { + test(function(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/empty-message'); + var foo = function() {} + ws[events[i]] = foo; + assert_equals(ws[events[i]], foo, events[i]); + ws[events[i]] = undefined; + assert_equals(ws[events[i]], null, events[i]); + }); +} +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/011.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/011.html new file mode 100644 index 0000000000..f64857579e --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/011.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>WebSockets: setting event handlers to 1</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var events = ['onclose', 'onopen', 'onerror', 'onmessage']; +for (var i = 0; i < events.length; ++i) { + test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/empty-message'); + ws[events[i]] = 1; + assert_equals(ws[events[i]], null); + }, events[i]); +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/012.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/012.html new file mode 100644 index 0000000000..bdd63e3f69 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/012.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>WebSockets: setting event handlers to ";"</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var events = ['onclose', 'onopen', 'onerror', 'onmessage']; +for (var i = 0; i < events.length; ++i) { + test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/empty-message'); + ws[events[i]] = ";"; + assert_equals(ws[events[i]], null); + }, events[i]); +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/013.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/013.html new file mode 100644 index 0000000000..9e251c6217 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/013.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>WebSockets: setting event handlers to {handleEvent:function(){}}</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var events = ['onclose', 'onopen', 'onerror', 'onmessage']; +for (var i = 0; i < events.length; ++i) { + test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/empty-message'); + var obj = {handleEvent:this.unreached_func("handleEvent was called")}; + ws[events[i]] = obj; + assert_equals(ws[events[i]], obj); + ws.dispatchEvent(new Event(events[i].substr(2))); + }, events[i]); +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/014.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/014.html new file mode 100644 index 0000000000..9fcd8b3f6a --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/014.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>WebSockets: setting event handlers to null</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var events = ['onclose', 'onopen', 'onerror', 'onmessage']; +for (var i = 0; i < events.length; ++i) { + test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/empty-message'); + var foo = function() {} + ws[events[i]] = foo; + assert_equals(ws[events[i]], foo, events[i]); + ws[events[i]] = null; + assert_equals(ws[events[i]], null, events[i]); + }, "Setting event handlers to null " + events[i]); +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/015.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/015.html new file mode 100644 index 0000000000..5089c0fb67 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/015.html @@ -0,0 +1,36 @@ +<!doctype html> +<title>WebSockets: instanceof on events</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo_raw'); + ws.onopen = t.step_func(function(e) { + assert_true(e instanceof Event); + // first a text frame, then a frame with reserved opcode 3 + // which should fail the connection + + // send '\\x81\\x04test\\x83\\x03LOL' in bytes + ws.send(new Uint8Array([129, 4, 116, 101, 115, 116, 131, 3, 76, 79, 76])); + }); + ws.onmessage = t.step_func(function(e) { + assert_true(e instanceof Event); + assert_true(e instanceof MessageEvent); + assert_equals(ws.readyState, ws.OPEN); + }) + ws.onerror = t.step_func(function(e) { + assert_true(e instanceof Event); + assert_equals(ws.readyState, ws.CLOSED); + }) + ws.onclose = t.step_func(function(e) { + assert_true(e instanceof Event); + assert_true(e instanceof CloseEvent); + t.done(); + }) +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/016.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/016.html new file mode 100644 index 0000000000..8b5aaf9f42 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/016.html @@ -0,0 +1,39 @@ +<!doctype html> +<title>WebSockets: addEventListener</title> +<meta name="timeout" content="long"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var count = 0; + var checkCount = t.step_func(function (c, e) { + count++; + assert_equals(count, c); + }); + // no spec requires this order for event listeners but the web does + ws.addEventListener('open', t.step_func(function(e) { + checkCount(1, e); + ws.send('Goodbye'); + }), false); + ws.onopen = t.step_func(function(e) {checkCount(2, e) }); + ws.addEventListener('open', t.step_func(function(e) {checkCount(3, e); }), false); + + ws.addEventListener('message', t.step_func(function(e) {checkCount(4, e); }), false); + ws.onmessage = t.step_func(function(e) {checkCount(5, e) }); + ws.addEventListener('message', t.step_func(function(e) {checkCount(6, e); }), false); + + ws.addEventListener('close', t.step_func(function(e) {checkCount(7, e); }), false); + ws.onclose = t.step_func(function(e) {checkCount(8, e) }); + ws.addEventListener('close', t.step_func(function(e) { + checkCount(9, e); + t.done(); + }), false); + +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/017.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/017.html new file mode 100644 index 0000000000..a9f06eaf7d --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/017.html @@ -0,0 +1,56 @@ +<!doctype html> +<title>WebSockets: this, e.target, e.currentTarget, e.eventPhase</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo_raw'); + ws.addEventListener('open', function(e) { + var this_val = this; + t.step(function() { + // first a text frame, then a frame with reserved opcode 3 + // which should fail the connection + + // send '\\x81\\x04test\\x83\\x03LOL' in bytes + ws.send(new Uint8Array([129, 4, 116, 101, 115, 116, 131, 3, 76, 79, 76])); + assert_equals(this_val, ws); + assert_equals(e.target, ws); + assert_equals(e.currentTarget, ws); + assert_equals(e.eventPhase, 2); + }); + }, false); + ws.addEventListener('message', function(e) { + var this_val = this; + t.step(function() { + assert_equals(this_val, ws); + assert_equals(e.target, ws); + assert_equals(e.currentTarget, ws); + assert_equals(e.eventPhase, 2); + }); + }, false); + ws.addEventListener('error', function(e) { + var this_val = this; + t.step(function() { + assert_equals(this_val, ws); + assert_equals(e.target, ws); + assert_equals(e.currentTarget, ws); + assert_equals(e.eventPhase, 2); + }); + }, false); + ws.addEventListener('close', function(e) { + var this_val = this; + t.step(function() { + assert_equals(this_val, ws); + assert_equals(e.target, ws); + assert_equals(e.currentTarget, ws); + assert_equals(e.eventPhase, 2); + t.done(); + }); + }, false); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/018.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/018.html new file mode 100644 index 0000000000..a340c69f45 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/018.html @@ -0,0 +1,52 @@ +<!doctype html> +<title>WebSockets: toString(), bubbles, cancelable</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +var ws = null; +setup(function() { + ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo_raw'); +}); + +async_test(function(t) { + let openFired = false; + let messageFired = false; + let errorFired = false; + ws.addEventListener('open', t.step_func(function(e) { + openFired = true; + // first a text frame, then a frame with reserved opcode 3 + // which should fail the connection + + // send '\\x81\\x04test\\x83\\x03LOL' in bytes + ws.send(new Uint8Array([129, 4, 116, 101, 115, 116, 131, 3, 76, 79, 76])); + assert_equals(e.toString(), '[object Event]', "open e.toString()"); + assert_equals(e.bubbles, false, 'open e.bubbles'); + assert_equals(e.cancelable, false, 'open e.cancelable'); + }), false); + ws.addEventListener('message', t.step_func(function(e) { + messageFired = true; + assert_equals(e.toString(), '[object MessageEvent]', "message e.toString()"); + assert_equals(e.bubbles, false, 'message e.bubbles'); + assert_equals(e.cancelable, false, 'message e.cancelable'); + }), false); + ws.addEventListener('error', t.step_func(function(e) { + errorFired = true; + assert_equals(e.toString(), '[object Event]', "error e.toString()"); + assert_equals(e.bubbles, false, 'error e.bubbles'); + assert_equals(e.cancelable, false, 'error e.cancelable'); + }), false); + ws.addEventListener('close', t.step_func_done(function(e) { + assert_true(openFired, 'open event should fire'); + assert_true(messageFired, 'message event should fire'); + assert_true(errorFired, 'error event should fire'); + assert_equals(e.toString(), '[object CloseEvent]', "close e.toString()"); + assert_equals(e.bubbles, false, 'close e.bubbles'); + assert_equals(e.cancelable, false, 'close e.cancelable'); + }), false); +}, "open, message, error and close events"); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/019.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/019.html new file mode 100644 index 0000000000..deb079f81a --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/019.html @@ -0,0 +1,31 @@ +<!doctype html> +<title>WebSockets: removeEventListener</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +var events = ['open', 'message', 'error', 'close']; +for (var i = 0; i < events.length; ++i) { + test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.close(); + var got = []; + var event; + function addThis(e) { + got.push(e.type); + } + ws.addEventListener(events[i], addThis, false); + ws.removeEventListener(events[i], addThis, false); + event = document.createEvent('Event'); + event.initEvent(events[i], false, false); + ws.dispatchEvent(event); + assert_equals(got.length, 0); + if (got.length) { + debug('Got: '+got); + } + }) +}; +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/events/020.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/020.html new file mode 100644 index 0000000000..f43b0af93f --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/events/020.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>WebSockets: error events</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket('ws://example.invalid/'); + ws.onerror = t.step_func(function(e) { + assert_true(e instanceof Event); + t.done(); + }) +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/extensions/001.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/extensions/001.html new file mode 100644 index 0000000000..bd26483a79 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/extensions/001.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>WebSockets: getting extensions in connecting</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(t) { + // The extensions attribute must initially return the empty string + assert_equals((new WebSocket(SCHEME_DOMAIN_PORT+'/empty-message')).extensions, ''); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/protocol/protocol-initial.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/protocol/protocol-initial.html new file mode 100644 index 0000000000..2e7bf66557 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/protocol/protocol-initial.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>WebSockets: getting protocol in connecting</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(t) { + // The protocol attribute must initially return the empty string + assert_equals((new WebSocket(SCHEME_DOMAIN_PORT + '/empty-message')).protocol, ''); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/001.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/001.html new file mode 100644 index 0000000000..15b73fdb7c --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/001.html @@ -0,0 +1,13 @@ +<!doctype html> +<title>WebSockets: getting readyState in connecting</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(t) { + assert_equals((new WebSocket(SCHEME_DOMAIN_PORT+'/')).readyState, WebSocket.CONNECTING); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/002.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/002.html new file mode 100644 index 0000000000..239e5d7cf8 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/002.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>WebSockets: setting readyState</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + ws.readyState = 5; + assert_equals(ws.readyState, ws.CONNECTING); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/003.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/003.html new file mode 100644 index 0000000000..65d86c437f --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/003.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>WebSockets: delete readyState</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + ws.close(); + delete ws.readyState; + assert_equals(ws.readyState, ws.CLOSING, 'delete ws.readyState'); + delete WebSocket.prototype.readyState; + assert_equals(ws.readyState, undefined, 'delete WebSocket.prototype.readyState'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/004.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/004.html new file mode 100644 index 0000000000..0645816a6c --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/004.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>WebSockets: defineProperty getter for readyState</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + Object.defineProperty(WebSocket.prototype, 'readyState', { + get: function() { return 'foo'; } + }); + var ws = new WebSocket('ws://example.invalid/'); + assert_equals(ws.readyState, 'foo'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/005.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/005.html new file mode 100644 index 0000000000..bee179ffcb --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/005.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>WebSockets: defineProperty setter for readyState</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(){ + window.setter_ran = false; + Object.defineProperty(WebSocket.prototype, 'readyState', { + set: function(v) { window[v] = true; } + }); + var ws = new WebSocket('ws://example.invalid/'); + ws.readyState = 'setter_ran'; + assert_true(setter_ran); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/006.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/006.html new file mode 100644 index 0000000000..4290c00836 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/006.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>WebSockets: getting readyState in open</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + assert_equals(ws.readyState, ws.OPEN); + ws.close(); + t.done(); + }); + ws.onerror = ws.onmessage = ws.onclose = t.step_func(function() {assert_unreached()}); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/007.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/007.html new file mode 100644 index 0000000000..69b5d9c9a9 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/007.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>WebSockets: getting readyState in closing</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + ws.close(); + assert_equals(ws.readyState, ws.CLOSING); + t.done(); + }); + ws.onerror = ws.onmessage = ws.onclose = t.step_func(function() {assert_unreached()}); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/008.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/008.html new file mode 100644 index 0000000000..d085a7f4e3 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/readyState/008.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>WebSockets: getting readyState in closed</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + ws.onclose = t.step_func(function(e) { + assert_equals(ws.readyState, ws.CLOSED); + t.done(); + }) + ws.close(); + }); + ws.onerror = ws.onmessage = ws.onclose = t.step_func(function() {assert_unreached()}); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/001.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/001.html new file mode 100644 index 0000000000..8abc655f5d --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/001.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>WebSockets: send() with no args</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_throws_js(TypeError, function(){ws.send()}); +}); +</script> + diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/002.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/002.html new file mode 100644 index 0000000000..a51c67762c --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/002.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>WebSockets: replacing send</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + ws.send = 5; + assert_equals(ws.send, 5); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/003.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/003.html new file mode 100644 index 0000000000..069f24cde5 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/003.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>WebSockets: send() when readyState is CONNECTING</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_throws_dom("INVALID_STATE_ERR", function(){ws.send('a')}); +}); +</script> + diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/004.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/004.html new file mode 100644 index 0000000000..7125d1922a --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/004.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>WebSockets: send() with unpaired surrogate when readyState is CONNECTING</title> + +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_throws_dom("INVALID_STATE_ERR", function(){ws.send('a\uDC00x')}); +}, "lone low surrogate"); + +test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_throws_dom("INVALID_STATE_ERR", function(){ws.send('a\uD800x')}); +}, "lone high surrogate"); + +test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_throws_dom("INVALID_STATE_ERR", function(){ws.send('a\uDC00\uD800x')}); +}, "surrogates in wrong order"); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/005.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/005.html new file mode 100644 index 0000000000..5da4600771 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/005.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>WebSockets: send() return value</title> +<meta name="timeout" content="long"> + +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + assert_equals(ws.send('test'), undefined); + t.done(); + }); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/006.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/006.html new file mode 100644 index 0000000000..4095c0ba6b --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/006.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>WebSockets: send() with unpaired surrogate when readyState is OPEN</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id="log"></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + // lone low surrogate, lone high surrogate + surrogates in wrong order. + ws.send('a\uDC00xb\uD800xc\uDC00\uD800x'); + }) + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, 'a\uFFFDxb\uFFFDxc\uFFFD\uFFFDx'); + ws.onclose = t.step_func(function(e) { + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }); + ws.close(); + }) + // This will be overridden if the message event fires. + ws.onclose = t.unreached_func('close event should not fire before message event'); + }); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/007.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/007.html new file mode 100644 index 0000000000..6a5614257a --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/007.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>WebSockets: close() followed by send()</title> + +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> + +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + // test that nothing strange happens if we send something after close() + ws.close(); + var sent = ws.send('test'); + assert_equals(sent, undefined); + }); + ws.onclose = t.step_func(function(e) { + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }); + ws.onerror = ws.onmessage = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/008.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/008.html new file mode 100644 index 0000000000..709c066ade --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/008.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>WebSockets: send() in onclose</title> + +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + ws.send('Goodbye'); + }) + ws.onclose = t.step_func(function(e) { + // test that nothing strange happens when send()ing in closed state + var sent = ws.send('test'); + assert_equals(sent, undefined); + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }) + ws.onerror = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/009.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/009.html new file mode 100644 index 0000000000..57da896ea6 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/009.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>WebSockets: send('')</title> + +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/empty-message'); + ws.onopen = t.step_func(function(e) { + ws.send(''); + }) + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, 'pass'); + ws.close(); + }); + ws.onclose = t.step_func(function(e) { + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }); + ws.onerror = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/010.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/010.html new file mode 100644 index 0000000000..4a008b610c --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/010.html @@ -0,0 +1,42 @@ +<!doctype html> +<title>WebSockets: sending non-strings</title> +<meta name="timeout" content="long"> + +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(outer) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + var stuffToSend = [null, undefined, 1, window, document.body, {}, [], ws, function(){}, new Error()] + var tests = []; + + for (var i=0; i<stuffToSend.length; i++) { + tests.push(async_test(document.title + " (" + stuffToSend[i] + ")")); + } + + i = 0; + function sendNext() { + if (i === stuffToSend.length) { + outer.done() + ws.close(); + } else { + var t = tests[i]; + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, String(stuffToSend[i])); + i++; + sendNext(); + t.done(); + }); + ws.onclose = ws.onerror = t.step_func(function() {assert_unreached()}); + ws.send(stuffToSend[i]); + } + } + ws.onopen = outer.step_func(function(e) { + sendNext(); + }); +}, "Constructor succeeds"); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/011.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/011.html new file mode 100644 index 0000000000..5f63c4471c --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/011.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>WebSockets: sending non-ascii, combining chars and non-BMP</title> + +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> + +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + ws.send('\u00E5 a\u030A \uD801\uDC7E'); + }); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, '\u00E5 a\u030A \uD801\uDC7E'); + ws.onclose = t.step_func(function(e) { + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }) + ws.close(); + }) + ws.onclose = ws.onerror = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/send/012.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/012.html new file mode 100644 index 0000000000..9876c7bdd3 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/send/012.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>WebSockets: sending null</title> + +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> + +async_test(function(t){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + ws.send(null); + }); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, 'null'); + ws.onclose = t.step_func(function(e) { + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }) + ws.close(); + }); + ws.onclose = ws.onerror = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/url/001.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/001.html new file mode 100644 index 0000000000..6c7306d038 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/001.html @@ -0,0 +1,13 @@ +<!doctype html> +<title>WebSockets: getting url</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + assert_equals((new WebSocket(SCHEME_DOMAIN_PORT)).url, SCHEME_DOMAIN_PORT+'/'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/url/002.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/002.html new file mode 100644 index 0000000000..e1cc6d0c01 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/002.html @@ -0,0 +1,15 @@ +<!doctype html> +<title>WebSockets: setting url</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + ws.url = SCHEME_DOMAIN_PORT+'/test'; + assert_equals(ws.url, SCHEME_DOMAIN_PORT+'/'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/url/003.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/003.html new file mode 100644 index 0000000000..aaae33a4cc --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/003.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>WebSockets: deleting url</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + delete ws.url; + assert_equals(ws.url, SCHEME_DOMAIN_PORT+'/', 'delete ws.url'); + delete WebSocket.prototype.url; + assert_equals(ws.url, undefined, 'delete WebSocket.prototype.url'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/url/004.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/004.html new file mode 100644 index 0000000000..7db5e1e425 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/004.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>WebSockets: 'URL'</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/'); + assert_equals(ws.URL, undefined); + assert_equals('URL' in ws, false); + assert_equals(WebSocket.prototype.URL, undefined); + assert_equals('URL' in WebSocket.prototype, false); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/url/005.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/005.html new file mode 100644 index 0000000000..00a5d90024 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/005.html @@ -0,0 +1,17 @@ +<!doctype html> +<title>WebSockets: defineProperty getter for url</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + Object.defineProperty(WebSocket.prototype, 'url', { + get: function() { return 'foo'; } + }); + var ws = new WebSocket('ws://example.invalid/'); + assert_equals(ws.url, 'foo'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/url/006.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/006.html new file mode 100644 index 0000000000..6e83770405 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/006.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>WebSockets: defineProperty setter for url</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + window.setter_ran = false; + Object.defineProperty(WebSocket.prototype, 'url', { + set: function(v) { window[v] = true; } + }); + var ws = new WebSocket('ws://example.invalid/'); + ws.url = 'setter_ran'; + assert_true(setter_ran); +}); +</script> diff --git a/testing/web-platform/tests/websockets/interfaces/WebSocket/url/resolve.html b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/resolve.html new file mode 100644 index 0000000000..2452073827 --- /dev/null +++ b/testing/web-platform/tests/websockets/interfaces/WebSocket/url/resolve.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>WebSocket#url: resolving</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../../../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +test(function() { + var ws = new WebSocket(SCHEME_DOMAIN_PORT + '/echo?foo%20bar baz'); + assert_equals(ws.url, SCHEME_DOMAIN_PORT + '/echo?foo%20bar%20baz'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/keeping-connection-open/001.html b/testing/web-platform/tests/websockets/keeping-connection-open/001.html new file mode 100644 index 0000000000..ab5bd1a540 --- /dev/null +++ b/testing/web-platform/tests/websockets/keeping-connection-open/001.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>WebSockets: 20s inactivity after handshake</title> +<meta name=timeout content=long> +<p>Note: This test takes 20 seconds to run.</p> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onclose = ws.onerror = ws.onmessage = t.unreached_func(); + ws.onopen = t.step_func(function(e) { + t.step_timeout(function() { + ws.send('test'); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, 'test'); + ws.onclose = t.step_func(function(e) { + t.step_timeout(() => t.done(), 50); + }); + ws.close(); + }); + }, 20000); + }) +}); +</script> diff --git a/testing/web-platform/tests/websockets/mixed-content.https.any.js b/testing/web-platform/tests/websockets/mixed-content.https.any.js new file mode 100644 index 0000000000..b7a6d8381d --- /dev/null +++ b/testing/web-platform/tests/websockets/mixed-content.https.any.js @@ -0,0 +1,7 @@ +// META: global=window,worker +// META: script=constants.sub.js + +test(() => { + assert_throws_dom('SecurityError', () => CreateInsecureWebSocket(), + 'constructor should throw'); +}, 'constructing an insecure WebSocket in a secure context should throw'); diff --git a/testing/web-platform/tests/websockets/multi-globals/message-received.html b/testing/web-platform/tests/websockets/multi-globals/message-received.html new file mode 100644 index 0000000000..704b1e357b --- /dev/null +++ b/testing/web-platform/tests/websockets/multi-globals/message-received.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<title>"A WebSocket message has been received", with multiple globals in play</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/comms.html#feedback-from-the-protocol"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- This is the entry global --> + +<iframe src="support/incumbent.sub.html"></iframe> + +<script> +"use strict"; +setup({ explicit_done: true }); + +window.onload = function() { + async_test(function(t) { + frames[0].setupWebSocket("arraybuffer", t.step_func_done(function(relevantWindow, event) { + assert_equals(event.constructor, relevantWindow.MessageEvent); + assert_equals(event.data.constructor, relevantWindow.ArrayBuffer); + })); + }, "ArrayBuffer should be created in the relevant realm of the WebSocket"); + + async_test(function(t) { + frames[0].setupWebSocket("blob", t.step_func_done(function(relevantWindow, event) { + assert_equals(event.constructor, relevantWindow.MessageEvent); + assert_equals(event.data.constructor, relevantWindow.Blob); + })); + }, "Blob should be created in the relevant realm of the WebSocket"); + + done(); +}; +</script> diff --git a/testing/web-platform/tests/websockets/multi-globals/support/incumbent.sub.html b/testing/web-platform/tests/websockets/multi-globals/support/incumbent.sub.html new file mode 100644 index 0000000000..a138b70235 --- /dev/null +++ b/testing/web-platform/tests/websockets/multi-globals/support/incumbent.sub.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<title>Incumbent page used as a test helper</title> + +<iframe src="relevant.html" id="r"></iframe> + +<script> +"use strict"; + +const relevant = document.querySelector("#r").contentWindow; + +window.setupWebSocket = (binaryType, fn) => { + const wsocket = new relevant.WebSocket("ws://{{host}}:{{ports[ws][0]}}/echo"); + + wsocket.addEventListener("open", () => { + wsocket.binaryType = binaryType; + wsocket.send(new ArrayBuffer(15)); + }); + + wsocket.addEventListener("message", ev => { + fn(relevant, ev); + }); +}; + +</script> diff --git a/testing/web-platform/tests/websockets/multi-globals/support/relevant.html b/testing/web-platform/tests/websockets/multi-globals/support/relevant.html new file mode 100644 index 0000000000..44f42eda49 --- /dev/null +++ b/testing/web-platform/tests/websockets/multi-globals/support/relevant.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<title>Relevant page used as a test helper</title> diff --git a/testing/web-platform/tests/websockets/multi-globals/url-parsing/current/current.html b/testing/web-platform/tests/websockets/multi-globals/url-parsing/current/current.html new file mode 100644 index 0000000000..82a48d4099 --- /dev/null +++ b/testing/web-platform/tests/websockets/multi-globals/url-parsing/current/current.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<title>Current page used as a test helper</title> diff --git a/testing/web-platform/tests/websockets/multi-globals/url-parsing/incumbent/incumbent.html b/testing/web-platform/tests/websockets/multi-globals/url-parsing/incumbent/incumbent.html new file mode 100644 index 0000000000..2c5572b774 --- /dev/null +++ b/testing/web-platform/tests/websockets/multi-globals/url-parsing/incumbent/incumbent.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<title>Incumbent page used as a test helper</title> + +<iframe src="../current/current.html" id="current"></iframe> + +<script> + const current = document.querySelector("#current").contentWindow; + + window.hello = () => { + window.ws = new current.WebSocket('foo'); + ws.close(); + }; +</script> diff --git a/testing/web-platform/tests/websockets/multi-globals/url-parsing/url-parsing.html b/testing/web-platform/tests/websockets/multi-globals/url-parsing/url-parsing.html new file mode 100644 index 0000000000..21ef6cd3a9 --- /dev/null +++ b/testing/web-platform/tests/websockets/multi-globals/url-parsing/url-parsing.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<title>Multiple globals for base URL in WebSocket constructor</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- This is the entry global --> + +<iframe src="incumbent/incumbent.html"></iframe> + +<script> +async_test((t) => { + onload = t.step_func_done(() => { + frames[0].hello(); + // Inside constructors, "this's relevant settings object" === "current settings object", + // because of how "this" is constructed. + // https://github.com/whatwg/websockets/issues/46 + const expectedUrl = new URL('current/foo', location.href); + expectedUrl.protocol = 'ws:'; + assert_equals(frames[0].ws.url, expectedUrl.href); + }); +}); +</script> diff --git a/testing/web-platform/tests/websockets/opening-handshake/001.html b/testing/web-platform/tests/websockets/opening-handshake/001.html new file mode 100644 index 0000000000..d8585d833b --- /dev/null +++ b/testing/web-platform/tests/websockets/opening-handshake/001.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>WebSockets: invalid handshake</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/invalid'); + ws.onclose = t.step_func(function(e) { + assert_false(e.wasClean); + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }); + ws.onmessage = ws.onopen = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/opening-handshake/002.html b/testing/web-platform/tests/websockets/opening-handshake/002.html new file mode 100644 index 0000000000..00d8dccaee --- /dev/null +++ b/testing/web-platform/tests/websockets/opening-handshake/002.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>WebSockets: valid handshake</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + ws.onclose = t.step_func(function(e) { + assert_equals(e.wasClean, true); + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }) + ws.close(); + }); + ws.onerror = ws.onmessage = ws.onclose = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/opening-handshake/003-sets-origin.worker.js b/testing/web-platform/tests/websockets/opening-handshake/003-sets-origin.worker.js new file mode 100644 index 0000000000..d10e8cb4c4 --- /dev/null +++ b/testing/web-platform/tests/websockets/opening-handshake/003-sets-origin.worker.js @@ -0,0 +1,17 @@ +importScripts("/resources/testharness.js"); +importScripts('../constants.sub.js'); + +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/origin'); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.data, location.protocol+'//'+location.host); + ws.onclose = t.step_func(function(e) { + assert_equals(e.wasClean, true); + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }) + ws.close(); + }) + ws.onerror = ws.onclose = t.unreached_func(); +}, "origin set in a Worker"); +done(); diff --git a/testing/web-platform/tests/websockets/opening-handshake/003.html b/testing/web-platform/tests/websockets/opening-handshake/003.html new file mode 100644 index 0000000000..1fc7535d50 --- /dev/null +++ b/testing/web-platform/tests/websockets/opening-handshake/003.html @@ -0,0 +1,27 @@ +<!doctype html> +<meta charset=utf-8> +<title>WebSockets: origin</title> +<meta name="timeout" content="long"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + const url = SCHEME_DOMAIN_PORT+'/origin', + ws = new WebSocket(url.replace("://", "://天気ã®è‰¯ã„æ—¥.")); + ws.onmessage = t.step_func(function(e) { + assert_equals(e.origin, new URL(url).origin.replace("://", "://xn--n8j6ds53lwwkrqhv28a.")) + assert_equals(e.data, location.protocol+'//'+location.host); + ws.onclose = t.step_func(function(e) { + assert_equals(e.wasClean, true); + ws.onclose = t.unreached_func(); + t.step_timeout(() => t.done(), 50); + }) + ws.close(); + }) + ws.onerror = ws.onclose = t.unreached_func(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/opening-handshake/005.html b/testing/web-platform/tests/websockets/opening-handshake/005.html new file mode 100644 index 0000000000..dcbd8dfebb --- /dev/null +++ b/testing/web-platform/tests/websockets/opening-handshake/005.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>WebSockets: response header and close frame in same packet</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/simple_handshake'); + ws.onmessage = t.unreached_func(); + ws.onopen = t.step_func(function(e) { + ws.onclose = t.step_func(function(e) { + assert_equals(e.wasClean, true); + assert_equals(e.code, 1001); + assert_equals(e.reason, 'PASS'); + ws.onclose = t.unreached_func('onclose should not be called twice'); + t.step_timeout(() => t.done(), 50); + }) + ws.close(); + }) + ws.onclose = t.unreached_func('onclose should not be called before onopen'); +}); +</script> diff --git a/testing/web-platform/tests/websockets/opening-handshake/006.html b/testing/web-platform/tests/websockets/opening-handshake/006.html new file mode 100644 index 0000000000..304069037c --- /dev/null +++ b/testing/web-platform/tests/websockets/opening-handshake/006.html @@ -0,0 +1,58 @@ +<!doctype html> +<title>WebSockets: Serialized connection attempts</title> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../constants.sub.js"></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id="log"></div> +<script> +async_test(function(t) { + const paths = ['/invalid1', '/invalid2', '/invalid3', '/echo']; // /echo is valid + let currentTestIndex = 0; + let isPreviousConnectionClosed = true; + + function testNextPath() { + if (currentTestIndex < paths.length) { + t.step(function() { + assert_true(isPreviousConnectionClosed, "Previous connection should be closed before attempting a new one"); + isPreviousConnectionClosed = false; + + const path = paths[currentTestIndex]; + const ws = new WebSocket(SCHEME_DOMAIN_PORT + path); + + ws.onclose = t.step_func(function(e) { + if (path !== '/echo') { + assert_false(e.wasClean, "Connection should fail uncleanly for path: " + path); + } else { + assert_true(e.wasClean, "Connection to /echo should close cleanly"); + } + isPreviousConnectionClosed = true; + currentTestIndex++; + t.step_timeout(testNextPath, 0); // Schedule the next test + }); + + ws.onopen = t.step_func(function() { + if (path === '/echo') { + assert_true(true, "Connection to /echo should succeed"); + ws.close(); + } else { + t.unreached_func("Invalid path should not succeed"); + } + }); + + ws.onerror = t.step_func(function() { + if (path === '/echo') { + t.unreached_func("Connection to /echo should not encounter an error"); + } // otherwise failure is expected + }); + }); + } else { + t.done(); + } + } + + testNextPath(); +}); +</script> diff --git a/testing/web-platform/tests/websockets/referrer.any.js b/testing/web-platform/tests/websockets/referrer.any.js new file mode 100644 index 0000000000..0972a1dc4d --- /dev/null +++ b/testing/web-platform/tests/websockets/referrer.any.js @@ -0,0 +1,13 @@ +// META: script=constants.sub.js + +async_test(t => { + const ws = new WebSocket(SCHEME_DOMAIN_PORT + "/referrer"); + ws.onmessage = t.step_func_done(e => { + assert_equals(e.data, "MISSING AS PER FETCH"); + ws.close(); + }); + + // Avoid timeouts in case of failure + ws.onclose = t.unreached_func("close"); + ws.onerror = t.unreached_func("error"); +}, "Ensure no Referer header is included"); diff --git a/testing/web-platform/tests/websockets/remove-own-iframe-during-onerror.window.js b/testing/web-platform/tests/websockets/remove-own-iframe-during-onerror.window.js new file mode 100644 index 0000000000..aa1cf6028f --- /dev/null +++ b/testing/web-platform/tests/websockets/remove-own-iframe-during-onerror.window.js @@ -0,0 +1,23 @@ +// META: script=constants.sub.js +// META: timeout=long +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +async_test(t => { + window.wsurl = SCHEME_DOMAIN_PORT + '/does-not-exist'; + let wsframe; + window.wsonerror = () => { + wsframe.remove(); + // If this didn't crash then the test passed. + t.done(); + }; + wsframe = document.createElement('iframe'); + wsframe.srcdoc = `<script> +const ws = new WebSocket(parent.wsurl); +ws.onerror = parent.wsonerror; +</script>`; + onload = () => document.body.appendChild(wsframe); +}, 'removing an iframe from within an onerror handler should work'); + +done(); diff --git a/testing/web-platform/tests/websockets/resources/websockets-test-helpers.sub.js b/testing/web-platform/tests/websockets/resources/websockets-test-helpers.sub.js new file mode 100644 index 0000000000..2680670cc6 --- /dev/null +++ b/testing/web-platform/tests/websockets/resources/websockets-test-helpers.sub.js @@ -0,0 +1,25 @@ +// The file including this must also include `/websockets/constants.sub.js to +// pick up the necessary constants. + +// Opens a new WebSocket connection. +async function openWebSocket(remoteContextHelper) { + let return_value = await remoteContextHelper.executeScript((domain) => { + return new Promise((resolve) => { + var webSocketInNotRestoredReasonsTests = new WebSocket(domain + '/echo'); + webSocketInNotRestoredReasonsTests.onopen = () => { resolve(42); }; + }); + }, [SCHEME_DOMAIN_PORT]); + assert_equals(return_value, 42); +} + +// Opens a new WebSocket connection and then close it. +async function openThenCloseWebSocket(remoteContextHelper) { + let return_value = await remoteContextHelper.executeScript((domain) => { + return new Promise((resolve) => { + var testWebSocket = new WebSocket(domain + '/echo'); + testWebSocket.onopen = () => { testWebSocket.close() }; + testWebSocket.onclose = () => { resolve(42) }; + }); + }, [SCHEME_DOMAIN_PORT]); + assert_equals(return_value, 42); +} diff --git a/testing/web-platform/tests/websockets/security/001.html b/testing/web-platform/tests/websockets/security/001.html new file mode 100644 index 0000000000..a34ae39639 --- /dev/null +++ b/testing/web-platform/tests/websockets/security/001.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>WebSockets: wrong accept key</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/wrong_accept_key'); + ws.onclose = t.step_func(function(e) { + t.done(); + }); +}); +</script> diff --git a/testing/web-platform/tests/websockets/security/002.html b/testing/web-platform/tests/websockets/security/002.html new file mode 100644 index 0000000000..3286cca980 --- /dev/null +++ b/testing/web-platform/tests/websockets/security/002.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>WebSockets: check Sec-WebSocket-Key</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<div id=log></div> +<script> +async_test(function(t) { + var xhr = new XMLHttpRequest(); + xhr.onload = t.step_func(function() { + assert_equals(xhr.responseText, 'PASS'); + t.done(); + }); + xhr.open("GET", "check.py", true); + xhr.setRequestHeader('Sec-WebSocket-Key', 'jW7qmdXj5Kk5jTClF1BN3'); + xhr.send(null); +}); +</script> diff --git a/testing/web-platform/tests/websockets/security/check.py b/testing/web-platform/tests/websockets/security/check.py new file mode 100644 index 0000000000..716b837f49 --- /dev/null +++ b/testing/web-platform/tests/websockets/security/check.py @@ -0,0 +1,2 @@ +def main(request, response): + return b"FAIL" if b'Sec-WebSocket-Key' in request.headers else b"PASS" diff --git a/testing/web-platform/tests/websockets/send-many-64K-messages-with-backpressure.any.js b/testing/web-platform/tests/websockets/send-many-64K-messages-with-backpressure.any.js new file mode 100644 index 0000000000..78c244b262 --- /dev/null +++ b/testing/web-platform/tests/websockets/send-many-64K-messages-with-backpressure.any.js @@ -0,0 +1,49 @@ +// META: global=window,worker +// META: script=constants.sub.js +// META: timeout=long +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +// This is a repro for Chromium bug https://crbug.com/1286909. It will timeout +// if the bug is present. + +// With 0.1 second server-side delay per message, sending 50 messages will take +// around 5 seconds. +const MESSAGES_TO_SEND = 50; + +// 65536 is the magic number that triggers the bug, as it precisely fills the +// mojo pipe. +const MESSAGE_SIZE = 65536; + +promise_test(async t => { + const message = new Uint8Array(MESSAGE_SIZE); + const ws = + new WebSocket(SCHEME_DOMAIN_PORT + '/receive-many-with-backpressure'); + let opened = false; + ws.onopen = t.step_func(() => { + opened = true; + for (let i = 0; i < MESSAGES_TO_SEND; i++) { + ws.send(message); + } + }); + let responsesReceived = 0; + ws.onmessage = t.step_func(({data}) => { + assert_equals(data, String(MESSAGE_SIZE), 'size must match'); + if (++responsesReceived == MESSAGES_TO_SEND) { + ws.close(); + } + }); + let resolvePromise; + const promise = new Promise(resolve => { + resolvePromise = resolve; + }); + ws.onclose = t.step_func(({wasClean}) => { + assert_true(opened, 'connection should have been opened'); + assert_true(wasClean, 'close should be clean'); + resolvePromise(); + }); + return promise; +}, + `sending ${MESSAGES_TO_SEND} messages of size ${MESSAGE_SIZE} with ` + + 'backpressure applied should not hang'); diff --git a/testing/web-platform/tests/websockets/stream/tentative/README.md b/testing/web-platform/tests/websockets/stream/tentative/README.md new file mode 100644 index 0000000000..6c51588774 --- /dev/null +++ b/testing/web-platform/tests/websockets/stream/tentative/README.md @@ -0,0 +1,9 @@ +# WebSocketStream tentative tests + +Tests in this directory are for the proposed "WebSocketStream" interface to the +WebSocket protocol. This is not yet standardised and browsers should not be +expected to pass these tests. + +See the explainer at +https://github.com/ricea/websocketstream-explainer/blob/master/README.md for +more information about the API. diff --git a/testing/web-platform/tests/websockets/stream/tentative/abort.any.js b/testing/web-platform/tests/websockets/stream/tentative/abort.any.js new file mode 100644 index 0000000000..9047f246f9 --- /dev/null +++ b/testing/web-platform/tests/websockets/stream/tentative/abort.any.js @@ -0,0 +1,50 @@ +// META: script=../../constants.sub.js +// META: script=resources/url-constants.js +// META: script=/common/utils.js +// META: global=window,worker +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +promise_test(async t => { + const controller = new AbortController(); + controller.abort(); + const key = token(); + const wsUrl = new URL( + `/fetch/api/resources/stash-put.py?key=${key}&value=connected`, + location.href); + wsUrl.protocol = wsUrl.protocol.replace('http', 'ws'); + // We intentionally use the port for the HTTP server, not the WebSocket + // server, because we don't expect the connection to be performed. + const wss = new WebSocketStream(wsUrl, { signal: controller.signal }); + await promise_rejects_dom( + t, 'AbortError', wss.opened, 'opened should reject'); + await promise_rejects_dom( + t, 'AbortError', wss.closed, 'closed should reject'); + // An incorrect implementation could pass this test due a race condition, + // but it is hard to completely eliminate the possibility. + const response = await fetch(`/fetch/api/resources/stash-take.py?key=${key}`); + assert_equals(await response.text(), 'null', 'response should be null'); +}, 'abort before constructing should prevent connection'); + +promise_test(async t => { + const controller = new AbortController(); + const wss = new WebSocketStream(`${BASEURL}/handshake_sleep_2`, + { signal: controller.signal }); + // Give the connection a chance to start. + await new Promise(resolve => t.step_timeout(resolve, 0)); + controller.abort(); + await promise_rejects_dom( + t, 'AbortError', wss.opened, 'opened should reject'); + await promise_rejects_dom( + t, 'AbortError', wss.closed, 'closed should reject'); +}, 'abort during handshake should work'); + +promise_test(async t => { + const controller = new AbortController(); + const wss = new WebSocketStream(ECHOURL, { signal: controller.signal }); + const { readable, writable } = await wss.opened; + controller.abort(); + writable.getWriter().write('connected'); + const { value } = await readable.getReader().read(); + assert_equals(value, 'connected', 'value should match'); +}, 'abort after connect should do nothing'); diff --git a/testing/web-platform/tests/websockets/stream/tentative/backpressure-receive.any.js b/testing/web-platform/tests/websockets/stream/tentative/backpressure-receive.any.js new file mode 100644 index 0000000000..236bb2e40f --- /dev/null +++ b/testing/web-platform/tests/websockets/stream/tentative/backpressure-receive.any.js @@ -0,0 +1,40 @@ +// META: script=../../constants.sub.js +// META: script=resources/url-constants.js +// META: global=window,worker +// META: timeout=long +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +// Allow for this much timer jitter. +const JITTER_ALLOWANCE_MS = 200; +const LARGE_MESSAGE_COUNT = 16; + +// This test works by using a server WebSocket handler which sends a large +// message, and then sends a second message with the time it measured the first +// message taking. On the browser side, we wait 2 seconds before reading from +// the socket. This should ensure it takes at least 2 seconds to finish sending +// the large message. +promise_test(async t => { + const wss = new WebSocketStream(`${BASEURL}/send-backpressure`); + const { readable } = await wss.opened; + const reader = readable.getReader(); + + // Create backpressure for 2 seconds. + await new Promise(resolve => t.step_timeout(resolve, 2000)); + + // Skip the empty message used to fill the readable queue. + await reader.read(); + + // Skip the large messages. + for (let i = 0; i < LARGE_MESSAGE_COUNT; ++i) { + await reader.read(); + } + + // Read the time it took. + const { value, done } = await reader.read(); + + // A browser can pass this test simply by being slow. This may be a source of + // flakiness for browsers that do not implement backpressure properly. + assert_greater_than_equal(Number(value), 2 - JITTER_ALLOWANCE_MS / 1000, + 'data send should have taken at least 2 seconds'); +}, 'backpressure should be applied to received messages'); diff --git a/testing/web-platform/tests/websockets/stream/tentative/backpressure-send.any.js b/testing/web-platform/tests/websockets/stream/tentative/backpressure-send.any.js new file mode 100644 index 0000000000..e4a80f6e1c --- /dev/null +++ b/testing/web-platform/tests/websockets/stream/tentative/backpressure-send.any.js @@ -0,0 +1,25 @@ +// META: script=../../constants.sub.js +// META: script=resources/url-constants.js +// META: global=window,worker +// META: timeout=long +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +// Allow for this much timer jitter. +const JITTER_ALLOWANCE_MS = 200; + +// The amount of buffering a WebSocket connection has is not standardised, but +// it's reasonable to expect that it will not be as large as 8MB. +const MESSAGE_SIZE = 8 * 1024 * 1024; + +// In this test, the server WebSocket handler waits 2 seconds, and the browser +// times how long it takes to send the first message. +promise_test(async t => { + const wss = new WebSocketStream(`${BASEURL}/receive-backpressure`); + const { writable } = await wss.opened; + const writer = writable.getWriter(); + const start = performance.now(); + await writer.write(new Uint8Array(MESSAGE_SIZE)); + const elapsed = performance.now() - start; + assert_greater_than_equal(elapsed, 2000 - JITTER_ALLOWANCE_MS); +}, 'backpressure should be applied to sent messages'); diff --git a/testing/web-platform/tests/websockets/stream/tentative/close.any.js b/testing/web-platform/tests/websockets/stream/tentative/close.any.js new file mode 100644 index 0000000000..098caf31c8 --- /dev/null +++ b/testing/web-platform/tests/websockets/stream/tentative/close.any.js @@ -0,0 +1,183 @@ +// META: script=../../constants.sub.js +// META: script=resources/url-constants.js +// META: global=window,worker +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +'use strict'; + +promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + await wss.opened; + wss.close({ closeCode: 3456, reason: 'pizza' }); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 3456, 'code should match'); + assert_equals(reason, 'pizza', 'reason should match'); +}, 'close code should be sent to server and reflected back'); + +promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + await wss.opened; + wss.close(); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1005, 'code should be unset'); + assert_equals(reason, '', 'reason should be empty'); +}, 'no close argument should send empty Close frame'); + +promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + await wss.opened; + wss.close({}); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1005, 'code should be unset'); + assert_equals(reason, '', 'reason should be empty'); +}, 'unspecified close code should send empty Close frame'); + +promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + await wss.opened; + wss.close({reason: ''}); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1005, 'code should be unset'); + assert_equals(reason, '', 'reason should be empty'); +}, 'unspecified close code with empty reason should send empty Close frame'); + +promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + await wss.opened; + wss.close({reason: 'non-empty'}); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1000, 'code should be set'); + assert_equals(reason, 'non-empty', 'reason should match'); +}, 'unspecified close code with non-empty reason should set code to 1000'); + +promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + await wss.opened; + assert_throws_js(TypeError, () => wss.close(true), + 'close should throw a TypeError'); +}, 'close(true) should throw a TypeError'); + +promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + await wss.opened; + const reason = '.'.repeat(124); + assert_throws_dom('SyntaxError', () => wss.close({ reason }), + 'close should throw a SyntaxError'); +}, 'close() with an overlong reason should throw'); + +function IsWebSocketError(e) { + return e.constructor == WebSocketError; +} + +promise_test(t => { + const wss = new WebSocketStream(ECHOURL); + wss.close(); + return Promise.all([ + wss.opened.then(t.unreached_func('should have rejected')).catch(e => assert_true(IsWebSocketError(e))), + wss.closed.then(t.unreached_func('should have rejected')).catch(e => assert_true(IsWebSocketError(e))), + ]); +}, 'close during handshake should work'); + +for (const invalidCode of [999, 1001, 2999, 5000]) { + promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + await wss.opened; + assert_throws_dom('InvalidAccessError', () => wss.close({ closeCode: invalidCode }), + 'close should throw an InvalidAccessError'); + }, `close() with invalid code ${invalidCode} should throw`); +} + +promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + const { writable } = await wss.opened; + writable.getWriter().close(); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1005, 'code should be unset'); + assert_equals(reason, '', 'reason should be empty'); +}, 'closing the writable should result in a clean close'); + +promise_test(async () => { + const wss = new WebSocketStream(`${BASEURL}/delayed-passive-close`); + const { writable } = await wss.opened; + const startTime = performance.now(); + await writable.getWriter().close(); + const elapsed = performance.now() - startTime; + const jitterAllowance = 100; + assert_greater_than_equal(elapsed, 1000 - jitterAllowance, + 'one second should have elapsed'); +}, 'writer close() promise should not resolve until handshake completes'); + +const abortOrCancel = [ + { + method: 'abort', + voweling: 'aborting', + stream: 'writable', + }, + { + method: 'cancel', + voweling: 'canceling', + stream: 'readable', + }, +]; + +for (const { method, voweling, stream } of abortOrCancel) { + + promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + const info = await wss.opened; + info[stream][method](); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1005, 'code should be unset'); + assert_equals(reason, '', 'reason should be empty'); + }, `${voweling} the ${stream} should result in a clean close`); + + promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + const info = await wss.opened; + info[stream][method]({ closeCode: 3333, reason: 'obsolete' }); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1005, 'code should be unset'); + assert_equals(reason, '', 'reason should be empty'); + }, `${voweling} the ${stream} with attributes not wrapped in a WebSocketError should be ignored`); + + promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + const info = await wss.opened; + info[stream][method](new WebSocketError('', { closeCode: 3333 })); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 3333, 'code should be used'); + assert_equals(reason, '', 'reason should be empty'); + }, `${voweling} the ${stream} with a code should send that code`); + + promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + const info = await wss.opened; + info[stream][method](new WebSocketError('', { closeCode: 3456, reason: 'set' })); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 3456, 'code should be used'); + assert_equals(reason, 'set', 'reason should be used'); + }, `${voweling} the ${stream} with a code and reason should use them`); + + promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + const info = await wss.opened; + info[stream][method](new WebSocketError('', { reason: 'specified' })); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1000, 'code should be defaulted'); + assert_equals(reason, 'specified', 'reason should be used'); + }, `${voweling} the ${stream} with a reason but no code should default the close code`); + + promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + const info = await wss.opened; + const domException = new DOMException('yes', 'DataCloneError'); + domException.closeCode = 1000; + domException.reason = 'should be ignored'; + info[stream][method](domException); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1005, 'code should be unset'); + assert_equals(reason, '', 'reason should be empty'); + }, `${voweling} the ${stream} with a DOMException not set code or reason`); + +} diff --git a/testing/web-platform/tests/websockets/stream/tentative/constructor.any.js b/testing/web-platform/tests/websockets/stream/tentative/constructor.any.js new file mode 100644 index 0000000000..66df974303 --- /dev/null +++ b/testing/web-platform/tests/websockets/stream/tentative/constructor.any.js @@ -0,0 +1,71 @@ +// META: script=../../constants.sub.js +// META: script=resources/url-constants.js +// META: global=window,worker +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +test(() => { + assert_throws_js(TypeError, () => new WebSocketStream(), + 'constructor should throw'); +}, 'constructing with no URL should throw'); + +test(() => { + assert_throws_dom('SyntaxError', () => new WebSocketStream('invalid:'), + 'constructor should throw'); +}, 'constructing with an invalid URL should throw'); + +test(() => { + assert_throws_js(TypeError, + () => new WebSocketStream(`${BASEURL}/`, true), + 'constructor should throw'); +}, 'constructing with invalid options should throw'); + +test(() => { + assert_throws_js(TypeError, + () => new WebSocketStream(`${BASEURL}/`, {protocols: 'hi'}), + 'constructor should throw'); +}, 'protocols should be required to be a list'); + +promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + await wss.opened; + assert_equals(wss.url, ECHOURL, 'url should match'); + wss.close(); +}, 'constructing with a valid URL should work'); + +promise_test(async () => { + const wss = new WebSocketStream(`${BASEURL}/protocol_array`, + {protocols: ['alpha', 'beta']}); + const { readable, protocol } = await wss.opened; + assert_equals(protocol, 'alpha', 'protocol should be right'); + const reader = readable.getReader(); + const { value, done } = await reader.read(); + assert_equals(value, 'alpha', 'message contents should match'); + wss.close(); +}, 'setting a protocol in the constructor should work'); + +function IsWebSocketError(e) { + return e.constructor == WebSocketError; +} + +promise_test(t => { + const wss = new WebSocketStream(`${BASEURL}/404`); + return Promise.all([ + wss.opened.then(t.unreached_func('should have rejected')).catch(e => assert_true(IsWebSocketError(e))), + wss.closed.then(t.unreached_func('should have rejected')).catch(e => assert_true(IsWebSocketError(e))), + ]); +}, 'connection failure should reject the promises'); + +promise_test(async () => { + const wss = new WebSocketStream(ECHOURL); + const { readable, writable, protocol, extensions} = await wss.opened; + // Verify that |readable| really is a ReadableStream using the getReader() + // brand check. If it doesn't throw the test passes. + ReadableStream.prototype.getReader.call(readable); + // Verify that |writable| really is a WritableStream using the getWriter() + // brand check. If it doesn't throw the test passes. + WritableStream.prototype.getWriter.call(writable); + assert_equals(typeof protocol, 'string', 'protocol should be a string'); + assert_equals(typeof extensions, 'string', 'extensions should be a string'); + wss.close(); +}, 'wss.opened should resolve to the right types'); diff --git a/testing/web-platform/tests/websockets/stream/tentative/resources/url-constants.js b/testing/web-platform/tests/websockets/stream/tentative/resources/url-constants.js new file mode 100644 index 0000000000..fe681af5c4 --- /dev/null +++ b/testing/web-platform/tests/websockets/stream/tentative/resources/url-constants.js @@ -0,0 +1,8 @@ +// The file including this must also include ../constants.sub.js to pick up the +// necessary constants. + +const {BASEURL, ECHOURL} = (() => { + const BASEURL = SCHEME_DOMAIN_PORT; + const ECHOURL = `${BASEURL}/echo`; + return {BASEURL, ECHOURL}; +})(); diff --git a/testing/web-platform/tests/websockets/stream/tentative/websocket-error.any.js b/testing/web-platform/tests/websockets/stream/tentative/websocket-error.any.js new file mode 100644 index 0000000000..b114bbb3e3 --- /dev/null +++ b/testing/web-platform/tests/websockets/stream/tentative/websocket-error.any.js @@ -0,0 +1,50 @@ +// META: global=window,worker + +'use strict'; + +test(() => { + const error = new WebSocketError(); + assert_equals(error.code, 0, 'DOMException code should be 0'); + assert_equals(error.name, 'WebSocketError', 'name should be correct'); + assert_equals(error.message, '', 'DOMException message should be empty'); + assert_equals(error.closeCode, null, 'closeCode should be null'); + assert_equals(error.reason, '', 'reason should be empty'); +}, 'WebSocketError defaults should be correct'); + +test(() => { + const error = new WebSocketError('message', { closeCode: 3456, reason: 'reason' }); + assert_equals(error.code, 0, 'DOMException code should be 0'); + assert_equals(error.name, 'WebSocketError', 'name should be correct'); + assert_equals(error.message, 'message', 'DOMException message should be set'); + assert_equals(error.closeCode, 3456, 'closeCode should match'); + assert_equals(error.reason, 'reason', 'reason should match'); +}, 'WebSocketError should be initialised from arguments'); + +for (const invalidCode of [999, 1001, 2999, 5000]) { + test(() => { + assert_throws_dom('InvalidAccessError', () => new WebSocketError('', { closeCode: invalidCode }), + 'invalid code should throw an InvalidAccessError'); + }, `new WebSocketError with invalid code ${invalidCode} should throw`); +} + +test(() => { + const error = new WebSocketError('', { closeCode: 3333 }); + assert_equals(error.closeCode, 3333, 'code should be used'); + assert_equals(error.reason, '', 'reason should be empty'); +}, 'passing only close code to WebSocketError should work'); + +test(() => { + const error = new WebSocketError('', { reason: 'specified' }); + assert_equals(error.closeCode, 1000, 'code should be defaulted'); + assert_equals(error.reason, 'specified', 'reason should be used'); +}, 'passing a non-empty reason should cause the close code to be set to 1000'); + +test(() => { + assert_throws_dom('SyntaxError', () => new WebSocketError('', { closeCode: 1000, reason: 'x'.repeat(124) }), + 'overlong reason should trigger SyntaxError'); +}, 'overlong reason should throw'); + +test(() => { + assert_throws_dom('SyntaxError', () => new WebSocketError('', { reason: '🔌'.repeat(32) }), + 'overlong reason should throw'); +}, 'reason should be rejected based on utf-8 bytes, not character count'); diff --git a/testing/web-platform/tests/websockets/unload-a-document/001-1.html b/testing/web-platform/tests/websockets/unload-a-document/001-1.html new file mode 100644 index 0000000000..7cf4ab6ff8 --- /dev/null +++ b/testing/web-platform/tests/websockets/unload-a-document/001-1.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>WebSockets: navigating top-level browsing context</title> +<script src=../constants.sub.js></script> +<script> +var controller = opener || parent; +var t = controller.t; +var assert_unreached = controller.assert_unreached; +var uuid = controller.uuid; +t.add_cleanup(function() {delete sessionStorage[uuid];}); +t.step(function() { + if (sessionStorage[uuid]) { + t.done(); + } else { + sessionStorage[uuid] = 'true'; + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + t.step_timeout(function() { + assert_unreached('document was not discarded'); + }, 1000); + controller.navigate(); + }) + ws.onerror = ws.onmessage = t.step_func(e => assert_unreached("Got unexpected event " + e.type)); + } +}); +</script> diff --git a/testing/web-platform/tests/websockets/unload-a-document/001-2.html b/testing/web-platform/tests/websockets/unload-a-document/001-2.html new file mode 100644 index 0000000000..24c419ce18 --- /dev/null +++ b/testing/web-platform/tests/websockets/unload-a-document/001-2.html @@ -0,0 +1,4 @@ +<!doctype html> +<title>WebSockets: navigating top-level browsing context</title> +<body onload="history.back()"></body> +</html> diff --git a/testing/web-platform/tests/websockets/unload-a-document/001.html b/testing/web-platform/tests/websockets/unload-a-document/001.html new file mode 100644 index 0000000000..28ce9c4614 --- /dev/null +++ b/testing/web-platform/tests/websockets/unload-a-document/001.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>WebSockets: navigating top-level browsing context</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/common/utils.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<p>Test requires popup blocker disabled</p> +<div id=log></div> +<script> +var t = async_test(); +var w; +var uuid; +t.step(function() { + uuid = token() + w = window.open("001-1.html" + location.search); + add_result_callback(function() { + w.close(); + }); +}); +navigate = t.step_func(function() { + w.location = w.location.href.replace("001-1.html", "001-2.html"); +}); +</script> diff --git a/testing/web-platform/tests/websockets/unload-a-document/002-1.html b/testing/web-platform/tests/websockets/unload-a-document/002-1.html new file mode 100644 index 0000000000..1922bb4cae --- /dev/null +++ b/testing/web-platform/tests/websockets/unload-a-document/002-1.html @@ -0,0 +1,32 @@ +<!doctype html> +<title>WebSockets: navigating top-level browsing context with closed websocket</title> +<script src=../constants.sub.js></script> +<script> +var controller = opener || parent; +var t = controller.t; +var assert_equals = controller.assert_equals; +var assert_unreached = controller.assert_unreached ; +var uuid = controller.uuid; +t.add_cleanup(function() {delete sessionStorage[uuid];}); +t.step(function() { + // this test can fail if the document is unloaded on navigation e.g. due to OOM + if (sessionStorage[uuid]) { + assert_unreached('document was discarded'); + } else { + sessionStorage[uuid] = 'true'; + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + + t.step_timeout(function() { + assert_equals(ws.readyState, ws.CLOSED, 'ws.readyState'); + t.done(); + }, 4000); + ws.close(); + ws.onclose = t.step_func(function() { + controller.navigate(); + }); + }) + ws.onerror = ws.onmessage = t.step_func(e => assert_unreached("Got unexpected event " + e.type)); + } +}); +</script> diff --git a/testing/web-platform/tests/websockets/unload-a-document/002-2.html b/testing/web-platform/tests/websockets/unload-a-document/002-2.html new file mode 100644 index 0000000000..9a246a1dd8 --- /dev/null +++ b/testing/web-platform/tests/websockets/unload-a-document/002-2.html @@ -0,0 +1,4 @@ +<!doctype html> +<title>WebSockets: navigating top-level browsing context with closed websocket</title> +<body onload="history.back()"></body> +</html> diff --git a/testing/web-platform/tests/websockets/unload-a-document/002.html b/testing/web-platform/tests/websockets/unload-a-document/002.html new file mode 100644 index 0000000000..f79b3b7297 --- /dev/null +++ b/testing/web-platform/tests/websockets/unload-a-document/002.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>WebSockets: navigating top-level browsing context with closed websocket</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/common/utils.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<p>Test requires popup blocker disabled</p> +<div id=log></div> +<script> +var t = async_test(); +var w; +var uuid; +t.step(function() { + uuid = token() + w = window.open("002-1.html" + location.search); + add_result_callback(function() { + w.close(); + }); +}); +navigate = t.step_func(function() { + w.location = w.location.href.replace("002-1.html", "002-2.html"); +}); +</script> diff --git a/testing/web-platform/tests/websockets/unload-a-document/003.html b/testing/web-platform/tests/websockets/unload-a-document/003.html new file mode 100644 index 0000000000..554daf458a --- /dev/null +++ b/testing/web-platform/tests/websockets/unload-a-document/003.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>WebSockets: navigating nested browsing context</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/common/utils.js></script> +<div id=log></div> +<script> +var uuid; +var t = async_test(function() {uuid = token()}); +var navigate = t.step_func(function() { + document.getElementsByTagName("iframe")[0].src = 'data:text/html,<body onload="history.back()">'; +}); +</script> +<iframe src=001-1.html></iframe>
\ No newline at end of file diff --git a/testing/web-platform/tests/websockets/unload-a-document/004.html b/testing/web-platform/tests/websockets/unload-a-document/004.html new file mode 100644 index 0000000000..bb15cd8ef9 --- /dev/null +++ b/testing/web-platform/tests/websockets/unload-a-document/004.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>WebSockets: navigating nested browsing context with closed websocket</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/common/utils.js></script> +<div id=log></div> +<script> +var uuid; +var t = async_test(); +t.step(function() {uuid = token()}); +var navigate = t.step_func(function() { + document.getElementsByTagName("iframe")[0].src = 'data:text/html,<body onload="history.back()">'; +}); +</script> +<iframe src=002-1.html></iframe> diff --git a/testing/web-platform/tests/websockets/unload-a-document/005-1.html b/testing/web-platform/tests/websockets/unload-a-document/005-1.html new file mode 100644 index 0000000000..e084ade7e5 --- /dev/null +++ b/testing/web-platform/tests/websockets/unload-a-document/005-1.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>WebSockets: navigating nested browsing context with a websocket in top-level</title> +<script src=../constants.sub.js></script> +<script> +var t = opener.t; +var assert_unreached = opener.assert_unreached; +var hasRun = false; +function run(){ + var ws = new WebSocket(SCHEME_DOMAIN_PORT+'/echo'); + ws.onopen = t.step_func(function(e) { + t.step_timeout(function() { + ws.send('test'); + }, 1000); + window[0].location = 'data:text/html,<body onload="history.back()">'; + ws.onmessage = t.step_func_done(function(e) { + ws.close(); + }); + }); + ws.onerror = ws.onmessage = ws.onclose = t.step_func(e => assert_unreached("Got unexpected event " + e.type)); +} +</script> +<iframe src='data:text/html,foo' onload='if (hasRun) return; hasRun = true; t.step(run)'></iframe> diff --git a/testing/web-platform/tests/websockets/unload-a-document/005.html b/testing/web-platform/tests/websockets/unload-a-document/005.html new file mode 100644 index 0000000000..1abb1b552f --- /dev/null +++ b/testing/web-platform/tests/websockets/unload-a-document/005.html @@ -0,0 +1,21 @@ +<!doctype html> +<title>WebSockets: navigating nested browsing context with a websocket in top-level</title> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../constants.sub.js></script> +<meta name="variant" content="?default"> +<meta name="variant" content="?wss"> +<meta name="variant" content="?wpt_flags=h2"> +<div id=log></div> +<p>Test requires popup blocker disabled</p> +<div id=log></div> +<script> +var t = async_test(); +t.step(function() { + var w = window.open("005-1.html" + location.search); + add_result_callback(function() { + w.close(); + }); +}); +</script> |