-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Kestrel response header encoding #33776
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
Changes from all commits
941c90c
ca17faf
134458d
8534569
a0ab85f
1b2b675
d31b314
ed83a04
a6834a6
7080853
d1a8fd6
9ae09d4
0f96bbd
759ef3a
2d47ee4
8b01902
30499c5
d2797d5
c1f9efd
0def2d1
d89a9b0
465249d
056d853
b518b31
94d51ed
0c03bf2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
using System.IO.Pipelines; | ||
using System.Net.Http; | ||
using System.Net.Http.QPack; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Connections; | ||
|
@@ -44,7 +45,7 @@ internal class Http3FrameWriter | |
// Write headers to a buffer that can grow. Possible performance improvement | ||
// by writing directly to output writer (difficult as frame length is prefixed). | ||
private readonly ArrayBufferWriter<byte> _headerEncodingBuffer; | ||
private IEnumerator<KeyValuePair<string, string>>? _headersEnumerator; | ||
private Http3HeadersEnumerator _headersEnumerator = new(); | ||
private int _headersTotalSize; | ||
|
||
private long _unflushedBytes; | ||
|
@@ -271,7 +272,7 @@ public ValueTask<FlushResult> WriteResponseTrailersAsync(long streamId, HttpResp | |
|
||
try | ||
{ | ||
_headersEnumerator = EnumerateHeaders(headers).GetEnumerator(); | ||
_headersEnumerator.Initialize(headers); | ||
_headersTotalSize = 0; | ||
_headerEncodingBuffer.Clear(); | ||
|
||
|
@@ -280,9 +281,12 @@ public ValueTask<FlushResult> WriteResponseTrailersAsync(long streamId, HttpResp | |
var done = QPackHeaderWriter.BeginEncode(_headersEnumerator, buffer, ref _headersTotalSize, out var payloadLength); | ||
FinishWritingHeaders(payloadLength, done); | ||
} | ||
catch (QPackEncodingException ex) | ||
// Any exception from the QPack encoder can leave the dynamic table in a corrupt state. | ||
// Since we allow custom header encoders we don't know what type of exceptions to expect. | ||
catch (Exception ex) | ||
{ | ||
_log.QPackEncodingError(_connectionId, streamId, ex); | ||
_connectionContext.Abort(new ConnectionAbortedException(ex.Message, ex)); | ||
_http3Stream.Abort(new ConnectionAbortedException(ex.Message, ex), Http3ErrorCode.InternalError); | ||
Tratcher marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't aborting the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @JamesNK? I wasn't sure about that part, I know state is tracked much differently from HTTP/2. |
||
} | ||
|
||
|
@@ -314,7 +318,7 @@ public ValueTask<FlushResult> FlushAsync(IHttpOutputAborter? outputAborter, Canc | |
} | ||
} | ||
|
||
internal void WriteResponseHeaders(int statusCode, IHeaderDictionary headers) | ||
internal void WriteResponseHeaders(int statusCode, HttpResponseHeaders headers) | ||
{ | ||
lock (_writeLock) | ||
{ | ||
|
@@ -325,15 +329,19 @@ internal void WriteResponseHeaders(int statusCode, IHeaderDictionary headers) | |
|
||
try | ||
{ | ||
_headersEnumerator = EnumerateHeaders(headers).GetEnumerator(); | ||
_headersEnumerator.Initialize(headers); | ||
|
||
_outgoingFrame.PrepareHeaders(); | ||
var buffer = _headerEncodingBuffer.GetSpan(HeaderBufferSize); | ||
var done = QPackHeaderWriter.BeginEncode(statusCode, _headersEnumerator, buffer, ref _headersTotalSize, out var payloadLength); | ||
FinishWritingHeaders(payloadLength, done); | ||
} | ||
catch (QPackEncodingException ex) | ||
// Any exception from the QPack encoder can leave the dynamic table in a corrupt state. | ||
// Since we allow custom header encoders we don't know what type of exceptions to expect. | ||
catch (Exception ex) | ||
{ | ||
_log.QPackEncodingError(_connectionId, _http3Stream.StreamId, ex); | ||
_connectionContext.Abort(new ConnectionAbortedException(ex.Message, ex)); | ||
_http3Stream.Abort(new ConnectionAbortedException(ex.Message, ex), Http3ErrorCode.InternalError); | ||
throw new InvalidOperationException(ex.Message, ex); // Report the error to the user if this was the first write. | ||
} | ||
|
@@ -347,7 +355,6 @@ private void FinishWritingHeaders(int payloadLength, bool done) | |
while (!done) | ||
{ | ||
ValidateHeadersTotalSize(); | ||
|
||
var buffer = _headerEncodingBuffer.GetSpan(HeaderBufferSize); | ||
done = QPackHeaderWriter.Encode(_headersEnumerator!, buffer, ref _headersTotalSize, out payloadLength); | ||
_headerEncodingBuffer.Advance(payloadLength); | ||
|
@@ -404,16 +411,5 @@ public void Abort(ConnectionAbortedException error) | |
_outputWriter.Complete(); | ||
} | ||
} | ||
|
||
private static IEnumerable<KeyValuePair<string, string>> EnumerateHeaders(IHeaderDictionary headers) | ||
{ | ||
foreach (var header in headers) | ||
{ | ||
foreach (var value in header.Value) | ||
{ | ||
yield return new KeyValuePair<string, string>(header.Key, value); | ||
} | ||
} | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.