mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
http: fix content-length checking (denoland/deno_std#437)
Original: ce4e3ccdc3
This commit is contained in:
parent
b7082f1640
commit
632fbd7734
2 changed files with 70 additions and 34 deletions
|
@ -196,6 +196,25 @@ export class ServerRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fixLength(req: ServerRequest): void {
|
||||||
|
const contentLength = req.headers.get("Content-Length");
|
||||||
|
if (contentLength) {
|
||||||
|
const arrClen = contentLength.split(",");
|
||||||
|
if (arrClen.length > 1) {
|
||||||
|
const distinct = [...new Set(arrClen.map((e): string => e.trim()))];
|
||||||
|
if (distinct.length > 1) {
|
||||||
|
throw Error("cannot contain multiple Content-Length headers");
|
||||||
|
} else {
|
||||||
|
req.headers.set("Content-Length", distinct[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const c = req.headers.get("Content-Length");
|
||||||
|
if (req.method === "HEAD" && c && c !== "0") {
|
||||||
|
throw Error("http: method cannot contain a Content-Length");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function readRequest(
|
export async function readRequest(
|
||||||
bufr: BufReader
|
bufr: BufReader
|
||||||
): Promise<[ServerRequest, BufState]> {
|
): Promise<[ServerRequest, BufState]> {
|
||||||
|
@ -211,6 +230,11 @@ export async function readRequest(
|
||||||
}
|
}
|
||||||
[req.method, req.url, req.proto] = firstLine.split(" ", 3);
|
[req.method, req.url, req.proto] = firstLine.split(" ", 3);
|
||||||
[req.headers, err] = await tp.readMIMEHeader();
|
[req.headers, err] = await tp.readMIMEHeader();
|
||||||
|
fixLength(req);
|
||||||
|
// TODO(zekth) : add parsing of headers eg:
|
||||||
|
// rfc: https://tools.ietf.org/html/rfc7230#section-3.3.2
|
||||||
|
// A sender MUST NOT send a Content-Length header field in any message
|
||||||
|
// that contains a Transfer-Encoding header field.
|
||||||
return [req, err];
|
return [req, err];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -322,55 +322,67 @@ test(async function testReadRequestError(): Promise<void> {
|
||||||
},
|
},
|
||||||
1: { in: "GET / HTTP/1.1\r\nheader:foo\r\n", err: "EOF", headers: [] },
|
1: { in: "GET / HTTP/1.1\r\nheader:foo\r\n", err: "EOF", headers: [] },
|
||||||
2: { in: "", err: "EOF", headers: [] },
|
2: { in: "", err: "EOF", headers: [] },
|
||||||
// 3: {
|
3: {
|
||||||
// in: "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n",
|
in: "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n",
|
||||||
// err: "http: method cannot contain a Content-Length"
|
err: "http: method cannot contain a Content-Length"
|
||||||
// },
|
},
|
||||||
4: {
|
4: {
|
||||||
in: "HEAD / HTTP/1.1\r\n\r\n",
|
in: "HEAD / HTTP/1.1\r\n\r\n",
|
||||||
headers: [],
|
headers: [],
|
||||||
err: null
|
err: null
|
||||||
}
|
},
|
||||||
// Multiple Content-Length values should either be
|
// Multiple Content-Length values should either be
|
||||||
// deduplicated if same or reject otherwise
|
// deduplicated if same or reject otherwise
|
||||||
// See Issue 16490.
|
// See Issue 16490.
|
||||||
// 5: {
|
5: {
|
||||||
// in:
|
in:
|
||||||
// "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\nGopher hey\r\n",
|
"POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\nGopher hey\r\n",
|
||||||
// err: "cannot contain multiple Content-Length headers"
|
err: "cannot contain multiple Content-Length headers"
|
||||||
// },
|
},
|
||||||
// 6: {
|
6: {
|
||||||
// in:
|
in:
|
||||||
// "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\nGopher\r\n",
|
"POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\nGopher\r\n",
|
||||||
// err: "cannot contain multiple Content-Length headers"
|
err: "cannot contain multiple Content-Length headers"
|
||||||
// },
|
},
|
||||||
// 7: {
|
7: {
|
||||||
// in:
|
in:
|
||||||
// "PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\nContent-Length:6\r\n\r\nGopher\r\n",
|
"PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\nContent-Length:6\r\n\r\nGopher\r\n",
|
||||||
// err: null,
|
err: null,
|
||||||
// headers: [{ key: "Content-Length", value: "6" }]
|
headers: [{ key: "Content-Length", value: "6" }]
|
||||||
// },
|
},
|
||||||
// 8: {
|
8: {
|
||||||
// in: "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n",
|
in: "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n",
|
||||||
// err: "cannot contain multiple Content-Length headers"
|
err: "cannot contain multiple Content-Length headers"
|
||||||
// },
|
},
|
||||||
|
// Setting an empty header is swallowed by textproto
|
||||||
|
// see: readMIMEHeader()
|
||||||
// 9: {
|
// 9: {
|
||||||
// in: "POST / HTTP/1.1\r\nContent-Length:\r\nContent-Length: 3\r\n\r\n",
|
// in: "POST / HTTP/1.1\r\nContent-Length:\r\nContent-Length: 3\r\n\r\n",
|
||||||
// err: "cannot contain multiple Content-Length headers"
|
// err: "cannot contain multiple Content-Length headers"
|
||||||
// },
|
// },
|
||||||
// 10: {
|
10: {
|
||||||
// in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n",
|
in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n",
|
||||||
// headers: [{ key: "Content-Length", value: "0" }],
|
headers: [{ key: "Content-Length", value: "0" }],
|
||||||
// err: null
|
err: null
|
||||||
// }
|
}
|
||||||
};
|
};
|
||||||
for (const p in testCases) {
|
for (const p in testCases) {
|
||||||
const test = testCases[p];
|
const test = testCases[p];
|
||||||
const reader = new BufReader(new StringReader(test.in));
|
const reader = new BufReader(new StringReader(test.in));
|
||||||
const [req, err] = await readRequest(reader);
|
let _err;
|
||||||
assertEquals(test.err, err);
|
if (test.err && test.err != "EOF") {
|
||||||
for (const h of test.headers) {
|
try {
|
||||||
assertEquals(req.headers.get(h.key), h.value);
|
await readRequest(reader);
|
||||||
|
} catch (e) {
|
||||||
|
_err = e;
|
||||||
|
}
|
||||||
|
assertEquals(_err.message, test.err);
|
||||||
|
} else {
|
||||||
|
const [req, err] = await readRequest(reader);
|
||||||
|
assertEquals(test.err, err);
|
||||||
|
for (const h of test.headers) {
|
||||||
|
assertEquals(req.headers.get(h.key), h.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue