Skip to content
This repository was archived by the owner on Mar 19, 2019. It is now read-only.

Commit e2e5779

Browse files
committed
New setting EnableKernelResponseBuffering to improve response throughtput
1 parent ede025f commit e2e5779

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ public HttpSysOptions()
6161
/// </summary>
6262
public bool ThrowWriteExceptions { get; set; }
6363

64+
/// <summary>
65+
/// Enable buffering of response data in the Kernel.
66+
/// It should be used by an application doing synchronous I/O or by an application doing asynchronous I/O with
67+
/// no more than one outstanding write at a time, and can significantly improve throughput over high-latency connections.
68+
/// Applications that use asynchronous I/O and that may have more than one send outstanding at a time should not use this flag.
69+
/// Enabling this can results in higher CPU and memory usage by Http.Sys.
70+
/// </summary>
71+
public bool EnableKernelResponseBuffering { get; set; }
72+
6473
/// <summary>
6574
/// Gets or sets the maximum number of concurrent connections to accept, -1 for infinite, or null to
6675
/// use the machine wide setting from the registry. The default value is null.

src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ internal RequestContext RequestContext
4343

4444
internal bool ThrowWriteExceptions => RequestContext.Server.Options.ThrowWriteExceptions;
4545

46+
internal bool EnableKernelResponseBuffering => RequestContext.Server.Options.EnableKernelResponseBuffering;
47+
4648
internal bool IsDisposed => _disposed;
4749

4850
public override bool CanSeek
@@ -436,6 +438,10 @@ private HttpApiTypes.HTTP_FLAGS ComputeLeftToWrite(long writeCount, bool endOfRe
436438
else if (!endOfRequest && _leftToWrite != writeCount)
437439
{
438440
flags |= HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
441+
if (EnableKernelResponseBuffering)
442+
{
443+
flags |= HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA;
444+
}
439445
}
440446

441447
// Update _leftToWrite now so we can queue up additional async writes.

test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ResponseBodyTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,41 @@ public async Task ResponseBody_WriteNoHeaders_SetsChunked()
3838
}
3939
}
4040

41+
[ConditionalTheory]
42+
[InlineData(true)]
43+
[InlineData(false)]
44+
public async Task ResponseBody_WriteNoHeaders_SetsChunked_LargeBody(bool enableKernelBuffering)
45+
{
46+
const int WriteSize = 1024 * 1024;
47+
const int NumWrites = 32;
48+
49+
string address;
50+
using (Utilities.CreateHttpServer(
51+
baseAddress: out address,
52+
configureOptions: options => { options.EnableKernelResponseBuffering = enableKernelBuffering; },
53+
app: async httpContext =>
54+
{
55+
httpContext.Features.Get<IHttpBodyControlFeature>().AllowSynchronousIO = true;
56+
for (int i = 0; i < NumWrites - 1; i++)
57+
{
58+
httpContext.Response.Body.Write(new byte[WriteSize], 0, WriteSize);
59+
}
60+
await httpContext.Response.Body.WriteAsync(new byte[WriteSize], 0, WriteSize);
61+
}))
62+
{
63+
var response = await SendRequestAsync(address);
64+
Assert.Equal(200, (int)response.StatusCode);
65+
Assert.Equal(new Version(1, 1), response.Version);
66+
IEnumerable<string> ignored;
67+
Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length");
68+
Assert.True(response.Headers.TransferEncodingChunked.HasValue, "Chunked");
69+
70+
var bytes = await response.Content.ReadAsByteArrayAsync();
71+
Assert.Equal(WriteSize * NumWrites, bytes.Length);
72+
Assert.True(bytes.All(b => b == 0));
73+
}
74+
}
75+
4176
[ConditionalFact]
4277
public async Task ResponseBody_WriteNoHeadersAndFlush_DefaultsToChunked()
4378
{

0 commit comments

Comments
 (0)