React to new SocketHttpHandler (#434)

This commit is contained in:
Chris Ross 2018-03-16 10:56:36 -07:00 committed by GitHub
parent 80345b7f8f
commit fbc5b64cd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 131 additions and 137 deletions

View File

@ -4,17 +4,17 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="Package Versions"> <PropertyGroup Label="Package Versions">
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview2-15728</InternalAspNetCoreSdkPackageVersion> <InternalAspNetCoreSdkPackageVersion>2.1.0-preview2-15728</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.0-preview2-30272</MicrosoftAspNetCoreAuthenticationCorePackageVersion> <MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.0-preview2-30301</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.1.0-preview2-30272</MicrosoftAspNetCoreHostingPackageVersion> <MicrosoftAspNetCoreHostingPackageVersion>2.1.0-preview2-30301</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview2-30272</MicrosoftAspNetCoreTestingPackageVersion> <MicrosoftAspNetCoreTestingPackageVersion>2.1.0-preview2-30301</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.0-preview2-30272</MicrosoftExtensionsLoggingConsolePackageVersion> <MicrosoftExtensionsLoggingConsolePackageVersion>2.1.0-preview2-30301</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion> <MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview2-26225-03</MicrosoftNETCoreApp21PackageVersion> <MicrosoftNETCoreApp21PackageVersion>2.1.0-preview2-26308-01</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview2-30272</MicrosoftNetHttpHeadersPackageVersion> <MicrosoftNetHttpHeadersPackageVersion>2.1.0-preview2-30301</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.0</MicrosoftNETTestSdkPackageVersion> <MicrosoftNETTestSdkPackageVersion>15.6.0</MicrosoftNETTestSdkPackageVersion>
<MicrosoftWin32RegistryPackageVersion>4.5.0-preview2-26224-02</MicrosoftWin32RegistryPackageVersion> <MicrosoftWin32RegistryPackageVersion>4.5.0-preview2-26308-02</MicrosoftWin32RegistryPackageVersion>
<SystemNetHttpWinHttpHandlerPackageVersion>4.5.0-preview2-26224-02</SystemNetHttpWinHttpHandlerPackageVersion> <SystemNetHttpWinHttpHandlerPackageVersion>4.5.0-preview2-26308-02</SystemNetHttpWinHttpHandlerPackageVersion>
<SystemSecurityPrincipalWindowsPackageVersion>4.5.0-preview2-26224-02</SystemSecurityPrincipalWindowsPackageVersion> <SystemSecurityPrincipalWindowsPackageVersion>4.5.0-preview2-26308-02</SystemSecurityPrincipalWindowsPackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion> <XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion> <XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
</PropertyGroup> </PropertyGroup>

View File

@ -133,12 +133,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys
dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
} }
if (_dataChunkIndex == -1 && dataRead < size) if (_dataChunkIndex == -1 && dataRead == 0)
{ {
uint statusCode = 0; uint statusCode = 0;
uint extraDataRead = 0; uint extraDataRead = 0;
offset += (int)dataRead;
size -= (int)dataRead;
// the http.sys team recommends that we limit the size to 128kb // the http.sys team recommends that we limit the size to 128kb
if (size > MaxReadSize) if (size > MaxReadSize)
@ -209,72 +207,68 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{ {
dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
if (_dataChunkIndex != -1 && dataRead == size) if (dataRead > 0)
{ {
asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, 0); asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, 0);
asyncResult.Complete((int)dataRead); asyncResult.Complete((int)dataRead);
return asyncResult;
} }
} }
if (_dataChunkIndex == -1 && dataRead < size) uint statusCode = 0;
// the http.sys team recommends that we limit the size to 128kb
if (size > MaxReadSize)
{ {
uint statusCode = 0; size = MaxReadSize;
offset += (int)dataRead; }
size -= (int)dataRead;
// the http.sys team recommends that we limit the size to 128kb asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, dataRead);
if (size > MaxReadSize) uint bytesReturned;
{
size = MaxReadSize;
}
asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, dataRead); try
uint bytesReturned; {
uint flags = 0;
try statusCode =
{ HttpApi.HttpReceiveRequestEntityBody(
uint flags = 0; RequestQueueHandle,
RequestId,
flags,
asyncResult.PinnedBuffer,
(uint)size,
out bytesReturned,
asyncResult.NativeOverlapped);
}
catch (Exception e)
{
LogHelper.LogException(Logger, "BeginRead", e);
asyncResult.Dispose();
throw;
}
statusCode = if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
HttpApi.HttpReceiveRequestEntityBody( {
RequestQueueHandle, asyncResult.Dispose();
RequestId, if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
flags,
asyncResult.PinnedBuffer,
(uint)size,
out bytesReturned,
asyncResult.NativeOverlapped);
}
catch (Exception e)
{ {
LogHelper.LogException(Logger, "BeginRead", e); asyncResult = new RequestStreamAsyncResult(this, state, callback, dataRead);
asyncResult.Dispose(); asyncResult.Complete((int)bytesReturned);
throw;
} }
else
if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
{ {
asyncResult.Dispose(); Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode));
if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) LogHelper.LogException(Logger, "BeginRead", exception);
{ Abort();
asyncResult = new RequestStreamAsyncResult(this, state, callback, dataRead); throw exception;
asyncResult.Complete((int)bytesReturned);
}
else
{
Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode));
LogHelper.LogException(Logger, "BeginRead", exception);
Abort();
throw exception;
}
}
else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
HttpSysListener.SkipIOCPCallbackOnSuccess)
{
// IO operation completed synchronously - callback won't be called to signal completion.
asyncResult.IOCompleted(statusCode, bytesReturned);
} }
} }
else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
HttpSysListener.SkipIOCPCallbackOnSuccess)
{
// IO operation completed synchronously - callback won't be called to signal completion.
asyncResult.IOCompleted(statusCode, bytesReturned);
}
return asyncResult; return asyncResult;
} }
@ -322,7 +316,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
if (_dataChunkIndex != -1) if (_dataChunkIndex != -1)
{ {
dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
if (_dataChunkIndex != -1 && dataRead == size) if (dataRead > 0)
{ {
UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead); UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead);
if (TryCheckSizeLimit((int)dataRead, out var exception)) if (TryCheckSizeLimit((int)dataRead, out var exception))
@ -334,85 +328,82 @@ namespace Microsoft.AspNetCore.Server.HttpSys
} }
} }
if (_dataChunkIndex == -1 && dataRead < size) uint statusCode = 0;
offset += (int)dataRead;
size -= (int)dataRead;
// the http.sys team recommends that we limit the size to 128kb
if (size > MaxReadSize)
{ {
uint statusCode = 0; size = MaxReadSize;
offset += (int)dataRead; }
size -= (int)dataRead;
// the http.sys team recommends that we limit the size to 128kb var cancellationRegistration = default(CancellationTokenRegistration);
if (size > MaxReadSize) if (cancellationToken.CanBeCanceled)
{ {
size = MaxReadSize; cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken);
} }
var cancellationRegistration = default(CancellationTokenRegistration); asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead, cancellationRegistration);
if (cancellationToken.CanBeCanceled) uint bytesReturned;
{
cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken);
}
asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead, cancellationRegistration); try
uint bytesReturned; {
uint flags = 0;
try statusCode =
{ HttpApi.HttpReceiveRequestEntityBody(
uint flags = 0; RequestQueueHandle,
RequestId,
flags,
asyncResult.PinnedBuffer,
(uint)size,
out bytesReturned,
asyncResult.NativeOverlapped);
}
catch (Exception e)
{
asyncResult.Dispose();
Abort();
LogHelper.LogException(Logger, "ReadAsync", e);
throw;
}
statusCode = if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
HttpApi.HttpReceiveRequestEntityBody( {
RequestQueueHandle, asyncResult.Dispose();
RequestId, if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
flags,
asyncResult.PinnedBuffer,
(uint)size,
out bytesReturned,
asyncResult.NativeOverlapped);
}
catch (Exception e)
{ {
asyncResult.Dispose();
Abort();
LogHelper.LogException(Logger, "ReadAsync", e);
throw;
}
if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
{
asyncResult.Dispose();
if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
{
uint totalRead = dataRead + bytesReturned;
UpdateAfterRead(statusCode, totalRead);
if (TryCheckSizeLimit((int)totalRead, out var exception))
{
return Task.FromException<int>(exception);
}
// TODO: Verbose log totalRead
return Task.FromResult<int>((int)totalRead);
}
else
{
Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode));
LogHelper.LogException(Logger, "ReadAsync", exception);
Abort();
throw exception;
}
}
else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
HttpSysListener.SkipIOCPCallbackOnSuccess)
{
// IO operation completed synchronously - callback won't be called to signal completion.
asyncResult.Dispose();
uint totalRead = dataRead + bytesReturned; uint totalRead = dataRead + bytesReturned;
UpdateAfterRead(statusCode, totalRead); UpdateAfterRead(statusCode, totalRead);
if (TryCheckSizeLimit((int)totalRead, out var exception)) if (TryCheckSizeLimit((int)totalRead, out var exception))
{ {
return Task.FromException<int>(exception); return Task.FromException<int>(exception);
} }
// TODO: Verbose log // TODO: Verbose log totalRead
return Task.FromResult<int>((int)totalRead); return Task.FromResult<int>((int)totalRead);
} }
else
{
Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode));
LogHelper.LogException(Logger, "ReadAsync", exception);
Abort();
throw exception;
}
}
else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
HttpSysListener.SkipIOCPCallbackOnSuccess)
{
// IO operation completed synchronously - callback won't be called to signal completion.
asyncResult.Dispose();
uint totalRead = dataRead + bytesReturned;
UpdateAfterRead(statusCode, totalRead);
if (TryCheckSizeLimit((int)totalRead, out var exception))
{
return Task.FromException<int>(exception);
}
// TODO: Verbose log
return Task.FromResult<int>((int)totalRead);
} }
return asyncResult.Task; return asyncResult.Task;
} }

