1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-01 16:51:13 -05:00

fix: readTrailer didn't evaluate header names by case-insensitive (#4902)

This commit is contained in:
Yusuke Sakurai 2020-05-29 21:40:54 +09:00 committed by GitHub
parent 49c7077401
commit b97459b5ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 18 deletions

View file

@ -113,11 +113,10 @@ export function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader {
return { read }; return { read };
} }
const kProhibitedTrailerHeaders = [ function isProhibidedForTrailer(key: string): boolean {
"transfer-encoding", const s = new Set(["transfer-encoding", "content-length", "trailer"]);
"content-length", return s.has(key.toLowerCase());
"trailer", }
];
/** /**
* Read trailer headers from reader and append values to headers. * Read trailer headers from reader and append values to headers.
@ -127,36 +126,36 @@ export async function readTrailers(
headers: Headers, headers: Headers,
r: BufReader r: BufReader
): Promise<void> { ): Promise<void> {
const keys = parseTrailer(headers.get("trailer")); const headerKeys = parseTrailer(headers.get("trailer"));
if (!keys) return; if (!headerKeys) return;
const tp = new TextProtoReader(r); const tp = new TextProtoReader(r);
const result = await tp.readMIMEHeader(); const result = await tp.readMIMEHeader();
assert(result !== null, "trailer must be set"); assert(result !== null, "trailer must be set");
for (const [k, v] of result) { for (const [k, v] of result) {
if (!keys.has(k)) { if (!headerKeys.has(k)) {
throw new Error("Undeclared trailer field"); throw new Error("Undeclared trailer field");
} }
keys.delete(k); headerKeys.delete(k);
headers.append(k, v); headers.append(k, v);
} }
assert(keys.size === 0, "Missing trailers"); assert(Array.from(headerKeys).length === 0, "Missing trailers");
headers.delete("trailer"); headers.delete("trailer");
} }
function parseTrailer(field: string | null): Set<string> | undefined { function parseTrailer(field: string | null): Headers | undefined {
if (field == null) { if (field == null) {
return undefined; return undefined;
} }
const keys = field.split(",").map((v) => v.trim()); const keys = field.split(",").map((v) => v.trim().toLowerCase());
if (keys.length === 0) { if (keys.length === 0) {
throw new Error("Empty trailer"); throw new Error("Empty trailer");
} }
for (const invalid of kProhibitedTrailerHeaders) { for (const key of keys) {
if (keys.includes(invalid)) { if (isProhibidedForTrailer(key)) {
throw new Error(`Prohibited field for trailer`); throw new Error(`Prohibited field for trailer`);
} }
} }
return new Set(keys); return new Headers(keys.map((key) => [key, ""]));
} }
export async function writeChunkedBody( export async function writeChunkedBody(
@ -199,7 +198,7 @@ export async function writeTrailers(
.map((s) => s.trim().toLowerCase()); .map((s) => s.trim().toLowerCase());
for (const f of trailerHeaderFields) { for (const f of trailerHeaderFields) {
assert( assert(
!kProhibitedTrailerHeaders.includes(f), !isProhibidedForTrailer(f),
`"${f}" is prohibited for trailer header` `"${f}" is prohibited for trailer header`
); );
} }

View file

@ -82,7 +82,7 @@ test("chunkedBodyReader with trailers", async () => {
test("readTrailers", async () => { test("readTrailers", async () => {
const h = new Headers({ const h = new Headers({
trailer: "deno,node", trailer: "Deno, Node",
}); });
const trailer = ["deno: land", "node: js", "", ""].join("\r\n"); const trailer = ["deno: land", "node: js", "", ""].join("\r\n");
await readTrailers(h, new BufReader(new Buffer(encode(trailer)))); await readTrailers(h, new BufReader(new Buffer(encode(trailer))));
@ -112,7 +112,7 @@ test("readTrailer should throw if undeclared headers found in trailer", async ()
}); });
test("readTrailer should throw if trailer contains prohibited fields", async () => { test("readTrailer should throw if trailer contains prohibited fields", async () => {
for (const f of ["content-length", "trailer", "transfer-encoding"]) { for (const f of ["Content-Length", "Trailer", "Transfer-Encoding"]) {
const h = new Headers({ const h = new Headers({
trailer: f, trailer: f,
}); });