'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' }); }