Skip to content

Commit f442353

Browse files
committed
quic: convert incoming :status header to number
1 parent 92f48f4 commit f442353

22 files changed

Lines changed: 117 additions & 44 deletions

doc/api/quic.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3825,8 +3825,9 @@ A few things to note:
38253825
the request is `HEADERS` followed by `END_STREAM`.
38263826
* The `onheaders` callback receives the response pseudo-headers and
38273827
regular headers in a single object with lowercase string keys.
3828-
After the callback returns, the same object is also accessible
3829-
via [`stream.headers`][].
3828+
For incoming headers, the `:status` pseudo-header is converted to
3829+
a `number`, matching HTTP/2 behavior. After the callback returns,
3830+
the same object is also accessible via [`stream.headers`][].
38303831
* Reading `for await (const chunks of stream)` consumes the response
38313832
body. Each iteration yields a `Uint8Array[]` batch of chunks.
38323833
* HTTP semantic helpers (URL parsing, method/status validation,

lib/internal/quic/quic.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,14 +1203,19 @@ function parseHeaderPairs(pairs) {
12031203
assert(pairs.length % 2 === 0);
12041204
const block = { __proto__: null };
12051205
for (let n = 0; n + 1 < pairs.length; n += 2) {
1206-
if (block[pairs[n]] !== undefined) {
1207-
if (ArrayIsArray(block[pairs[n]])) {
1208-
ArrayPrototypePush(block[pairs[n]], pairs[n + 1]);
1206+
const name = pairs[n];
1207+
let value = pairs[n + 1];
1208+
// Match HTTP/2 behavior: incoming :status is exposed as a number.
1209+
if (name === ':status')
1210+
value |= 0;
1211+
if (block[name] !== undefined) {
1212+
if (ArrayIsArray(block[name])) {
1213+
ArrayPrototypePush(block[name], value);
12091214
} else {
1210-
block[pairs[n]] = [block[pairs[n]], pairs[n + 1]];
1215+
block[name] = [block[name], value];
12111216
}
12121217
} else {
1213-
block[pairs[n]] = pairs[n + 1];
1218+
block[name] = value;
12141219
}
12151220
}
12161221
return block;

test/parallel/test-quic-h3-callback-errors.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ async function makeServer(onheadersHandler, extraOpts = {}) {
154154
':authority': 'localhost',
155155
},
156156
onheaders: mustCall(function(headers) {
157-
strictEqual(headers[':status'], '200');
157+
strictEqual(headers[':status'], 200);
158158
}),
159159
ontrailers: mustCall(function() {
160160
throw new Error('ontrailers sync error');
@@ -268,7 +268,7 @@ async function makeServer(onheadersHandler, extraOpts = {}) {
268268
':authority': 'localhost',
269269
},
270270
onheaders: mustCall(function(headers) {
271-
strictEqual(headers[':status'], '200');
271+
strictEqual(headers[':status'], 200);
272272
}),
273273
});
274274

test/parallel/test-quic-h3-close-behavior.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const decoder = new TextDecoder();
6565
':authority': 'localhost',
6666
},
6767
onheaders: mustCall((headers) => {
68-
strictEqual(headers[':status'], '200');
68+
strictEqual(headers[':status'], 200);
6969
}),
7070
});
7171

@@ -77,7 +77,7 @@ const decoder = new TextDecoder();
7777
':authority': 'localhost',
7878
},
7979
onheaders: mustCall((headers) => {
80-
strictEqual(headers[':status'], '200');
80+
strictEqual(headers[':status'], 200);
8181
}),
8282
});
8383

test/parallel/test-quic-h3-concurrent-requests.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ const requests = paths.map(mustCall(async (path) => {
7575
':authority': 'localhost',
7676
},
7777
onheaders: mustCall((headers) => {
78-
strictEqual(headers[':status'], '200');
78+
strictEqual(headers[':status'], 200);
7979
headersReceived.resolve();
8080
}),
8181
});

