Compare commits

...

95 Commits

Author SHA1 Message Date
Ciro Spaciari
f727a06a63 Merge branch 'main' into ciro/http2-more-rebased-2 2025-06-12 10:41:35 -07:00
Ciro Spaciari
ea2a41bf15 Merge branch 'main' into ciro/http2-more-rebased-2 2025-06-06 08:48:27 -07:00
Ciro Spaciari
e23701e6fd settings error fixes 2025-06-05 15:53:39 -07:00
Ciro Spaciari
3a78d28931 deflake 2025-06-05 15:54:30 -07:00
cirospaciari
ce0655f1a8 bun run prettier 2025-06-05 22:09:42 +00:00
Ciro Spaciari
862b94a235 Update test/js/third_party/grpc-js/test-resolver.test.ts 2025-06-05 15:07:41 -07:00
Ciro Spaciari
b44daf72bc Merge branch 'main' into ciro/http2-more-rebased 2025-06-05 07:40:27 -07:00
Ciro Spaciari
e5b818b2cc Merge branch 'main' into ciro/http2-more-rebased 2025-06-04 16:57:31 -07:00
cirospaciari
b3438e7a0d bun run clang-format 2025-06-04 23:54:41 +00:00
Ciro Spaciari
bec13e2d4a fix 2025-06-04 16:53:17 -07:00
Ciro Spaciari
637961e385 Merge branch 'main' into ciro/http2-more-rebased 2025-06-04 15:05:33 -07:00
Ciro Spaciari
d3ff571d3e comment 2025-06-04 14:48:20 -07:00
Ciro Spaciari
9bd3aa0434 use getValue 2025-06-04 14:45:24 -07:00
Ciro Spaciari
35a242280b :D 2025-06-04 11:10:50 -07:00
Ciro Spaciari
88984b7ccf Merge branch 'main' into ciro/http2-more-rebased 2025-06-04 11:05:53 -07:00
cirospaciari
70d80c8c15 bun run clang-format 2025-06-04 17:55:33 +00:00
Ciro Spaciari
e9e5714d94 opsie 2025-06-04 10:54:02 -07:00
Ciro Spaciari
5cf5bc5c6f review++ 2025-06-04 10:52:20 -07:00
Ciro Spaciari
77dff097dd revert 2025-06-03 17:36:08 -07:00
Ciro Spaciari
f05635951c review 2025-06-03 17:20:24 -07:00
Ciro Spaciari
491fd99192 Update test/js/third_party/grpc-js/test-resolver.test.ts 2025-06-03 15:48:32 -07:00
Ciro Spaciari
6d339e7aa5 Merge branch 'main' into ciro/http2-more-rebased 2025-06-03 15:47:25 -07:00
Ciro Spaciari
aef0087097 revert this 2025-06-03 15:47:53 -07:00
Ciro Spaciari
d94bc310e7 ok 2025-06-03 15:47:08 -07:00
Ciro Spaciari
bd93866976 test 2025-06-03 14:21:27 -07:00
Ciro Spaciari
929b7c78ce test 2025-06-03 14:20:57 -07:00
Ciro Spaciari
d0230299a9 partial 2025-06-03 14:16:52 -07:00
Ciro Spaciari
9c6d3c37b7 ok 2025-06-03 13:37:56 -07:00
Ciro Spaciari
a47c15e32a revert disconnect 2025-06-03 13:34:05 -07:00
Ciro Spaciari
b9c3440932 UV_DISCONNECT 2025-06-03 13:04:51 -07:00
Ciro Spaciari
a953934bd8 ok 2025-06-03 12:40:26 -07:00
Ciro Spaciari
f1b4e42b80 local 2025-06-03 12:13:37 -07:00
Ciro Spaciari
da8e274c68 logs 2025-06-03 12:13:03 -07:00
Ciro Spaciari
eec455b0ff name things 2025-06-03 11:44:01 -07:00
Ciro Spaciari
7b247d60fb test 2025-06-03 11:42:14 -07:00
Ciro Spaciari
1dea06d0f2 Merge branch 'main' into ciro/http2-more-rebased 2025-06-03 11:37:44 -07:00
Ciro Spaciari
6cc40db1b2 maybe 2025-06-03 11:05:43 -07:00
Ciro Spaciari
54c2174d06 maybe 2025-06-02 18:39:30 -07:00
Ciro Spaciari
49b80a8480 opsie 2025-06-02 18:10:54 -07:00
Ciro Spaciari
1eb0fc5d74 dont need to be locale 2025-06-02 18:08:45 -07:00
Ciro Spaciari
4bdd5f0b5f maybe 2025-06-02 18:03:16 -07:00
Ciro Spaciari
6a6ca7517c refactor 2025-06-02 17:26:19 -07:00
Ciro Spaciari
a60252ee75 ok 2025-06-02 16:23:30 -07:00
Ciro Spaciari
f4ca604af9 more 2025-06-02 11:39:42 -07:00
Ciro Spaciari
e649fc3ec1 back 2025-06-02 10:46:28 -07:00
Ciro Spaciari
e1a2fcf93b failing on linux 2025-06-02 10:46:28 -07:00
Ciro Spaciari
53c59ee348 remove logs + fix 2025-06-02 10:46:28 -07:00
Ciro Spaciari
aecaa7242c ok 2025-06-02 10:46:28 -07:00
cirospaciari
04ec8a81e1 bun run zig-format 2025-06-02 10:46:28 -07:00
Ciro Spaciari
bd69a85fc5 ok 2025-06-02 10:46:28 -07:00
Ciro Spaciari
fcef720d48 uno 2025-06-02 10:46:28 -07:00
Ciro Spaciari
c54a739d28 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
3f3cbefbc2 ok 2025-06-02 10:46:28 -07:00
Ciro Spaciari
04dd0f6ecf always close 2025-06-02 10:46:28 -07:00
Ciro Spaciari
139fc76166 ok 2025-06-02 10:46:28 -07:00
Ciro Spaciari
81d2141d6a update 2025-06-02 10:46:28 -07:00
Ciro Spaciari
ec9e318c6f deref 2025-06-02 10:46:28 -07:00
Ciro Spaciari
1c48c251a2 maybe 2025-06-02 10:46:28 -07:00
Ciro Spaciari
a7b0cf9d8b ok 2025-06-02 10:46:28 -07:00
Ciro Spaciari
1791a5b589 ok 2025-06-02 10:46:28 -07:00
Ciro Spaciari
abed93168b ok 2025-06-02 10:46:28 -07:00
Ciro Spaciari
ab523d523b disable cork 2025-06-02 10:46:28 -07:00
Ciro Spaciari
0e68af960d break more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
f1cf05cba6 opsie 2025-06-02 10:46:28 -07:00
Ciro Spaciari
db33b3568c more fixes 2025-06-02 10:46:28 -07:00
Ciro Spaciari
a767618ccf almost 2025-06-02 10:46:28 -07:00
Ciro Spaciari
4de68eda5b fix graceful shutdown 2025-06-02 10:46:28 -07:00
Ciro Spaciari
2f81cc7ddd dont do mistakes 2025-06-02 10:46:28 -07:00
Ciro Spaciari
5aae453c80 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
a9d23f1908 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
eb26c3edf9 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
822e3b8cf0 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
f451ddb910 more and break more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
7da15d4e72 flush 2025-06-02 10:46:28 -07:00
Ciro Spaciari
6e3ef2dc28 not yet 2025-06-02 10:46:28 -07:00
Ciro Spaciari
6cee7c0ec1 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
b1846a0c69 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
8f81e77a6f more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
3b1e194103 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
43cff4bc42 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
d3ba69ba47 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
7ddd568f4f more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
9f8d5caf07 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
a92975828e more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
43769fd805 only handle update window instead of flow control it self 2025-06-02 10:46:28 -07:00
Ciro Spaciari
59acf758d7 limit is only per stream not general 2025-06-02 10:46:28 -07:00
Ciro Spaciari
43a606fad6 comments 2025-06-02 10:46:28 -07:00
Ciro Spaciari
9e0bc5e5c7 not anymore 2025-06-02 10:46:28 -07:00
Ciro Spaciari
ea50253dbe uncomment 2025-06-02 10:46:28 -07:00
Ciro Spaciari
50de52b35a more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
1bc6eb5464 more 2025-06-02 10:46:28 -07:00
Ciro Spaciari
40ce107f32 opsie 2025-06-02 10:46:28 -07:00
Ciro Spaciari
f3502a0319 cleanup 2025-06-02 10:46:28 -07:00
Ciro Spaciari
7c665caed3 still wrong 2 2025-06-02 10:46:28 -07:00
Ciro Spaciari
6f7f6af643 still wrong 2025-06-02 10:46:28 -07:00
6 changed files with 853 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const h2 = require('http2');
const server = h2.createServer();
// We use the lower-level API here
server.on('stream', common.mustCall((stream, headers, flags) => {
stream.respond();
stream.end('ok');
}));
server.on('session', common.mustCall((session) => {
session.on('remoteSettings', common.mustCall(2));
}));
server.listen(0, common.mustCall(() => {
const client = h2.connect(`http://127.0.0.1:${server.address().port}`);
[
['headerTableSize', -1, RangeError],
['headerTableSize', 2 ** 32, RangeError],
['initialWindowSize', -1, RangeError],
['initialWindowSize', 2 ** 32, RangeError],
['maxFrameSize', 1, RangeError],
['maxFrameSize', 2 ** 24, RangeError],
['maxConcurrentStreams', -1, RangeError],
['maxConcurrentStreams', 2 ** 32, RangeError],
['maxHeaderListSize', -1, RangeError],
['maxHeaderListSize', 2 ** 32, RangeError],
['maxHeaderSize', -1, RangeError],
['maxHeaderSize', 2 ** 32, RangeError],
['enablePush', 'a', TypeError],
['enablePush', 1, TypeError],
['enablePush', 0, TypeError],
['enablePush', null, TypeError],
['enablePush', {}, TypeError],
].forEach(([name, value, errorType]) =>
assert.throws(
() => client.settings({ [name]: value }),
{
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: errorType.name
}
)
);
assert.throws(
() => client.settings({ customSettings: {
0x11: 5,
0x12: 5,
0x13: 5,
0x14: 5,
0x15: 5,
0x16: 5,
0x17: 5,
0x18: 5,
0x19: 5,
0x1A: 5, // more than 10
0x1B: 5
} }),
{
code: 'ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS',
name: 'Error'
}
);
assert.throws(
() => client.settings({ customSettings: {
0x10000: 5,
} }),
{
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError'
}
);
assert.throws(
() => client.settings({ customSettings: {
0x55: 0x100000000,
} }),
{
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError'
}
);
assert.throws(
() => client.settings({ customSettings: {
0x55: -1,
} }),
{
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError'
}
);
[1, true, {}, []].forEach((invalidCallback) =>
assert.throws(
() => client.settings({}, invalidCallback),
{
name: 'TypeError',
code: 'ERR_INVALID_ARG_TYPE',
}
)
);
client.settings({ maxFrameSize: 1234567, customSettings: { 0xbf: 12 } });
const req = client.request();
req.on('response', common.mustCall());
req.resume();
req.on('close', common.mustCall(() => {
server.close();
client.close();
}));
}));

