diff options
author | Kevin (Kun) "Kassimo" Qian <kevinkassimo@gmail.com> | 2019-12-11 16:46:03 -0800 |
---|---|---|
committer | Ry Dahl <ry@tinyclouds.org> | 2019-12-12 08:46:03 +0800 |
commit | c3c69aff7e1df1a9480d2a5e9a0fa17cf3af6409 (patch) | |
tree | a00e51e02cb7390b684065d3a4018eb84d80a78c /std/http/server_test.ts | |
parent | 407195ea870a82f4341671d6718f813bd9a3b7ac (diff) |
fix(std/http): close connection on .respond() error (#3475)
Diffstat (limited to 'std/http/server_test.ts')
-rw-r--r-- | std/http/server_test.ts | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/std/http/server_test.ts b/std/http/server_test.ts index 30070b272..557223164 100644 --- a/std/http/server_test.ts +++ b/std/http/server_test.ts @@ -17,7 +17,7 @@ import { readRequest, parseHTTPVersion } from "./server.ts"; -import { delay } from "../util/async.ts"; +import { delay, deferred } from "../util/async.ts"; import { BufReader, BufWriter, @@ -590,4 +590,69 @@ test({ } }); +// TODO(kevinkassimo): create a test that works on Windows. +// The following test is to ensure that if an error occurs during respond +// would result in connection closed. (such that fd/resource is freed). +// On *nix, a delayed second attempt to write to a CLOSE_WAIT connection would +// receive a RST and thus trigger an error during response for us to test. +// We need to find a way to similarly trigger an error on Windows so that +// we can test if connection is closed. +if (Deno.build.os !== "win") { + test({ + name: "[http] respond error handling", + async fn(): Promise<void> { + const connClosedPromise = deferred(); + const serverRoutine = async (): Promise<void> => { + let reqCount = 0; + const server = serve(":8124"); + const serverRid = server.listener["rid"]; + let connRid = -1; + for await (const req of server) { + connRid = req.conn.rid; + reqCount++; + await req.body(); + await connClosedPromise; + try { + await req.respond({ + body: new TextEncoder().encode("Hello World") + }); + await delay(100); + req.done = deferred(); + // This duplicate respond is to ensure we get a write failure from the + // other side. Our client would enter CLOSE_WAIT stage after close(), + // meaning first server .send (.respond) after close would still work. + // However, a second send would fail under RST, which is similar + // to the scenario where a failure happens during .respond + await req.respond({ + body: new TextEncoder().encode("Hello World") + }); + } catch { + break; + } + } + server.close(); + const resources = Deno.resources(); + assert(reqCount === 1); + // Server should be gone + assert(!(serverRid in resources)); + // The connection should be destroyed + assert(!(connRid in resources)); + }; + const p = serverRoutine(); + const conn = await Deno.dial({ + hostname: "127.0.0.1", + port: 8124 + }); + await Deno.writeAll( + conn, + new TextEncoder().encode("GET / HTTP/1.1\r\n\r\n") + ); + conn.close(); // abruptly closing connection before response. + // conn on server side enters CLOSE_WAIT state. + connClosedPromise.resolve(); + await p; + } + }); +} + runIfMain(import.meta); |