From 60d9ab08dbcf2b9874206bc8411a25ca44e8118e Mon Sep 17 00:00:00 2001 From: lideming Date: Thu, 19 Nov 2020 00:47:47 +0800 Subject: fix(std/http): fix error handling in the request iterator (#8365) If the request body is using chunked encoding, errors may be thrown in "request.finalize()". In this case, we should untrack and close the connection. --- std/http/server_test.ts | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) (limited to 'std/http/server_test.ts') diff --git a/std/http/server_test.ts b/std/http/server_test.ts index f26dc63cd..e7a1c42dc 100644 --- a/std/http/server_test.ts +++ b/std/http/server_test.ts @@ -564,6 +564,118 @@ Deno.test({ }, }); +Deno.test({ + name: "[http] finalizing invalid chunked data closes connection", + async fn(): Promise { + const serverRoutine = async (): Promise => { + const server = serve(":8124"); + for await (const req of server) { + await req.respond({ status: 200, body: "Hello, world!" }); + break; + } + server.close(); + }; + const p = serverRoutine(); + const conn = await Deno.connect({ + hostname: "127.0.0.1", + port: 8124, + }); + await Deno.writeAll( + conn, + encode( + "PUT / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\nzzzzzzz\r\nhello", + ), + ); + await conn.closeWrite(); + const responseString = decode(await Deno.readAll(conn)); + assertEquals( + responseString, + "HTTP/1.1 200 OK\r\ncontent-length: 13\r\n\r\nHello, world!", + ); + conn.close(); + await p; + }, +}); + +Deno.test({ + name: "[http] finalizing chunked unexpected EOF closes connection", + async fn(): Promise { + const serverRoutine = async (): Promise => { + const server = serve(":8124"); + for await (const req of server) { + await req.respond({ status: 200, body: "Hello, world!" }); + break; + } + server.close(); + }; + const p = serverRoutine(); + const conn = await Deno.connect({ + hostname: "127.0.0.1", + port: 8124, + }); + await Deno.writeAll( + conn, + encode("PUT / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nHello"), + ); + conn.closeWrite(); + const responseString = decode(await Deno.readAll(conn)); + assertEquals( + responseString, + "HTTP/1.1 200 OK\r\ncontent-length: 13\r\n\r\nHello, world!", + ); + conn.close(); + await p; + }, +}); + +Deno.test({ + name: + "[http] receiving bad request from a closed connection should not throw", + async fn(): Promise { + const server = serve(":8124"); + const serverRoutine = async (): Promise => { + for await (const req of server) { + await req.respond({ status: 200, body: "Hello, world!" }); + } + }; + const p = serverRoutine(); + const conn = await Deno.connect({ + hostname: "127.0.0.1", + port: 8124, + }); + await Deno.writeAll( + conn, + encode([ + // A normal request is required: + "GET / HTTP/1.1", + "Host: localhost", + "", + // The bad request: + "GET / HTTP/1.1", + "Host: localhost", + "INVALID!HEADER!", + "", + "", + ].join("\r\n")), + ); + // After sending the two requests, don't receive the reponses. + + // Closing the connection now. + conn.close(); + + // The server will write responses to the closed connection, + // the first few `write()` calls will not throws, until the server received + // the TCP RST. So we need the normal request before the bad request to + // make the server do a few writes before it writes that `400` response. + + // Wait for server to handle requests. + await delay(10); + + server.close(); + await p; + }, +}); + Deno.test({ name: "serveTLS Invalid Cert", fn: async (): Promise => { -- cgit v1.2.3