Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
Allow HTTP2 encoder to split headers across frames #55322
Allow HTTP2 encoder to split headers across frames #55322
Changes from 26 commits
a10d9ee
5cad996
f53dd7c
231c716
887f505
b91a34c
a655a38
f31c8c8
6ab7271
e21620a
9720c3a
f8f8ff9
994b27d
a77a930
4f14b0c
46be03f
9857dcb
95c9553
c4b93d6
3fe0a73
0dfc97b
79be13b
8773062
a98500b
9014f28
957dfc3
57cc264
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
_headersEncodingLargeBufferSize
is updated to be bigger when required, but I don't see anywhere that resets it back it a smaller size.For example, request 1 has a response header that is 10megs in size, so this field and the buffer eventually grows to that size. Then request 2 has a response header that is 100kb in size (larger than max frame size) but the writer rents a 10meg buffer because that is
_headersEncodingLargeBufferSize
size from last time.Is this behavior intentional? Is the size preserved to avoid retrying because a connection keeps sending large response headers? Should add a comment if that is the case.
If the behavior isn't intentional, then I believe the field is only used inside
FinishWritingHeadersUnsynchronized
. It could be changed to a local variable.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.
This behavior was intentional, exactly as you said: it might be ie. a cookie that is sent on all streams and that is always large. If you think that is not a desired behavior, I am happy to make it local. In the meantime, I will leave a comment explaining 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.
@JamesNK There's some discussion here: #55322 (comment)
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.
This will throw when the header is at least
maxint / 2
bytes? What does it do when it throws? I remember there was an earlier fix to make sure an error didn't result in an infinite loop of empty writes. I'm pretty sure this won't cause that, but I thought I should confirm.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.
Note that the header may be actually already larger to
int.MaxValue / 2
. For example a client updates the_maxFrameSize
to a custom value and we end up here with(2/3) * int.MaxValue
Of course the next increase would throw, but to be clear, it does not limit the max response header size.When it throws there, this is what it would throw:
which then ends up handled in
WriteResponseHeadersUnsynchronized
with aConnectionAbortedException
But I could only get here by forcing a large initial value to
_headersEncodingLargeBufferSize
because in practise my machine throws an OOM way earlier, already when I try to allocate the string value of such large header.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.
Should returning the buffer be in a finally to ensure its returned when an error occurs? There are definitely ways to throw when encoding headers.
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.
My understanding was that in these cases the buffer would be garbage collected.
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.
That's my default inclination as well, but I understood we (dotnet? aspnetcore?) had guidelines saying rented objects should not be returned in the event of an exception.
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.
Let me know, I am happy to change already prepared on my machine.
I used to see try-finally all over for ArrayPool, but lately I see less and less.
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.
Yes, there's definitely strong precedent for only recycling on success, especially when async operations are possible; as a side-effect this also avoids the need for some
try
. There might be a caveat here if we expect failure in a significant % (exceptions as flow control), but I don't think that applies hereThere 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.
Should this be in a finally?
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.
My understanding was that in these cases the buffer would be garbage collected.
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.
Not returning doesn't create a memory leak, but it could cause future rent calls to allocate because buffers haven't been returned.