From cb5f028ebfe4f1b8dba5989e0e163155c0fb4c22 Mon Sep 17 00:00:00 2001 From: Vincent LE GOFF Date: Fri, 24 May 2019 16:50:05 +0200 Subject: [PATCH 1/3] add ParseHTTPVersion --- http/server.ts | 40 ++++++++++++++++++++++++++++++++++++++++ http/server_test.ts | 15 +++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/http/server.ts b/http/server.ts index baccaacfb95c..83b10927b32b 100644 --- a/http/server.ts +++ b/http/server.ts @@ -102,6 +102,8 @@ export class ServerRequest { url: string; method: string; proto: string; + protoMinor: number; + protoMajor: number; headers: Headers; r: BufReader; w: BufWriter; @@ -215,6 +217,37 @@ function fixLength(req: ServerRequest): void { } } +// ParseHTTPVersion parses a HTTP version string. +// "HTTP/1.0" returns (1, 0, true). +// Ported from https://github.com/golang/go/blob/f5c43b9/src/net/http/request.go#L766-L792 +function ParseHTTPVersion(vers: string): [number, number, boolean] { + const Big = 1000000; // arbitrary upper bound + let major: number; + let minor: number; + switch (vers) { + case "HTTP/1.1": + return [1, 1, true]; + case "HTTP/1.0": + return [1, 0, true]; + } + if (!vers.startsWith("HTTP/")) { + return [0, 0, false]; + } + const dot = vers.indexOf("."); + if (dot < 0) { + return [0, 0, false]; + } + major = parseInt(vers[dot - 1]); + if (isNaN(major) || major < 0 || major > Big) { + return [0, 0, false]; + } + minor = parseInt(vers[dot + 1]); + if (isNaN(minor) || minor < 0 || minor > Big) { + return [0, 0, false]; + } + return [major, minor, true]; +} + export async function readRequest( bufr: BufReader ): Promise<[ServerRequest, BufState]> { @@ -229,6 +262,13 @@ export async function readRequest( return [null, err]; } [req.method, req.url, req.proto] = firstLine.split(" ", 3); + + let ok: boolean; + [req.protoMinor, req.protoMajor, ok] = ParseHTTPVersion(req.proto); + if (!ok) { + throw Error(`malformed HTTP version ${req.proto}`); + } + [req.headers, err] = await tp.readMIMEHeader(); fixLength(req); // TODO(zekth) : add parsing of headers eg: diff --git a/http/server_test.ts b/http/server_test.ts index 705fea1baeb6..3b3b0d0282a2 100644 --- a/http/server_test.ts +++ b/http/server_test.ts @@ -364,6 +364,21 @@ test(async function testReadRequestError(): Promise { in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n", headers: [{ key: "Content-Length", value: "0" }], err: null + }, + 11: { + in: "GET / HTTP/1.A\r\nContent-Length:0\r\n\r\n", + headers: [{ key: "Content-Length", value: "0" }], + err: `malformed HTTP version HTTP/1.A` + }, + 12: { + in: "GET / HTTP/A.1\r\nContent-Length:0\r\n\r\n", + headers: [], + err: `malformed HTTP version HTTP/A.1` + }, + 13: { + in: "GET / HTTP/1.0\r\nContent-Length:4\r\n\r\n", + headers: [{ key: "Content-Length", value: "4" }], + err: null } }; for (const p in testCases) { From 94fe772ce785796b3816329e8490a2bed32a9e02 Mon Sep 17 00:00:00 2001 From: LE GOFF Vincent Date: Sat, 25 May 2019 16:34:48 +0200 Subject: [PATCH 2/3] fixing tests / cases --- http/server.ts | 20 ++++++++++++++------ http/server_test.ts | 28 +++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/http/server.ts b/http/server.ts index 83b10927b32b..68a9d8780ecd 100644 --- a/http/server.ts +++ b/http/server.ts @@ -220,29 +220,37 @@ function fixLength(req: ServerRequest): void { // ParseHTTPVersion parses a HTTP version string. // "HTTP/1.0" returns (1, 0, true). // Ported from https://github.com/golang/go/blob/f5c43b9/src/net/http/request.go#L766-L792 -function ParseHTTPVersion(vers: string): [number, number, boolean] { +export function parseHTTPVersion(vers: string): [number, number, boolean] { const Big = 1000000; // arbitrary upper bound + const digitReg = /^\d+$/; // test if string is only digit let major: number; let minor: number; + switch (vers) { case "HTTP/1.1": return [1, 1, true]; case "HTTP/1.0": return [1, 0, true]; } + if (!vers.startsWith("HTTP/")) { return [0, 0, false]; } + const dot = vers.indexOf("."); if (dot < 0) { return [0, 0, false]; } - major = parseInt(vers[dot - 1]); - if (isNaN(major) || major < 0 || major > Big) { + + let majorStr = vers.substring(vers.indexOf("/") + 1, dot); + major = parseInt(majorStr); + if (!digitReg.test(majorStr) || isNaN(major) || major < 0 || major > Big) { return [0, 0, false]; } - minor = parseInt(vers[dot + 1]); - if (isNaN(minor) || minor < 0 || minor > Big) { + + let minorStr = vers.substring(dot + 1); + minor = parseInt(minorStr); + if (!digitReg.test(minorStr) || isNaN(minor) || minor < 0 || minor > Big) { return [0, 0, false]; } return [major, minor, true]; @@ -264,7 +272,7 @@ export async function readRequest( [req.method, req.url, req.proto] = firstLine.split(" ", 3); let ok: boolean; - [req.protoMinor, req.protoMajor, ok] = ParseHTTPVersion(req.proto); + [req.protoMinor, req.protoMajor, ok] = parseHTTPVersion(req.proto); if (!ok) { throw Error(`malformed HTTP version ${req.proto}`); } diff --git a/http/server_test.ts b/http/server_test.ts index 3b3b0d0282a2..dbfc948fc231 100644 --- a/http/server_test.ts +++ b/http/server_test.ts @@ -12,7 +12,8 @@ import { Response, ServerRequest, writeResponse, - readRequest + readRequest, + parseHTTPVersion } from "./server.ts"; import { BufReader, BufWriter } from "../io/bufio.ts"; import { StringReader } from "../io/readers.ts"; @@ -401,4 +402,29 @@ test(async function testReadRequestError(): Promise { } } }); + +// Ported from https://github.com/golang/go/blob/f5c43b9/src/net/http/request_test.go#L535-L565 +test({ + name: "[http] parseHttpVersion", + fn(): void { + const testCases = [ + { in: "HTTP/0.9", want: [0, 9, true] }, + { in: "HTTP/1.0", want: [1, 0, true] }, + { in: "HTTP/1.1", want: [1, 1, true] }, + { in: "HTTP/3.14", want: [3, 14, true] }, + { in: "HTTP", want: [0, 0, false] }, + { in: "HTTP/one.one", want: [0, 0, false] }, + { in: "HTTP/1.1/", want: [0, 0, false] }, + { in: "HTTP/-1.0", want: [0, 0, false] }, + { in: "HTTP/0.-1", want: [0, 0, false] }, + { in: "HTTP/", want: [0, 0, false] }, + { in: "HTTP/1,0", want: [0, 0, false] } + ]; + for (const t of testCases) { + const r = parseHTTPVersion(t.in); + assertEquals(r, t.want, t.in); + } + } +}); + runIfMain(import.meta); From 6e88d9ba8cd70a7e3d53f8df787910ea5e0a0695 Mon Sep 17 00:00:00 2001 From: LE GOFF Vincent Date: Sat, 25 May 2019 18:16:33 +0200 Subject: [PATCH 3/3] disable useless tests --- http/server_test.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/http/server_test.ts b/http/server_test.ts index dbfc948fc231..fbab0234f042 100644 --- a/http/server_test.ts +++ b/http/server_test.ts @@ -365,21 +365,6 @@ test(async function testReadRequestError(): Promise { in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n", headers: [{ key: "Content-Length", value: "0" }], err: null - }, - 11: { - in: "GET / HTTP/1.A\r\nContent-Length:0\r\n\r\n", - headers: [{ key: "Content-Length", value: "0" }], - err: `malformed HTTP version HTTP/1.A` - }, - 12: { - in: "GET / HTTP/A.1\r\nContent-Length:0\r\n\r\n", - headers: [], - err: `malformed HTTP version HTTP/A.1` - }, - 13: { - in: "GET / HTTP/1.0\r\nContent-Length:4\r\n\r\n", - headers: [{ key: "Content-Length", value: "4" }], - err: null } }; for (const p in testCases) {