mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
fix(std/http): Fix respond error test on Windows (#4408)
This commit is contained in:
parent
a6d8098b35
commit
b7e6a31a42
3 changed files with 15 additions and 50 deletions
|
@ -242,7 +242,7 @@ export async function writeResponse(
|
||||||
const statusText = STATUS_TEXT.get(statusCode);
|
const statusText = STATUS_TEXT.get(statusCode);
|
||||||
const writer = BufWriter.create(w);
|
const writer = BufWriter.create(w);
|
||||||
if (!statusText) {
|
if (!statusText) {
|
||||||
throw Error("bad status code");
|
throw new Deno.errors.InvalidData("Bad status code");
|
||||||
}
|
}
|
||||||
if (!r.body) {
|
if (!r.body) {
|
||||||
r.body = new Uint8Array();
|
r.body = new Uint8Array();
|
||||||
|
|
|
@ -10,11 +10,12 @@ import {
|
||||||
assert,
|
assert,
|
||||||
assertEquals,
|
assertEquals,
|
||||||
assertNotEOF,
|
assertNotEOF,
|
||||||
assertStrContains
|
assertStrContains,
|
||||||
|
assertThrowsAsync
|
||||||
} from "../testing/asserts.ts";
|
} from "../testing/asserts.ts";
|
||||||
import { Response, ServerRequest, Server, serve } from "./server.ts";
|
import { Response, ServerRequest, Server, serve } from "./server.ts";
|
||||||
import { BufReader, BufWriter } from "../io/bufio.ts";
|
import { BufReader, BufWriter } from "../io/bufio.ts";
|
||||||
import { delay, deferred } from "../util/async.ts";
|
import { delay } from "../util/async.ts";
|
||||||
import { encode, decode } from "../strings/mod.ts";
|
import { encode, decode } from "../strings/mod.ts";
|
||||||
import { mockConn } from "./mock.ts";
|
import { mockConn } from "./mock.ts";
|
||||||
|
|
||||||
|
@ -488,57 +489,23 @@ 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.
|
|
||||||
test({
|
test({
|
||||||
ignore: Deno.build.os == "win",
|
name: "respond error closes connection",
|
||||||
name: "respond error handling",
|
|
||||||
async fn(): Promise<void> {
|
async fn(): Promise<void> {
|
||||||
const connClosedPromise = deferred();
|
|
||||||
const serverRoutine = async (): Promise<void> => {
|
const serverRoutine = async (): Promise<void> => {
|
||||||
let reqCount = 0;
|
|
||||||
const server = serve(":8124");
|
const server = serve(":8124");
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const serverRid = server.listener["rid"];
|
|
||||||
let connRid = -1;
|
|
||||||
for await (const req of server) {
|
for await (const req of server) {
|
||||||
connRid = req.conn.rid;
|
await assertThrowsAsync(async () => {
|
||||||
reqCount++;
|
|
||||||
await Deno.readAll(req.body);
|
|
||||||
await connClosedPromise;
|
|
||||||
try {
|
|
||||||
await req.respond({
|
await req.respond({
|
||||||
|
status: 12345,
|
||||||
body: new TextEncoder().encode("Hello World")
|
body: new TextEncoder().encode("Hello World")
|
||||||
});
|
});
|
||||||
await delay(100);
|
}, Deno.errors.InvalidData);
|
||||||
req.done = deferred();
|
// The connection should be destroyed
|
||||||
// This duplicate respond is to ensure we get a write failure from the
|
assert(!(req.conn.rid in Deno.resources()));
|
||||||
// other side. Our client would enter CLOSE_WAIT stage after close(),
|
server.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();
|
|
||||||
// Let event loop do another turn so server
|
|
||||||
// finishes all pending ops.
|
|
||||||
await delay(0);
|
|
||||||
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 p = serverRoutine();
|
||||||
const conn = await Deno.connect({
|
const conn = await Deno.connect({
|
||||||
|
@ -549,9 +516,7 @@ test({
|
||||||
conn,
|
conn,
|
||||||
new TextEncoder().encode("GET / HTTP/1.1\r\n\r\n")
|
new TextEncoder().encode("GET / HTTP/1.1\r\n\r\n")
|
||||||
);
|
);
|
||||||
conn.close(); // abruptly closing connection before response.
|
conn.close();
|
||||||
// conn on server side enters CLOSE_WAIT state.
|
|
||||||
connClosedPromise.resolve();
|
|
||||||
await p;
|
await p;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -348,9 +348,9 @@ export async function assertThrowsAsync(
|
||||||
await fn();
|
await fn();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (ErrorClass && !(Object.getPrototypeOf(e) === ErrorClass.prototype)) {
|
if (ErrorClass && !(Object.getPrototypeOf(e) === ErrorClass.prototype)) {
|
||||||
msg = `Expected error to be instance of "${ErrorClass.name}"${
|
msg = `Expected error to be instance of "${ErrorClass.name}", but got "${
|
||||||
msg ? `: ${msg}` : "."
|
e.name
|
||||||
}`;
|
}"${msg ? `: ${msg}` : "."}`;
|
||||||
throw new AssertionError(msg);
|
throw new AssertionError(msg);
|
||||||
}
|
}
|
||||||
if (msgIncludes && !e.message.includes(msgIncludes)) {
|
if (msgIncludes && !e.message.includes(msgIncludes)) {
|
||||||
|
|
Loading…
Reference in a new issue