View File

@@ -0,0 +1,340 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const http2 = require('http2');
const check = Buffer.from([0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x00, 0x03, 0xff, 0xff, 0xff, 0xff,
0x00, 0x04, 0x00, 0x00, 0xff, 0xff,
0x00, 0x05, 0x00, 0x00, 0x40, 0x00,
0x00, 0x06, 0x00, 0x00, 0xff, 0xff,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00]);
const val = http2.getPackedSettings(http2.getDefaultSettings());
assert.deepStrictEqual(val, check);
[
['headerTableSize', 0],
['headerTableSize', 2 ** 32 - 1],
['initialWindowSize', 0],
['initialWindowSize', 2 ** 32 - 1],
['maxFrameSize', 16384],
['maxFrameSize', 2 ** 24 - 1],
['maxConcurrentStreams', 0],
['maxConcurrentStreams', 2 ** 31 - 1],
['maxHeaderListSize', 0],
['maxHeaderListSize', 2 ** 32 - 1],
['maxHeaderSize', 0],
['maxHeaderSize', 2 ** 32 - 1],
['customSettings', { '9999': 301 }],
].forEach((i) => {
// Valid options should not throw.
http2.getPackedSettings({ [i[0]]: i[1] });
});
http2.getPackedSettings({ enablePush: true });
http2.getPackedSettings({ enablePush: false });
[
['headerTableSize', -1],
['headerTableSize', 2 ** 32],
['initialWindowSize', -1],
['initialWindowSize', 2 ** 32],
['maxFrameSize', 16383],
['maxFrameSize', 2 ** 24],
['maxConcurrentStreams', -1],
['maxConcurrentStreams', 2 ** 32],
['maxHeaderListSize', -1],
['maxHeaderListSize', 2 ** 32],
['maxHeaderSize', -1],
['maxHeaderSize', 2 ** 32],
].forEach((i) => {
assert.throws(() => {
http2.getPackedSettings({ [i[0]]: i[1] });
}, {
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError',
message: `Invalid value for setting "${i[0]}": ${i[1]}`
});
});
[
1, null, '', Infinity, new Date(), {}, NaN, [false],
].forEach((i) => {
assert.throws(() => {
http2.getPackedSettings({ enablePush: i });
}, {
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'TypeError',
message: `Invalid value for setting "enablePush": ${i}`
});
});
[
1, null, '', Infinity, new Date(), {}, NaN, [false],
].forEach((i) => {
assert.throws(() => {
http2.getPackedSettings({ enableConnectProtocol: i });
}, {
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'TypeError',
message: `Invalid value for setting "enableConnectProtocol": ${i}`
});
});
{
const check = Buffer.from([
0x00, 0x01, 0x00, 0x00, 0x00, 0x64,
0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x00, 0x03, 0x00, 0x00, 0x00, 0xc8,
0x00, 0x04, 0x00, 0x00, 0x00, 0x64,
0x00, 0x05, 0x00, 0x00, 0x4e, 0x20,
0x00, 0x06, 0x00, 0x00, 0x00, 0x64,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x27, 0x0F, 0x00, 0x00, 0x01, 0x2d,
]);
const packed = http2.getPackedSettings({
headerTableSize: 100,
initialWindowSize: 100,
maxFrameSize: 20000,
maxConcurrentStreams: 200,
maxHeaderListSize: 100,
maxHeaderSize: 100,
enablePush: true,
enableConnectProtocol: false,
foo: 'ignored',
customSettings: { '9999': 301 }
});
assert.strictEqual(packed.length, 48);
assert.deepStrictEqual(packed, check);
}
// Check if multiple custom settings can be set
{
const check = Buffer.from([
0x00, 0x01, 0x00, 0x00, 0x00, 0x64,
0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x00, 0x03, 0x00, 0x00, 0x00, 0xc8,
0x00, 0x04, 0x00, 0x00, 0x00, 0x64,
0x00, 0x05, 0x00, 0x00, 0x4e, 0x20,
0x00, 0x06, 0x00, 0x00, 0x00, 0x64,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x03, 0xf3, 0x00, 0x00, 0x07, 0x9F,
0x0a, 0x2e, 0x00, 0x00, 0x00, 0x58,
]);
const packed = http2.getPackedSettings({
headerTableSize: 100,
initialWindowSize: 100,
maxFrameSize: 20000,
maxConcurrentStreams: 200,
maxHeaderListSize: 100,
maxHeaderSize: 100,
enablePush: true,
enableConnectProtocol: false,
customSettings: { '2606': 88, '1011': 1951 }
});
assert.strictEqual(packed.length, 54);
assert.deepStrictEqual(packed, check);
}
{
// Check if wrong custom settings cause an error
assert.throws(() => {
http2.getPackedSettings({
customSettings: { '-1': 659685 }
});
}, {
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError'
});
assert.throws(() => {
http2.getPackedSettings({
customSettings: { '10': 34577577777 }
});
}, {
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError'
});
assert.throws(() => {
http2.getPackedSettings({
customSettings: { 'notvalid': -777 }
});
}, {
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError'
});
assert.throws(() => {
http2.getPackedSettings({
customSettings: { '11': 11, '12': 12, '13': 13, '14': 14, '15': 15, '16': 16,
'17': 17, '18': 18, '19': 19, '20': 20, '21': 21 }
});
}, {
code: 'ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS'
});
assert.throws(() => {
http2.getPackedSettings({
customSettings: { '11': 11, '12': 12, '13': 13, '14': 14, '15': 15, '16': 16,
'17': 17, '18': 18, '19': 19, '20': 20, '21': 21, '22': 22 }
});
}, {
code: 'ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS'
});
}
// Check for not passing settings.
{
const packed = http2.getPackedSettings();
assert.strictEqual(packed.length, 0);
}
{
const packed = Buffer.from([
0x00, 0x01, 0x00, 0x00, 0x00, 0x64,
0x00, 0x03, 0x00, 0x00, 0x00, 0xc8,
0x00, 0x05, 0x00, 0x00, 0x4e, 0x20,
0x00, 0x04, 0x00, 0x00, 0x00, 0x64,
0x00, 0x06, 0x00, 0x00, 0x00, 0x64,
0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x27, 0x0F, 0x00, 0x00, 0x01, 0x2d]);
[1, true, '', [], {}, NaN].forEach((input) => {
assert.throws(() => {
http2.getUnpackedSettings(input);
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message:
'The "buf" argument must be an instance of Buffer or TypedArray.' +
common.invalidArgTypeHelper(input)
});
});
assert.throws(() => {
http2.getUnpackedSettings(packed.slice(5));
}, {
code: 'ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH',
name: 'RangeError',
message: 'Packed settings length must be a multiple of six'
});
const settings = http2.getUnpackedSettings(packed);
assert(settings);
assert.strictEqual(settings.headerTableSize, 100);
assert.strictEqual(settings.initialWindowSize, 100);
assert.strictEqual(settings.maxFrameSize, 20000);
assert.strictEqual(settings.maxConcurrentStreams, 200);
assert.strictEqual(settings.maxHeaderListSize, 100);
assert.strictEqual(settings.maxHeaderSize, 100);
assert.strictEqual(settings.enablePush, true);
assert.strictEqual(settings.enableConnectProtocol, false);
assert.deepStrictEqual(settings.customSettings, { '9999': 301 });
}
{
const packed = new Uint16Array([
0x00, 0x01, 0x00, 0x00, 0x00, 0x64,
0x00, 0x03, 0x00, 0x00, 0x00, 0xc8,
0x00, 0x05, 0x00, 0x00, 0x4e, 0x20,
0x00, 0x04, 0x00, 0x00, 0x00, 0x64,
0x00, 0x06, 0x00, 0x00, 0x00, 0x64,
0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00]);
assert.throws(() => {
http2.getUnpackedSettings(packed.slice(5));
}, {
code: 'ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH',
name: 'RangeError',
message: 'Packed settings length must be a multiple of six'
});
const settings = http2.getUnpackedSettings(packed);
assert(settings);
assert.strictEqual(settings.headerTableSize, 100);
assert.strictEqual(settings.initialWindowSize, 100);
assert.strictEqual(settings.maxFrameSize, 20000);
assert.strictEqual(settings.maxConcurrentStreams, 200);
assert.strictEqual(settings.maxHeaderListSize, 100);
assert.strictEqual(settings.maxHeaderSize, 100);
assert.strictEqual(settings.enablePush, true);
assert.strictEqual(settings.enableConnectProtocol, false);
}
{
const packed = new DataView(Buffer.from([
0x00, 0x01, 0x00, 0x00, 0x00, 0x64,
0x00, 0x03, 0x00, 0x00, 0x00, 0xc8,
0x00, 0x05, 0x00, 0x00, 0x4e, 0x20,
0x00, 0x04, 0x00, 0x00, 0x00, 0x64,
0x00, 0x06, 0x00, 0x00, 0x00, 0x64,
0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00]).buffer);
assert.throws(() => {
http2.getUnpackedSettings(packed);
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message:
'The "buf" argument must be an instance of Buffer or TypedArray.' +
common.invalidArgTypeHelper(packed)
});
}
{
const packed = Buffer.from([
0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00]);
const settings = http2.getUnpackedSettings(packed, { validate: true });
assert.strictEqual(settings.enablePush, false);
assert.strictEqual(settings.enableConnectProtocol, false);
}
{
const packed = Buffer.from([
0x00, 0x02, 0x00, 0x00, 0x00, 0x64,
0x00, 0x08, 0x00, 0x00, 0x00, 0x64]);
const settings = http2.getUnpackedSettings(packed, { validate: true });
assert.strictEqual(settings.enablePush, true);
assert.strictEqual(settings.enableConnectProtocol, true);
}
// Verify that passing {validate: true} does not throw.
{
const packed = Buffer.from([
0x00, 0x01, 0x00, 0x00, 0x00, 0x64,
0x00, 0x03, 0x00, 0x00, 0x00, 0xc8,
0x00, 0x05, 0x00, 0x00, 0x4e, 0x20,
0x00, 0x04, 0x00, 0x00, 0x00, 0x64,
0x00, 0x06, 0x00, 0x00, 0x00, 0x64,
0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00]);
http2.getUnpackedSettings(packed, { validate: true });
}
// Check for maxFrameSize failing the max number.
{
const packed = Buffer.from([0x00, 0x05, 0x01, 0x00, 0x00, 0x00]);
assert.throws(() => {
http2.getUnpackedSettings(packed, { validate: true });
}, {
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError',
message: 'Invalid value for setting "maxFrameSize": 16777216'
});
}

