private static void OnReadCompleted(object sender, HttpListenerAsyncEventArgs eventArgs)
        {
            Contract.Assert(eventArgs != null, "'eventArgs' MUST NOT be NULL.");
            WebSocketHttpListenerDuplexStream thisPtr = eventArgs.CurrentStream;

            Contract.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL.");
#if DEBUG
            Contract.Assert(Interlocked.Decrement(ref thisPtr.m_OutstandingOperations.m_Reads) >= 0,
                            "'thisPtr.m_OutstandingOperations.m_Reads' MUST NOT be negative.");
#endif

            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Enter(Logging.WebSockets, thisPtr, Methods.OnReadCompleted, string.Empty);
            }

            if (eventArgs.Exception != null)
            {
                thisPtr.m_ReadTaskCompletionSource.TrySetException(eventArgs.Exception);
            }
            else
            {
                thisPtr.m_ReadTaskCompletionSource.TrySetResult(eventArgs.BytesTransferred);
            }

            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Exit(Logging.WebSockets, thisPtr, Methods.OnReadCompleted, string.Empty);
            }
        }
        public void SwitchToOpaqueMode(WebSocketBase webSocket)
        {
            Debug.Assert(webSocket != null, "'webSocket' MUST NOT be NULL.");
            Debug.Assert(_outputStream != null, "'m_OutputStream' MUST NOT be NULL.");
            Debug.Assert(_outputStream.InternalHttpContext != null,
                         "'m_OutputStream.InternalHttpContext' MUST NOT be NULL.");
            Debug.Assert(_outputStream.InternalHttpContext.Response != null,
                         "'m_OutputStream.InternalHttpContext.Response' MUST NOT be NULL.");
            Debug.Assert(_outputStream.InternalHttpContext.Response.SentHeaders,
                         "Headers MUST have been sent at this point.");
            Debug.Assert(!_inOpaqueMode, "SwitchToOpaqueMode MUST NOT be called multiple times.");

            if (_inOpaqueMode)
            {
                throw new InvalidOperationException();
            }

            _webSocket                 = webSocket;
            _inOpaqueMode              = true;
            _readEventArgs             = new HttpListenerAsyncEventArgs(webSocket, this);
            _readEventArgs.Completed  += s_OnReadCompleted;
            _writeEventArgs            = new HttpListenerAsyncEventArgs(webSocket, this);
            _writeEventArgs.Completed += s_OnWriteCompleted;

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Associate(this, webSocket);
            }
        }
        public void SwitchToOpaqueMode(WebSocketBase webSocket)
        {
            Contract.Assert(webSocket != null, "'webSocket' MUST NOT be NULL.");
            Contract.Assert(m_OutputStream != null, "'m_OutputStream' MUST NOT be NULL.");
            Contract.Assert(m_OutputStream.InternalHttpContext != null,
                            "'m_OutputStream.InternalHttpContext' MUST NOT be NULL.");
            Contract.Assert(m_OutputStream.InternalHttpContext.Response != null,
                            "'m_OutputStream.InternalHttpContext.Response' MUST NOT be NULL.");
            Contract.Assert(m_OutputStream.InternalHttpContext.Response.SentHeaders,
                            "Headers MUST have been sent at this point.");
            Contract.Assert(!m_InOpaqueMode, "SwitchToOpaqueMode MUST NOT be called multiple times.");

            if (m_InOpaqueMode)
            {
                throw new InvalidOperationException();
            }

            m_WebSocket                 = webSocket;
            m_InOpaqueMode              = true;
            m_ReadEventArgs             = new HttpListenerAsyncEventArgs(webSocket, this);
            m_ReadEventArgs.Completed  += s_OnReadCompleted;
            m_WriteEventArgs            = new HttpListenerAsyncEventArgs(webSocket, this);
            m_WriteEventArgs.Completed += s_OnWriteCompleted;

            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Associate(Logging.WebSockets, this, webSocket);
            }
        }
        private static void OnReadCompleted(object sender, HttpListenerAsyncEventArgs eventArgs)
        {
            Debug.Assert(eventArgs != null, "'eventArgs' MUST NOT be NULL.");
            WebSocketHttpListenerDuplexStream thisPtr = eventArgs.CurrentStream;

            Debug.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL.");
#if DEBUG
            Debug.Assert(Interlocked.Decrement(ref thisPtr._outstandingOperations._reads) >= 0,
                         "'thisPtr.m_OutstandingOperations.m_Reads' MUST NOT be negative.");
#endif

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(thisPtr);
            }

            if (eventArgs.Exception != null)
            {
                thisPtr._readTaskCompletionSource.TrySetException(eventArgs.Exception);
            }
            else
            {
                thisPtr._readTaskCompletionSource.TrySetResult(eventArgs.BytesTransferred);
            }

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Exit(thisPtr);
            }
        }
            protected virtual void OnCompleted(HttpListenerAsyncEventArgs e)
            {
                EventHandler <HttpListenerAsyncEventArgs> handler = m_Completed;

                if (handler != null)
                {
                    handler(e.m_CurrentStream, e);
                }
            }
        private static void OnWriteCompleted(object?sender, HttpListenerAsyncEventArgs eventArgs)
        {
            Debug.Assert(eventArgs != null, "'eventArgs' MUST NOT be NULL.");
            WebSocketHttpListenerDuplexStream thisPtr = eventArgs.CurrentStream;

            Debug.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL.");
#if DEBUG
            Debug.Assert(Interlocked.Decrement(ref thisPtr._outstandingOperations._writes) >= 0,
                         "'thisPtr.m_OutstandingOperations.m_Writes' MUST NOT be negative.");
#endif

            if (eventArgs.Exception != null)
            {
                thisPtr._writeTaskCompletionSource !.TrySetException(eventArgs.Exception);
            }
            else
            {
                thisPtr._writeTaskCompletionSource !.TrySetResult();
            }
        }
 protected virtual void OnCompleted(HttpListenerAsyncEventArgs e)
 {
     m_Completed?.Invoke(e._currentStream, e);
 }
        private static void OnReadCompleted(object sender, HttpListenerAsyncEventArgs eventArgs)
        {
            Debug.Assert(eventArgs != null, "'eventArgs' MUST NOT be NULL.");
            WebSocketHttpListenerDuplexStream thisPtr = eventArgs.CurrentStream;
            Debug.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL.");
#if DEBUG
            Debug.Assert(Interlocked.Decrement(ref thisPtr._outstandingOperations._reads) >= 0,
                "'thisPtr.m_OutstandingOperations.m_Reads' MUST NOT be negative.");
#endif

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(thisPtr);
            }

            if (eventArgs.Exception != null)
            {
                thisPtr._readTaskCompletionSource.TrySetException(eventArgs.Exception);
            }
            else
            {
                thisPtr._readTaskCompletionSource.TrySetResult(eventArgs.BytesTransferred);
            }

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Exit(thisPtr);
            }
        }
        public void SwitchToOpaqueMode(WebSocketBase webSocket)
        {
            Debug.Assert(webSocket != null, "'webSocket' MUST NOT be NULL.");
            Debug.Assert(_outputStream != null, "'m_OutputStream' MUST NOT be NULL.");
            Debug.Assert(_outputStream.InternalHttpContext != null,
                "'m_OutputStream.InternalHttpContext' MUST NOT be NULL.");
            Debug.Assert(_outputStream.InternalHttpContext.Response != null,
                "'m_OutputStream.InternalHttpContext.Response' MUST NOT be NULL.");
            Debug.Assert(_outputStream.InternalHttpContext.Response.SentHeaders,
                "Headers MUST have been sent at this point.");
            Debug.Assert(!_inOpaqueMode, "SwitchToOpaqueMode MUST NOT be called multiple times.");

            if (_inOpaqueMode)
            {
                throw new InvalidOperationException();
            }

            _webSocket = webSocket;
            _inOpaqueMode = true;
            _readEventArgs = new HttpListenerAsyncEventArgs(webSocket, this);
            _readEventArgs.Completed += s_OnReadCompleted;
            _writeEventArgs = new HttpListenerAsyncEventArgs(webSocket, this);
            _writeEventArgs.Completed += s_OnWriteCompleted;

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Associate(this, webSocket);
            }
        }
        // return value indicates [....] vs async completion
        // false: [....] completion
        // true: async completion
        private bool WriteAsyncFast(HttpListenerAsyncEventArgs eventArgs)
        {
            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Enter(Logging.WebSockets, this, Methods.WriteAsyncFast, string.Empty);
            }

            UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE;

            eventArgs.StartOperationCommon(this);
            eventArgs.StartOperationSend();

            uint statusCode;
            bool completedAsynchronously = false;

            try
            {
                if (m_OutputStream.Closed ||
                    (eventArgs.Buffer != null && eventArgs.Count == 0))
                {
                    eventArgs.FinishOperationSuccess(eventArgs.Count, true);
                    return(false);
                }

                if (eventArgs.ShouldCloseOutput)
                {
                    flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT;
                }
                else
                {
                    flags |= UnsafeNclNativeMethods.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 |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA;
                }

                m_OutputStream.InternalHttpContext.EnsureBoundHandle();
                uint bytesSent;
                statusCode =
                    UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody2(
                        m_OutputStream.InternalHttpContext.RequestQueueHandle,
                        m_OutputStream.InternalHttpContext.RequestId,
                        (uint)flags,
                        eventArgs.EntityChunkCount,
                        eventArgs.EntityChunks,
                        out bytesSent,
                        SafeLocalFree.Zero,
                        0,
                        eventArgs.NativeOverlapped,
                        IntPtr.Zero);

                if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
                    statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
                {
                    throw new HttpListenerException((int)statusCode);
                }
                else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.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)
            {
                m_WriteEventArgs.FinishOperationFailure(e, true);
                m_OutputStream.SetClosedFlag();
                m_OutputStream.InternalHttpContext.Abort();

                throw;
            }
            finally
            {
                if (WebSocketBase.LoggingEnabled)
                {
                    Logging.Exit(Logging.WebSockets, this, Methods.WriteAsyncFast, 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);
        }
        private static void OnReadCompleted(object sender, HttpListenerAsyncEventArgs eventArgs)
        {
            Contract.Assert(eventArgs != null, "'eventArgs' MUST NOT be NULL.");
            WebSocketHttpListenerDuplexStream thisPtr = eventArgs.CurrentStream;
            Contract.Assert(thisPtr != null, "'thisPtr' MUST NOT be NULL.");
#if DEBUG
            Contract.Assert(Interlocked.Decrement(ref thisPtr.m_OutstandingOperations.m_Reads) >= 0,
                "'thisPtr.m_OutstandingOperations.m_Reads' MUST NOT be negative.");
#endif

            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Enter(Logging.WebSockets, thisPtr, Methods.OnReadCompleted, string.Empty);
            }

            if (eventArgs.Exception != null)
            {
                thisPtr.m_ReadTaskCompletionSource.TrySetException(eventArgs.Exception);
            }
            else
            {
                thisPtr.m_ReadTaskCompletionSource.TrySetResult(eventArgs.BytesTransferred);
            }

            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Exit(Logging.WebSockets, thisPtr, Methods.OnReadCompleted, string.Empty);
            }
        }
        public void SwitchToOpaqueMode(WebSocketBase webSocket)
        {
            Contract.Assert(webSocket != null, "'webSocket' MUST NOT be NULL.");
            Contract.Assert(m_OutputStream != null, "'m_OutputStream' MUST NOT be NULL.");
            Contract.Assert(m_OutputStream.InternalHttpContext != null,
                "'m_OutputStream.InternalHttpContext' MUST NOT be NULL.");
            Contract.Assert(m_OutputStream.InternalHttpContext.Response != null,
                "'m_OutputStream.InternalHttpContext.Response' MUST NOT be NULL.");
            Contract.Assert(m_OutputStream.InternalHttpContext.Response.SentHeaders,
                "Headers MUST have been sent at this point.");
            Contract.Assert(!m_InOpaqueMode, "SwitchToOpaqueMode MUST NOT be called multiple times.");

            if (m_InOpaqueMode)
            {
                throw new InvalidOperationException();
            }

            m_WebSocket = webSocket;
            m_InOpaqueMode = true;
            m_ReadEventArgs = new HttpListenerAsyncEventArgs(webSocket, this);
            m_ReadEventArgs.Completed += s_OnReadCompleted;
            m_WriteEventArgs = new HttpListenerAsyncEventArgs(webSocket, this);
            m_WriteEventArgs.Completed += s_OnWriteCompleted;

            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Associate(Logging.WebSockets, this, webSocket);
            }
        }
        // return value indicates sync vs async completion
        // false: sync completion
        // true: async completion
        private bool WriteAsyncFast(HttpListenerAsyncEventArgs eventArgs)
        {
            if (WebSocketBase.LoggingEnabled)
            {
                Logging.Enter(Logging.WebSockets, this, Methods.WriteAsyncFast, string.Empty);
            }

            UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE;

            eventArgs.StartOperationCommon(this);
            eventArgs.StartOperationSend();

            uint statusCode;
            bool completedAsynchronously = false;
            try
            {
                if (m_OutputStream.Closed || 
                    (eventArgs.Buffer != null && eventArgs.Count == 0))
                {
                    eventArgs.FinishOperationSuccess(eventArgs.Count, true);
                    return false;
                }

                if (eventArgs.ShouldCloseOutput)
                {
                    flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT;
                }
                else
                {
                    flags |= UnsafeNclNativeMethods.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 |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA;
                }

                m_OutputStream.InternalHttpContext.EnsureBoundHandle();
                uint bytesSent;
                statusCode =
                    UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody2(
                        m_OutputStream.InternalHttpContext.RequestQueueHandle,
                        m_OutputStream.InternalHttpContext.RequestId,
                        (uint)flags,
                        eventArgs.EntityChunkCount,
                        eventArgs.EntityChunks,
                        out bytesSent,
                        SafeLocalFree.Zero,
                        0,
                        eventArgs.NativeOverlapped,
                        IntPtr.Zero);

                if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
                    statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
                {
                    throw new HttpListenerException((int)statusCode);
                }
                else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.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)
            {
                m_WriteEventArgs.FinishOperationFailure(e, true);
                m_OutputStream.SetClosedFlag();
                m_OutputStream.InternalHttpContext.Abort();

                throw;
            }
            finally
            {
                if (WebSocketBase.LoggingEnabled)
                {
                    Logging.Exit(Logging.WebSockets, this, Methods.WriteAsyncFast, completedAsynchronously);
                }
            }

            return completedAsynchronously;
        }
 protected virtual void OnCompleted(HttpListenerAsyncEventArgs e)
 {
     EventHandler<HttpListenerAsyncEventArgs> handler = m_Completed;
     if (handler != null)
     {
         handler(e.m_CurrentStream, e);
     }
 }
 protected virtual void OnCompleted(HttpListenerAsyncEventArgs e)
 {
     m_Completed?.Invoke(e._currentStream, e);
 }
        // 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 with error
        private unsafe bool WriteAsyncFast(HttpListenerAsyncEventArgs eventArgs)
        {
            Interop.HttpApi.HTTP_FLAGS flags = Interop.HttpApi.HTTP_FLAGS.NONE;

            eventArgs.StartOperationCommon(this, _outputStream.InternalHttpContext.RequestQueueBoundHandle);
            eventArgs.StartOperationSend();

            uint statusCode;
            bool completedAsynchronouslyOrWithError;

            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);
                    completedAsynchronouslyOrWithError = false;
                }
                else
                {
                    completedAsynchronouslyOrWithError = true;
                }
            }
            catch (Exception e)
            {
                _writeEventArgs !.FinishOperationFailure(e, true);
                _outputStream.SetClosedFlag();
                _outputStream.InternalHttpContext.Abort();

                completedAsynchronouslyOrWithError = true;
            }

            return(completedAsynchronouslyOrWithError);
        }
        // return value indicates sync vs async completion
        // false: sync completion
        // true: async completion
        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;
        }
 private void OnCompleted(HttpListenerAsyncEventArgs e)
 {
     m_Completed?.Invoke(e._currentStream, e);
 }
        // 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);
        }