View File

@ -344,7 +344,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
content.Block.Release(); content.Block.Release();
context.Dispose(); context.Dispose();
await Assert.ThrowsAsync<TaskCanceledException>(async () => await responseTask); await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await responseTask);
} }
} }
@ -421,6 +421,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{ {
await stream.WriteAsync(new byte[5], 0, 5); await stream.WriteAsync(new byte[5], 0, 5);
await stream.FlushAsync();
await Block.WaitAsync(); await Block.WaitAsync();
await stream.WriteAsync(new byte[5], 0, 5); await stream.WriteAsync(new byte[5], 0, 5);
} }

View File

@ -427,7 +427,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
var context = await server.AcceptAsync(Utilities.DefaultTimeout); var context = await server.AcceptAsync(Utilities.DefaultTimeout);
// First write sends headers // First write sends headers
cts.Cancel(); cts.Cancel();
await Assert.ThrowsAsync<TaskCanceledException>(() => responseTask); await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)));
Assert.Throws<IOException>(() => Assert.Throws<IOException>(() =>
{ {
@ -458,7 +458,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
// First write sends headers // First write sends headers
cts.Cancel(); cts.Cancel();
await Assert.ThrowsAsync<TaskCanceledException>(() => responseTask); await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)));
await Assert.ThrowsAsync<IOException>(async () => await Assert.ThrowsAsync<IOException>(async () =>
@ -489,7 +489,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
var context = await server.AcceptAsync(Utilities.DefaultTimeout); var context = await server.AcceptAsync(Utilities.DefaultTimeout);
// First write sends headers // First write sends headers
cts.Cancel(); cts.Cancel();
await Assert.ThrowsAsync<TaskCanceledException>(() => responseTask); await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)));
// It can take several tries before Write notices the disconnect. // It can take several tries before Write notices the disconnect.
for (int i = 0; i < Utilities.WriteRetryLimit; i++) for (int i = 0; i < Utilities.WriteRetryLimit; i++)
@ -512,7 +512,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
var context = await server.AcceptAsync(Utilities.DefaultTimeout); var context = await server.AcceptAsync(Utilities.DefaultTimeout);
// First write sends headers // First write sends headers
cts.Cancel(); cts.Cancel();
await Assert.ThrowsAsync<TaskCanceledException>(() => responseTask); await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)));
// It can take several tries before Write notices the disconnect. // It can take several tries before Write notices the disconnect.
for (int i = 0; i < Utilities.WriteRetryLimit; i++) for (int i = 0; i < Utilities.WriteRetryLimit; i++)

