0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

net: Check for closing status when iterating Listener (#3309)

std/http/server.ts: Use listener.next() instead of listener.accept()
This commit is contained in:
Nayeem Rahman 2019-11-09 19:40:22 +00:00 committed by Ry Dahl
parent 9889a28008
commit d586f119fa
4 changed files with 46 additions and 6 deletions

View file

@ -82,7 +82,8 @@ export class ListenerImpl implements Listener {
constructor(
readonly rid: number,
private transport: Transport,
private localAddr: string
private localAddr: string,
private closing: boolean = false
) {}
async accept(): Promise<Conn> {
@ -91,6 +92,7 @@ export class ListenerImpl implements Listener {
}
close(): void {
this.closing = true;
close(this.rid);
}
@ -102,10 +104,20 @@ export class ListenerImpl implements Listener {
}
async next(): Promise<IteratorResult<Conn>> {
return {
done: false,
value: await this.accept()
};
if (this.closing) {
return { value: undefined, done: true };
}
return await this.accept()
.then(value => ({ value, done: false }))
.catch(e => {
// It wouldn't be correct to simply check this.closing here.
// TODO: Get a proper error kind for this case, don't check the message.
// The current error kind is Other.
if (e.message == "Listener has been closed") {
return { value: undefined, done: true };
}
throw e;
});
}
[Symbol.asyncIterator](): AsyncIterator<Conn> {

View file

@ -77,6 +77,18 @@ testPerm({ net: true }, async function netDialListen(): Promise<void> {
conn.close();
});
testPerm({ net: true }, async function netListenCloseWhileIterating(): Promise<
void
> {
const listener = Deno.listen({ port: 8000 });
const nextWhileClosing = listener[Symbol.asyncIterator]().next();
listener.close();
assertEquals(await nextWhileClosing, { value: undefined, done: true });
const nextAfterClosing = listener[Symbol.asyncIterator]().next();
assertEquals(await nextAfterClosing, { value: undefined, done: true });
});
/* TODO(ry) Re-enable this test.
testPerm({ net: true }, async function netListenAsyncIterator(): Promise<void> {
const listener = Deno.listen(":4500");

View file

@ -371,7 +371,9 @@ export class Server implements AsyncIterable<ServerRequest> {
): AsyncIterableIterator<ServerRequest> {
if (this.closing) return;
// Wait for a new connection.
const conn = await this.listener.accept();
const { value, done } = await this.listener.next();
if (done) return;
const conn = value as 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.

View file

@ -14,6 +14,7 @@ import {
ServerRequest,
writeResponse,
readRequest,
serve,
parseHTTPVersion
} from "./server.ts";
import { delay } from "../util/async.ts";
@ -580,4 +581,17 @@ test({
}
});
test({
name: "[http] close server while iterating",
async fn(): Promise<void> {
const server = serve(":8123");
const nextWhileClosing = server[Symbol.asyncIterator]().next();
server.close();
assertEquals(await nextWhileClosing, { value: undefined, done: true });
const nextAfterClosing = server[Symbol.asyncIterator]().next();
assertEquals(await nextAfterClosing, { value: undefined, done: true });
}
});
runIfMain(import.meta);