// Begin an asynchronous read of the request entity body. To read the entire entity, invoke // repeatedly until total bytes read is equal to Request.ContentLength or EndRead indicates // that zero bytes were read. If Request.ContentLength is zero and the request is chunked, // then invoke repeatedly until EndRead indicates that zero bytes were read. // // If an error occurs and the client is no longer connected, an HttpException will be thrown. // // This implements Stream.BeginRead, and as such, should throw // exceptions as described on MSDN when errors occur. public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) { // Do as Stream does. if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0) throw new ArgumentOutOfRangeException("offset"); if (count < 0) throw new ArgumentOutOfRangeException("count"); if (buffer.Length - offset < count) throw new ArgumentException(SR.GetString(SR.InvalidOffsetOrCount, "offset", "count")); if (_ecb == IntPtr.Zero) throw new InvalidOperationException(); ReadAsyncResult ar = new ReadAsyncResult(callback, state, buffer, offset, count, updatePerfCounter: false); if (count == 0) { ar.Complete(0, HResults.S_OK, IntPtr.Zero, synchronous: true); return ar; } // we only allow one async operation at a time if (Interlocked.CompareExchange(ref _asyncResultBase, ar, null) != null) throw new InvalidOperationException(SR.GetString(SR.Async_operation_pending)); // initiate async operation here if (_asyncCompletionCallback == null) { _asyncCompletionCallback = new AsyncCompletionCallback(OnAsyncCompletion); } _rootedThis = GCHandle.Alloc(this); // root for duration of async operation int hresult; try { ar.MarkCallToBeginMethodStarted(); hresult = UnsafeNativeMethods.EcbReadClientAsync(_ecb, count, _asyncCompletionCallback); } finally { ar.MarkCallToBeginMethodCompleted(); } if (hresult < 0) { _rootedThis.Free(); _asyncResultBase = null; // treat every error as if the client disconnected IncrementRequestsDisconnected(); throw new HttpException(SR.GetString(SR.ClientDisconnected), hresult); } else { return ar; } }
internal static extern int EcbReadClientAsync(IntPtr pECB, int dwBytesToRead, AsyncCompletionCallback pfnCallback);
// Begin an asynchronous flush of the response. To support this, the worker request buffers // the status, headers, and resonse body until an asynchronous flush operation is initiated. public override IAsyncResult BeginFlush(AsyncCallback callback, Object state) { if (_ecb == IntPtr.Zero) { throw new InvalidOperationException(); } FlushAsyncResult ar = new FlushAsyncResult(callback, state); // we only allow one async operation at a time if (Interlocked.CompareExchange(ref _asyncResultBase, ar, null) != null) throw new InvalidOperationException(SR.GetString(SR.Async_operation_pending)); // initiate async operation here if (_asyncCompletionCallback == null) { _asyncCompletionCallback = new AsyncCompletionCallback(OnAsyncCompletion); } try { ar.MarkCallToBeginMethodStarted(); FlushResponse(finalFlush: false); } finally { ar.MarkCallToBeginMethodCompleted(); } return ar; }