public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(this);
if (NetEventSource.IsEnabled) NetEventSource.Info(this, "buffer.Length:" + buffer.Length + " size:" + size + " offset:" + offset);
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0 || offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (size < 0 || size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
if (size == 0 || _closed)
{
if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
HttpRequestStreamAsyncResult result = new HttpRequestStreamAsyncResult(this, state, callback);
result.InvokeCallback((uint)0);
return result;
}
HttpRequestStreamAsyncResult asyncResult = null;
uint dataRead = 0;
if (_dataChunkIndex != -1)
{
dataRead = Interop.HttpApi.GetChunks(_httpContext.Request.RequestBuffer, _httpContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
if (_dataChunkIndex != -1 && dataRead == size)
{
asyncResult = new HttpRequestStreamAsyncResult(_httpContext.RequestQueueBoundHandle, this, state, callback, buffer, offset, (uint)size, 0);
asyncResult.InvokeCallback(dataRead);
}
}
if (_dataChunkIndex == -1 && dataRead < size)
{
if (NetEventSource.IsEnabled) NetEventSource.Info(this, "size:" + size + " offset:" + offset);
uint statusCode = 0;
offset += (int)dataRead;
size -= (int)dataRead;
//the http.sys team recommends that we limit the size to 128kb
if (size > MaxReadSize)
{
size = MaxReadSize;
}
asyncResult = new HttpRequestStreamAsyncResult(_httpContext.RequestQueueBoundHandle, this, state, callback, buffer, offset, (uint)size, dataRead);
uint bytesReturned;
try
{
fixed (byte* pBuffer = buffer)
{
// issue unmanaged blocking call
if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Calling Interop.HttpApi.HttpReceiveRequestEntityBody");
uint flags = 0;
if (!_inOpaqueMode)
{
flags = (uint)Interop.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY;
}
statusCode =
Interop.HttpApi.HttpReceiveRequestEntityBody(
_httpContext.RequestQueueHandle,
_httpContext.RequestId,
flags,
asyncResult._pPinnedBuffer,
(uint)size,
out bytesReturned,
asyncResult._pOverlapped);
if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Call to Interop.HttpApi.HttpReceiveRequestEntityBody returned:" + statusCode + " dataRead:" + dataRead);
}
}
catch (Exception e)
{
if (NetEventSource.IsEnabled) NetEventSource.Error(this, e.ToString());
asyncResult.InternalCleanup();
throw;
}
if (statusCode != Interop.HttpApi.ERROR_SUCCESS && statusCode != Interop.HttpApi.ERROR_IO_PENDING)
{
asyncResult.InternalCleanup();
if (statusCode == Interop.HttpApi.ERROR_HANDLE_EOF)
{
asyncResult = new HttpRequestStreamAsyncResult(this, state, callback, dataRead);
asyncResult.InvokeCallback((uint)0);
}
else
{
Exception exception = new HttpListenerException((int)statusCode);
if (NetEventSource.IsEnabled) NetEventSource.Error(this, exception.ToString());
asyncResult.InternalCleanup();
throw exception;
}
}
else if (statusCode == Interop.HttpApi.ERROR_SUCCESS &&
HttpListener.SkipIOCPCallbackOnSuccess)
{
// IO operation completed synchronously - callback won't be called to signal completion.
asyncResult.IOCompleted(statusCode, bytesReturned);
}
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
return asyncResult;
}