Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34.3k
Initial proposal for additional http2settings#49025
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -8,6 +8,7 @@ const{ | ||
| Error, | ||
| MathMax, | ||
| Number, | ||
| NumberIsNaN, | ||
| ObjectKeys, | ||
| SafeSet, | ||
| String, | ||
| @@ -24,6 +25,7 @@ const{ | ||
| ERR_HTTP2_INVALID_CONNECTION_HEADERS, | ||
| ERR_HTTP2_INVALID_PSEUDOHEADER:{HideStackFramesError: ERR_HTTP2_INVALID_PSEUDOHEADER }, | ||
| ERR_HTTP2_INVALID_SETTING_VALUE, | ||
| ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS, | ||
| ERR_INVALID_ARG_TYPE, | ||
| ERR_INVALID_HTTP_TOKEN, | ||
| }, | ||
| @@ -190,6 +192,9 @@ const IDX_SETTINGS_MAX_HEADER_LIST_SIZE = 5; | ||
| const IDX_SETTINGS_ENABLE_CONNECT_PROTOCOL = 6; | ||
| const IDX_SETTINGS_FLAGS = 7; | ||
| // Maximum number of allowed additional settings | ||
| const MAX_ADDITIONAL_SETTINGS = 10; | ||
| const IDX_SESSION_STATE_EFFECTIVE_LOCAL_WINDOW_SIZE = 0; | ||
| const IDX_SESSION_STATE_EFFECTIVE_RECV_DATA_LENGTH = 1; | ||
| const IDX_SESSION_STATE_NEXT_STREAM_ID = 2; | ||
| @@ -348,6 +353,80 @@ function getSettings(session, remote){ | ||
| function updateSettingsBuffer(settings){ | ||
| let flags = 0; | ||
| let numCustomSettings = 0; | ||
| if (typeof settings.customSettings === 'object'){ | ||
| const customSettings = settings.customSettings; | ||
| for (const setting in customSettings){ | ||
| const val = customSettings[setting]; | ||
| if (typeof val === 'number'){ | ||
| let set = false; | ||
| const nsetting = Number(setting); | ||
jasnell marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| if (NumberIsNaN(nsetting) || | ||
| typeof nsetting !== 'number' || | ||
| 0 >= nsetting || | ||
| nsetting > 0xffff) | ||
| throw new ERR_HTTP2_INVALID_SETTING_VALUE.RangeError( | ||
| 'Range Error', nsetting, 0, 0xffff); | ||
| if (NumberIsNaN(val) || | ||
| typeof val !== 'number' || | ||
| 0 >= val || | ||
| val > 0xffffffff) | ||
| throw new ERR_HTTP2_INVALID_SETTING_VALUE.RangeError( | ||
| 'Range Error', val, 0, 0xffffffff); | ||
| if (nsetting < IDX_SETTINGS_FLAGS){ | ||
| set = true; | ||
| switch (nsetting){ | ||
jasnell marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| case IDX_SETTINGS_HEADER_TABLE_SIZE: | ||
| flags |= (1 << IDX_SETTINGS_HEADER_TABLE_SIZE); | ||
| settingsBuffer[IDX_SETTINGS_HEADER_TABLE_SIZE] = | ||
| val; | ||
| break; | ||
| case IDX_SETTINGS_ENABLE_PUSH: | ||
| flags |= (1 << IDX_SETTINGS_ENABLE_PUSH); | ||
| settingsBuffer[IDX_SETTINGS_ENABLE_PUSH] = val; | ||
| break; | ||
| case IDX_SETTINGS_INITIAL_WINDOW_SIZE: | ||
| flags |= (1 << IDX_SETTINGS_INITIAL_WINDOW_SIZE); | ||
| settingsBuffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE] = | ||
| val; | ||
| break; | ||
| case IDX_SETTINGS_MAX_FRAME_SIZE: | ||
| flags |= (1 << IDX_SETTINGS_MAX_FRAME_SIZE); | ||
| settingsBuffer[IDX_SETTINGS_MAX_FRAME_SIZE] = | ||
| val; | ||
| break; | ||
| case IDX_SETTINGS_MAX_CONCURRENT_STREAMS: | ||
| flags |= (1 << IDX_SETTINGS_MAX_CONCURRENT_STREAMS); | ||
| settingsBuffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS] = val; | ||
| break; | ||
| case IDX_SETTINGS_MAX_HEADER_LIST_SIZE: | ||
| flags |= (1 << IDX_SETTINGS_MAX_HEADER_LIST_SIZE); | ||
| settingsBuffer[IDX_SETTINGS_MAX_HEADER_LIST_SIZE] = | ||
| val; | ||
| break; | ||
| case IDX_SETTINGS_ENABLE_CONNECT_PROTOCOL: | ||
| flags |= (1 << IDX_SETTINGS_ENABLE_CONNECT_PROTOCOL); | ||
| settingsBuffer[IDX_SETTINGS_ENABLE_CONNECT_PROTOCOL] = val; | ||
| break; | ||
| default: | ||
| set = false; | ||
| break; | ||
| } | ||
| } | ||
| if (!set){// not supported | ||
| if (numCustomSettings === MAX_ADDITIONAL_SETTINGS) | ||
| throw new ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS(); | ||
| settingsBuffer[IDX_SETTINGS_FLAGS + 1 + 2 * numCustomSettings + 1] = nsetting; | ||
jasnell marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| settingsBuffer[IDX_SETTINGS_FLAGS + 1 + 2 * numCustomSettings + 2] = val; | ||
| numCustomSettings++; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| settingsBuffer[IDX_SETTINGS_FLAGS + 1] = numCustomSettings; | ||
| if (typeof settings.headerTableSize === 'number'){ | ||
| flags |= (1 << IDX_SETTINGS_HEADER_TABLE_SIZE); | ||
| settingsBuffer[IDX_SETTINGS_HEADER_TABLE_SIZE] = | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -21,6 +21,9 @@ namespace http2{ | ||
| IDX_SETTINGS_COUNT | ||
| }; | ||
| // number of max additional settings, thus settings not implemented by nghttp2 | ||
| const size_t MAX_ADDITIONAL_SETTINGS = 10; | ||
| enum Http2SessionStateIndex{ | ||
| IDX_SESSION_STATE_EFFECTIVE_LOCAL_WINDOW_SIZE, | ||
| IDX_SESSION_STATE_EFFECTIVE_RECV_DATA_LENGTH, | ||
| @@ -108,10 +111,11 @@ class Http2State : public BaseObject{ | ||
| offsetof(http2_state_internal, options_buffer), | ||
| IDX_OPTIONS_FLAGS + 1, | ||
| root_buffer), | ||
| settings_buffer(realm->isolate(), | ||
| offsetof(http2_state_internal, settings_buffer), | ||
| IDX_SETTINGS_COUNT + 1, | ||
| root_buffer){} | ||
| settings_buffer( | ||
| realm->isolate(), | ||
| offsetof(http2_state_internal, settings_buffer), | ||
| IDX_SETTINGS_COUNT + 1 + 1 + 2 * MAX_ADDITIONAL_SETTINGS, | ||
| root_buffer){} | ||
| AliasedUint8Array root_buffer; | ||
| AliasedFloat64Array session_state_buffer; | ||
| @@ -135,7 +139,12 @@ class Http2State : public BaseObject{ | ||
| double stream_stats_buffer[IDX_STREAM_STATS_COUNT]; | ||
| double session_stats_buffer[IDX_SESSION_STATS_COUNT]; | ||
| uint32_t options_buffer[IDX_OPTIONS_FLAGS + 1]; | ||
| uint32_t settings_buffer[IDX_SETTINGS_COUNT + 1]; | ||
| // first + 1: number of actual nghttp2 supported settings | ||
| // second + 1: number of additional settings not suppoted by nghttp2 | ||
| // 2 * MAX_ADDITIONAL_SETTINGS: settings id and value for each | ||
| // additional setting | ||
| uint32_t settings_buffer[IDX_SETTINGS_COUNT + 1 + 1 + | ||
| 2 * MAX_ADDITIONAL_SETTINGS]; | ||
jasnell marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| }; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -29,6 +29,7 @@ assert.deepStrictEqual(val, check); | ||
| ['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] }); | ||
| @@ -93,6 +94,7 @@ http2.getPackedSettings({enablePush: false }); | ||
| 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({ | ||
| @@ -104,12 +106,90 @@ http2.getPackedSettings({enablePush: false }); | ||
| maxHeaderSize: 100, | ||
| enablePush: true, | ||
| enableConnectProtocol: false, | ||
| foo: 'ignored' | ||
| foo: 'ignored', | ||
| customSettings:{'9999': 301 } | ||
| }); | ||
| assert.strictEqual(packed.length, 42); | ||
| 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(); | ||
| @@ -124,7 +204,8 @@ http2.getPackedSettings({enablePush: false }); | ||
| 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, | ||
| 0x00, 0x06, 0x00, 0x00, 0x00, 0x64, | ||
| 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, | ||
| 0x00, 0x08, 0x00, 0x00, 0x00, 0x00]); | ||
| 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, | ||
| 0x27, 0x0F, 0x00, 0x00, 0x01, 0x2d]); | ||
| [1, true, '', [],{}, NaN].forEach((input) =>{ | ||
| assert.throws(() =>{ | ||
| @@ -157,6 +238,7 @@ http2.getPackedSettings({enablePush: false }); | ||
| assert.strictEqual(settings.maxHeaderSize, 100); | ||
| assert.strictEqual(settings.enablePush, true); | ||
| assert.strictEqual(settings.enableConnectProtocol, false); | ||
| assert.deepStrictEqual(settings.customSettings,{'9999': 301 }); | ||
jasnell marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| { | ||
Uh oh!
There was an error while loading. Please reload this page.