Skip to content

Commit 4c2f19f

Browse files
committed
Fix tests
1 parent 5477e28 commit 4c2f19f

File tree

1 file changed

+45
-27
lines changed

1 file changed

+45
-27
lines changed

src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -85,31 +85,8 @@ public Http2Connection(HttpConnectionContext context)
8585
// Capture the ExecutionContext before dispatching HTTP/2 middleware. Will be restored by streams when processing request
8686
_context.InitialExecutionContext = ExecutionContext.Capture();
8787

88-
var inputPipeOptions = new PipeOptions(pool: context.MemoryPool,
89-
readerScheduler: context.ServiceContext.Scheduler,
90-
writerScheduler: PipeScheduler.Inline,
91-
pauseWriterThreshold: 1,
92-
resumeWriterThreshold: 1,
93-
minimumSegmentSize: context.MemoryPool.GetMinimumSegmentSize(),
94-
useSynchronizationContext: false);
95-
96-
// Never write inline because we do not want to hold Http2FramerWriter._writeLock for potentially expensive TLS
97-
// write operations. This essentially doubles the MaxResponseBufferSize for HTTP/2 connections compared to
98-
// HTTP/1.x. This seems reasonable given HTTP/2's support for many concurrent streams per connection. We don't
99-
// want every write to return an incomplete ValueTasK now that we're dispatching TLS write operations which
100-
// would likely happen with a pauseWriterThreashold of 1, but we still need to respect connection backpressure.
101-
var maxWriteBufferSize = httpLimits.MaxResponseBufferSize ?? 0;
102-
103-
var outputPipeOptions = new PipeOptions(pool: context.MemoryPool,
104-
readerScheduler: PipeScheduler.ThreadPool,
105-
writerScheduler: PipeScheduler.Inline,
106-
pauseWriterThreshold: maxWriteBufferSize,
107-
resumeWriterThreshold: maxWriteBufferSize / 2,
108-
minimumSegmentSize: context.MemoryPool.GetMinimumSegmentSize(),
109-
useSynchronizationContext: false);
110-
111-
_input = new Pipe(inputPipeOptions);
112-
_output = new Pipe(outputPipeOptions);
88+
_input = new Pipe(GetInputPipeOptions());
89+
_output = new Pipe(GetOutputPipeOptions());
11390

11491
_frameWriter = new Http2FrameWriter(
11592
_output.Writer,
@@ -1677,6 +1654,46 @@ public void DecrementActiveClientStreamCount()
16771654
Interlocked.Decrement(ref _clientActiveStreamCount);
16781655
}
16791656

1657+
private PipeOptions GetInputPipeOptions() => new PipeOptions(pool: _context.MemoryPool,
1658+
readerScheduler: _context.ServiceContext.Scheduler,
1659+
writerScheduler: PipeScheduler.Inline,
1660+
pauseWriterThreshold: 1,
1661+
resumeWriterThreshold: 1,
1662+
minimumSegmentSize: _context.MemoryPool.GetMinimumSegmentSize(),
1663+
useSynchronizationContext: false);
1664+
1665+
private PipeOptions GetOutputPipeOptions()
1666+
{
1667+
// Never write inline because we do not want to hold Http2FramerWriter._writeLock for potentially expensive TLS
1668+
// write operations. This essentially doubles the MaxResponseBufferSize for HTTP/2 connections compared to
1669+
// HTTP/1.x. This seems reasonable given HTTP/2's support for many concurrent streams per connection. We don't
1670+
// want every write to return an incomplete ValueTask now that we're dispatching TLS write operations which
1671+
// would likely happen with a pauseWriterThreashold of 1, but we still need to respect connection back pressure.
1672+
var pauseWriterThreshold = _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize switch
1673+
{
1674+
// null means that we have no back pressure
1675+
null => 0,
1676+
// 0 = no buffering so we need to configure the pipe so the writer waits on the reader directly
1677+
0 => 1,
1678+
long limit => limit,
1679+
};
1680+
1681+
var resumeWriterThreshold = pauseWriterThreshold switch
1682+
{
1683+
// The resumeWriterThreashould must be at least 1 to ever resume after pausing.
1684+
1 => 1,
1685+
long limit => limit / 2,
1686+
};
1687+
1688+
return new PipeOptions(pool: _context.MemoryPool,
1689+
readerScheduler: _context.ServiceContext.Scheduler,
1690+
writerScheduler: PipeScheduler.Inline,
1691+
pauseWriterThreshold: pauseWriterThreshold,
1692+
resumeWriterThreshold: resumeWriterThreshold,
1693+
minimumSegmentSize: _context.MemoryPool.GetMinimumSegmentSize(),
1694+
useSynchronizationContext: false);
1695+
}
1696+
16801697
private async Task CopyPipe(PipeReader reader, PipeWriter writer)
16811698
{
16821699
Exception? error = null;
@@ -1699,11 +1716,12 @@ private async Task CopyPipe(PipeReader reader, PipeWriter writer)
16991716

17001717
bufferSlice.CopyTo(outputBuffer.Span);
17011718

1702-
reader.AdvanceTo(bufferSlice.End);
17031719
writer.Advance(copyAmount);
17041720

17051721
var result = await writer.FlushAsync();
17061722

1723+
reader.AdvanceTo(bufferSlice.End);
1724+
17071725
if (result.IsCompleted || result.IsCanceled)
17081726
{
17091727
// flushResult should not be canceled.
@@ -1718,7 +1736,7 @@ private async Task CopyPipe(PipeReader reader, PipeWriter writer)
17181736
}
17191737
finally
17201738
{
1721-
await reader.CompleteAsync();
1739+
await reader.CompleteAsync(error);
17221740
await writer.CompleteAsync(error);
17231741
}
17241742
}

0 commit comments

Comments
 (0)