summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--http/server.ts48
-rw-r--r--http/server_test.ts28
2 files changed, 75 insertions, 1 deletions
diff --git a/http/server.ts b/http/server.ts
index baccaacfb..68a9d8780 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,45 @@ 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
+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];
+ }
+
+ 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];
+ }
+
+ 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];
+}
+
export async function readRequest(
bufr: BufReader
): Promise<[ServerRequest, BufState]> {
@@ -229,6 +270,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 705fea1ba..fbab0234f 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";
@@ -386,4 +387,29 @@ test(async function testReadRequestError(): Promise<void> {
}
}
});
+
+// 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);