View File

@ -468,7 +468,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
// First write sends headers // First write sends headers
cts.Cancel(); cts.Cancel();
await Assert.ThrowsAsync<TaskCanceledException>(() => responseTask); await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)));
await Assert.ThrowsAsync<IOException>(async () => await Assert.ThrowsAsync<IOException>(async () =>
@ -499,7 +499,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
var context = await server.AcceptAsync(Utilities.DefaultTimeout); var context = await server.AcceptAsync(Utilities.DefaultTimeout);
// First write sends headers // First write sends headers
cts.Cancel(); cts.Cancel();
await Assert.ThrowsAsync<TaskCanceledException>(() => responseTask); await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)));
// It can take several tries before Send notices the disconnect. // It can take several tries before Send notices the disconnect.
for (int i = 0; i < Utilities.WriteRetryLimit; i++) for (int i = 0; i < Utilities.WriteRetryLimit; i++)

View File

@ -96,7 +96,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
Assert.True(canceled.WaitOne(interval), "canceled"); Assert.True(canceled.WaitOne(interval), "canceled");
Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested");
await Assert.ThrowsAsync<TaskCanceledException>(() => responseTask); await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
context.Dispose(); context.Dispose();
} }
@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener
var context = await server.AcceptAsync(Utilities.DefaultTimeout); var context = await server.AcceptAsync(Utilities.DefaultTimeout);
client.CancelPendingRequests(); client.CancelPendingRequests();
await Assert.ThrowsAsync<TaskCanceledException>(() => responseTask); await Assert.ThrowsAnyAsync<OperationCanceledException>(() => responseTask);
var ct = context.DisconnectToken; var ct = context.DisconnectToken;
Assert.True(ct.CanBeCanceled, "CanBeCanceled"); Assert.True(ct.CanBeCanceled, "CanBeCanceled");

View File

@ -413,6 +413,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{ {
await stream.WriteAsync(new byte[10], 0, 10); await stream.WriteAsync(new byte[10], 0, 10);
await stream.FlushAsync();
Assert.True(await Block.WaitAsync(TimeSpan.FromSeconds(10))); Assert.True(await Block.WaitAsync(TimeSpan.FromSeconds(10)));
await stream.WriteAsync(new byte[10], 0, 10); await stream.WriteAsync(new byte[10], 0, 10);
} }

View File

@ -232,7 +232,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{ {
await stream.WriteAsync(new byte[5], 0, 5); await stream.WriteAsync(new byte[5], 0, 5);
await Block.WaitAsync(); await stream.FlushAsync();
Assert.True(await Block.WaitAsync(TimeSpan.FromSeconds(10)));
await stream.WriteAsync(new byte[5], 0, 5); await stream.WriteAsync(new byte[5], 0, 5);
} }