View File

@@ -0,0 +1,80 @@
// Flags: --expose-internals
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const {
assertIsObject,
assertWithinRange,
sessionName,
assertIsArray
} = require('internal/http2/util');
// Code coverage for sessionName utility function
assert.strictEqual(sessionName(0), 'server');
assert.strictEqual(sessionName(1), 'client');
[2, '', 'test', {}, [], true].forEach((i) => {
assert.strictEqual(sessionName(2), '<invalid>');
});
// Code coverage for assertWithinRange function
assert.throws(
() => assertWithinRange('test', -1),
{
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError',
message: 'Invalid value for setting "test": -1'
});
assertWithinRange('test', 1);
assert.throws(
() => assertIsObject('foo', 'test'),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "test" argument must be of type object. Received ' +
"type string ('foo')"
});
assert.throws(
() => assertIsObject('foo', 'test', ['Date']),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "test" argument must be an instance of Date. Received type ' +
"string ('foo')"
});
assertIsObject({}, 'test');
assert.throws(
() => assertIsArray('foo', 'test'), {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "test" argument must be an instance of Array. Received type ' +
"string ('foo')"
}
);
assert.throws(
() => assertIsArray({}, 'test'), {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "test" argument must be an instance of Array. Received an instance of Object'
}
);
assert.throws(
() => assertIsArray(1, 'test'), {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "test" argument must be an instance of Array. Received type ' +
'number (1)'
}
);
assertIsArray([], 'test');

