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.ts | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'std/http/server.ts') diff --git a/std/http/server.ts b/std/http/server.ts index 34b17cc26..72bd1e5f3 100644 --- a/std/http/server.ts +++ b/std/http/server.ts @@ -124,12 +124,23 @@ export class ServerRequest { export class Server implements AsyncIterable { private closing = false; + private connections: Conn[] = []; constructor(public listener: Listener) {} close(): void { this.closing = true; this.listener.close(); + for (const conn of this.connections) { + try { + conn.close(); + } catch (e) { + // Connection might have been already closed + if (!(e instanceof Deno.errors.BadResource)) { + throw e; + } + } + } } // Yields all HTTP requests on a single TCP connection. @@ -162,6 +173,7 @@ export class Server implements AsyncIterable { // Something bad happened during response. // (likely other side closed during pipelined req) // req.done implies this connection already closed, so we can just return. + this.untrackConnection(req.conn); return; } // Consume unread body and trailers if receiver didn't consume those data @@ -186,7 +198,23 @@ export class Server implements AsyncIterable { // TODO(ry): send a back a HTTP 503 Service Unavailable status. } - conn.close(); + this.untrackConnection(conn); + try { + conn.close(); + } catch (e) { + // might have been already closed + } + } + + private trackConnection(conn: Conn): void { + this.connections.push(conn); + } + + private untrackConnection(conn: Conn): void { + const index = this.connections.indexOf(conn); + if (index !== -1) { + this.connections.splice(index, 1); + } } // Accepts a new TCP connection and yields all HTTP requests that arrive on @@ -207,6 +235,7 @@ export class Server implements AsyncIterable { } throw error; } + this.trackConnection(conn); // Try to accept another connection and add it to the multiplexer. mux.add(this.acceptConnAndIterateHttpRequests(mux)); // Yield the requests that arrive on the just-accepted connection. -- cgit v1.2.3