summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--http/racing_server.ts7
-rw-r--r--http/racing_server_test.ts2
-rw-r--r--http/server.ts13
-rw-r--r--http/server_test.ts45
-rw-r--r--http/testdata/simple_server.ts11
-rw-r--r--util/async.ts10
6 files changed, 78 insertions, 10 deletions
diff --git a/http/racing_server.ts b/http/racing_server.ts
index 0053fa428..9d118dc6d 100644
--- a/http/racing_server.ts
+++ b/http/racing_server.ts
@@ -1,5 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { serve, ServerRequest } from "./server.ts";
+import { delay } from "../util/async.ts";
const addr = Deno.args[1] || "127.0.0.1:4501";
const server = serve(addr);
@@ -7,12 +8,8 @@ const server = serve(addr);
const body = new TextEncoder().encode("Hello 1\n");
const body4 = new TextEncoder().encode("World 4\n");
-function sleep(ms: number): Promise<void> {
- return new Promise((res): number => setTimeout(res, ms));
-}
-
async function delayedRespond(request: ServerRequest): Promise<void> {
- await sleep(3000);
+ await delay(3000);
await request.respond({ status: 200, body });
}
diff --git a/http/racing_server_test.ts b/http/racing_server_test.ts
index 428e339a5..dc16a49e1 100644
--- a/http/racing_server_test.ts
+++ b/http/racing_server_test.ts
@@ -11,7 +11,7 @@ async function startServer(): Promise<void> {
args: ["deno", "run", "-A", "http/racing_server.ts"],
stdout: "piped"
});
- // Once fileServer is ready it will write to its stdout.
+ // Once racing server is ready it will write to its stdout.
const r = new TextProtoReader(new BufReader(server.stdout!));
const s = await r.readLine();
assert(s !== Deno.EOF && s.includes("Racing server listening..."));
diff --git a/http/server.ts b/http/server.ts
index 265dde943..54ec397d3 100644
--- a/http/server.ts
+++ b/http/server.ts
@@ -342,10 +342,15 @@ export class Server implements AsyncIterable<ServerRequest> {
// The connection was gracefully closed.
} else if (err) {
// An error was thrown while parsing request headers.
- await writeResponse(req!.w, {
- status: 400,
- body: new TextEncoder().encode(`${err.message}\r\n\r\n`)
- });
+ try {
+ await writeResponse(req!.w, {
+ status: 400,
+ body: new TextEncoder().encode(`${err.message}\r\n\r\n`)
+ });
+ } catch (_) {
+ // The connection is destroyed.
+ // Ignores the error.
+ }
} else if (this.closing) {
// There are more requests incoming but the server is closing.
// TODO(ry): send a back a HTTP 503 Service Unavailable status.
diff --git a/http/server_test.ts b/http/server_test.ts
index 04ff4ba15..da1a08dc0 100644
--- a/http/server_test.ts
+++ b/http/server_test.ts
@@ -6,6 +6,7 @@
// https://github.com/golang/go/blob/master/src/net/http/responsewrite_test.go
const { Buffer } = Deno;
+import { TextProtoReader } from "../textproto/mod.ts";
import { test, runIfMain } from "../testing/mod.ts";
import { assert, assertEquals, assertNotEquals } from "../testing/asserts.ts";
import {
@@ -15,6 +16,7 @@ import {
readRequest,
parseHTTPVersion
} from "./server.ts";
+import { delay } from "../util/async.ts";
import {
BufReader,
BufWriter,
@@ -456,4 +458,47 @@ test({
}
});
+test({
+ name: "[http] destroyed connection",
+ async fn(): Promise<void> {
+ // TODO: don't skip on windows when process.kill is implemented on windows.
+ if (Deno.build.os === "win") {
+ return;
+ }
+ // Runs a simple server as another process
+ const p = Deno.run({
+ args: [Deno.execPath, "http/testdata/simple_server.ts", "--allow-net"],
+ stdout: "piped"
+ });
+
+ try {
+ const r = new TextProtoReader(new BufReader(p.stdout!));
+ const s = await r.readLine();
+ assert(s !== Deno.EOF && s.includes("server listening"));
+
+ let serverIsRunning = true;
+ p.status().then(
+ (): void => {
+ serverIsRunning = false;
+ }
+ );
+
+ await delay(100);
+
+ // Reqeusts to the server and immediately closes the connection
+ const conn = await Deno.dial("tcp", "127.0.0.1:4502");
+ await conn.write(new TextEncoder().encode("GET / HTTP/1.0\n\n"));
+ conn.close();
+
+ // Waits for the server to handle the above (broken) request
+ await delay(100);
+
+ assert(serverIsRunning);
+ } finally {
+ // Stops the sever.
+ p.kill(Deno.Signal.SIGINT);
+ }
+ }
+});
+
runIfMain(import.meta);
diff --git a/http/testdata/simple_server.ts b/http/testdata/simple_server.ts
new file mode 100644
index 000000000..4f8b0e801
--- /dev/null
+++ b/http/testdata/simple_server.ts
@@ -0,0 +1,11 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+// This is an example of a server that responds with an empty body
+import { serve } from "../server.ts";
+
+window.onload = async function main() {
+ const addr = "0.0.0.0:4502";
+ console.log(`Simple server listening on ${addr}`);
+ for await (let req of serve(addr)) {
+ req.respond({});
+ }
+}
diff --git a/util/async.ts b/util/async.ts
index b737c4cc8..01df39cc8 100644
--- a/util/async.ts
+++ b/util/async.ts
@@ -108,3 +108,13 @@ export async function collectUint8Arrays(
}
return collected;
}
+
+// Delays the given milliseconds and resolves.
+export function delay(ms: number): Promise<void> {
+ return new Promise(
+ (res): number =>
+ setTimeout((): void => {
+ res();
+ }, ms)
+ );
+}