test/parallel/test-quic-h3-datagram.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const decoder = new TextDecoder();
9090
':authority': 'localhost',
9191
},
9292
onheaders: mustCall(function(headers) {
93-
strictEqual(headers[':status'], '200');
93+
strictEqual(headers[':status'], 200);
9494
}),
9595
});
9696

@@ -154,7 +154,7 @@ const decoder = new TextDecoder();
154154
':authority': 'localhost',
155155
},
156156
onheaders: mustCall((headers) => {
157-
strictEqual(headers[':status'], '200');
157+
strictEqual(headers[':status'], 200);
158158
}),
159159
});
160160

test/parallel/test-quic-h3-error-codes.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const decoder = new TextDecoder();
5858
':authority': 'localhost',
5959
},
6060
onheaders: mustCall(function(headers) {
61-
strictEqual(headers[':status'], '200');
61+
strictEqual(headers[':status'], 200);
6262
}),
6363
});
6464

@@ -109,7 +109,7 @@ const decoder = new TextDecoder();
109109
':authority': 'localhost',
110110
},
111111
onheaders: mustCall(function(headers) {
112-
strictEqual(headers[':status'], '200');
112+
strictEqual(headers[':status'], 200);
113113
}),
114114
});
115115

test/parallel/test-quic-h3-goaway.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ dc.subscribe('quic.session.goaway', mustCall((msg) => {
8181
await clientSession.opened;
8282

8383
const onClientHeaders = mustCall(function(headers) {
84-
strictEqual(headers[':status'], '200');
84+
strictEqual(headers[':status'], 200);
8585
if (++clientHeaderCount === 2) {
8686
bothHeadersReceived.resolve();
8787
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const decoder = new TextDecoder();
9494
},
9595
onheaders: mustCall(function(headers) {
9696
// Client should also receive lowercased response header names.
97-
strictEqual(headers[':status'], '200');
97+
strictEqual(headers[':status'], 200);
9898
strictEqual(headers['content-type'], 'text/html');
9999
strictEqual(headers['x-response-header'], 'ResponseValue');
100100

@@ -151,7 +151,7 @@ const decoder = new TextDecoder();
151151
':authority': 'localhost',
152152
},
153153
onheaders: mustCall((headers) => {
154-
strictEqual(headers[':status'], '204');
154+
strictEqual(headers[':status'], 204);
155155
}),
156156
});
157157

test/parallel/test-quic-h3-informational-headers.mjs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ dc.subscribe('quic.stream.info', mustCall((msg) => {
3737
ok(msg.stream, 'stream.info should include stream');
3838
ok(msg.session, 'stream.info should include session');
3939
ok(msg.headers, 'stream.info should include headers');
40-
strictEqual(msg.headers[':status'], '103');
40+
strictEqual(msg.headers[':status'], 103);
4141
}));
4242

4343
// quic.stream.headers also fires for the final response headers.
@@ -92,12 +92,12 @@ const stream = await clientSession.createBidirectionalStream({
9292
':authority': 'localhost',
9393
},
9494
oninfo: mustCall(function(headers) {
95-
strictEqual(headers[':status'], '103');
95+
strictEqual(headers[':status'], 103);
9696
strictEqual(headers.link, '</style.css>; rel=preload; as=style');
9797
clientInfoReceived.resolve();
9898
}),
9999
onheaders: mustCall(function(headers) {
100-
strictEqual(headers[':status'], '200');
100+
strictEqual(headers[':status'], 200);
101101
strictEqual(headers['content-type'], 'text/plain');
102102
clientHeadersReceived.resolve();
103103
}),
@@ -110,7 +110,7 @@ const body = await bytes(stream);
110110
strictEqual(decoder.decode(body), responseBody);
111111

112112
// stream.headers should return the final (initial) headers, not 1xx.
113-
strictEqual(stream.headers[':status'], '200');
113+
strictEqual(stream.headers[':status'], 200);
114114

115115
await Promise.all([stream.closed, serverDone.promise]);
116116
await clientSession.close();

0 commit comments

Comments
 (0)