View File

@@ -0,0 +1,208 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const h2 = require('http2');
const server = h2.createServer({
remoteCustomSettings: [
55,
],
settings: {
customSettings: {
1244: 456
}
}
}
);
server.on(
'stream',
common.mustCall((stream) => {
const assertSettings = (settings) => {
assert.strictEqual(typeof settings, 'object');
assert.strictEqual(typeof settings.headerTableSize, 'number');
assert.strictEqual(typeof settings.enablePush, 'boolean');
assert.strictEqual(typeof settings.initialWindowSize, 'number');
assert.strictEqual(typeof settings.maxFrameSize, 'number');
assert.strictEqual(typeof settings.maxConcurrentStreams, 'number');
assert.strictEqual(typeof settings.maxHeaderListSize, 'number');
assert.strictEqual(typeof settings.maxHeaderSize, 'number');
assert.strictEqual(typeof settings.customSettings, 'object');
let countCustom = 0;
if (settings.customSettings[55]) {
assert.strictEqual(typeof settings.customSettings[55], 'number');
assert.strictEqual(settings.customSettings[55], 12);
countCustom++;
}
if (settings.customSettings[155]) {
// Should not happen actually
assert.strictEqual(typeof settings.customSettings[155], 'number');
countCustom++;
}
if (settings.customSettings[1244]) {
assert.strictEqual(typeof settings.customSettings[1244], 'number');
assert.strictEqual(settings.customSettings[1244], 456);
countCustom++;
}
assert.strictEqual(countCustom, 1);
};
const localSettings = stream.session.localSettings;
const remoteSettings = stream.session.remoteSettings;
assertSettings(localSettings);
assertSettings(remoteSettings);
// Test that stored settings are returned when called for second time
assert.strictEqual(stream.session.localSettings, localSettings);
assert.strictEqual(stream.session.remoteSettings, remoteSettings);
stream.respond({
'content-type': 'text/html',
':status': 200
});
stream.end('hello world');
})
);
server.on('session', (session) => {
session.settings({
maxConcurrentStreams: 2
});
});
server.listen(
0,
common.mustCall(() => {
const client = h2.connect(`http://127.0.0.1:${server.address().port}`, {
settings: {
enablePush: false,
initialWindowSize: 123456,
customSettings: {
55: 12,
155: 144 // should not arrive
},
},
remoteCustomSettings: [
1244,
]
});
client.on(
'localSettings',
common.mustCall((settings) => {
assert(settings);
assert.strictEqual(settings.enablePush, false);
assert.strictEqual(settings.initialWindowSize, 123456);
assert.strictEqual(settings.maxFrameSize, 16384);
assert.strictEqual(settings.customSettings[55], 12);
}, 2)
);
let calledOnce = false;
client.on(
'remoteSettings',
common.mustCall((settings) => {
assert(settings);
assert.strictEqual(
settings.maxConcurrentStreams,
calledOnce ? 2 : (2 ** 32) - 1
);
calledOnce = true;
}, 2)
);
const headers = { ':path': '/' };
const req = client.request(headers);
req.on('ready', common.mustCall(() => {
// pendingSettingsAck will be true if a SETTINGS frame
// has been sent but we are still waiting for an acknowledgement
assert(client.pendingSettingsAck);
}));
// State will only be valid after connect event is emitted
req.on('ready', common.mustCall(() => {
client.settings({ maxHeaderListSize: 1 }, common.mustCall());
// Verify valid error ranges
[
['headerTableSize', -1],
['headerTableSize', 2 ** 32],
['initialWindowSize', -1],
['initialWindowSize', 2 ** 32],
['maxFrameSize', 16383],
['maxFrameSize', 2 ** 24],
['maxHeaderListSize', -1],
['maxHeaderListSize', 2 ** 32],
['maxHeaderSize', -1],
['maxHeaderSize', 2 ** 32],
].forEach(([key, value]) => {
const settings = {};
settings[key] = value;
assert.throws(
() => client.settings(settings),
{
name: 'RangeError',
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
message: `Invalid value for setting "${key}": ${value}`
}
);
});
// Same tests as for the client on customSettings
assert.throws(
() => client.settings({ customSettings: {
0x10000: 5,
} }),
{
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError'
}
);
assert.throws(
() => client.settings({ customSettings: {
55: 0x100000000,
} }),
{
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError'
}
);
assert.throws(
() => client.settings({ customSettings: {
55: -1,
} }),
{
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError'
}
);
// Error checks for enablePush
[1, {}, 'test', [], null, Infinity, NaN].forEach((i) => {
assert.throws(
() => client.settings({ enablePush: i }),
{
name: 'TypeError',
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
message: `Invalid value for setting "enablePush": ${i}`
}
);
});
}));
req.on('response', common.mustCall());
req.resume();
req.on('end', common.mustCall(() => {
server.close();
client.close();
}));
req.end();
})
);

