mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
fix(ext/websocket): drop connection when close frame not ack (#24301)
Fixes #24292
This commit is contained in:
parent
13aa1d70e9
commit
a1ff1a453c
3 changed files with 62 additions and 2 deletions
|
@ -424,6 +424,18 @@ class WebSocket extends EventTarget {
|
||||||
const rid = this[_rid];
|
const rid = this[_rid];
|
||||||
while (this[_readyState] !== CLOSED) {
|
while (this[_readyState] !== CLOSED) {
|
||||||
const kind = await op_ws_next_event(rid);
|
const kind = await op_ws_next_event(rid);
|
||||||
|
/* close the connection if read was cancelled, and we didn't get a close frame */
|
||||||
|
if (
|
||||||
|
(this[_readyState] == CLOSING) &&
|
||||||
|
kind <= 3 && this[_role] !== CLIENT
|
||||||
|
) {
|
||||||
|
this[_readyState] = CLOSED;
|
||||||
|
|
||||||
|
const event = new CloseEvent("close");
|
||||||
|
this.dispatchEvent(event);
|
||||||
|
core.tryClose(rid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case 0: {
|
case 0: {
|
||||||
|
|
|
@ -699,10 +699,14 @@ pub async fn op_ws_close(
|
||||||
#[smi] code: Option<u16>,
|
#[smi] code: Option<u16>,
|
||||||
#[string] reason: Option<String>,
|
#[string] reason: Option<String>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let resource = state
|
let Ok(resource) = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<ServerWebSocket>(rid)?;
|
.get::<ServerWebSocket>(rid)
|
||||||
|
else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
let frame = reason
|
let frame = reason
|
||||||
.map(|reason| Frame::close(code.unwrap_or(1005), reason.as_bytes()))
|
.map(|reason| Frame::close(code.unwrap_or(1005), reason.as_bytes()))
|
||||||
.unwrap_or_else(|| Frame::close_raw(vec![].into()));
|
.unwrap_or_else(|| Frame::close_raw(vec![].into()));
|
||||||
|
|
|
@ -761,3 +761,47 @@ Deno.test("Close without frame", async () => {
|
||||||
};
|
};
|
||||||
await promise;
|
await promise;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Deno.test("Close connection", async () => {
|
||||||
|
const ac = new AbortController();
|
||||||
|
const listeningDeferred = Promise.withResolvers<void>();
|
||||||
|
|
||||||
|
const server = Deno.serve({
|
||||||
|
handler: (req) => {
|
||||||
|
const { socket, response } = Deno.upgradeWebSocket(req);
|
||||||
|
socket.onmessage = function (e) {
|
||||||
|
socket.close(1008);
|
||||||
|
assertEquals(e.data, "Hello");
|
||||||
|
};
|
||||||
|
socket.onclose = () => {
|
||||||
|
ac.abort();
|
||||||
|
};
|
||||||
|
socket.onerror = () => fail();
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
signal: ac.signal,
|
||||||
|
onListen: () => listeningDeferred.resolve(),
|
||||||
|
hostname: "localhost",
|
||||||
|
port: servePort,
|
||||||
|
});
|
||||||
|
|
||||||
|
await listeningDeferred.promise;
|
||||||
|
|
||||||
|
const conn = await Deno.connect({ port: servePort, hostname: "localhost" });
|
||||||
|
await conn.write(
|
||||||
|
new TextEncoder().encode(
|
||||||
|
"GET / HTTP/1.1\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Write a 2 text frame saying "Hello"
|
||||||
|
await conn.write(new Uint8Array([0x81, 0x05]));
|
||||||
|
await conn.write(new TextEncoder().encode("Hello"));
|
||||||
|
|
||||||
|
// We are a bad client so we won't acknowledge the close frame
|
||||||
|
await conn.write(new Uint8Array([0x81, 0x05]));
|
||||||
|
await conn.write(new TextEncoder().encode("Hello"));
|
||||||
|
|
||||||
|
await server.finished;
|
||||||
|
conn.close();
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue