mirror of
https://github.com/morluto/rea
synced 2026-10-25 14:01:13 -04:00
fix(protobuf): exclude trailing whitespace from gRPC-web trailer values (#7069)
RFC 9110 section 5.5 excludes leading and trailing whitespace from a field value. The gRPC-web trailer parser stripped only leading SP/HTAB, so 'grpc-status: 0 ' was reported as '0 '. Trailing SP/HTAB is now excluded too; internal whitespace and the examined byte count are unchanged.
This commit is contained in:
@@ -73,6 +73,25 @@ it("retains allowed whitespace, visible text, and valid UTF-8 obs-text", async (
|
||||
expect(result.examined_bytes).toBe(5 + Buffer.byteLength(text));
|
||||
});
|
||||
|
||||
it("excludes trailing whitespace from trailer field values", async () => {
|
||||
const text =
|
||||
"grpc-status: 0 \r\ngrpc-message: alpha\tbeta \t\r\nx-empty: \t\r\n";
|
||||
const result = await decodeProtobufBody(
|
||||
trailerFrame(text),
|
||||
"grpc-web",
|
||||
source,
|
||||
same,
|
||||
new ProtobufBudget(),
|
||||
);
|
||||
expect(result.status).toBe("complete");
|
||||
expect(result.frames[0]?.trailers).toEqual([
|
||||
{ name: "grpc-status", value: "0" },
|
||||
{ name: "grpc-message", value: "alpha\tbeta" },
|
||||
{ name: "x-empty", value: "" },
|
||||
]);
|
||||
expect(result.examined_bytes).toBe(5 + Buffer.byteLength(text));
|
||||
});
|
||||
|
||||
it.each(["grpc-web", "grpc-web-text"] as const)(
|
||||
"keeps valid trailer fields around an opaque non-UTF-8 value in %s framing",
|
||||
async (framing) => {
|
||||
|
||||
@@ -84,9 +84,13 @@ export const parseGrpcWebTrailers = (
|
||||
"gRPC-web trailer field value contains a forbidden control character",
|
||||
});
|
||||
}
|
||||
// RFC 9110 section 5.5: a field value excludes surrounding whitespace.
|
||||
let valueEnd = lineEnd;
|
||||
while (valueEnd > valueStart && [9, 32].includes(bytes[valueEnd - 1]!))
|
||||
valueEnd -= 1;
|
||||
let value: string;
|
||||
try {
|
||||
value = decoder.decode(bytes.subarray(valueStart, lineEnd));
|
||||
value = decoder.decode(bytes.subarray(valueStart, valueEnd));
|
||||
} catch (cause) {
|
||||
if (!(cause instanceof TypeError)) throw cause;
|
||||
decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
||||
|
||||
Reference in New Issue
Block a user