private unsafe bool WriteAsyncFast(HttpListenerAsyncEventArgs eventArgs)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Enter(this);
}
Interop.HttpApi.HTTP_FLAGS flags = Interop.HttpApi.HTTP_FLAGS.NONE;
eventArgs.StartOperationCommon(this, _outputStream.InternalHttpContext.RequestQueueBoundHandle);
eventArgs.StartOperationSend();
uint statusCode;
bool completedAsynchronously = false;
try
{
if (_outputStream.Closed ||
(eventArgs.Buffer != null && eventArgs.Count == 0))
{
eventArgs.FinishOperationSuccess(eventArgs.Count, true);
return false;
}
if (eventArgs.ShouldCloseOutput)
{
flags |= Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT;
}
else
{
flags |= Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
// When using HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA HTTP.SYS will copy the payload to
// kernel memory (Non-Paged Pool). Http.Sys will buffer up to
// Math.Min(16 MB, current TCP window size)
flags |= Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA;
}
uint bytesSent;
statusCode =
Interop.HttpApi.HttpSendResponseEntityBody(
_outputStream.InternalHttpContext.RequestQueueHandle,
_outputStream.InternalHttpContext.RequestId,
(uint)flags,
eventArgs.EntityChunkCount,
(Interop.HttpApi.HTTP_DATA_CHUNK*)eventArgs.EntityChunks,
&bytesSent,
SafeLocalAllocHandle.Zero,
0,
eventArgs.NativeOverlapped,
null);
if (statusCode != Interop.HttpApi.ERROR_SUCCESS &&
statusCode != Interop.HttpApi.ERROR_IO_PENDING)
{
throw new HttpListenerException((int)statusCode);
}
else if (statusCode == Interop.HttpApi.ERROR_SUCCESS &&
HttpListener.SkipIOCPCallbackOnSuccess)
{
// IO operation completed synchronously - callback won't be called to signal completion.
eventArgs.FinishOperationSuccess((int)bytesSent, true);
completedAsynchronously = false;
}
else
{
completedAsynchronously = true;
}
}
catch (Exception e)
{
_writeEventArgs.FinishOperationFailure(e, true);
_outputStream.SetClosedFlag();
_outputStream.InternalHttpContext.Abort();
throw;
}
finally
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Exit(this, completedAsynchronously);
}
}
return completedAsynchronously;
}