View File

@@ -0,0 +1,60 @@
'use strict';
// This test ensures that the Http2SecureServer and Http2Server
// settings are updated when the setting object is valid.
// When the setting object is invalid, this test ensures that
// updateSettings throws an exception.
const common = require('../common');
if (!common.hasCrypto) { common.skip('missing crypto'); }
const assert = require('assert');
const http2 = require('http2');
testUpdateSettingsWith({
server: http2.createSecureServer(),
newServerSettings: {
'headerTableSize': 1,
'initialWindowSize': 1,
'maxConcurrentStreams': 1,
'maxHeaderListSize': 1,
'maxFrameSize': 16385,
'enablePush': false,
'enableConnectProtocol': true,
'customSettings': { '9999': 301 }
}
});
testUpdateSettingsWith({
server: http2.createServer(),
newServerSettings: {
'enablePush': false
}
});
function testUpdateSettingsWith({ server, newServerSettings }) {
const oldServerSettings = getServerSettings(server);
assert.notDeepStrictEqual(oldServerSettings, newServerSettings);
server.updateSettings(newServerSettings);
const updatedServerSettings = getServerSettings(server);
assert.deepStrictEqual(updatedServerSettings, { ...oldServerSettings,
...newServerSettings });
assert.throws(() => server.updateSettings(''), {
message: 'The "settings" argument must be of type object. ' +
'Received type string (\'\')',
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError'
});
assert.throws(() => server.updateSettings({
'maxHeaderListSize': 'foo'
}), {
message: 'Invalid value for setting "maxHeaderListSize": foo',
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
name: 'RangeError'
});
}
function getServerSettings(server) {
const options = Object
.getOwnPropertySymbols(server)
.find((s) => s.toString() === 'Symbol(options)');
return server[options].settings;
}

View File

@@ -0,0 +1,45 @@
// Flags: --expose-internals
'use strict';
const common = require('../common');
const assert = require('assert');
const {
assertIsObject,
assertWithinRange,
} = require('internal/http2/util');
[
undefined,
{},
{ __proto__: null },
new Date(),
new (class Foo {})(),
].forEach((input) => {
assertIsObject(input, 'foo', 'Object');
});
[
1,
false,
'hello',
NaN,
Infinity,
[],
[{}],
].forEach((input) => {
assert.throws(
() => assertIsObject(input, 'foo', 'Object'),
{
code: 'ERR_INVALID_ARG_TYPE',
message: 'The "foo" argument must be of type object.' +
common.invalidArgTypeHelper(input)
});
});
assertWithinRange('foo', 1, 0, 2);
assert.throws(() => assertWithinRange('foo', 1, 2, 3),
{
code: 'ERR_HTTP2_INVALID_SETTING_VALUE',
message: 'Invalid value for setting "foo": 1'
});