From 3ef34673c9b92aa3c54dfccb37c06b82d6fb3eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 19 Mar 2020 16:04:26 +0100 Subject: std(http/server): close open connections on server close (#3679) Due to structure of "Server" for each open connection there's a pending "read" op. Because connection owned by "Server" are not tracked, calling "Server.close()" doesn't close open connections. This commit introduces simple tracking of connections for server and ensures owned connections are closed on "Server.close()". --- std/http/server_test.ts | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'std/http/server_test.ts') diff --git a/std/http/server_test.ts b/std/http/server_test.ts index b4d86c468..d3f36a1d3 100644 --- a/std/http/server_test.ts +++ b/std/http/server_test.ts @@ -6,8 +6,13 @@ // https://github.com/golang/go/blob/master/src/net/http/responsewrite_test.go import { TextProtoReader } from "../textproto/mod.ts"; -import { assert, assertEquals, assertNotEOF } from "../testing/asserts.ts"; -import { Response, ServerRequest, serve } from "./server.ts"; +import { + assert, + assertEquals, + assertNotEOF, + assertStrContains +} from "../testing/asserts.ts"; +import { Response, ServerRequest, Server, serve } from "./server.ts"; import { BufReader, BufWriter } from "../io/bufio.ts"; import { delay, deferred } from "../util/async.ts"; import { encode, decode } from "../strings/mod.ts"; @@ -451,6 +456,38 @@ test("close server while iterating", async (): Promise => { assertEquals(await nextAfterClosing, { value: undefined, done: true }); }); +test({ + name: "[http] close server while connection is open", + async fn(): Promise { + async function iteratorReq(server: Server): Promise { + for await (const req of server) { + req.respond({ body: new TextEncoder().encode(req.url) }); + } + } + + const server = serve(":8123"); + iteratorReq(server); + const conn = await Deno.connect({ hostname: "127.0.0.1", port: 8123 }); + await Deno.writeAll( + conn, + new TextEncoder().encode("GET /hello HTTP/1.1\r\n\r\n") + ); + const res = new Uint8Array(100); + const nread = await conn.read(res); + assert(nread !== Deno.EOF); + const resStr = new TextDecoder().decode(res.subarray(0, nread)); + assertStrContains(resStr, "/hello"); + server.close(); + // Defer to allow async ops to resolve after server has been closed. + await delay(0); + // Client connection should still be open, verify that + // it's visible in resource table. + const resources = Deno.resources(); + assertEquals(resources[conn.rid], "tcpStream"); + conn.close(); + } +}); + // 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). -- cgit v1.2.3