-
Notifications
You must be signed in to change notification settings - Fork 30k
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
http2: refactor Http2Stream and inbound headers #16676
Conversation
a26dbcf
to
fc76961
Compare
of header list that will be accepted. There is no default value. The minimum | ||
allowed value is 0. The maximum allowed value is 2<sup>32</sup>-1. | ||
of header list that will be accepted. The minimum allowed value is 0. The | ||
maximum allowed value is 2<sup>32</sup>-1. **Default:** 65535. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should probably update the changelog in the docs somehow for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point
src/node_http2_core-inl.h
Outdated
uint32_t maxHeaderListSize = session->GetMaxHeaderPairs(); | ||
if (maxHeaderListSize == 0) | ||
maxHeaderListSize = DEFAULT_MAX_HEADER_LIST_PAIRS; | ||
current_headers_.AllocateSufficientStorage(maxHeaderListSize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this mean we are preallocating an array of maxHeaderListSize
? Do we need this to be 65535 as the default? IMHO we are wasting memory and time for each stream.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two limits: the max number of header pairs, and the max number of header octets. We are preallocating an array of nhgttp2_header structs. These consist of two pointers and an 8 bit flag. Current number is a generous 1024, which can likely be tuned much much lower. The 65535 is the total number of octets and is maintained as a size_t counter only. There's no preallocation for that.
We should be able to tune the number of header pairs down to something much much smaller than 1024.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would go for 128
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you’re calling AllocateSufficientStorage()
, you kind of shouldn’t be using a MaybeStackBuffer
in the first place – all this will give you is unused memory inside the Nghttp2Stream
instance.
I’d suggest just going with a std::vector
here … you don’t need to care about pre-allocating memory in that case, plus you can still reserve memory ahead of time using e.g. vector.reserve(128)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, I keep going back and forth on this, just playing with the various options to see which is going to provide the best performance. std::vector
is likely the best approach based on everything I've seen.
// block is 1024, including the HTTP pseudo-header fields, by | ||
// setting one here, no request should be acccepted because it | ||
// does not allow for even the basic HTTP pseudo-headers | ||
const server = http2.createServer({ maxHeaderListPairs: 1 }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these types of settings should throw. What's the minimum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can set whatever minimum we want here. For the request to work, we need at least 4 to account for the required pseudoheaders.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say we validate it's greater than 4.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about rather than report an error, we just automatically allow for the number of pseudo-headers? So if a user sets 0, the internal value is 4....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with the default changed.
buffer[IDX_SETTINGS_COUNT] = | ||
(1 << IDX_SETTINGS_HEADER_TABLE_SIZE) | | ||
(1 << IDX_SETTINGS_ENABLE_PUSH) | | ||
(1 << IDX_SETTINGS_INITIAL_WINDOW_SIZE) | | ||
(1 << IDX_SETTINGS_MAX_FRAME_SIZE); | ||
(1 << IDX_SETTINGS_MAX_FRAME_SIZE) | | ||
(1 << IDX_SETTINGS_MAX_HEADER_LIST_SIZE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, this is … clever 😄
while (!headers->empty() && j < arraysize(argv) / 2) { | ||
nghttp2_header item = headers->front(); | ||
while (count > 0 && j < arraysize(argv) / 2) { | ||
nghttp2_header item = headers[n++]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can’t this just be headers[--count]
? I don’t think you really need the n
if you didn’t need it before
src/node_http2_core-inl.h
Outdated
uint32_t maxHeaderListSize = session->GetMaxHeaderPairs(); | ||
if (maxHeaderListSize == 0) | ||
maxHeaderListSize = DEFAULT_MAX_HEADER_LIST_PAIRS; | ||
current_headers_.AllocateSufficientStorage(maxHeaderListSize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you’re calling AllocateSufficientStorage()
, you kind of shouldn’t be using a MaybeStackBuffer
in the first place – all this will give you is unused memory inside the Nghttp2Stream
instance.
I’d suggest just going with a std::vector
here … you don’t need to care about pre-allocating memory in that case, plus you can still reserve memory ahead of time using e.g. vector.reserve(128)
.
99ce733
to
e067c58
Compare
After testing, the pooling is not having any tangible benefit and makes things more complicated. Simplify. Simplify.
Enforce MAX_HEADERS_LIST setting and limit the number of header pairs accepted from the peer. Use the ENHANCE_YOUR_CALM error code when receiving either too many headers or too many octets. Use a MaybeStackBuffer to store the headers instead of a queue
e067c58
to
59614d7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
* eliminate pooling of Nghttp2Stream instances. After testing, the pooling is not having any tangible benefit and makes things more complicated. Simplify. Simplify. * refactor inbound headers * Enforce MAX_HEADERS_LIST setting and limit the number of header pairs accepted from the peer. Use the ENHANCE_YOUR_CALM error code when receiving either too many headers or too many octets. Use a vector to store the headers instead of a queue PR-URL: #16676 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Landed in 9f3d59e |
* eliminate pooling of Nghttp2Stream instances. After testing, the pooling is not having any tangible benefit and makes things more complicated. Simplify. Simplify. * refactor inbound headers * Enforce MAX_HEADERS_LIST setting and limit the number of header pairs accepted from the peer. Use the ENHANCE_YOUR_CALM error code when receiving either too many headers or too many octets. Use a vector to store the headers instead of a queue PR-URL: nodejs#16676 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
* eliminate pooling of Nghttp2Stream instances. After testing, the pooling is not having any tangible benefit and makes things more complicated. Simplify. Simplify. * refactor inbound headers * Enforce MAX_HEADERS_LIST setting and limit the number of header pairs accepted from the peer. Use the ENHANCE_YOUR_CALM error code when receiving either too many headers or too many octets. Use a vector to store the headers instead of a queue PR-URL: #16676 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
* eliminate pooling of Nghttp2Stream instances. After testing, the pooling is not having any tangible benefit and makes things more complicated. Simplify. Simplify. * refactor inbound headers * Enforce MAX_HEADERS_LIST setting and limit the number of header pairs accepted from the peer. Use the ENHANCE_YOUR_CALM error code when receiving either too many headers or too many octets. Use a vector to store the headers instead of a queue PR-URL: #16676 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Nghttp2Stream
instancesChecklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
http2