// return value indicates sync vs async completion // false: sync completion // true: async completion 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; }
// return value indicates sync vs async completion // false: sync completion // true: async completion or error private unsafe bool ReadAsyncFast(HttpListenerAsyncEventArgs eventArgs) { eventArgs.StartOperationCommon(this, _inputStream.InternalHttpContext.RequestQueueBoundHandle); eventArgs.StartOperationReceive(); bool completedAsynchronouslyOrWithError; 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; uint 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); completedAsynchronouslyOrWithError = false; } else if (statusCode == Interop.HttpApi.ERROR_HANDLE_EOF) { eventArgs.FinishOperationSuccess(0, true); completedAsynchronouslyOrWithError = false; } else { completedAsynchronouslyOrWithError = true; } } catch (Exception e) { _readEventArgs !.FinishOperationFailure(e, true); _outputStream.SetClosedFlag(); _outputStream.InternalHttpContext.Abort(); completedAsynchronouslyOrWithError = true; } return(completedAsynchronouslyOrWithError); }
// return value indicates [....] vs async completion // false: [....] completion // true: async completion private unsafe bool ReadAsyncFast(HttpListenerAsyncEventArgs eventArgs) { if (WebSocketBase.LoggingEnabled) { Logging.Enter(Logging.WebSockets, this, Methods.ReadAsyncFast, string.Empty); } eventArgs.StartOperationCommon(this); eventArgs.StartOperationReceive(); uint statusCode = 0; bool completedAsynchronously = false; try { Contract.Assert(eventArgs.Buffer != null, "'BufferList' is not supported for read operations."); if (eventArgs.Count == 0 || m_InputStream.Closed) { eventArgs.FinishOperationSuccess(0, true); return(false); } uint dataRead = 0; int offset = eventArgs.Offset; int remainingCount = eventArgs.Count; if (m_InputStream.BufferedDataChunksAvailable) { dataRead = m_InputStream.GetChunks(eventArgs.Buffer, eventArgs.Offset, eventArgs.Count); if (m_InputStream.BufferedDataChunksAvailable && dataRead == eventArgs.Count) { eventArgs.FinishOperationSuccess(eventArgs.Count, true); return(false); } } Contract.Assert(!m_InputStream.BufferedDataChunksAvailable, "'m_InputStream.BufferedDataChunksAvailable' MUST BE 'FALSE' at this point."); Contract.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); } m_InputStream.InternalHttpContext.EnsureBoundHandle(); uint flags = 0; uint bytesReturned = 0; statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody2( m_InputStream.InternalHttpContext.RequestQueueHandle, m_InputStream.InternalHttpContext.RequestId, flags, (byte *)m_WebSocket.InternalBuffer.ToIntPtr(eventArgs.Offset), (uint)eventArgs.Count, out bytesReturned, eventArgs.NativeOverlapped); if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { throw new HttpListenerException((int)statusCode); } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.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) { m_ReadEventArgs.FinishOperationFailure(e, true); m_OutputStream.SetClosedFlag(); m_OutputStream.InternalHttpContext.Abort(); throw; } finally { if (WebSocketBase.LoggingEnabled) { Logging.Exit(Logging.WebSockets, this, Methods.ReadAsyncFast, completedAsynchronously); } } return(completedAsynchronously); }