mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 09:31:22 -05:00
feat(std/http/server): Respond with 400 on request parse failure (#4614)
This commit is contained in:
parent
dd3a94933a
commit
e586d0c8b8
2 changed files with 49 additions and 14 deletions
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { encode } from "../encoding/utf8.ts";
|
||||
import { BufReader, BufWriter } from "../io/bufio.ts";
|
||||
import { assert } from "../testing/asserts.ts";
|
||||
import { deferred, Deferred, MuxAsyncIterator } from "../util/async.ts";
|
||||
|
@ -146,36 +147,45 @@ export class Server implements AsyncIterable<ServerRequest> {
|
|||
private async *iterateHttpRequests(
|
||||
conn: Conn
|
||||
): AsyncIterableIterator<ServerRequest> {
|
||||
const bufr = new BufReader(conn);
|
||||
const w = new BufWriter(conn);
|
||||
let req: ServerRequest | Deno.EOF = Deno.EOF;
|
||||
let err: Error | undefined;
|
||||
const reader = new BufReader(conn);
|
||||
const writer = new BufWriter(conn);
|
||||
|
||||
while (!this.closing) {
|
||||
let request: ServerRequest | Deno.EOF;
|
||||
try {
|
||||
req = await readRequest(conn, bufr);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
request = await readRequest(conn, reader);
|
||||
} catch (error) {
|
||||
if (
|
||||
error instanceof Deno.errors.InvalidData ||
|
||||
error instanceof Deno.errors.UnexpectedEof
|
||||
) {
|
||||
// An error was thrown while parsing request headers.
|
||||
await writeResponse(writer, {
|
||||
status: 400,
|
||||
body: encode(`${error.message}\r\n\r\n`),
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (err != null || req === Deno.EOF) {
|
||||
if (request == Deno.EOF) {
|
||||
break;
|
||||
}
|
||||
|
||||
req.w = w;
|
||||
yield req;
|
||||
request.w = writer;
|
||||
yield request;
|
||||
|
||||
// Wait for the request to be processed before we accept a new request on
|
||||
// this connection.
|
||||
const procError = await req.done;
|
||||
if (procError) {
|
||||
const responseError = await request.done;
|
||||
if (responseError) {
|
||||
// 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);
|
||||
this.untrackConnection(request.conn);
|
||||
return;
|
||||
}
|
||||
// Consume unread body and trailers if receiver didn't consume those data
|
||||
await req.finalize();
|
||||
await request.finalize();
|
||||
}
|
||||
|
||||
this.untrackConnection(conn);
|
||||
|
|
|
@ -9,6 +9,7 @@ import { TextProtoReader } from "../textproto/mod.ts";
|
|||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
assertMatch,
|
||||
assertNotEOF,
|
||||
assertStrContains,
|
||||
assertThrowsAsync,
|
||||
|
@ -519,3 +520,27 @@ test({
|
|||
await p;
|
||||
},
|
||||
});
|
||||
|
||||
test({
|
||||
name: "[http] request error gets 400 response",
|
||||
async fn(): Promise<void> {
|
||||
const server = serve(":8124");
|
||||
const entry = server[Symbol.asyncIterator]().next();
|
||||
const conn = await Deno.connect({
|
||||
hostname: "127.0.0.1",
|
||||
port: 8124,
|
||||
});
|
||||
await Deno.writeAll(
|
||||
conn,
|
||||
encode("GET / HTTP/1.1\r\nmalformedHeader\r\n\r\n\r\n\r\n")
|
||||
);
|
||||
const responseString = decode(await Deno.readAll(conn));
|
||||
assertMatch(
|
||||
responseString,
|
||||
/^HTTP\/1\.1 400 Bad Request\r\ncontent-length: \d+\r\n\r\n.*\r\n\r\n$/ms
|
||||
);
|
||||
conn.close();
|
||||
server.close();
|
||||
assert((await entry).done);
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue