private unsafe bool ReadAsyncFast(HttpListenerAsyncEventArgs eventArgs)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Enter(this);
}
eventArgs.StartOperationCommon(this, _inputStream.InternalHttpContext.RequestQueueBoundHandle);
eventArgs.StartOperationReceive();
uint statusCode = 0;
bool completedAsynchronously = false;
try
{
Debug.Assert(eventArgs.Buffer != null, "'BufferList' is not supported for read operations.");
if (eventArgs.Count == 0 || _inputStream.Closed)
{
eventArgs.FinishOperationSuccess(0, true);
return false;
}
uint dataRead = 0;
int offset = eventArgs.Offset;
int remainingCount = eventArgs.Count;
if (_inputStream.BufferedDataChunksAvailable)
{
dataRead = _inputStream.GetChunks(eventArgs.Buffer, eventArgs.Offset, eventArgs.Count);
if (_inputStream.BufferedDataChunksAvailable && dataRead == eventArgs.Count)
{
eventArgs.FinishOperationSuccess(eventArgs.Count, true);
return false;
}
}
Debug.Assert(!_inputStream.BufferedDataChunksAvailable, "'m_InputStream.BufferedDataChunksAvailable' MUST BE 'FALSE' at this point.");
Debug.Assert(dataRead <= eventArgs.Count, "'dataRead' MUST NOT be bigger than 'eventArgs.Count'.");
if (dataRead != 0)
{
offset += (int)dataRead;
remainingCount -= (int)dataRead;
//the http.sys team recommends that we limit the size to 128kb
if (remainingCount > HttpRequestStream.MaxReadSize)
{
remainingCount = HttpRequestStream.MaxReadSize;
}
eventArgs.SetBuffer(eventArgs.Buffer, offset, remainingCount);
}
else if (remainingCount > HttpRequestStream.MaxReadSize)
{
remainingCount = HttpRequestStream.MaxReadSize;
eventArgs.SetBuffer(eventArgs.Buffer, offset, remainingCount);
}
uint flags = 0;
uint bytesReturned = 0;
statusCode =
Interop.HttpApi.HttpReceiveRequestEntityBody(
_inputStream.InternalHttpContext.RequestQueueHandle,
_inputStream.InternalHttpContext.RequestId,
flags,
(byte*)_webSocket.InternalBuffer.ToIntPtr(eventArgs.Offset),
(uint)eventArgs.Count,
out bytesReturned,
eventArgs.NativeOverlapped);
if (statusCode != Interop.HttpApi.ERROR_SUCCESS &&
statusCode != Interop.HttpApi.ERROR_IO_PENDING &&
statusCode != Interop.HttpApi.ERROR_HANDLE_EOF)
{
throw new HttpListenerException((int)statusCode);
}
else if (statusCode == Interop.HttpApi.ERROR_SUCCESS &&
HttpListener.SkipIOCPCallbackOnSuccess)
{
// IO operation completed synchronously. No IO completion port callback is used because
// it was disabled in SwitchToOpaqueMode()
eventArgs.FinishOperationSuccess((int)bytesReturned, true);
completedAsynchronously = false;
}
else
{
completedAsynchronously = true;
}
}
catch (Exception e)
{
_readEventArgs.FinishOperationFailure(e, true);
_outputStream.SetClosedFlag();
_outputStream.InternalHttpContext.Abort();
throw;
}
finally
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Exit(this, completedAsynchronously);
}
}
return completedAsynchronously;
}