Skip to content

Commit bc50e17

Browse files
author
Archkon
committed
quic: validate :path in sendHeaders
Reject invalid :path values before passing headers to nghttp3. Signed-off-by: Archkon <180910180+Archkon@users.noreply.github.com>
1 parent a4aa3c0 commit bc50e17

2 files changed

Lines changed: 27 additions & 10 deletions

File tree

lib/internal/quic/quic.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const {
1919
PromiseResolve,
2020
PromiseWithResolvers,
2121
SafeSet,
22+
String,
2223
Symbol,
2324
SymbolAsyncDispose,
2425
SymbolAsyncIterator,
@@ -2065,6 +2066,14 @@ class QuicStream {
20652066
'The negotiated QUIC application protocol does not support headers');
20662067
}
20672068
validateObject(headers, 'headers');
2069+
const path = headers[':path'];
2070+
if (path !== undefined) {
2071+
const value = String(path);
2072+
if (value[0] !== '/' && value !== '*') {
2073+
throw new ERR_INVALID_ARG_VALUE(
2074+
'headers.:path', path, 'must start with "/"');
2075+
}
2076+
}
20682077
const { terminal = false } = options;
20692078
const headerString = buildNgHeaderString(
20702079
headers, assertValidPseudoHeader, true /* strictSingleValueFields */);

test/parallel/test-quic-h3-header-validation.mjs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,18 @@ const decoder = new TextDecoder();
7878
});
7979
await clientSession.opened;
8080

81+
const requestHeaders = {
82+
// Mixed-case names — should be lowercased by buildNgHeaderString.
83+
':method': 'GET',
84+
':path': '/test',
85+
':scheme': 'https',
86+
':authority': 'localhost',
87+
'X-Custom-Header': 'Value1',
88+
'Content-Type': 'text/plain',
89+
'X-Mixed-Case': 'MixedValue',
90+
};
91+
8192
const stream = await clientSession.createBidirectionalStream({
82-
headers: {
83-
// Mixed-case names — should be lowercased by buildNgHeaderString.
84-
':method': 'GET',
85-
':path': '/test',
86-
':scheme': 'https',
87-
':authority': 'localhost',
88-
'X-Custom-Header': 'Value1',
89-
'Content-Type': 'text/plain',
90-
'X-Mixed-Case': 'MixedValue',
91-
},
9293
onheaders: mustCall(function(headers) {
9394
// Client should also receive lowercased response header names.
9495
assert.strictEqual(headers[':status'], '200');
@@ -103,6 +104,13 @@ const decoder = new TextDecoder();
103104
}),
104105
});
105106

107+
assert.throws(() => stream.sendHeaders({
108+
...requestHeaders,
109+
':path': 'testwtpath',
110+
}), { code: 'ERR_INVALID_ARG_VALUE' });
111+
assert.strictEqual(
112+
stream.sendHeaders(requestHeaders, { terminal: true }), true);
113+
106114
const body = await bytes(stream);
107115
assert.strictEqual(decoder.decode(body), 'ok');
108116
await Promise.all([stream.closed, serverDone.promise]);

0 commit comments

Comments
 (0)