summaryrefslogtreecommitdiffstats
path: root/test/wpt/tests/websockets
diff options
context:
space:
mode:
Diffstat (limited to 'test/wpt/tests/websockets')
-rw-r--r--test/wpt/tests/websockets/Close-1000-reason.any.js21
-rw-r--r--test/wpt/tests/websockets/Close-1000-verify-code.any.js21
-rw-r--r--test/wpt/tests/websockets/Close-1000.any.js21
-rw-r--r--test/wpt/tests/websockets/Close-1005-verify-code.any.js21
-rw-r--r--test/wpt/tests/websockets/Close-1005.any.js18
-rw-r--r--test/wpt/tests/websockets/Close-2999-reason.any.js17
-rw-r--r--test/wpt/tests/websockets/Close-3000-reason.any.js21
-rw-r--r--test/wpt/tests/websockets/Close-3000-verify-code.any.js20
-rw-r--r--test/wpt/tests/websockets/Close-4999-reason.any.js21
-rw-r--r--test/wpt/tests/websockets/Close-Reason-124Bytes.any.js20
-rw-r--r--test/wpt/tests/websockets/Close-delayed.any.js27
-rw-r--r--test/wpt/tests/websockets/Close-onlyReason.any.js17
-rw-r--r--test/wpt/tests/websockets/Close-readyState-Closed.any.js21
-rw-r--r--test/wpt/tests/websockets/Close-readyState-Closing.any.js20
-rw-r--r--test/wpt/tests/websockets/Close-reason-unpaired-surrogates.any.js22
-rw-r--r--test/wpt/tests/websockets/Close-server-initiated-close.any.js21
-rw-r--r--test/wpt/tests/websockets/Close-undefined.any.js19
-rw-r--r--test/wpt/tests/websockets/Create-asciiSep-protocol-string.any.js12
-rw-r--r--test/wpt/tests/websockets/Create-blocked-port.any.js97
-rw-r--r--test/wpt/tests/websockets/Create-extensions-empty.any.js20
-rw-r--r--test/wpt/tests/websockets/Create-http-urls.any.js19
-rw-r--r--test/wpt/tests/websockets/Create-invalid-urls.any.js14
-rw-r--r--test/wpt/tests/websockets/Create-non-absolute-url.any.js14
-rw-r--r--test/wpt/tests/websockets/Create-nonAscii-protocol-string.any.js12
-rw-r--r--test/wpt/tests/websockets/Create-on-worker-shutdown.any.js26
-rw-r--r--test/wpt/tests/websockets/Create-protocol-with-space.any.js11
-rw-r--r--test/wpt/tests/websockets/Create-protocols-repeated-case-insensitive.any.js11
-rw-r--r--test/wpt/tests/websockets/Create-protocols-repeated.any.js11
-rw-r--r--test/wpt/tests/websockets/Create-url-with-space.any.js12
-rw-r--r--test/wpt/tests/websockets/Create-url-with-windows-1252-encoding.html20
-rw-r--r--test/wpt/tests/websockets/Create-valid-url-array-protocols.any.js21
-rw-r--r--test/wpt/tests/websockets/Create-valid-url-binaryType-blob.any.js21
-rw-r--r--test/wpt/tests/websockets/Create-valid-url-protocol-empty.any.js10
-rw-r--r--test/wpt/tests/websockets/Create-valid-url-protocol-setCorrectly.any.js21
-rw-r--r--test/wpt/tests/websockets/Create-valid-url-protocol-string.any.js21
-rw-r--r--test/wpt/tests/websockets/Create-valid-url-protocol.any.js21
-rw-r--r--test/wpt/tests/websockets/Create-valid-url.any.js21
-rw-r--r--test/wpt/tests/websockets/META.yml6
-rw-r--r--test/wpt/tests/websockets/README.md1
-rw-r--r--test/wpt/tests/websockets/Send-0byte-data.any.js30
-rw-r--r--test/wpt/tests/websockets/Send-65K-data.any.js33
-rw-r--r--test/wpt/tests/websockets/Send-before-open.any.js11
-rw-r--r--test/wpt/tests/websockets/Send-binary-65K-arraybuffer.any.js33
-rw-r--r--test/wpt/tests/websockets/Send-binary-arraybuffer.any.js33
-rw-r--r--test/wpt/tests/websockets/Send-binary-arraybufferview-float32.any.js40
-rw-r--r--test/wpt/tests/websockets/Send-binary-arraybufferview-float64.any.js40
-rw-r--r--test/wpt/tests/websockets/Send-binary-arraybufferview-int16-offset.any.js40
-rw-r--r--test/wpt/tests/websockets/Send-binary-arraybufferview-int32.any.js40
-rw-r--r--test/wpt/tests/websockets/Send-binary-arraybufferview-int8.any.js40
-rw-r--r--test/wpt/tests/websockets/Send-binary-arraybufferview-uint16-offset-length.any.js40
-rw-r--r--test/wpt/tests/websockets/Send-binary-arraybufferview-uint32-offset.any.js40
-rw-r--r--test/wpt/tests/websockets/Send-binary-arraybufferview-uint8-offset-length.any.js40
-rw-r--r--test/wpt/tests/websockets/Send-binary-arraybufferview-uint8-offset.any.js40
-rw-r--r--test/wpt/tests/websockets/Send-binary-blob.any.js36
-rw-r--r--test/wpt/tests/websockets/Send-data.any.js30
-rw-r--r--test/wpt/tests/websockets/Send-data.worker.js26
-rw-r--r--test/wpt/tests/websockets/Send-null.any.js32
-rw-r--r--test/wpt/tests/websockets/Send-paired-surrogates.any.js30
-rw-r--r--test/wpt/tests/websockets/Send-unicode-data.any.js30
-rw-r--r--test/wpt/tests/websockets/Send-unpaired-surrogates.any.js30
-rw-r--r--test/wpt/tests/websockets/back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js31
-rw-r--r--test/wpt/tests/websockets/back-forward-cache-with-closed-websocket-connection.window.js20
-rw-r--r--test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js32
-rw-r--r--test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection.window.js21
-rw-r--r--test/wpt/tests/websockets/basic-auth.any.js17
-rw-r--r--test/wpt/tests/websockets/binary/001.html27
-rw-r--r--test/wpt/tests/websockets/binary/002.html28
-rw-r--r--test/wpt/tests/websockets/binary/004.html27
-rw-r--r--test/wpt/tests/websockets/binary/005.html26
-rw-r--r--test/wpt/tests/websockets/binaryType-wrong-value.any.js23
-rw-r--r--test/wpt/tests/websockets/bufferedAmount-unchanged-by-sync-xhr.any.js25
-rw-r--r--test/wpt/tests/websockets/close-invalid.any.js21
-rw-r--r--test/wpt/tests/websockets/closing-handshake/002.html23
-rw-r--r--test/wpt/tests/websockets/closing-handshake/003.html24
-rw-r--r--test/wpt/tests/websockets/closing-handshake/004.html25
-rw-r--r--test/wpt/tests/websockets/constants.sub.js94
-rw-r--r--test/wpt/tests/websockets/constructor.any.js10
-rw-r--r--test/wpt/tests/websockets/constructor/001.html14
-rw-r--r--test/wpt/tests/websockets/constructor/004.html36
-rw-r--r--test/wpt/tests/websockets/constructor/005.html14
-rw-r--r--test/wpt/tests/websockets/constructor/006.html29
-rw-r--r--test/wpt/tests/websockets/constructor/007.html17
-rw-r--r--test/wpt/tests/websockets/constructor/008.html15
-rw-r--r--test/wpt/tests/websockets/constructor/009.html24
-rw-r--r--test/wpt/tests/websockets/constructor/010.html22
-rw-r--r--test/wpt/tests/websockets/constructor/011.html28
-rw-r--r--test/wpt/tests/websockets/constructor/012.html20
-rw-r--r--test/wpt/tests/websockets/constructor/013.html42
-rw-r--r--test/wpt/tests/websockets/constructor/014.html39
-rw-r--r--test/wpt/tests/websockets/constructor/016.html20
-rw-r--r--test/wpt/tests/websockets/constructor/017.html19
-rw-r--r--test/wpt/tests/websockets/constructor/018.html20
-rw-r--r--test/wpt/tests/websockets/constructor/019.html21
-rw-r--r--test/wpt/tests/websockets/constructor/020.html21
-rw-r--r--test/wpt/tests/websockets/constructor/021.html12
-rw-r--r--test/wpt/tests/websockets/constructor/022.html23
-rw-r--r--test/wpt/tests/websockets/cookies/001.html28
-rw-r--r--test/wpt/tests/websockets/cookies/002.html26
-rw-r--r--test/wpt/tests/websockets/cookies/003.html34
-rw-r--r--test/wpt/tests/websockets/cookies/004.html31
-rw-r--r--test/wpt/tests/websockets/cookies/005.html35
-rw-r--r--test/wpt/tests/websockets/cookies/006.html35
-rw-r--r--test/wpt/tests/websockets/cookies/007.html36
-rw-r--r--test/wpt/tests/websockets/cookies/support/set-cookie.py7
-rw-r--r--test/wpt/tests/websockets/cookies/support/websocket-cookies-helper.sub.js57
-rw-r--r--test/wpt/tests/websockets/cookies/third-party-cookie-accepted.https.html25
-rw-r--r--test/wpt/tests/websockets/eventhandlers.any.js15
-rw-r--r--test/wpt/tests/websockets/extended-payload-length.html72
-rw-r--r--test/wpt/tests/websockets/handlers/basic_auth_wsh.py26
-rw-r--r--test/wpt/tests/websockets/handlers/delayed-passive-close_wsh.py27
-rw-r--r--test/wpt/tests/websockets/handlers/echo-cookie_wsh.py12
-rw-r--r--test/wpt/tests/websockets/handlers/echo-query_v13_wsh.py11
-rw-r--r--test/wpt/tests/websockets/handlers/echo-query_wsh.py9
-rw-r--r--test/wpt/tests/websockets/handlers/echo_close_data_wsh.py20
-rw-r--r--test/wpt/tests/websockets/handlers/echo_exit_wsh.py19
-rw-r--r--test/wpt/tests/websockets/handlers/echo_raw_wsh.py16
-rw-r--r--test/wpt/tests/websockets/handlers/echo_wsh.py36
-rw-r--r--test/wpt/tests/websockets/handlers/empty-message_wsh.py13
-rw-r--r--test/wpt/tests/websockets/handlers/handshake_no_extensions_wsh.py9
-rw-r--r--test/wpt/tests/websockets/handlers/handshake_no_protocol_wsh.py8
-rw-r--r--test/wpt/tests/websockets/handlers/handshake_protocol_wsh.py7
-rw-r--r--test/wpt/tests/websockets/handlers/handshake_sleep_2_wsh.py9
-rw-r--r--test/wpt/tests/websockets/handlers/invalid_wsh.py8
-rw-r--r--test/wpt/tests/websockets/handlers/msg_channel_wsh.py234
-rw-r--r--test/wpt/tests/websockets/handlers/origin_wsh.py11
-rw-r--r--test/wpt/tests/websockets/handlers/protocol_array_wsh.py14
-rw-r--r--test/wpt/tests/websockets/handlers/protocol_wsh.py12
-rw-r--r--test/wpt/tests/websockets/handlers/receive-backpressure_wsh.py14
-rw-r--r--test/wpt/tests/websockets/handlers/receive-many-with-backpressure_wsh.py23
-rw-r--r--test/wpt/tests/websockets/handlers/referrer_wsh.py12
-rw-r--r--test/wpt/tests/websockets/handlers/send-backpressure_wsh.py39
-rw-r--r--test/wpt/tests/websockets/handlers/set-cookie-secure_wsh.py11
-rw-r--r--test/wpt/tests/websockets/handlers/set-cookie_http_wsh.py11
-rw-r--r--test/wpt/tests/websockets/handlers/set-cookie_wsh.py11
-rw-r--r--test/wpt/tests/websockets/handlers/set-cookies-samesite_wsh.py25
-rw-r--r--test/wpt/tests/websockets/handlers/simple_handshake_wsh.py35
-rw-r--r--test/wpt/tests/websockets/handlers/sleep_10_v13_wsh.py24
-rw-r--r--test/wpt/tests/websockets/handlers/stash_responder_blocking_wsh.py45
-rw-r--r--test/wpt/tests/websockets/handlers/stash_responder_wsh.py45
-rw-r--r--test/wpt/tests/websockets/handlers/wrong_accept_key_wsh.py19
-rw-r--r--test/wpt/tests/websockets/idlharness.any.js17
-rw-r--r--test/wpt/tests/websockets/interfaces/CloseEvent/clean-close.html24
-rw-r--r--test/wpt/tests/websockets/interfaces/CloseEvent/constructor.html35
-rw-r--r--test/wpt/tests/websockets/interfaces/CloseEvent/historical.html12
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html27
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html28
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html18
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-setter.html20
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-deleting.html23
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-getting.html54
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-initial.html15
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-large.html29
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-readonly.html16
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-unicode.html25
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/close/close-basic.html26
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/close/close-connecting.html25
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/close/close-multiple.html29
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/close/close-nested.html28
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/close/close-replace.html15
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/close/close-return.html14
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/constants/001.html17
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/constants/002.html24
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/constants/003.html22
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/constants/004.html21
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/constants/005.html20
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/constants/006.html20
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/001.html18
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/002.html20
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/003.html21
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/004.html16
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/006.html17
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/007.html22
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/008.html24
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/009.html21
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/010.html21
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/011.html18
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/012.html18
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/013.html20
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/014.html21
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/015.html36
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/016.html39
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/017.html56
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/018.html52
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/019.html31
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/events/020.html17
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/extensions/001.html14
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/protocol/protocol-initial.html14
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/readyState/001.html13
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/readyState/002.html15
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/readyState/003.html18
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/readyState/004.html17
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/readyState/005.html19
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/readyState/006.html19
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/readyState/007.html19
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/readyState/008.html21
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/001.html15
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/002.html15
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/003.html15
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/004.html25
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/005.html19
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/006.html28
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/007.html27
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/008.html25
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/009.html27
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/010.html42
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/011.html28
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/send/012.html28
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/url/001.html13
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/url/002.html15
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/url/003.html17
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/url/004.html17
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/url/005.html17
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/url/006.html19
-rw-r--r--test/wpt/tests/websockets/interfaces/WebSocket/url/resolve.html14
-rw-r--r--test/wpt/tests/websockets/keeping-connection-open/001.html29
-rw-r--r--test/wpt/tests/websockets/mixed-content.https.any.js7
-rw-r--r--test/wpt/tests/websockets/multi-globals/message-received.html33
-rw-r--r--test/wpt/tests/websockets/multi-globals/support/incumbent.sub.html24
-rw-r--r--test/wpt/tests/websockets/multi-globals/support/relevant.html2
-rw-r--r--test/wpt/tests/websockets/multi-globals/url-parsing/current/current.html2
-rw-r--r--test/wpt/tests/websockets/multi-globals/url-parsing/incumbent/incumbent.html13
-rw-r--r--test/wpt/tests/websockets/multi-globals/url-parsing/url-parsing.html22
-rw-r--r--test/wpt/tests/websockets/opening-handshake/001.html20
-rw-r--r--test/wpt/tests/websockets/opening-handshake/002.html24
-rw-r--r--test/wpt/tests/websockets/opening-handshake/003-sets-origin.worker.js17
-rw-r--r--test/wpt/tests/websockets/opening-handshake/003.html27
-rw-r--r--test/wpt/tests/websockets/opening-handshake/005.html25
-rw-r--r--test/wpt/tests/websockets/referrer.any.js13
-rw-r--r--test/wpt/tests/websockets/remove-own-iframe-during-onerror.window.js23
-rw-r--r--test/wpt/tests/websockets/resources/websockets-test-helpers.sub.js25
-rw-r--r--test/wpt/tests/websockets/security/001.html16
-rw-r--r--test/wpt/tests/websockets/security/002.html20
-rw-r--r--test/wpt/tests/websockets/security/check.py2
-rw-r--r--test/wpt/tests/websockets/send-many-64K-messages-with-backpressure.any.js49
-rw-r--r--test/wpt/tests/websockets/stream/tentative/README.md9
-rw-r--r--test/wpt/tests/websockets/stream/tentative/abort.any.js50
-rw-r--r--test/wpt/tests/websockets/stream/tentative/backpressure-receive.any.js40
-rw-r--r--test/wpt/tests/websockets/stream/tentative/backpressure-send.any.js25
-rw-r--r--test/wpt/tests/websockets/stream/tentative/close.any.js187
-rw-r--r--test/wpt/tests/websockets/stream/tentative/constructor.any.js67
-rw-r--r--test/wpt/tests/websockets/stream/tentative/resources/url-constants.js8
-rw-r--r--test/wpt/tests/websockets/unload-a-document/001-1.html25
-rw-r--r--test/wpt/tests/websockets/unload-a-document/001-2.html4
-rw-r--r--test/wpt/tests/websockets/unload-a-document/001.html26
-rw-r--r--test/wpt/tests/websockets/unload-a-document/002-1.html32
-rw-r--r--test/wpt/tests/websockets/unload-a-document/002-2.html4
-rw-r--r--test/wpt/tests/websockets/unload-a-document/002.html27
-rw-r--r--test/wpt/tests/websockets/unload-a-document/003.html14
-rw-r--r--test/wpt/tests/websockets/unload-a-document/004.html16
-rw-r--r--test/wpt/tests/websockets/unload-a-document/005-1.html22
-rw-r--r--test/wpt/tests/websockets/unload-a-document/005.html21
251 files changed, 6247 insertions, 0 deletions
diff --git a/test/wpt/tests/websockets/Close-1000-reason.any.js b/test/wpt/tests/websockets/Close-1000-reason.any.js
new file mode 100644
index 0000000..79ad6a0
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-1000-verify-code.any.js b/test/wpt/tests/websockets/Close-1000-verify-code.any.js
new file mode 100644
index 0000000..c3a9274
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-1000.any.js b/test/wpt/tests/websockets/Close-1000.any.js
new file mode 100644
index 0000000..2f535ba
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-1005-verify-code.any.js b/test/wpt/tests/websockets/Close-1005-verify-code.any.js
new file mode 100644
index 0000000..28f84c8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-1005.any.js b/test/wpt/tests/websockets/Close-1005.any.js
new file mode 100644
index 0000000..5055e28
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-2999-reason.any.js b/test/wpt/tests/websockets/Close-2999-reason.any.js
new file mode 100644
index 0000000..6336c7d
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-3000-reason.any.js b/test/wpt/tests/websockets/Close-3000-reason.any.js
new file mode 100644
index 0000000..8e34ce7
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-3000-verify-code.any.js b/test/wpt/tests/websockets/Close-3000-verify-code.any.js
new file mode 100644
index 0000000..a6703de
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-4999-reason.any.js b/test/wpt/tests/websockets/Close-4999-reason.any.js
new file mode 100644
index 0000000..8c2a1c9
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-Reason-124Bytes.any.js b/test/wpt/tests/websockets/Close-Reason-124Bytes.any.js
new file mode 100644
index 0000000..063b12b
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-delayed.any.js b/test/wpt/tests/websockets/Close-delayed.any.js
new file mode 100644
index 0000000..9e0a60c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-onlyReason.any.js b/test/wpt/tests/websockets/Close-onlyReason.any.js
new file mode 100644
index 0000000..243eb05
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-readyState-Closed.any.js b/test/wpt/tests/websockets/Close-readyState-Closed.any.js
new file mode 100644
index 0000000..6c7b5f1
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-readyState-Closing.any.js b/test/wpt/tests/websockets/Close-readyState-Closing.any.js
new file mode 100644
index 0000000..221130b
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-reason-unpaired-surrogates.any.js b/test/wpt/tests/websockets/Close-reason-unpaired-surrogates.any.js
new file mode 100644
index 0000000..e5a71d2
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-server-initiated-close.any.js b/test/wpt/tests/websockets/Close-server-initiated-close.any.js
new file mode 100644
index 0000000..82fd457
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Close-undefined.any.js b/test/wpt/tests/websockets/Close-undefined.any.js
new file mode 100644
index 0000000..e24ef0c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-asciiSep-protocol-string.any.js b/test/wpt/tests/websockets/Create-asciiSep-protocol-string.any.js
new file mode 100644
index 0000000..d0102ce
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-blocked-port.any.js b/test/wpt/tests/websockets/Create-blocked-port.any.js
new file mode 100644
index 0000000..2962312
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-extensions-empty.any.js b/test/wpt/tests/websockets/Create-extensions-empty.any.js
new file mode 100644
index 0000000..98a7d65
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-http-urls.any.js b/test/wpt/tests/websockets/Create-http-urls.any.js
new file mode 100644
index 0000000..17590fc
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-invalid-urls.any.js b/test/wpt/tests/websockets/Create-invalid-urls.any.js
new file mode 100644
index 0000000..73c9fad
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-non-absolute-url.any.js b/test/wpt/tests/websockets/Create-non-absolute-url.any.js
new file mode 100644
index 0000000..5a7b179
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-nonAscii-protocol-string.any.js b/test/wpt/tests/websockets/Create-nonAscii-protocol-string.any.js
new file mode 100644
index 0000000..fda926a
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-on-worker-shutdown.any.js b/test/wpt/tests/websockets/Create-on-worker-shutdown.any.js
new file mode 100644
index 0000000..218bf7c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-protocol-with-space.any.js b/test/wpt/tests/websockets/Create-protocol-with-space.any.js
new file mode 100644
index 0000000..a85d4e5
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-protocols-repeated-case-insensitive.any.js b/test/wpt/tests/websockets/Create-protocols-repeated-case-insensitive.any.js
new file mode 100644
index 0000000..1a508e8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-protocols-repeated.any.js b/test/wpt/tests/websockets/Create-protocols-repeated.any.js
new file mode 100644
index 0000000..2f12a47
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-url-with-space.any.js b/test/wpt/tests/websockets/Create-url-with-space.any.js
new file mode 100644
index 0000000..f2bea5b
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-url-with-windows-1252-encoding.html b/test/wpt/tests/websockets/Create-url-with-windows-1252-encoding.html
new file mode 100644
index 0000000..6596b5e
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-valid-url-array-protocols.any.js b/test/wpt/tests/websockets/Create-valid-url-array-protocols.any.js
new file mode 100644
index 0000000..fe71fd7
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-valid-url-binaryType-blob.any.js b/test/wpt/tests/websockets/Create-valid-url-binaryType-blob.any.js
new file mode 100644
index 0000000..7840ff3
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-valid-url-protocol-empty.any.js b/test/wpt/tests/websockets/Create-valid-url-protocol-empty.any.js
new file mode 100644
index 0000000..f18a9d8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-valid-url-protocol-setCorrectly.any.js b/test/wpt/tests/websockets/Create-valid-url-protocol-setCorrectly.any.js
new file mode 100644
index 0000000..c5d06ac
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-valid-url-protocol-string.any.js b/test/wpt/tests/websockets/Create-valid-url-protocol-string.any.js
new file mode 100644
index 0000000..10e928d
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-valid-url-protocol.any.js b/test/wpt/tests/websockets/Create-valid-url-protocol.any.js
new file mode 100644
index 0000000..37b5a0e
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Create-valid-url.any.js b/test/wpt/tests/websockets/Create-valid-url.any.js
new file mode 100644
index 0000000..1df995f
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/META.yml b/test/wpt/tests/websockets/META.yml
new file mode 100644
index 0000000..da999b9
--- /dev/null
+++ b/test/wpt/tests/websockets/META.yml
@@ -0,0 +1,6 @@
+spec: https://websockets.spec.whatwg.org/
+suggested_reviewers:
+ - jdm
+ - ricea
+ - yutakahirano
+ - zqzhang
diff --git a/test/wpt/tests/websockets/README.md b/test/wpt/tests/websockets/README.md
new file mode 100644
index 0000000..ea35c70
--- /dev/null
+++ b/test/wpt/tests/websockets/README.md
@@ -0,0 +1 @@
+Tests for the [WebSockets Standard](https://websockets.spec.whatwg.org/).
diff --git a/test/wpt/tests/websockets/Send-0byte-data.any.js b/test/wpt/tests/websockets/Send-0byte-data.any.js
new file mode 100644
index 0000000..4176de4
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-65K-data.any.js b/test/wpt/tests/websockets/Send-65K-data.any.js
new file mode 100644
index 0000000..20e5ba7
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-before-open.any.js b/test/wpt/tests/websockets/Send-before-open.any.js
new file mode 100644
index 0000000..4fdbf71
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-65K-arraybuffer.any.js b/test/wpt/tests/websockets/Send-binary-65K-arraybuffer.any.js
new file mode 100644
index 0000000..6bee660
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-arraybuffer.any.js b/test/wpt/tests/websockets/Send-binary-arraybuffer.any.js
new file mode 100644
index 0000000..0b34e0c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-arraybufferview-float32.any.js b/test/wpt/tests/websockets/Send-binary-arraybufferview-float32.any.js
new file mode 100644
index 0000000..47ee5b1
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-arraybufferview-float64.any.js b/test/wpt/tests/websockets/Send-binary-arraybufferview-float64.any.js
new file mode 100644
index 0000000..78bcb13
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-arraybufferview-int16-offset.any.js b/test/wpt/tests/websockets/Send-binary-arraybufferview-int16-offset.any.js
new file mode 100644
index 0000000..3dd6455
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-arraybufferview-int32.any.js b/test/wpt/tests/websockets/Send-binary-arraybufferview-int32.any.js
new file mode 100644
index 0000000..853ba39
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-arraybufferview-int8.any.js b/test/wpt/tests/websockets/Send-binary-arraybufferview-int8.any.js
new file mode 100644
index 0000000..aa90020
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-arraybufferview-uint16-offset-length.any.js b/test/wpt/tests/websockets/Send-binary-arraybufferview-uint16-offset-length.any.js
new file mode 100644
index 0000000..a3c1f32
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-arraybufferview-uint32-offset.any.js b/test/wpt/tests/websockets/Send-binary-arraybufferview-uint32-offset.any.js
new file mode 100644
index 0000000..fede995
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-arraybufferview-uint8-offset-length.any.js b/test/wpt/tests/websockets/Send-binary-arraybufferview-uint8-offset-length.any.js
new file mode 100644
index 0000000..de3ae00
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-arraybufferview-uint8-offset.any.js b/test/wpt/tests/websockets/Send-binary-arraybufferview-uint8-offset.any.js
new file mode 100644
index 0000000..089174b
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-binary-blob.any.js b/test/wpt/tests/websockets/Send-binary-blob.any.js
new file mode 100644
index 0000000..5131b71
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-data.any.js b/test/wpt/tests/websockets/Send-data.any.js
new file mode 100644
index 0000000..a606ada
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-data.worker.js b/test/wpt/tests/websockets/Send-data.worker.js
new file mode 100644
index 0000000..5a8bdd5
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-null.any.js b/test/wpt/tests/websockets/Send-null.any.js
new file mode 100644
index 0000000..e621bb8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-paired-surrogates.any.js b/test/wpt/tests/websockets/Send-paired-surrogates.any.js
new file mode 100644
index 0000000..51e4fb9
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-unicode-data.any.js b/test/wpt/tests/websockets/Send-unicode-data.any.js
new file mode 100644
index 0000000..a3556b2
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/Send-unpaired-surrogates.any.js b/test/wpt/tests/websockets/Send-unpaired-surrogates.any.js
new file mode 100644
index 0000000..cbbcc6e
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js b/test/wpt/tests/websockets/back-forward-cache-with-closed-websocket-connection-ccns.tentative.window.js
new file mode 100644
index 0000000..f6ee5ed
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/back-forward-cache-with-closed-websocket-connection.window.js b/test/wpt/tests/websockets/back-forward-cache-with-closed-websocket-connection.window.js
new file mode 100644
index 0000000..30b8e63
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js b/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection-ccns.tentative.window.js
new file mode 100644
index 0000000..f37a04a
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection.window.js b/test/wpt/tests/websockets/back-forward-cache-with-open-websocket-connection.window.js
new file mode 100644
index 0000000..6c48a57
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/basic-auth.any.js b/test/wpt/tests/websockets/basic-auth.any.js
new file mode 100644
index 0000000..9fbdc5d
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/binary/001.html b/test/wpt/tests/websockets/binary/001.html
new file mode 100644
index 0000000..077bf79
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/binary/002.html b/test/wpt/tests/websockets/binary/002.html
new file mode 100644
index 0000000..5587776
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/binary/004.html b/test/wpt/tests/websockets/binary/004.html
new file mode 100644
index 0000000..8ca4e92
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/binary/005.html b/test/wpt/tests/websockets/binary/005.html
new file mode 100644
index 0000000..e89f4c0
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/binaryType-wrong-value.any.js b/test/wpt/tests/websockets/binaryType-wrong-value.any.js
new file mode 100644
index 0000000..683fb47
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/bufferedAmount-unchanged-by-sync-xhr.any.js b/test/wpt/tests/websockets/bufferedAmount-unchanged-by-sync-xhr.any.js
new file mode 100644
index 0000000..c15536d
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/close-invalid.any.js b/test/wpt/tests/websockets/close-invalid.any.js
new file mode 100644
index 0000000..c964c83
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/closing-handshake/002.html b/test/wpt/tests/websockets/closing-handshake/002.html
new file mode 100644
index 0000000..8d1e43b
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/closing-handshake/003.html b/test/wpt/tests/websockets/closing-handshake/003.html
new file mode 100644
index 0000000..43e1603
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/closing-handshake/004.html b/test/wpt/tests/websockets/closing-handshake/004.html
new file mode 100644
index 0000000..96411ea
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constants.sub.js b/test/wpt/tests/websockets/constants.sub.js
new file mode 100644
index 0000000..fd3c3b8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor.any.js b/test/wpt/tests/websockets/constructor.any.js
new file mode 100644
index 0000000..0cef206
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/001.html b/test/wpt/tests/websockets/constructor/001.html
new file mode 100644
index 0000000..13493e3
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/004.html b/test/wpt/tests/websockets/constructor/004.html
new file mode 100644
index 0000000..8143210
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/005.html b/test/wpt/tests/websockets/constructor/005.html
new file mode 100644
index 0000000..9d467de
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/006.html b/test/wpt/tests/websockets/constructor/006.html
new file mode 100644
index 0000000..5987583
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/007.html b/test/wpt/tests/websockets/constructor/007.html
new file mode 100644
index 0000000..e126d1a
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/008.html b/test/wpt/tests/websockets/constructor/008.html
new file mode 100644
index 0000000..e10c652
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/009.html b/test/wpt/tests/websockets/constructor/009.html
new file mode 100644
index 0000000..f8123c2
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/010.html b/test/wpt/tests/websockets/constructor/010.html
new file mode 100644
index 0000000..e5bc6ec
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/011.html b/test/wpt/tests/websockets/constructor/011.html
new file mode 100644
index 0000000..33b09db
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/012.html b/test/wpt/tests/websockets/constructor/012.html
new file mode 100644
index 0000000..ba2b6b2
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/013.html b/test/wpt/tests/websockets/constructor/013.html
new file mode 100644
index 0000000..d599fde
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/014.html b/test/wpt/tests/websockets/constructor/014.html
new file mode 100644
index 0000000..afa0dac
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/016.html b/test/wpt/tests/websockets/constructor/016.html
new file mode 100644
index 0000000..1860505
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/017.html b/test/wpt/tests/websockets/constructor/017.html
new file mode 100644
index 0000000..e1795b1
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/018.html b/test/wpt/tests/websockets/constructor/018.html
new file mode 100644
index 0000000..71f7376
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/019.html b/test/wpt/tests/websockets/constructor/019.html
new file mode 100644
index 0000000..8fbb1cb
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/020.html b/test/wpt/tests/websockets/constructor/020.html
new file mode 100644
index 0000000..e4d61f3
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/021.html b/test/wpt/tests/websockets/constructor/021.html
new file mode 100644
index 0000000..d3854fe
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/constructor/022.html b/test/wpt/tests/websockets/constructor/022.html
new file mode 100644
index 0000000..fd53c0f
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/cookies/001.html b/test/wpt/tests/websockets/cookies/001.html
new file mode 100644
index 0000000..abec94e
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/cookies/002.html b/test/wpt/tests/websockets/cookies/002.html
new file mode 100644
index 0000000..758ce47
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/cookies/003.html b/test/wpt/tests/websockets/cookies/003.html
new file mode 100644
index 0000000..9f770ae
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/cookies/004.html b/test/wpt/tests/websockets/cookies/004.html
new file mode 100644
index 0000000..523daba
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/cookies/005.html b/test/wpt/tests/websockets/cookies/005.html
new file mode 100644
index 0000000..f3e334c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/cookies/006.html b/test/wpt/tests/websockets/cookies/006.html
new file mode 100644
index 0000000..6e12bfa
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/cookies/007.html b/test/wpt/tests/websockets/cookies/007.html
new file mode 100644
index 0000000..3e69bfc
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/cookies/support/set-cookie.py b/test/wpt/tests/websockets/cookies/support/set-cookie.py
new file mode 100644
index 0000000..71cd8bc
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/cookies/support/websocket-cookies-helper.sub.js b/test/wpt/tests/websockets/cookies/support/websocket-cookies-helper.sub.js
new file mode 100644
index 0000000..a7fae25
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/cookies/third-party-cookie-accepted.https.html b/test/wpt/tests/websockets/cookies/third-party-cookie-accepted.https.html
new file mode 100644
index 0000000..208d297
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/eventhandlers.any.js b/test/wpt/tests/websockets/eventhandlers.any.js
new file mode 100644
index 0000000..f596328
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/extended-payload-length.html b/test/wpt/tests/websockets/extended-payload-length.html
new file mode 100644
index 0000000..92e3802
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/basic_auth_wsh.py b/test/wpt/tests/websockets/handlers/basic_auth_wsh.py
new file mode 100644
index 0000000..72e920a
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/delayed-passive-close_wsh.py b/test/wpt/tests/websockets/handlers/delayed-passive-close_wsh.py
new file mode 100644
index 0000000..7d55b88
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/echo-cookie_wsh.py b/test/wpt/tests/websockets/handlers/echo-cookie_wsh.py
new file mode 100644
index 0000000..98620b6
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/echo-query_v13_wsh.py b/test/wpt/tests/websockets/handlers/echo-query_v13_wsh.py
new file mode 100644
index 0000000..d670e6e
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/echo-query_wsh.py b/test/wpt/tests/websockets/handlers/echo-query_wsh.py
new file mode 100644
index 0000000..3921913
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/echo_close_data_wsh.py b/test/wpt/tests/websockets/handlers/echo_close_data_wsh.py
new file mode 100644
index 0000000..31ffcbb
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/echo_exit_wsh.py b/test/wpt/tests/websockets/handlers/echo_exit_wsh.py
new file mode 100644
index 0000000..8f6f7f8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/echo_raw_wsh.py b/test/wpt/tests/websockets/handlers/echo_raw_wsh.py
new file mode 100644
index 0000000..e1fc266
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/echo_wsh.py b/test/wpt/tests/websockets/handlers/echo_wsh.py
new file mode 100644
index 0000000..7367b70
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/empty-message_wsh.py b/test/wpt/tests/websockets/handlers/empty-message_wsh.py
new file mode 100644
index 0000000..0eb107f
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/handshake_no_extensions_wsh.py b/test/wpt/tests/websockets/handlers/handshake_no_extensions_wsh.py
new file mode 100644
index 0000000..0d0f0a8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/handshake_no_protocol_wsh.py b/test/wpt/tests/websockets/handlers/handshake_no_protocol_wsh.py
new file mode 100644
index 0000000..ffc2ae8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/handshake_protocol_wsh.py b/test/wpt/tests/websockets/handlers/handshake_protocol_wsh.py
new file mode 100644
index 0000000..2ca20c0
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/handshake_sleep_2_wsh.py b/test/wpt/tests/websockets/handlers/handshake_sleep_2_wsh.py
new file mode 100644
index 0000000..78de7c7
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/invalid_wsh.py b/test/wpt/tests/websockets/handlers/invalid_wsh.py
new file mode 100644
index 0000000..4bfc3ce
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/msg_channel_wsh.py b/test/wpt/tests/websockets/handlers/msg_channel_wsh.py
new file mode 100644
index 0000000..7a66646
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/origin_wsh.py b/test/wpt/tests/websockets/handlers/origin_wsh.py
new file mode 100644
index 0000000..ce5f3a7
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/protocol_array_wsh.py b/test/wpt/tests/websockets/handlers/protocol_array_wsh.py
new file mode 100644
index 0000000..be24ee0
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/protocol_wsh.py b/test/wpt/tests/websockets/handlers/protocol_wsh.py
new file mode 100644
index 0000000..10bdf33
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/receive-backpressure_wsh.py b/test/wpt/tests/websockets/handlers/receive-backpressure_wsh.py
new file mode 100644
index 0000000..9c2e470
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/receive-many-with-backpressure_wsh.py b/test/wpt/tests/websockets/handlers/receive-many-with-backpressure_wsh.py
new file mode 100644
index 0000000..8e35bee
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/referrer_wsh.py b/test/wpt/tests/websockets/handlers/referrer_wsh.py
new file mode 100644
index 0000000..9df652d
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/send-backpressure_wsh.py b/test/wpt/tests/websockets/handlers/send-backpressure_wsh.py
new file mode 100644
index 0000000..d3288d0
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/set-cookie-secure_wsh.py b/test/wpt/tests/websockets/handlers/set-cookie-secure_wsh.py
new file mode 100644
index 0000000..052a882
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/set-cookie_http_wsh.py b/test/wpt/tests/websockets/handlers/set-cookie_http_wsh.py
new file mode 100644
index 0000000..5331091
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/set-cookie_wsh.py b/test/wpt/tests/websockets/handlers/set-cookie_wsh.py
new file mode 100644
index 0000000..5fe3ad9
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/set-cookies-samesite_wsh.py b/test/wpt/tests/websockets/handlers/set-cookies-samesite_wsh.py
new file mode 100644
index 0000000..59f0a4a
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/simple_handshake_wsh.py b/test/wpt/tests/websockets/handlers/simple_handshake_wsh.py
new file mode 100644
index 0000000..ad46687
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/sleep_10_v13_wsh.py b/test/wpt/tests/websockets/handlers/sleep_10_v13_wsh.py
new file mode 100644
index 0000000..b0f1dde
--- /dev/null
+++ b/test/wpt/tests/websockets/handlers/sleep_10_v13_wsh.py
@@ -0,0 +1,24 @@
+#!/usr/bin/python
+
+import sys, urllib, time
+from mod_pywebsocket import msgutil
+
+def web_socket_do_extra_handshake(request):
+ request.connection.write(b'x')
+ time.sleep(2)
+ request.connection.write(b'x')
+ time.sleep(2)
+ request.connection.write(b'x')
+ time.sleep(2)
+ request.connection.write(b'x')
+ time.sleep(2)
+ request.connection.write(b'x')
+ time.sleep(2)
+ 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/test/wpt/tests/websockets/handlers/stash_responder_blocking_wsh.py b/test/wpt/tests/websockets/handlers/stash_responder_blocking_wsh.py
new file mode 100644
index 0000000..10ecdfe
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/stash_responder_wsh.py b/test/wpt/tests/websockets/handlers/stash_responder_wsh.py
new file mode 100644
index 0000000..d18ad3b
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/handlers/wrong_accept_key_wsh.py b/test/wpt/tests/websockets/handlers/wrong_accept_key_wsh.py
new file mode 100644
index 0000000..43240e1
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/idlharness.any.js b/test/wpt/tests/websockets/idlharness.any.js
new file mode 100644
index 0000000..653cc36
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/CloseEvent/clean-close.html b/test/wpt/tests/websockets/interfaces/CloseEvent/clean-close.html
new file mode 100644
index 0000000..8614028
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/CloseEvent/constructor.html b/test/wpt/tests/websockets/interfaces/CloseEvent/constructor.html
new file mode 100644
index 0000000..1ed86bd
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/CloseEvent/historical.html b/test/wpt/tests/websockets/interfaces/CloseEvent/historical.html
new file mode 100644
index 0000000..24528a8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html b/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html
new file mode 100644
index 0000000..5d2bfd0
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html b/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html
new file mode 100644
index 0000000..d0028da
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html b/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-getter.html
new file mode 100644
index 0000000..ea6e70c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-setter.html b/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-defineProperty-setter.html
new file mode 100644
index 0000000..8f0fa5c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-deleting.html b/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-deleting.html
new file mode 100644
index 0000000..1d99636
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-getting.html b/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-getting.html
new file mode 100644
index 0000000..92bcea6
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-initial.html b/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-initial.html
new file mode 100644
index 0000000..be37b6d
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-large.html b/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-large.html
new file mode 100644
index 0000000..18c5482
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-readonly.html b/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-readonly.html
new file mode 100644
index 0000000..152da69
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-unicode.html b/test/wpt/tests/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-unicode.html
new file mode 100644
index 0000000..ab01f3c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/close/close-basic.html b/test/wpt/tests/websockets/interfaces/WebSocket/close/close-basic.html
new file mode 100644
index 0000000..b646ca4
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/close/close-connecting.html b/test/wpt/tests/websockets/interfaces/WebSocket/close/close-connecting.html
new file mode 100644
index 0000000..de038ca
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/close/close-multiple.html b/test/wpt/tests/websockets/interfaces/WebSocket/close/close-multiple.html
new file mode 100644
index 0000000..e440d80
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/close/close-nested.html b/test/wpt/tests/websockets/interfaces/WebSocket/close/close-nested.html
new file mode 100644
index 0000000..74b8fa0
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/close/close-replace.html b/test/wpt/tests/websockets/interfaces/WebSocket/close/close-replace.html
new file mode 100644
index 0000000..e9d2364
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/close/close-return.html b/test/wpt/tests/websockets/interfaces/WebSocket/close/close-return.html
new file mode 100644
index 0000000..e74c9b0
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/constants/001.html b/test/wpt/tests/websockets/interfaces/WebSocket/constants/001.html
new file mode 100644
index 0000000..7d79bf5
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/constants/002.html b/test/wpt/tests/websockets/interfaces/WebSocket/constants/002.html
new file mode 100644
index 0000000..6810bc6
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/constants/003.html b/test/wpt/tests/websockets/interfaces/WebSocket/constants/003.html
new file mode 100644
index 0000000..4a86af8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/constants/004.html b/test/wpt/tests/websockets/interfaces/WebSocket/constants/004.html
new file mode 100644
index 0000000..2ca3830
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/constants/005.html b/test/wpt/tests/websockets/interfaces/WebSocket/constants/005.html
new file mode 100644
index 0000000..26d5b24
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/constants/006.html b/test/wpt/tests/websockets/interfaces/WebSocket/constants/006.html
new file mode 100644
index 0000000..78126c8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/001.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/001.html
new file mode 100644
index 0000000..88dcf9e
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/002.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/002.html
new file mode 100644
index 0000000..4817308
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/003.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/003.html
new file mode 100644
index 0000000..a5373ec
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/004.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/004.html
new file mode 100644
index 0000000..9c5144c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/006.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/006.html
new file mode 100644
index 0000000..de2f556
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/007.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/007.html
new file mode 100644
index 0000000..0fe7241
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/008.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/008.html
new file mode 100644
index 0000000..066eb09
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/009.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/009.html
new file mode 100644
index 0000000..b9e56e2
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/010.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/010.html
new file mode 100644
index 0000000..360e7d9
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/011.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/011.html
new file mode 100644
index 0000000..f648575
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/012.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/012.html
new file mode 100644
index 0000000..bdd63e3
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/013.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/013.html
new file mode 100644
index 0000000..9e251c6
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/014.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/014.html
new file mode 100644
index 0000000..9fcd8b3
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/015.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/015.html
new file mode 100644
index 0000000..5089c0f
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/016.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/016.html
new file mode 100644
index 0000000..8b5aaf9
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/017.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/017.html
new file mode 100644
index 0000000..a9f06ea
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/018.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/018.html
new file mode 100644
index 0000000..a340c69
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/019.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/019.html
new file mode 100644
index 0000000..deb079f
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/events/020.html b/test/wpt/tests/websockets/interfaces/WebSocket/events/020.html
new file mode 100644
index 0000000..f43b0af
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/extensions/001.html b/test/wpt/tests/websockets/interfaces/WebSocket/extensions/001.html
new file mode 100644
index 0000000..bd26483
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/protocol/protocol-initial.html b/test/wpt/tests/websockets/interfaces/WebSocket/protocol/protocol-initial.html
new file mode 100644
index 0000000..2e7bf66
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/readyState/001.html b/test/wpt/tests/websockets/interfaces/WebSocket/readyState/001.html
new file mode 100644
index 0000000..15b73fd
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/readyState/002.html b/test/wpt/tests/websockets/interfaces/WebSocket/readyState/002.html
new file mode 100644
index 0000000..239e5d7
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/readyState/003.html b/test/wpt/tests/websockets/interfaces/WebSocket/readyState/003.html
new file mode 100644
index 0000000..65d86c4
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/readyState/004.html b/test/wpt/tests/websockets/interfaces/WebSocket/readyState/004.html
new file mode 100644
index 0000000..0645816
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/readyState/005.html b/test/wpt/tests/websockets/interfaces/WebSocket/readyState/005.html
new file mode 100644
index 0000000..bee179f
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/readyState/006.html b/test/wpt/tests/websockets/interfaces/WebSocket/readyState/006.html
new file mode 100644
index 0000000..4290c00
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/readyState/007.html b/test/wpt/tests/websockets/interfaces/WebSocket/readyState/007.html
new file mode 100644
index 0000000..69b5d9c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/readyState/008.html b/test/wpt/tests/websockets/interfaces/WebSocket/readyState/008.html
new file mode 100644
index 0000000..d085a7f
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/001.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/001.html
new file mode 100644
index 0000000..8abc655
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/002.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/002.html
new file mode 100644
index 0000000..a51c677
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/003.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/003.html
new file mode 100644
index 0000000..069f24c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/004.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/004.html
new file mode 100644
index 0000000..7125d19
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/005.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/005.html
new file mode 100644
index 0000000..5da4600
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/006.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/006.html
new file mode 100644
index 0000000..4095c0b
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/007.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/007.html
new file mode 100644
index 0000000..6a56142
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/008.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/008.html
new file mode 100644
index 0000000..709c066
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/009.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/009.html
new file mode 100644
index 0000000..57da896
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/010.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/010.html
new file mode 100644
index 0000000..4a008b6
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/011.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/011.html
new file mode 100644
index 0000000..5f63c44
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/send/012.html b/test/wpt/tests/websockets/interfaces/WebSocket/send/012.html
new file mode 100644
index 0000000..9876c7b
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/url/001.html b/test/wpt/tests/websockets/interfaces/WebSocket/url/001.html
new file mode 100644
index 0000000..6c7306d
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/url/002.html b/test/wpt/tests/websockets/interfaces/WebSocket/url/002.html
new file mode 100644
index 0000000..e1cc6d0
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/url/003.html b/test/wpt/tests/websockets/interfaces/WebSocket/url/003.html
new file mode 100644
index 0000000..aaae33a
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/url/004.html b/test/wpt/tests/websockets/interfaces/WebSocket/url/004.html
new file mode 100644
index 0000000..7db5e1e
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/url/005.html b/test/wpt/tests/websockets/interfaces/WebSocket/url/005.html
new file mode 100644
index 0000000..00a5d90
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/url/006.html b/test/wpt/tests/websockets/interfaces/WebSocket/url/006.html
new file mode 100644
index 0000000..6e83770
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/interfaces/WebSocket/url/resolve.html b/test/wpt/tests/websockets/interfaces/WebSocket/url/resolve.html
new file mode 100644
index 0000000..2452073
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/keeping-connection-open/001.html b/test/wpt/tests/websockets/keeping-connection-open/001.html
new file mode 100644
index 0000000..ab5bd1a
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/mixed-content.https.any.js b/test/wpt/tests/websockets/mixed-content.https.any.js
new file mode 100644
index 0000000..b7a6d83
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/multi-globals/message-received.html b/test/wpt/tests/websockets/multi-globals/message-received.html
new file mode 100644
index 0000000..704b1e3
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/multi-globals/support/incumbent.sub.html b/test/wpt/tests/websockets/multi-globals/support/incumbent.sub.html
new file mode 100644
index 0000000..a138b70
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/multi-globals/support/relevant.html b/test/wpt/tests/websockets/multi-globals/support/relevant.html
new file mode 100644
index 0000000..44f42ed
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/multi-globals/url-parsing/current/current.html b/test/wpt/tests/websockets/multi-globals/url-parsing/current/current.html
new file mode 100644
index 0000000..82a48d4
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/multi-globals/url-parsing/incumbent/incumbent.html b/test/wpt/tests/websockets/multi-globals/url-parsing/incumbent/incumbent.html
new file mode 100644
index 0000000..2c5572b
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/multi-globals/url-parsing/url-parsing.html b/test/wpt/tests/websockets/multi-globals/url-parsing/url-parsing.html
new file mode 100644
index 0000000..21ef6cd
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/opening-handshake/001.html b/test/wpt/tests/websockets/opening-handshake/001.html
new file mode 100644
index 0000000..d8585d8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/opening-handshake/002.html b/test/wpt/tests/websockets/opening-handshake/002.html
new file mode 100644
index 0000000..00d8dcc
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/opening-handshake/003-sets-origin.worker.js b/test/wpt/tests/websockets/opening-handshake/003-sets-origin.worker.js
new file mode 100644
index 0000000..d10e8cb
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/opening-handshake/003.html b/test/wpt/tests/websockets/opening-handshake/003.html
new file mode 100644
index 0000000..1fc7535
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/opening-handshake/005.html b/test/wpt/tests/websockets/opening-handshake/005.html
new file mode 100644
index 0000000..dcbd8df
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/referrer.any.js b/test/wpt/tests/websockets/referrer.any.js
new file mode 100644
index 0000000..0972a1d
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/remove-own-iframe-during-onerror.window.js b/test/wpt/tests/websockets/remove-own-iframe-during-onerror.window.js
new file mode 100644
index 0000000..aa1cf60
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/resources/websockets-test-helpers.sub.js b/test/wpt/tests/websockets/resources/websockets-test-helpers.sub.js
new file mode 100644
index 0000000..2680670
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/security/001.html b/test/wpt/tests/websockets/security/001.html
new file mode 100644
index 0000000..a34ae39
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/security/002.html b/test/wpt/tests/websockets/security/002.html
new file mode 100644
index 0000000..3286cca
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/security/check.py b/test/wpt/tests/websockets/security/check.py
new file mode 100644
index 0000000..716b837
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/send-many-64K-messages-with-backpressure.any.js b/test/wpt/tests/websockets/send-many-64K-messages-with-backpressure.any.js
new file mode 100644
index 0000000..78c244b
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/stream/tentative/README.md b/test/wpt/tests/websockets/stream/tentative/README.md
new file mode 100644
index 0000000..6c51588
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/stream/tentative/abort.any.js b/test/wpt/tests/websockets/stream/tentative/abort.any.js
new file mode 100644
index 0000000..9047f24
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/stream/tentative/backpressure-receive.any.js b/test/wpt/tests/websockets/stream/tentative/backpressure-receive.any.js
new file mode 100644
index 0000000..236bb2e
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/stream/tentative/backpressure-send.any.js b/test/wpt/tests/websockets/stream/tentative/backpressure-send.any.js
new file mode 100644
index 0000000..e4a80f6
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/stream/tentative/close.any.js b/test/wpt/tests/websockets/stream/tentative/close.any.js
new file mode 100644
index 0000000..2be9034
--- /dev/null
+++ b/test/wpt/tests/websockets/stream/tentative/close.any.js
@@ -0,0 +1,187 @@
+// META: script=../../constants.sub.js
+// META: script=resources/url-constants.js
+// META: global=window,worker
+// META: variant=?wss
+// META: variant=?wpt_flags=h2
+
+promise_test(async () => {
+ const wss = new WebSocketStream(ECHOURL);
+ await wss.opened;
+ wss.close({code: 3456, reason: 'pizza'});
+ const { code, reason } = await wss.closed;
+ assert_equals(code, 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 { code, reason } = await wss.closed;
+ assert_equals(code, 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 { code, reason } = await wss.closed;
+ assert_equals(code, 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 { code, reason } = await wss.closed;
+ assert_equals(code, 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 { code, reason } = await wss.closed;
+ assert_equals(code, 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 TypeError');
+}, 'close() with an overlong reason should throw');
+
+promise_test(t => {
+ const wss = new WebSocketStream(ECHOURL);
+ wss.close();
+ return Promise.all([
+ promise_rejects_dom(
+ t, 'NetworkError', wss.opened, 'opened promise should reject'),
+ promise_rejects_dom(
+ t, 'NetworkError', wss.closed, 'closed promise should reject'),
+ ]);
+}, '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({ code: invalidCode }),
+ 'close should throw a TypeError');
+ }, `close() with invalid code ${invalidCode} should throw`);
+}
+
+promise_test(async () => {
+ const wss = new WebSocketStream(ECHOURL);
+ const { writable } = await wss.opened;
+ writable.getWriter().close();
+ const { code, reason } = await wss.closed;
+ assert_equals(code, 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 { code, reason } = await wss.closed;
+ assert_equals(code, 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]({ code: 3333 });
+ const { code, reason } = await wss.closed;
+ assert_equals(code, 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]({ code: 3456, reason: 'set' });
+ const { code, reason } = await wss.closed;
+ assert_equals(code, 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]({ reason: 'specified' });
+ const { code, reason } = await wss.closed;
+ assert_equals(code, 1005, 'code should be unset');
+ assert_equals(reason, '', 'reason should be empty');
+ }, `${voweling} the ${stream} with a reason but no code should be ignored`);
+
+ promise_test(async () => {
+ const wss = new WebSocketStream(ECHOURL);
+ const info = await wss.opened;
+ info[stream][method]({ code: 999 });
+ const { code, reason } = await wss.closed;
+ assert_equals(code, 1005, 'code should be unset');
+ assert_equals(reason, '', 'reason should be empty');
+ }, `${voweling} the ${stream} with an invalid code should be ignored`);
+
+ promise_test(async () => {
+ const wss = new WebSocketStream(ECHOURL);
+ const info = await wss.opened;
+ info[stream][method]({ code: 1000, reason: 'x'.repeat(128) });
+ const { code, reason } = await wss.closed;
+ assert_equals(code, 1005, 'code should be unset');
+ assert_equals(reason, '', 'reason should be empty');
+ }, `${voweling} the ${stream} with an invalid reason should be ignored`);
+
+ // DOMExceptions are only ignored because the |code| attribute is too small to
+ // be a valid WebSocket close code.
+ promise_test(async () => {
+ const wss = new WebSocketStream(ECHOURL);
+ const info = await wss.opened;
+ info[stream][method](new DOMException('yes', 'DataCloneError'));
+ const { code, reason } = await wss.closed;
+ assert_equals(code, 1005, 'code should be unset');
+ assert_equals(reason, '', 'reason should be empty');
+ }, `${voweling} the ${stream} with a DOMException should be ignored`);
+
+}
diff --git a/test/wpt/tests/websockets/stream/tentative/constructor.any.js b/test/wpt/tests/websockets/stream/tentative/constructor.any.js
new file mode 100644
index 0000000..4d67d81
--- /dev/null
+++ b/test/wpt/tests/websockets/stream/tentative/constructor.any.js
@@ -0,0 +1,67 @@
+// 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');
+
+promise_test(t => {
+ const wss = new WebSocketStream(`${BASEURL}/404`);
+ return Promise.all([
+ promise_rejects_dom(t, 'NetworkError', wss.opened, 'opened should reject'),
+ promise_rejects_dom(t, 'NetworkError', wss.closed, 'closed should reject'),
+ ]);
+}, '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/test/wpt/tests/websockets/stream/tentative/resources/url-constants.js b/test/wpt/tests/websockets/stream/tentative/resources/url-constants.js
new file mode 100644
index 0000000..fe681af
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/unload-a-document/001-1.html b/test/wpt/tests/websockets/unload-a-document/001-1.html
new file mode 100644
index 0000000..7cf4ab6
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/unload-a-document/001-2.html b/test/wpt/tests/websockets/unload-a-document/001-2.html
new file mode 100644
index 0000000..24c419c
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/unload-a-document/001.html b/test/wpt/tests/websockets/unload-a-document/001.html
new file mode 100644
index 0000000..28ce9c4
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/unload-a-document/002-1.html b/test/wpt/tests/websockets/unload-a-document/002-1.html
new file mode 100644
index 0000000..1922bb4
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/unload-a-document/002-2.html b/test/wpt/tests/websockets/unload-a-document/002-2.html
new file mode 100644
index 0000000..9a246a1
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/unload-a-document/002.html b/test/wpt/tests/websockets/unload-a-document/002.html
new file mode 100644
index 0000000..f79b3b7
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/unload-a-document/003.html b/test/wpt/tests/websockets/unload-a-document/003.html
new file mode 100644
index 0000000..554daf4
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/unload-a-document/004.html b/test/wpt/tests/websockets/unload-a-document/004.html
new file mode 100644
index 0000000..bb15cd8
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/unload-a-document/005-1.html b/test/wpt/tests/websockets/unload-a-document/005-1.html
new file mode 100644
index 0000000..e084ade
--- /dev/null
+++ b/test/wpt/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/test/wpt/tests/websockets/unload-a-document/005.html b/test/wpt/tests/websockets/unload-a-document/005.html
new file mode 100644
index 0000000..1abb1b5
--- /dev/null
+++ b/test/wpt/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>