From fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:14:29 +0200 Subject: Merging upstream version 125.0.1. Signed-off-by: Daniel Baumann --- .../websockets/handlers/passive-close-abort_wsh.py | 24 +++++++ .../tests/websockets/handlers/remote-close_wsh.py | 44 +++++++++++++ .../tests/websockets/stream/tentative/close.any.js | 10 +++ .../stream/tentative/remote-close.any.js | 74 ++++++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 testing/web-platform/tests/websockets/handlers/passive-close-abort_wsh.py create mode 100644 testing/web-platform/tests/websockets/handlers/remote-close_wsh.py create mode 100644 testing/web-platform/tests/websockets/stream/tentative/remote-close.any.js (limited to 'testing/web-platform/tests/websockets') diff --git a/testing/web-platform/tests/websockets/handlers/passive-close-abort_wsh.py b/testing/web-platform/tests/websockets/handlers/passive-close-abort_wsh.py new file mode 100644 index 0000000000..ac3f67c8db --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/passive-close-abort_wsh.py @@ -0,0 +1,24 @@ +# Copyright (c) 2024 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Wait for a Close frame from the client and then close the connection without +sending a Close frame in return. +""" + +from mod_pywebsocket.handshake import AbortedByUserException + + +def web_socket_do_extra_handshake(request): + pass + + +def web_socket_transfer_data(request): + while True: + if request.ws_stream.receive_message() is None: + return + + +def web_socket_passive_closing_handshake(request): + raise AbortedByUserException('abrupt close') diff --git a/testing/web-platform/tests/websockets/handlers/remote-close_wsh.py b/testing/web-platform/tests/websockets/handlers/remote-close_wsh.py new file mode 100644 index 0000000000..aadd99ea95 --- /dev/null +++ b/testing/web-platform/tests/websockets/handlers/remote-close_wsh.py @@ -0,0 +1,44 @@ +# Copyright (c) 2024 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Perform a server-initiated close according to the parameters passed in the +query string. Supported parameters: + + * code=INT: The close code to send in the close frame. If omitted the Close + frame will have an empty body. + + * reason=TEXT: The reason to be sent in the close frame. Only sent if `code` is + set. + + * abrupt=1: Close the connection without sending a Close frame. + +Example: /remote-close?code=1000&reason=Done + +""" + +import urllib + +from mod_pywebsocket.handshake import AbortedByUserException + + +def web_socket_do_extra_handshake(request): + pass + + +def web_socket_transfer_data(request): + parts = urllib.parse.urlsplit(request.uri) + parameters = urllib.parse.parse_qs(parts.query) + if 'abrupt' in parameters: + # Send a ping frame to make sure this isn't misinterpreted as a + # handshake failure. + request.ws_stream.send_ping('ping') + # Rudely close the connection. + raise AbortedByUserException('Abort the connection') + code = None + reason = None + if 'code' in parameters: + code = int(parameters['code'][0]) + reason = parameters.get('reason', [''])[0] + request.ws_stream.close_connection(code, reason) diff --git a/testing/web-platform/tests/websockets/stream/tentative/close.any.js b/testing/web-platform/tests/websockets/stream/tentative/close.any.js index 098caf31c8..ad41dc6e2e 100644 --- a/testing/web-platform/tests/websockets/stream/tentative/close.any.js +++ b/testing/web-platform/tests/websockets/stream/tentative/close.any.js @@ -1,6 +1,7 @@ // META: script=../../constants.sub.js // META: script=resources/url-constants.js // META: global=window,worker +// META: variant=?default // META: variant=?wss // META: variant=?wpt_flags=h2 @@ -108,6 +109,15 @@ promise_test(async () => { 'one second should have elapsed'); }, 'writer close() promise should not resolve until handshake completes'); +promise_test(async t => { + const wss = new WebSocketStream(`${BASEURL}/passive-close-abort`); + await wss.opened; + wss.close({closeCode: 4000, reason: 'because'}); + const error = await wss.closed.then(t.unreached_func('closed should reject'), e => e); + assert_equals(error.constructor, WebSocketError, 'error should be WebSocketError'); + assert_equals(error.closeCode, 1006, 'close code should be Abnormal Closure'); +}, 'incomplete closing handshake should be considered unclean close'); + const abortOrCancel = [ { method: 'abort', diff --git a/testing/web-platform/tests/websockets/stream/tentative/remote-close.any.js b/testing/web-platform/tests/websockets/stream/tentative/remote-close.any.js new file mode 100644 index 0000000000..b7fd321914 --- /dev/null +++ b/testing/web-platform/tests/websockets/stream/tentative/remote-close.any.js @@ -0,0 +1,74 @@ +// META: script=../../constants.sub.js +// META: script=resources/url-constants.js +// META: global=window,worker +// META: variant=?default +// META: variant=?wss +// META: variant=?wpt_flags=h2 + +'use strict'; + +promise_test(async t => { + const wss = new WebSocketStream(`${BASEURL}/remote-close?code=1000`); + const { readable, writable } = await wss.opened; + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1000, 'code should be 1000'); + assert_equals(reason, '', 'reason should be empty'); + const { value, done } = await readable.getReader().read(); + assert_true(done, 'readable should be closed'); + await promise_rejects_dom(t, 'InvalidStateError', writable.getWriter().ready, + 'writable should be errored'); +}, 'clean close should be clean'); + +promise_test(async () => { + const wss = new WebSocketStream(`${BASEURL}/remote-close`); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 1005, 'code should be No Status Rcvd'); + assert_equals(reason, '', 'reason should be empty'); +}, 'close frame with no body should result in status code 1005'); + +promise_test(async () => { + const wss = new WebSocketStream(`${BASEURL}/remote-close?code=4000&reason=robot`); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 4000, 'code should be 4000'); + assert_equals(reason, 'robot', 'reason should be set'); +}, 'reason should be passed through'); + +promise_test(async () => { + const wss = new WebSocketStream(`${BASEURL}/remote-close?code=4000&` + + 'reason=%E3%83%AD%E3%83%9C%E3%83%83%E3%83%88'); + const { reason } = await wss.closed; + assert_equals(reason, 'ロボット', 'reason should be set'); +}, 'UTF-8 reason should work'); + +promise_test(async t => { + const wss = new WebSocketStream(`${BASEURL}/remote-close?code=4567`); + const { writable } = await wss.opened; + const veryLargeMessage = new Uint8Array(20 * 1024 * 1024); // 20MB. + const writePromise = writable.getWriter().write(veryLargeMessage); + const closedError = await wss.closed.then(t.unreached_func('closed should reject'), e => e); + assert_equals(closedError.constructor, WebSocketError, 'error should be WebSocketError'); + assert_equals(closedError.closeCode, 4567, 'closeCode should be set'); + promise_rejects_js(t, WebSocketError, writePromise, 'write() should reject'); +}, 'close with unwritten data should not be considered clean'); + +promise_test(async t => { + const wss = new WebSocketStream(`${BASEURL}/remote-close?code=4222&reason=remote`); + await wss.opened; + wss.close({closeCode: 4111, reason: 'local'}); + const { closeCode, reason } = await wss.closed; + assert_equals(closeCode, 4222, 'remote code should be used'); + assert_equals(reason, 'remote', 'remote reason should be used'); +}, 'remote code and reason should be used'); + +promise_test(async t => { + const wss = new WebSocketStream(`${BASEURL}/remote-close?abrupt=1`); + const { readable, writable } = await wss.opened; + const closedError = await wss.closed.then(t.unreached_func('closed should reject'), e => e); + assert_equals(closedError.constructor, WebSocketError, 'error should be a WebSocketError'); + assert_equals(closedError.name, 'WebSocketError', 'error name should be WebSocketError'); + assert_equals(closedError.closeCode, 1006, 'code should be Abnormal Closure'); + await promise_rejects_exactly(t, closedError, readable.getReader().read(), + 'readable should be errored with the same object'); + await promise_rejects_exactly(t, closedError, writable.getWriter().ready, + 'writable should be errored with the same object'); +}, 'abrupt close should give an error'); -- cgit v1.2.3