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:
parent
49c7077401
commit
b97459b5ae
2 changed files with 17 additions and 18 deletions
|
@ -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`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue