Skip to content

Commit

Permalink
http: add ParseHTTPVersion (denoland/std#452)
Browse files Browse the repository at this point in the history
  • Loading branch information
zekth authored and ry committed May 25, 2019
1 parent 74498f1 commit 8d94f70
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 1 deletion.
48 changes: 48 additions & 0 deletions http/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ export class ServerRequest {
url: string;
method: string;
proto: string;
protoMinor: number;
protoMajor: number;
headers: Headers;
r: BufReader;
w: BufWriter;
Expand Down Expand Up @@ -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]> {
Expand All @@ -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:
Expand Down
28 changes: 27 additions & 1 deletion http/server_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);

0 comments on commit 8d94f70

Please sign in to comment.