diff --git a/cli/tests/unit/flash_test.ts b/cli/tests/unit/flash_test.ts index 087e5d0f2a..a2011a0761 100644 --- a/cli/tests/unit/flash_test.ts +++ b/cli/tests/unit/flash_test.ts @@ -2205,6 +2205,35 @@ Deno.test( }, ); +// https://github.com/denoland/deno/issues/15549 +Deno.test( + { permissions: { net: true } }, + async function testIssue15549() { + const ac = new AbortController(); + const promise = deferred(); + let count = 0; + const server = Deno.serve(() => { + count++; + return new Response(`hello world ${count}`); + }, { + async onListen() { + const res1 = await fetch("http://localhost:9000/"); + assertEquals(await res1.text(), "hello world 1"); + + const res2 = await fetch("http://localhost:9000/"); + assertEquals(await res2.text(), "hello world 2"); + + promise.resolve(); + ac.abort(); + }, + signal: ac.signal, + }); + + await promise; + await server; + }, +); + function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader { // Based on https://tools.ietf.org/html/rfc2616#section-19.4.6 const tp = new TextProtoReader(r); diff --git a/ext/flash/lib.rs b/ext/flash/lib.rs index 65d52d083d..0714e379d7 100644 --- a/ext/flash/lib.rs +++ b/ext/flash/lib.rs @@ -987,22 +987,48 @@ fn run_server( // sockets.remove(&token); continue 'events; } - Ok(read) => match req.parse(&buffer[..offset + read]) { - Ok(httparse::Status::Complete(n)) => { - body_offset = n; - body_len = offset + read; - socket.parse_done = ParseStatus::None; - break; + Ok(read) => { + match req.parse(&buffer[..offset + read]) { + Ok(httparse::Status::Complete(n)) => { + body_offset = n; + body_len = offset + read; + socket.parse_done = ParseStatus::None; + // On Windows, We must keep calling socket.read() until it fails with WouldBlock. + // + // Mio tries to emulate edge triggered events on Windows. + // AFAICT it only rearms the event on WouldBlock, but it doesn't when a partial read happens. + // https://github.com/denoland/deno/issues/15549 + #[cfg(target_os = "windows")] + match &mut socket.inner { + InnerStream::Tcp(ref mut socket) => { + poll + .registry() + .reregister(socket, token, Interest::READABLE) + .unwrap(); + } + InnerStream::Tls(ref mut socket) => { + poll + .registry() + .reregister( + &mut socket.sock, + token, + Interest::READABLE, + ) + .unwrap(); + } + }; + break; + } + Ok(httparse::Status::Partial) => { + socket.parse_done = ParseStatus::Ongoing(offset + read); + continue; + } + Err(_) => { + let _ = socket.write(b"HTTP/1.1 400 Bad Request\r\n\r\n"); + continue 'events; + } } - Ok(httparse::Status::Partial) => { - socket.parse_done = ParseStatus::Ongoing(offset + read); - continue; - } - Err(_) => { - let _ = socket.write(b"HTTP/1.1 400 Bad Request\r\n\r\n"); - continue 'events; - } - }, + } Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => { break 'events }