| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8e75c73 commit cc7c11b
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1732,6 +1732,17 @@ added: v15.14.0 | |||
| 1732 | 1732 | The limit of acceptable invalid HTTP/2 protocol frames sent by the peer, | |
| 1733 | 1733 | as specified through the `maxSessionInvalidFrames` option, has been exceeded. | |
| 1734 | 1734 | ||
| 1735 | + <a id="ERR_HTTP2_TOO_MANY_ORIGINS"></a> | ||
| 1736 | + | ||
| 1737 | + ### `ERR_HTTP2_TOO_MANY_ORIGINS` | ||
| 1738 | + | ||
| 1739 | + <!-- YAML | ||
| 1740 | + added: REPLACEME | ||
| 1741 | + --> | ||
| 1742 | + | ||
| 1743 | + The number of uniq origin sent by the server has exceeded the value defined in | ||
| 1744 | + `options.maxOriginSetSize`. | ||
| 1745 | + | ||
| 1735 | 1746 | <a id="ERR_HTTP2_TRAILERS_ALREADY_SENT"></a> | |
| 1736 | 1747 | ||
| 1737 | 1748 | ### `ERR_HTTP2_TRAILERS_ALREADY_SENT` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3260,6 +3260,8 @@ changes: | |||
| 3260 | 3260 | This is similar to [`server.maxHeadersCount`][] or | |
| 3261 | 3261 | [`request.maxHeadersCount`][] in the `node:http` module. The minimum value | |
| 3262 | 3262 | is `1`. **Default:** `128`. | |
| 3263 | + * `maxOriginSetSize` {number} Sets the maximum number of uniq origin the sever | ||
| 3264 | + can send via ORIGIN frames. **Default:** `128`. | ||
| 3263 | 3265 | * `maxOutstandingPings` {number} Sets the maximum number of outstanding, | |
| 3264 | 3266 | unacknowledged pings. **Default:** `10`. | |
| 3265 | 3267 | * `maxReservedRemoteStreams` {number} Sets the maximum number of reserved push | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1323,6 +1323,8 @@ E('ERR_HTTP2_STREAM_SELF_DEPENDENCY', | |||
| 1323 | 1323 | E('ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS', | |
| 1324 | 1324 | 'Number of custom settings exceeds MAX_ADDITIONAL_SETTINGS', Error); | |
| 1325 | 1325 | E('ERR_HTTP2_TOO_MANY_INVALID_FRAMES', 'Too many invalid HTTP/2 frames', Error); | |
| 1326 | + E('ERR_HTTP2_TOO_MANY_ORIGINS', | ||
| 1327 | + 'The server sent more ORIGIN frames than the allowed number of %s', Error); | ||
| 1326 | 1328 | E('ERR_HTTP2_TRAILERS_ALREADY_SENT', | |
| 1327 | 1329 | 'Trailing headers have already been sent', Error); | |
| 1328 | 1330 | E('ERR_HTTP2_TRAILERS_NOT_READY', | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -102,6 +102,7 @@ const { | |||
| 102 | 102 | ERR_HTTP2_STREAM_ERROR, | |
| 103 | 103 | ERR_HTTP2_STREAM_SELF_DEPENDENCY, | |
| 104 | 104 | ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS, | |
| 105 | + ERR_HTTP2_TOO_MANY_ORIGINS, | ||
| 105 | 106 | ERR_HTTP2_TRAILERS_ALREADY_SENT, | |
| 106 | 107 | ERR_HTTP2_TRAILERS_NOT_READY, | |
| 107 | 108 | ERR_HTTP2_UNSUPPORTED_PROTOCOL, | |
@@ -255,6 +256,7 @@ const kInit = Symbol('init'); | |||
| 255 | 256 | const kInfoHeaders = Symbol('sent-info-headers'); | |
| 256 | 257 | const kLocalSettings = Symbol('local-settings'); | |
| 257 | 258 | const kNativeFields = Symbol('kNativeFields'); | |
| 259 | + const kMaxOriginSetSize = Symbol('max-ORIGIN-set-size'); | ||
| 258 | 260 | const kOptions = Symbol('options'); | |
| 259 | 261 | const kOwner = owner_symbol; | |
| 260 | 262 | const kOrigin = Symbol('origin'); | |
@@ -723,8 +725,13 @@ function onOrigin(origins) { | |||
| 723 | 725 | if (!session.encrypted || session.destroyed) | |
| 724 | 726 | return undefined; | |
| 725 | 727 | const originSet = initOriginSet(session); | |
| 726 | - for (let n = 0; n < origins.length; n++) | ||
| 728 | + for (let n = 0; n < origins.length; n++) { | ||
| 729 | + if (originSet.size >= session[kMaxOriginSetSize]) { | ||
| 730 | + session.destroy(new ERR_HTTP2_TOO_MANY_ORIGINS(session[kMaxOriginSetSize])); | ||
| 731 | + return; | ||
| 732 | + } | ||
| 727 | 733 | originSet.add(origins[n]); | |
| 734 | + } | ||
| 728 | 735 | session.emit('origin', origins); | |
| 729 | 736 | } | |
| 730 | 737 | ||
@@ -3579,6 +3586,13 @@ function connect(authority, options, listener) { | |||
| 3579 | 3586 | assertIsObject(options, 'options'); | |
| 3580 | 3587 | options = { ...options }; | |
| 3581 | 3588 | ||
| 3589 | + let { maxOriginSetSize } = options; | ||
| 3590 | + if (maxOriginSetSize != null) { | ||
| 3591 | + validateNumber(maxOriginSetSize, 'options.maxOriginSetSize', 0); | ||
| 3592 | + } else { | ||
| 3593 | + maxOriginSetSize = 128; | ||
| 3594 | + } | ||
| 3595 | + | ||
| 3582 | 3596 | assertIsArray(options.remoteCustomSettings, 'options.remoteCustomSettings'); | |
| 3583 | 3597 | if (options.remoteCustomSettings) { | |
| 3584 | 3598 | options.remoteCustomSettings = [ ...options.remoteCustomSettings ]; | |
@@ -3634,6 +3648,7 @@ function connect(authority, options, listener) { | |||
| 3634 | 3648 | ||
| 3635 | 3649 | session[kAuthority] = `${options.servername || host}:${port}`; | |
| 3636 | 3650 | session[kProtocol] = protocol; | |
| 3651 | + session[kMaxOriginSetSize] = maxOriginSetSize; | ||
| 3637 | 3652 | ||
| 3638 | 3653 | if (typeof listener === 'function') | |
| 3639 | 3654 | session.once('connect', listener); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,110 @@ | |||
| 1 | + import { | ||
| 2 | + expectsError, | ||
| 3 | + hasCrypto, | ||
| 4 | + mustCall, | ||
| 5 | + mustNotCall, | ||
| 6 | + mustSucceed, | ||
| 7 | + skip, | ||
| 8 | + } from '../common/index.mjs'; | ||
| 9 | + import * as fixtures from '../common/fixtures.mjs'; | ||
| 10 | + import assert from 'node:assert'; | ||
| 11 | + | ||
| 12 | + if (!hasCrypto) | ||
| 13 | + skip('missing crypto'); | ||
| 14 | + | ||
| 15 | + const { | ||
| 16 | + createSecureServer, | ||
| 17 | + connect, | ||
| 18 | + } = await import('node:http2'); | ||
| 19 | + | ||
| 20 | + const key = fixtures.readKey('agent8-key.pem', 'binary'); | ||
| 21 | + const cert = fixtures.readKey('agent8-cert.pem', 'binary'); | ||
| 22 | + const ca = fixtures.readKey('fake-startcom-root-cert.pem', 'binary'); | ||
| 23 | + | ||
| 24 | + const server = createSecureServer({ key, cert }); | ||
| 25 | + server.on('stream', (stream) => { | ||
| 26 | + stream.respond(); | ||
| 27 | + stream.end('ok'); | ||
| 28 | + }); | ||
| 29 | + server.on('session', (session) => { | ||
| 30 | + let i = 0; | ||
| 31 | + const timer = setInterval(() => { | ||
| 32 | + try { | ||
| 33 | + session.origin(...Array.from({ length: 10 }, () => `https://o${i++}.example.com`)); | ||
| 34 | + } catch { | ||
| 35 | + clearInterval(timer); | ||
| 36 | + } | ||
| 37 | + }, 10); | ||
| 38 | + | ||
| 39 | + session.on('close', () => { | ||
| 40 | + clearInterval(timer); | ||
| 41 | + }); | ||
| 42 | + }); | ||
| 43 | + | ||
| 44 | + await new Promise((resolve) => server.listen(0, resolve)); | ||
| 45 | + | ||
| 46 | + // Test fantasist values | ||
| 47 | + [Symbol(), '0', 1n, {}, [], true, false, /s/, () => {}].forEach((maxOriginSetSize) => { | ||
| 48 | + assert.throws( | ||
| 49 | + () => connect(`https://localhost:${server.address().port}`, { ca, maxOriginSetSize }), | ||
| 50 | + { code: 'ERR_INVALID_ARG_TYPE' }, | ||
| 51 | + ); | ||
| 52 | + }); | ||
| 53 | + [NaN, -1].forEach((maxOriginSetSize) => { | ||
| 54 | + assert.throws( | ||
| 55 | + () => connect(`https://localhost:${server.address().port}`, { ca, maxOriginSetSize }), | ||
| 56 | + { code: 'ERR_OUT_OF_RANGE' }, | ||
| 57 | + ); | ||
| 58 | + }); | ||
| 59 | + | ||
| 60 | + await new Promise((resolve) => server.getConnections(mustSucceed((count) => { | ||
| 61 | + assert.strictEqual(count, 0); | ||
| 62 | + resolve(); | ||
| 63 | + }))); | ||
| 64 | + | ||
| 65 | + // Test default value | ||
| 66 | + await new Promise((resolve) => { | ||
| 67 | + const client = connect(`https://localhost:${server.address().port}`, { ca }); | ||
| 68 | + | ||
| 69 | + client.on('origin', mustCall(12)); // Default value is 128, the first 12 frames should pass, the 13th one should error | ||
| 70 | + client.on('error', expectsError({ | ||
| 71 | + code: 'ERR_HTTP2_TOO_MANY_ORIGINS', | ||
| 72 | + })); | ||
| 73 | + client.on('goaway', mustNotCall()); | ||
| 74 | + client.on('close', resolve); | ||
| 75 | + | ||
| 76 | + client.request().resume(); | ||
| 77 | + }); | ||
| 78 | + | ||
| 79 | + // Test non-default values | ||
| 80 | + await Promise.all([-0, 9, 1.5].map((maxOriginSetSize) => new Promise((resolve) => { | ||
| 81 | + const client = connect(`https://localhost:${server.address().port}`, { ca, maxOriginSetSize }); | ||
| 82 | + | ||
| 83 | + client.on('origin', mustNotCall()); // The server send 10 origins on the first frame, that's already too many. | ||
| 84 | + client.on('error', expectsError({ | ||
| 85 | + code: 'ERR_HTTP2_TOO_MANY_ORIGINS', | ||
| 86 | + })); | ||
| 87 | + client.on('goaway', mustNotCall()); | ||
| 88 | + client.on('close', resolve); | ||
| 89 | + | ||
| 90 | + client.request().resume(); | ||
| 91 | + }))); | ||
| 92 | + | ||
| 93 | + | ||
| 94 | + // Test values higher than the default value | ||
| 95 | + await Promise.all([512, Infinity].map((maxOriginSetSize) => new Promise((resolve) => { | ||
| 96 | + const client = connect(`https://localhost:${server.address().port}`, { ca, maxOriginSetSize }); | ||
| 97 | + | ||
| 98 | + client.on('origin', mustCall(() => { | ||
| 99 | + if (client.originSet.length > 128) { | ||
| 100 | + client.destroy(); | ||
| 101 | + } | ||
| 102 | + }, 13)); | ||
| 103 | + client.on('error', mustNotCall()); | ||
| 104 | + client.on('goaway', mustNotCall()); | ||
| 105 | + client.on('close', resolve); | ||
| 106 | + | ||
| 107 | + client.request().resume(); | ||
| 108 | + }))); | ||
| 109 | + | ||
| 110 | + server.close(); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments