node/test/parallel/test-http2-session-settings.js
Marten Richter bf37d4be69
http2: receive customsettings
This commit gives node.js the ability to also receive custom settings,
in addition to sending, them which was implemented before.
The custom settings received are limited to setting ids,
that were specified before, when creating the session eithers through
the server or the client.

PR-URL: https://github.com/nodejs/node/pull/51323
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
2024-01-07 17:33:52 +00:00

209 lines
5.7 KiB
JavaScript

'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://localhost:${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();
})
);