private void EndWriteCore(IAsyncResult asyncResult)
        {
            HttpResponseStreamAsyncResult castedAsyncResult = asyncResult as HttpResponseStreamAsyncResult;

            if (castedAsyncResult == null || castedAsyncResult.AsyncObject != this)
            {
                throw new ArgumentException(SR.net_io_invalidasyncresult, nameof(asyncResult));
            }
            if (castedAsyncResult.EndCalled)
            {
                throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, nameof(EndWrite)));
            }
            castedAsyncResult.EndCalled = true;
            // wait & then check for errors
            object returnValue = castedAsyncResult.InternalWaitForCompletion();

            Exception exception = returnValue as Exception;

            if (exception != null)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(this, "Rethrowing exception:" + exception);
                }
                _closed = true;
                _httpContext.Abort();
                ExceptionDispatchInfo.Throw(exception);
            }
        }
Exemplo n.º 2
0
        private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped)
        {
            Overlapped callbackOverlapped             = Overlapped.Unpack(nativeOverlapped);
            HttpResponseStreamAsyncResult asyncResult = callbackOverlapped.AsyncResult as HttpResponseStreamAsyncResult;

            GlobalLog.Print("HttpResponseStreamAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::Callback() errorCode:0x" + errorCode.ToString("x8") + " numBytes:" + numBytes + " nativeOverlapped:0x" + ((IntPtr)nativeOverlapped).ToString("x8"));

            IOCompleted(asyncResult, errorCode, numBytes);
        }
Exemplo n.º 3
0
        internal void CancelLastWrite(CriticalHandle requestQueueHandle)
        {
            HttpResponseStreamAsyncResult asyncState = m_LastWrite;

            if (asyncState != null && !asyncState.IsCompleted)
            {
                UnsafeNclNativeMethods.CancelIoEx(requestQueueHandle, asyncState.m_pOverlapped);
            }
        }
        // The final Content-Length async write can only be cancelled by CancelIoEx.
        // Sync can only be cancelled by CancelSynchronousIo, but we don't attempt this right now.
        internal void CancelLastWrite(SafeHandle requestQueueHandle)
        {
            HttpResponseStreamAsyncResult asyncState = _lastWrite;

            if (asyncState != null && !asyncState.IsCompleted)
            {
                // It is safe to ignore the return value on a cancel operation because the connection is being closed
                Interop.Kernel32.CancelIoEx(requestQueueHandle, asyncState._pOverlapped);
            }
        }
        private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped)
        {
            object state = ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped) !;
            HttpResponseStreamAsyncResult asyncResult = (state as HttpResponseStreamAsyncResult) !;

            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Info(null, "errorCode:0x" + errorCode.ToString("x8") + " numBytes:" + numBytes + " nativeOverlapped:0x" + ((IntPtr)nativeOverlapped).ToString("x8"));
            }

            IOCompleted(asyncResult, errorCode, numBytes);
        }
        private static void IOCompleted(HttpResponseStreamAsyncResult asyncResult, uint errorCode, uint numBytes)
        {
            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Info(null, $"errorCode:0x{errorCode:x8} numBytes: {numBytes}");
            }
            object?result;

            try
            {
                if (errorCode != Interop.HttpApi.ERROR_SUCCESS && errorCode != Interop.HttpApi.ERROR_HANDLE_EOF)
                {
                    asyncResult.ErrorCode = (int)errorCode;
                    result = new HttpListenerException((int)errorCode);
                }
                else
                {
                    // if we sent headers and body together, numBytes will be the total, but we need to only account for the data
                    if (asyncResult._dataChunks == null)
                    {
                        result = (uint)0;
                        if (NetEventSource.Log.IsEnabled())
                        {
                            NetEventSource.DumpBuffer(null, IntPtr.Zero, 0);
                        }
                    }
                    else
                    {
                        result = asyncResult._dataChunks.Length == 1 ? asyncResult._dataChunks[0].BufferLength : 0;
                        if (NetEventSource.Log.IsEnabled())
                        {
                            for (int i = 0; i < asyncResult._dataChunks.Length; i++)
                            {
                                NetEventSource.DumpBuffer(null, (IntPtr)asyncResult._dataChunks[0].pBuffer, (int)asyncResult._dataChunks[0].BufferLength);
                            }
                        }
                    }
                }
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Info(null, "Calling Complete()");
                }
            }
            catch (Exception e)
            {
                result = e;
            }
            asyncResult.InvokeCallback(result);
        }
Exemplo n.º 7
0
        public override void EndWrite(IAsyncResult asyncResult)
        {
            if (Logging.On)
            {
                Logging.Enter(Logging.HttpListener, this, "EndWrite", "");
            }
            GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::EndWrite() asyncResult#" + ValidationHelper.HashString(asyncResult));
            if (asyncResult == null)
            {
                throw new ArgumentNullException("asyncResult");
            }
            HttpResponseStreamAsyncResult castedAsyncResult = asyncResult as HttpResponseStreamAsyncResult;

            if (castedAsyncResult == null || castedAsyncResult.AsyncObject != this)
            {
                throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
            }
            if (castedAsyncResult.EndCalled)
            {
                throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndWrite"));
            }
            castedAsyncResult.EndCalled = true;
            // wait & then check for errors
            object returnValue = castedAsyncResult.InternalWaitForCompletion();

            Exception exception = returnValue as Exception;

            if (exception != null)
            {
                GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::EndWrite() rethrowing exception:" + exception);
                if (Logging.On)
                {
                    Logging.Exception(Logging.HttpListener, this, "EndWrite", exception);
                }
                m_Closed = true;
                m_HttpContext.Abort();
                throw exception;
            }
            //


            GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::EndWrite()");
            if (Logging.On)
            {
                Logging.Exit(Logging.HttpListener, this, "EndWrite", "");
            }
        }
Exemplo n.º 8
0
        private static void IOCompleted(HttpResponseStreamAsyncResult asyncResult, uint errorCode, uint numBytes)
        {
            GlobalLog.Print("HttpResponseStreamAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::Callback() errorCode:0x" + errorCode.ToString("x8") + " numBytes:" + numBytes);
            object result = null;

            try {
                if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
                {
                    asyncResult.ErrorCode = (int)errorCode;
                    result = new HttpListenerException((int)errorCode);
                }
                else
                {
                    // if we sent headers and body together, numBytes will be the total, but we need to only account for the data
                    // result = numBytes;
                    if (asyncResult.m_DataChunks == null)
                    {
                        result = (uint)0;
                        if (Logging.On)
                        {
                            Logging.Dump(Logging.HttpListener, asyncResult, "Callback", IntPtr.Zero, 0);
                        }
                    }
                    else
                    {
                        result = asyncResult.m_DataChunks.Length == 1 ? asyncResult.m_DataChunks[0].BufferLength : 0;
                        if (Logging.On)
                        {
                            for (int i = 0; i < asyncResult.m_DataChunks.Length; i++)
                            {
                                Logging.Dump(Logging.HttpListener, asyncResult, "Callback", (IntPtr)asyncResult.m_DataChunks[0].pBuffer, (int)asyncResult.m_DataChunks[0].BufferLength);
                            }
                        }
                    }
                }
                GlobalLog.Print("HttpResponseStreamAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::Callback() calling Complete()");
            }
            catch (Exception e) {
                result = e;
            }
            asyncResult.InvokeCallback(result);
        }
Exemplo n.º 9
0
        public override void EndWrite(IAsyncResult asyncResult)
        {
            if (Logging.On)
            {
                Logging.Enter(Logging.HttpListener, this, "EndWrite", "");
            }
            if (asyncResult == null)
            {
                throw new ArgumentNullException("asyncResult");
            }
            HttpResponseStreamAsyncResult result = asyncResult as HttpResponseStreamAsyncResult;

            if ((result == null) || (result.AsyncObject != this))
            {
                throw new ArgumentException(SR.GetString("net_io_invalidasyncresult"), "asyncResult");
            }
            if (result.EndCalled)
            {
                throw new InvalidOperationException(SR.GetString("net_io_invalidendcall", new object[] { "EndWrite" }));
            }
            result.EndCalled = true;
            object    obj2 = result.InternalWaitForCompletion();
            Exception e    = obj2 as Exception;

            if (e != null)
            {
                if (Logging.On)
                {
                    Logging.Exception(Logging.HttpListener, this, "EndWrite", e);
                }
                this.m_HttpContext.Abort();
                throw e;
            }
            this.UpdateAfterWrite((uint)obj2);
            if (Logging.On)
            {
                Logging.Exit(Logging.HttpListener, this, "EndWrite", "");
            }
        }
        private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped *nativeOverlapped)
        {
            HttpResponseStreamAsyncResult asyncResult = Overlapped.Unpack(nativeOverlapped).AsyncResult as HttpResponseStreamAsyncResult;
            object result = null;

            try
            {
                if ((errorCode != 0) && (errorCode != 0x26))
                {
                    asyncResult.ErrorCode = (int)errorCode;
                    result = new HttpListenerException((int)errorCode);
                }
                else if (asyncResult.m_DataChunks == null)
                {
                    result = 0;
                    if (Logging.On)
                    {
                        Logging.Dump(Logging.HttpListener, asyncResult, "Callback", IntPtr.Zero, 0);
                    }
                }
                else
                {
                    result = (asyncResult.m_DataChunks.Length == 1) ? ((object)asyncResult.m_DataChunks[0].BufferLength) : ((object)0);
                    if (Logging.On)
                    {
                        for (int i = 0; i < asyncResult.m_DataChunks.Length; i++)
                        {
                            Logging.Dump(Logging.HttpListener, asyncResult, "Callback", (IntPtr)asyncResult.m_DataChunks[0].pBuffer, (int)asyncResult.m_DataChunks[0].BufferLength);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                result = exception;
            }
            asyncResult.InvokeCallback(result);
        }
        /*
         * 12.3
         * HttpSendHttpResponse() and HttpSendResponseEntityBody() Flag Values.
         * The following flags can be used on calls to HttpSendHttpResponse() and HttpSendResponseEntityBody() API calls:
         *
         #define HTTP_SEND_RESPONSE_FLAG_DISCONNECT          0x00000001
         #define HTTP_SEND_RESPONSE_FLAG_MORE_DATA           0x00000002
         #define HTTP_SEND_RESPONSE_FLAG_RAW_HEADER          0x00000004
         #define HTTP_SEND_RESPONSE_FLAG_VALID               0x00000007
         *
         * HTTP_SEND_RESPONSE_FLAG_DISCONNECT:
         *  specifies that the network connection should be disconnected immediately after
         *  sending the response, overriding the HTTP protocol's persistent connection features.
         * HTTP_SEND_RESPONSE_FLAG_MORE_DATA:
         *  specifies that additional entity body data will be sent by the caller. Thus,
         *  the last call HttpSendResponseEntityBody for a RequestId, will have this flag reset.
         * HTTP_SEND_RESPONSE_RAW_HEADER:
         *  specifies that a caller of HttpSendResponseEntityBody() is intentionally omitting
         *  a call to HttpSendHttpResponse() in order to bypass normal header processing. The
         *  actual HTTP header will be generated by the application and sent as entity body.
         *  This flag should be passed on the first call to HttpSendResponseEntityBody, and
         *  not after. Thus, flag is not applicable to HttpSendHttpResponse.
         */
        internal unsafe uint SendHeaders(Interop.HttpApi.HTTP_DATA_CHUNK *pDataChunk,
                                         HttpResponseStreamAsyncResult asyncResult,
                                         Interop.HttpApi.HTTP_FLAGS flags,
                                         bool isWebSocketHandshake)
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Info(this, $"pDataChunk: { ((IntPtr)pDataChunk)}, asyncResult: {asyncResult}");
            }
            Debug.Assert(!SentHeaders, "SentHeaders is true.");

            if (StatusCode == (int)HttpStatusCode.Unauthorized)
            {
                // User set 401
                // Using the configured Auth schemes, populate the auth challenge headers. This is for scenarios where
                // Anonymous access is allowed for some resources, but the server later determines that authorization
                // is required for this request.
                HttpListenerContext.SetAuthenticationHeaders();
            }

            // Log headers
            if (NetEventSource.IsEnabled)
            {
                StringBuilder sb = new StringBuilder("HttpListenerResponse Headers:\n");
                for (int i = 0; i < Headers.Count; i++)
                {
                    sb.Append("\t");
                    sb.Append(Headers.GetKey(i));
                    sb.Append(" : ");
                    sb.Append(Headers.Get(i));
                    sb.Append("\n");
                }
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(this, sb.ToString());
                }
            }
            _responseState = ResponseState.SentHeaders;

            uint            statusCode;
            uint            bytesSent;
            List <GCHandle> pinnedHeaders = SerializeHeaders(ref _nativeResponse.Headers, isWebSocketHandshake);

            try
            {
                if (pDataChunk != null)
                {
                    _nativeResponse.EntityChunkCount = 1;
                    _nativeResponse.pEntityChunks    = pDataChunk;
                }
                else if (asyncResult != null && asyncResult.pDataChunks != null)
                {
                    _nativeResponse.EntityChunkCount = asyncResult.dataChunkCount;
                    _nativeResponse.pEntityChunks    = asyncResult.pDataChunks;
                }
                else
                {
                    _nativeResponse.EntityChunkCount = 0;
                    _nativeResponse.pEntityChunks    = null;
                }
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(this, "Calling Interop.HttpApi.HttpSendHttpResponse flags:" + flags);
                }
                if (StatusDescription.Length > 0)
                {
                    byte[] statusDescriptionBytes = new byte[WebHeaderEncoding.GetByteCount(StatusDescription)];
                    fixed(byte *pStatusDescription = statusDescriptionBytes)
                    {
                        _nativeResponse.ReasonLength = (ushort)statusDescriptionBytes.Length;
                        WebHeaderEncoding.GetBytes(StatusDescription, 0, statusDescriptionBytes.Length, statusDescriptionBytes, 0);
                        _nativeResponse.pReason = (sbyte *)pStatusDescription;
                        fixed(Interop.HttpApi.HTTP_RESPONSE *pResponse = &_nativeResponse)
                        {
                            statusCode =
                                Interop.HttpApi.HttpSendHttpResponse(
                                    HttpListenerContext.RequestQueueHandle,
                                    HttpListenerRequest.RequestId,
                                    (uint)flags,
                                    pResponse,
                                    null,
                                    &bytesSent,
                                    SafeLocalAllocHandle.Zero,
                                    0,
                                    asyncResult == null ? null : asyncResult._pOverlapped,
                                    null);

                            if (asyncResult != null &&
                                statusCode == Interop.HttpApi.ERROR_SUCCESS &&
                                HttpListener.SkipIOCPCallbackOnSuccess)
                            {
                                asyncResult.IOCompleted(statusCode, bytesSent);
                                // IO operation completed synchronously - callback won't be called to signal completion.
                            }
                        }
                    }
                }
                else
                {
                    fixed(Interop.HttpApi.HTTP_RESPONSE *pResponse = &_nativeResponse)
                    {
                        statusCode =
                            Interop.HttpApi.HttpSendHttpResponse(
                                HttpListenerContext.RequestQueueHandle,
                                HttpListenerRequest.RequestId,
                                (uint)flags,
                                pResponse,
                                null,
                                &bytesSent,
                                SafeLocalAllocHandle.Zero,
                                0,
                                asyncResult == null ? null : asyncResult._pOverlapped,
                                null);

                        if (asyncResult != null &&
                            statusCode == Interop.HttpApi.ERROR_SUCCESS &&
                            HttpListener.SkipIOCPCallbackOnSuccess)
                        {
                            asyncResult.IOCompleted(statusCode, bytesSent);
                            // IO operation completed synchronously - callback won't be called to signal completion.
                        }
                    }
                }
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(this, "Call to Interop.HttpApi.HttpSendHttpResponse returned:" + statusCode);
                }
            }
            finally
            {
                FreePinnedHeaders(pinnedHeaders);
            }
            return(statusCode);
        }
Exemplo n.º 12
0
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
        {
            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));
            }
            Interop.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
            if (_closed || (size == 0 && _leftToWrite != 0))
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Exit(this);
                }
                HttpResponseStreamAsyncResult result = new HttpResponseStreamAsyncResult(this, state, callback);
                result.InvokeCallback((uint)0);
                return(result);
            }
            if (_leftToWrite >= 0 && size > _leftToWrite)
            {
                throw new ProtocolViolationException(SR.net_entitytoobig);
            }

            uint statusCode;
            uint bytesSent = 0;

            flags |= _leftToWrite == size ? Interop.HttpApi.HTTP_FLAGS.NONE : Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
            bool sentHeaders = _httpContext.Response.SentHeaders;
            HttpResponseStreamAsyncResult asyncResult = new HttpResponseStreamAsyncResult(this, state, callback, buffer, offset, size, _httpContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders, _httpContext.RequestQueueBoundHandle);

            // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite.
            UpdateAfterWrite((uint)((_httpContext.Response.BoundaryType == BoundaryType.Chunked) ? 0 : size));

            try
            {
                if (!sentHeaders)
                {
                    statusCode = _httpContext.Response.SendHeaders(null, asyncResult, flags, false);
                }
                else
                {
                    if (NetEventSource.IsEnabled)
                    {
                        NetEventSource.Info(this, "Calling Interop.HttpApi.HttpSendResponseEntityBody");
                    }

                    statusCode =
                        Interop.HttpApi.HttpSendResponseEntityBody(
                            _httpContext.RequestQueueHandle,
                            _httpContext.RequestId,
                            (uint)flags,
                            asyncResult.dataChunkCount,
                            asyncResult.pDataChunks,
                            &bytesSent,
                            SafeLocalAllocHandle.Zero,
                            0,
                            asyncResult._pOverlapped,
                            null);

                    if (NetEventSource.IsEnabled)
                    {
                        NetEventSource.Info(this, "Call to Interop.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                    }
                }
            }
            catch (Exception e)
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Error(this, e.ToString());
                }
                asyncResult.InternalCleanup();
                _closed = true;
                _httpContext.Abort();
                throw;
            }

            if (statusCode != Interop.HttpApi.ERROR_SUCCESS && statusCode != Interop.HttpApi.ERROR_IO_PENDING)
            {
                asyncResult.InternalCleanup();
                if (_httpContext.Listener.IgnoreWriteExceptions && sentHeaders)
                {
                    if (NetEventSource.IsEnabled)
                    {
                        NetEventSource.Info(this, "BeginWrite() Suppressing error");
                    }
                }
                else
                {
                    Exception exception = new HttpListenerException((int)statusCode);
                    if (NetEventSource.IsEnabled)
                    {
                        NetEventSource.Error(this, exception.ToString());
                    }
                    _closed = true;
                    _httpContext.Abort();
                    throw exception;
                }
            }

            if (statusCode == Interop.HttpApi.ERROR_SUCCESS && HttpListener.SkipIOCPCallbackOnSuccess)
            {
                // IO operation completed synchronously - callback won't be called to signal completion.
                asyncResult.IOCompleted(statusCode, bytesSent);
            }

            // Last write, cache it for special cancelation handling.
            if ((flags & Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0)
            {
                _lastWrite = asyncResult;
            }

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Exit(this);
            }
            return(asyncResult);
        }
Exemplo n.º 13
0
        public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
        {
            uint num;

            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if ((offset < 0) || (offset > buffer.Length))
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if ((size < 0) || (size > (buffer.Length - offset)))
            {
                throw new ArgumentOutOfRangeException("size");
            }
            UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = this.ComputeLeftToWrite();
            if (this.m_Closed || ((size == 0) && (this.m_LeftToWrite != 0L)))
            {
                if (Logging.On)
                {
                    Logging.Exit(Logging.HttpListener, this, "BeginWrite", "");
                }
                HttpResponseStreamAsyncResult result = new HttpResponseStreamAsyncResult(this, state, callback);
                result.InvokeCallback(0);
                return(result);
            }
            if ((this.m_LeftToWrite >= 0L) && (size > this.m_LeftToWrite))
            {
                throw new ProtocolViolationException(SR.GetString("net_entitytoobig"));
            }
            flags |= (this.m_LeftToWrite == size) ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
            bool sentHeaders = this.m_HttpContext.Response.SentHeaders;
            HttpResponseStreamAsyncResult asyncResult = new HttpResponseStreamAsyncResult(this, state, callback, buffer, offset, size, this.m_HttpContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders);

            try
            {
                if (!sentHeaders)
                {
                    num = this.m_HttpContext.Response.SendHeaders(null, asyncResult, flags);
                }
                else
                {
                    this.m_HttpContext.EnsureBoundHandle();
                    num = UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody(this.m_HttpContext.RequestQueueHandle, this.m_HttpContext.RequestId, (uint)flags, asyncResult.dataChunkCount, asyncResult.pDataChunks, null, SafeLocalFree.Zero, 0, asyncResult.m_pOverlapped, null);
                }
            }
            catch (Exception exception)
            {
                if (Logging.On)
                {
                    Logging.Exception(Logging.HttpListener, this, "BeginWrite", exception);
                }
                asyncResult.InternalCleanup();
                this.m_HttpContext.Abort();
                throw;
            }
            switch (num)
            {
            case 0:
            case 0x3e5:
                break;

            default:
                asyncResult.InternalCleanup();
                if (!this.m_HttpContext.Listener.IgnoreWriteExceptions || !sentHeaders)
                {
                    Exception e = new HttpListenerException((int)num);
                    if (Logging.On)
                    {
                        Logging.Exception(Logging.HttpListener, this, "BeginWrite", e);
                    }
                    this.m_HttpContext.Abort();
                    throw e;
                }
                break;
            }
            if (Logging.On)
            {
                Logging.Exit(Logging.HttpListener, this, "BeginWrite", "");
            }
            return(asyncResult);
        }
Exemplo n.º 14
0
        internal unsafe uint SendHeaders(UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK *pDataChunk, HttpResponseStreamAsyncResult asyncResult, UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags)
        {
            uint num2;

            if (Logging.On)
            {
                StringBuilder builder = new StringBuilder("HttpListenerResponse Headers:\n");
                for (int i = 0; i < this.Headers.Count; i++)
                {
                    builder.Append("\t");
                    builder.Append(this.Headers.GetKey(i));
                    builder.Append(" : ");
                    builder.Append(this.Headers.Get(i));
                    builder.Append("\n");
                }
                Logging.PrintInfo(Logging.HttpListener, this, ".ctor", builder.ToString());
            }
            this.m_ResponseState = ResponseState.SentHeaders;
            List <GCHandle> pinnedHeaders = this.SerializeHeaders(ref this.m_NativeResponse.Headers);

            try
            {
                if (pDataChunk != null)
                {
                    this.m_NativeResponse.EntityChunkCount = 1;
                    this.m_NativeResponse.pEntityChunks    = pDataChunk;
                }
                else if ((asyncResult != null) && (asyncResult.pDataChunks != null))
                {
                    this.m_NativeResponse.EntityChunkCount = asyncResult.dataChunkCount;
                    this.m_NativeResponse.pEntityChunks    = asyncResult.pDataChunks;
                }
                else
                {
                    this.m_NativeResponse.EntityChunkCount = 0;
                    this.m_NativeResponse.pEntityChunks    = null;
                }
                if (this.StatusDescription.Length > 0)
                {
                    ref byte pinned numRef;
                    byte[]          bytes = new byte[WebHeaderCollection.HeaderEncoding.GetByteCount(this.StatusDescription)];
                    try
                    {
                        byte[] buffer2;
                        if (((buffer2 = bytes) == null) || (buffer2.Length == 0))
                        {
                            numRef = null;
                        }
                        else
                        {
                            numRef = buffer2;
                        }
                        this.m_NativeResponse.ReasonLength = (ushort)bytes.Length;
                        WebHeaderCollection.HeaderEncoding.GetBytes(this.StatusDescription, 0, bytes.Length, bytes, 0);
                        this.m_NativeResponse.pReason = (sbyte *)numRef;
                        fixed(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE *http_responseRef = &this.m_NativeResponse)
                        {
                            if (asyncResult != null)
                            {
                                this.HttpListenerContext.EnsureBoundHandle();
                            }
                            num2 = UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse(this.HttpListenerContext.RequestQueueHandle, this.HttpListenerRequest.RequestId, (uint)flags, http_responseRef, null, null, SafeLocalFree.Zero, 0, (asyncResult == null) ? null : asyncResult.m_pOverlapped, null);
                        }
                        return(num2);
                    }
                    finally
                    {
                        numRef = null;
                    }
                }
                fixed(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE *http_responseRef2 = &this.m_NativeResponse)
                {
                    if (asyncResult != null)
                    {
                        this.HttpListenerContext.EnsureBoundHandle();
                    }
                    num2 = UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse(this.HttpListenerContext.RequestQueueHandle, this.HttpListenerRequest.RequestId, (uint)flags, http_responseRef2, null, null, SafeLocalFree.Zero, 0, (asyncResult == null) ? null : asyncResult.m_pOverlapped, null);
                }
            }
Exemplo n.º 15
0
        /*
        12.3
        HttpSendHttpResponse() and HttpSendResponseEntityBody() Flag Values.
        The following flags can be used on calls to HttpSendHttpResponse() and HttpSendResponseEntityBody() API calls:

        #define HTTP_SEND_RESPONSE_FLAG_DISCONNECT          0x00000001
        #define HTTP_SEND_RESPONSE_FLAG_MORE_DATA           0x00000002
        #define HTTP_SEND_RESPONSE_FLAG_RAW_HEADER          0x00000004
        #define HTTP_SEND_RESPONSE_FLAG_VALID               0x00000007

        HTTP_SEND_RESPONSE_FLAG_DISCONNECT:
            specifies that the network connection should be disconnected immediately after
            sending the response, overriding the HTTP protocol's persistent connection features.
        HTTP_SEND_RESPONSE_FLAG_MORE_DATA:
            specifies that additional entity body data will be sent by the caller. Thus,
            the last call HttpSendResponseEntityBody for a RequestId, will have this flag reset.
        HTTP_SEND_RESPONSE_RAW_HEADER:
            specifies that a caller of HttpSendResponseEntityBody() is intentionally omitting
            a call to HttpSendHttpResponse() in order to bypass normal header processing. The
            actual HTTP header will be generated by the application and sent as entity body.
            This flag should be passed on the first call to HttpSendResponseEntityBody, and
            not after. Thus, flag is not applicable to HttpSendHttpResponse.
        */
        internal unsafe uint SendHeaders(Interop.HttpApi.HTTP_DATA_CHUNK* pDataChunk,
            HttpResponseStreamAsyncResult asyncResult,
            Interop.HttpApi.HTTP_FLAGS flags,
            bool isWebSocketHandshake)
        {
            if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"pDataChunk: { ((IntPtr)pDataChunk)}, asyncResult: {asyncResult}");
            Debug.Assert(!SentHeaders, "SentHeaders is true.");

            if (StatusCode == (int)HttpStatusCode.Unauthorized)
            {
                // User set 401
                // Using the configured Auth schemes, populate the auth challenge headers. This is for scenarios where 
                // Anonymous access is allowed for some resources, but the server later determines that authorization 
                // is required for this request.
                HttpListenerContext.SetAuthenticationHeaders();
            }

            // Log headers
            if (NetEventSource.IsEnabled)
            {
                StringBuilder sb = new StringBuilder("HttpListenerResponse Headers:\n");
                for (int i = 0; i < Headers.Count; i++)
                {
                    sb.Append("\t");
                    sb.Append(Headers.GetKey(i));
                    sb.Append(" : ");
                    sb.Append(Headers.Get(i));
                    sb.Append("\n");
                }
                if (NetEventSource.IsEnabled) NetEventSource.Info(this, sb.ToString());
            }
            _responseState = ResponseState.SentHeaders;
            
            uint statusCode;
            uint bytesSent;
            List<GCHandle> pinnedHeaders = SerializeHeaders(ref _nativeResponse.Headers, isWebSocketHandshake);
            try
            {
                if (pDataChunk != null)
                {
                    _nativeResponse.EntityChunkCount = 1;
                    _nativeResponse.pEntityChunks = pDataChunk;
                }
                else if (asyncResult != null && asyncResult.pDataChunks != null)
                {
                    _nativeResponse.EntityChunkCount = asyncResult.dataChunkCount;
                    _nativeResponse.pEntityChunks = asyncResult.pDataChunks;
                }
                else
                {
                    _nativeResponse.EntityChunkCount = 0;
                    _nativeResponse.pEntityChunks = null;
                }
                if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Calling Interop.HttpApi.HttpSendHttpResponse flags:" + flags);
                if (StatusDescription.Length > 0)
                {
                    byte[] statusDescriptionBytes = new byte[WebHeaderEncoding.GetByteCount(StatusDescription)];
                    fixed (byte* pStatusDescription = statusDescriptionBytes)
                    {
                        _nativeResponse.ReasonLength = (ushort)statusDescriptionBytes.Length;
                        WebHeaderEncoding.GetBytes(StatusDescription, 0, statusDescriptionBytes.Length, statusDescriptionBytes, 0);
                        _nativeResponse.pReason = (sbyte*)pStatusDescription;
                        fixed (Interop.HttpApi.HTTP_RESPONSE* pResponse = &_nativeResponse)
                        {
                            statusCode =
                                Interop.HttpApi.HttpSendHttpResponse(
                                    HttpListenerContext.RequestQueueHandle,
                                    HttpListenerRequest.RequestId,
                                    (uint)flags,
                                    pResponse,
                                    null,
                                    &bytesSent,
                                    SafeLocalAllocHandle.Zero,
                                    0,
                                    asyncResult == null ? null : asyncResult._pOverlapped,
                                    null);

                            if (asyncResult != null &&
                                statusCode == Interop.HttpApi.ERROR_SUCCESS &&
                                HttpListener.SkipIOCPCallbackOnSuccess)
                            {
                                asyncResult.IOCompleted(statusCode, bytesSent);
                                // IO operation completed synchronously - callback won't be called to signal completion.
                            }
                        }
                    }
                }
                else
                {
                    fixed (Interop.HttpApi.HTTP_RESPONSE* pResponse = &_nativeResponse)
                    {
                        statusCode =
                            Interop.HttpApi.HttpSendHttpResponse(
                                HttpListenerContext.RequestQueueHandle,
                                HttpListenerRequest.RequestId,
                                (uint)flags,
                                pResponse,
                                null,
                                &bytesSent,
                                SafeLocalAllocHandle.Zero,
                                0,
                                asyncResult == null ? null : asyncResult._pOverlapped,
                                null);

                        if (asyncResult != null &&
                            statusCode == Interop.HttpApi.ERROR_SUCCESS &&
                            HttpListener.SkipIOCPCallbackOnSuccess)
                        {
                            asyncResult.IOCompleted(statusCode, bytesSent);
                            // IO operation completed synchronously - callback won't be called to signal completion.
                        }
                    }
                }
                if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Call to Interop.HttpApi.HttpSendHttpResponse returned:" + statusCode);
            }
            finally
            {
                FreePinnedHeaders(pinnedHeaders);
            }
            return statusCode;
        }
Exemplo n.º 16
0
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
        {
            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));
            }
            Interop.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
            if (_closed || (size == 0 && _leftToWrite != 0))
            {
                if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
                HttpResponseStreamAsyncResult result = new HttpResponseStreamAsyncResult(this, state, callback);
                result.InvokeCallback((uint)0);
                return result;
            }
            if (_leftToWrite >= 0 && size > _leftToWrite)
            {
                throw new ProtocolViolationException(SR.net_entitytoobig);
            }

            uint statusCode;
            uint bytesSent = 0;
            flags |= _leftToWrite == size ? Interop.HttpApi.HTTP_FLAGS.NONE : Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
            bool sentHeaders = _httpContext.Response.SentHeaders;
            HttpResponseStreamAsyncResult asyncResult = new HttpResponseStreamAsyncResult(this, state, callback, buffer, offset, size, _httpContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders, _httpContext.RequestQueueBoundHandle);

            // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite.
            UpdateAfterWrite((uint)((_httpContext.Response.BoundaryType == BoundaryType.Chunked) ? 0 : size));

            try
            {
                if (!sentHeaders)
                {
                    statusCode = _httpContext.Response.SendHeaders(null, asyncResult, flags, false);
                }
                else
                {
                    if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Calling Interop.HttpApi.HttpSendResponseEntityBody");

                    statusCode =
                        Interop.HttpApi.HttpSendResponseEntityBody(
                            _httpContext.RequestQueueHandle,
                            _httpContext.RequestId,
                            (uint)flags,
                            asyncResult.dataChunkCount,
                            asyncResult.pDataChunks,
                            &bytesSent,
                            SafeLocalAllocHandle.Zero,
                            0,
                            asyncResult._pOverlapped,
                            null);

                    if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Call to Interop.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                }
            }
            catch (Exception e)
            {
                if (NetEventSource.IsEnabled) NetEventSource.Error(this, e.ToString());
                asyncResult.InternalCleanup();
                _closed = true;
                _httpContext.Abort();
                throw;
            }

            if (statusCode != Interop.HttpApi.ERROR_SUCCESS && statusCode != Interop.HttpApi.ERROR_IO_PENDING)
            {
                asyncResult.InternalCleanup();
                if (_httpContext.Listener.IgnoreWriteExceptions && sentHeaders)
                {
                    if (NetEventSource.IsEnabled) NetEventSource.Info(this, "BeginWrite() Suppressing error");
                }
                else
                {
                    Exception exception = new HttpListenerException((int)statusCode);
                    if (NetEventSource.IsEnabled) NetEventSource.Error(this, exception.ToString());
                    _closed = true;
                    _httpContext.Abort();
                    throw exception;
                }
            }

            if (statusCode == Interop.HttpApi.ERROR_SUCCESS && HttpListener.SkipIOCPCallbackOnSuccess)
            {
                // IO operation completed synchronously - callback won't be called to signal completion.
                asyncResult.IOCompleted(statusCode, bytesSent);
            }

            // Last write, cache it for special cancelation handling.
            if ((flags & Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0)
            {
                _lastWrite = asyncResult;
            }

            if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
            return asyncResult;
        }
Exemplo n.º 17
0
 private static void IOCompleted(HttpResponseStreamAsyncResult asyncResult, uint errorCode, uint numBytes)
 {
     GlobalLog.Print("HttpResponseStreamAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::Callback() errorCode:0x" + errorCode.ToString("x8") + " numBytes:" + numBytes);
     object result = null;
     try {
         if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) {
             asyncResult.ErrorCode = (int)errorCode;
             result = new HttpListenerException((int)errorCode);
         }
         else {
             // if we sent headers and body together, numBytes will be the total, but we need to only account for the data
             // result = numBytes;
             if (asyncResult.m_DataChunks == null) {
                 result = (uint) 0;
                 if (Logging.On) { Logging.Dump(Logging.HttpListener, asyncResult, "Callback", IntPtr.Zero, 0); }
             }
             else {
                 result = asyncResult.m_DataChunks.Length == 1 ? asyncResult.m_DataChunks[0].BufferLength : 0;
                 if (Logging.On) { for (int i = 0; i < asyncResult.m_DataChunks.Length; i++) { Logging.Dump(Logging.HttpListener, asyncResult, "Callback", (IntPtr)asyncResult.m_DataChunks[0].pBuffer, (int)asyncResult.m_DataChunks[0].BufferLength); } }
             }
         }
         GlobalLog.Print("HttpResponseStreamAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::Callback() calling Complete()");
     }
     catch (Exception e) {
         result = e;
     }
     asyncResult.InvokeCallback(result);
 }
Exemplo n.º 18
0
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) {
           GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() buffer.Length:" + buffer.Length + " size:" + size + " offset:" + offset);
            if (buffer==null) {
                throw new ArgumentNullException("buffer");
            }
            if (offset<0 || offset>buffer.Length) {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (size<0 || size>buffer.Length-offset) {
                throw new ArgumentOutOfRangeException("size");
            }
            UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
            if (m_Closed || (size == 0 && m_LeftToWrite != 0)) {
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "BeginWrite", "");
                HttpResponseStreamAsyncResult result = new HttpResponseStreamAsyncResult(this, state, callback);
                result.InvokeCallback((uint) 0);
                return result;
            }
            if (m_LeftToWrite>=0 && size>m_LeftToWrite) {
                throw new ProtocolViolationException(SR.GetString(SR.net_entitytoobig));
            }

            uint statusCode;
            uint bytesSent = 0;
            flags |= m_LeftToWrite==size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
            bool sentHeaders = m_HttpContext.Response.SentHeaders;
            HttpResponseStreamAsyncResult asyncResult = new HttpResponseStreamAsyncResult(this, state, callback, buffer, offset, size, m_HttpContext.Response.BoundaryType==BoundaryType.Chunked, sentHeaders);
            
            // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite.
            UpdateAfterWrite((uint)((m_HttpContext.Response.BoundaryType == BoundaryType.Chunked) ? 0 : size));

            try {
                if (!sentHeaders) {
                    statusCode = m_HttpContext.Response.SendHeaders(null, asyncResult, flags, false);
                }
                else {
                    GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() calling UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody");

                    m_HttpContext.EnsureBoundHandle();
                    statusCode =
                        UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody(
                            m_HttpContext.RequestQueueHandle,
                            m_HttpContext.RequestId,
                            (uint)flags,
                            asyncResult.dataChunkCount,
                            asyncResult.pDataChunks,
                            &bytesSent,
                            SafeLocalFree.Zero,
                            0,
                            asyncResult.m_pOverlapped,
                            null);

                    GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() call to UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                }
            }
            catch (Exception e) {
                if (Logging.On) Logging.Exception(Logging.HttpListener, this, "BeginWrite", e);
                asyncResult.InternalCleanup();
                m_Closed = true;
                m_HttpContext.Abort();
                throw;
            }

            if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) {
                asyncResult.InternalCleanup();
                if (m_HttpContext.Listener.IgnoreWriteExceptions && sentHeaders) {
                    GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() suppressing error");
                }
                else {
                    Exception exception = new HttpListenerException((int)statusCode);
                    if (Logging.On) Logging.Exception(Logging.HttpListener, this, "BeginWrite", exception);
                    m_Closed = true;
                    m_HttpContext.Abort();
                    throw exception;
                }
            }

            if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && HttpListener.SkipIOCPCallbackOnSuccess)
            {
                // IO operation completed synchronously - callback won't be called to signal completion.
                asyncResult.IOCompleted(statusCode, bytesSent);
            }

            // Last write, cache it for special cancelation handling.
            if ((flags & UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0)
            {
                m_LastWrite = asyncResult;
            }

            if(Logging.On)Logging.Exit(Logging.HttpListener, this, "BeginWrite", "");
            return asyncResult;
        }
Exemplo n.º 19
0
/*
 * 12.3
 * HttpSendHttpResponse() and HttpSendResponseEntityBody() Flag Values.
 * The following flags can be used on calls to HttpSendHttpResponse() and HttpSendResponseEntityBody() API calls:
 *
 #define HTTP_SEND_RESPONSE_FLAG_DISCONNECT          0x00000001
 #define HTTP_SEND_RESPONSE_FLAG_MORE_DATA           0x00000002
 #define HTTP_SEND_RESPONSE_FLAG_RAW_HEADER          0x00000004
 #define HTTP_SEND_RESPONSE_FLAG_VALID               0x00000007
 *
 * HTTP_SEND_RESPONSE_FLAG_DISCONNECT:
 *  specifies that the network connection should be disconnected immediately after
 *  sending the response, overriding the HTTP protocol's persistent connection features.
 * HTTP_SEND_RESPONSE_FLAG_MORE_DATA:
 *  specifies that additional entity body data will be sent by the caller. Thus,
 *  the last call HttpSendResponseEntityBody for a RequestId, will have this flag reset.
 * HTTP_SEND_RESPONSE_RAW_HEADER:
 *  specifies that a caller of HttpSendResponseEntityBody() is intentionally omitting
 *  a call to HttpSendHttpResponse() in order to bypass normal header processing. The
 *  actual HTTP header will be generated by the application and sent as entity body.
 *  This flag should be passed on the first call to HttpSendResponseEntityBody, and
 *  not after. Thus, flag is not applicable to HttpSendHttpResponse.
 */
        internal unsafe uint SendHeaders(UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK *pDataChunk,
                                         HttpResponseStreamAsyncResult asyncResult,
                                         UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags,
                                         bool isWebSocketHandshake)
        {
            GlobalLog.Print("HttpListenerResponse#" + ValidationHelper.HashString(this) + "::SendHeaders() pDataChunk:" + ValidationHelper.ToString((IntPtr)pDataChunk) + " asyncResult:" + ValidationHelper.ToString(asyncResult));
            GlobalLog.Assert(!SentHeaders, "HttpListenerResponse#{0}::SendHeaders()|SentHeaders is true.", ValidationHelper.HashString(this));

            if (StatusCode == (int)HttpStatusCode.Unauthorized)   // User set 401
            // Using the configured Auth schemes, populate the auth challenge headers. This is for scenarios where
            // Anonymous access is allowed for some resources, but the server later determines that authorization
            // is required for this request.
            {
                HttpListenerContext.SetAuthenticationHeaders();
            }

            // Log headers
            if (Logging.On)
            {
                StringBuilder sb = new StringBuilder("HttpListenerResponse Headers:\n");
                for (int i = 0; i < Headers.Count; i++)
                {
                    sb.Append("\t");
                    sb.Append(Headers.GetKey(i));
                    sb.Append(" : ");
                    sb.Append(Headers.Get(i));
                    sb.Append("\n");
                }
                Logging.PrintInfo(Logging.HttpListener, this, ".ctor", sb.ToString());
            }
            m_ResponseState = ResponseState.SentHeaders;

            /*
             * if (m_BoundaryType==BoundaryType.Raw) {
             *  use HTTP_SEND_RESPONSE_FLAG_RAW_HEADER;
             * }
             */
            uint            statusCode;
            uint            bytesSent;
            List <GCHandle> pinnedHeaders = SerializeHeaders(ref m_NativeResponse.Headers, isWebSocketHandshake);

            try {
                if (pDataChunk != null)
                {
                    m_NativeResponse.EntityChunkCount = 1;
                    m_NativeResponse.pEntityChunks    = pDataChunk;
                }
                else if (asyncResult != null && asyncResult.pDataChunks != null)
                {
                    m_NativeResponse.EntityChunkCount = asyncResult.dataChunkCount;
                    m_NativeResponse.pEntityChunks    = asyncResult.pDataChunks;
                }
                else
                {
                    m_NativeResponse.EntityChunkCount = 0;
                    m_NativeResponse.pEntityChunks    = null;
                }
                GlobalLog.Print("HttpListenerResponse#" + ValidationHelper.HashString(this) + "::SendHeaders() calling UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse flags:" + flags);
                if (StatusDescription.Length > 0)
                {
                    byte[] statusDescriptionBytes = new byte[WebHeaderCollection.HeaderEncoding.GetByteCount(StatusDescription)];
                    fixed(byte *pStatusDescription = statusDescriptionBytes)
                    {
                        m_NativeResponse.ReasonLength = (ushort)statusDescriptionBytes.Length;
                        WebHeaderCollection.HeaderEncoding.GetBytes(StatusDescription, 0, statusDescriptionBytes.Length, statusDescriptionBytes, 0);
                        m_NativeResponse.pReason = (sbyte *)pStatusDescription;
                        fixed(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE *pResponse = &m_NativeResponse)
                        {
                            if (asyncResult != null)
                            {
                                HttpListenerContext.EnsureBoundHandle();
                            }
                            statusCode =
                                UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse(
                                    HttpListenerContext.RequestQueueHandle,
                                    HttpListenerRequest.RequestId,
                                    (uint)flags,
                                    pResponse,
                                    null,
                                    &bytesSent,
                                    SafeLocalFree.Zero,
                                    0,
                                    asyncResult == null ? null : asyncResult.m_pOverlapped,
                                    null);

                            if (asyncResult != null &&
                                statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
                                HttpListener.SkipIOCPCallbackOnSuccess)
                            {
                                asyncResult.IOCompleted(statusCode, bytesSent);
                                // IO operation completed synchronously - callback won't be called to signal completion.
                            }
                        }
                    }
                }
                else
                {
                    fixed(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE *pResponse = &m_NativeResponse)
                    {
                        if (asyncResult != null)
                        {
                            HttpListenerContext.EnsureBoundHandle();
                        }
                        statusCode =
                            UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse(
                                HttpListenerContext.RequestQueueHandle,
                                HttpListenerRequest.RequestId,
                                (uint)flags,
                                pResponse,
                                null,
                                &bytesSent,
                                SafeLocalFree.Zero,
                                0,
                                asyncResult == null ? null : asyncResult.m_pOverlapped,
                                null);

                        if (asyncResult != null &&
                            statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
                            HttpListener.SkipIOCPCallbackOnSuccess)
                        {
                            asyncResult.IOCompleted(statusCode, bytesSent);
                            // IO operation completed synchronously - callback won't be called to signal completion.
                        }
                    }
                }
                GlobalLog.Print("HttpListenerResponse#" + ValidationHelper.HashString(this) + "::SendHeaders() call to UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse returned:" + statusCode);
            }
            finally {
                FreePinnedHeaders(pinnedHeaders);
            }
            return(statusCode);
        }
        public override unsafe IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
        {
            uint num;
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if ((offset < 0) || (offset > buffer.Length))
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if ((size < 0) || (size > (buffer.Length - offset)))
            {
                throw new ArgumentOutOfRangeException("size");
            }
            UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = this.ComputeLeftToWrite();
            if (this.m_Closed || ((size == 0) && (this.m_LeftToWrite != 0L)))
            {
                if (Logging.On)
                {
                    Logging.Exit(Logging.HttpListener, this, "BeginWrite", "");
                }
                HttpResponseStreamAsyncResult result = new HttpResponseStreamAsyncResult(this, state, callback);
                result.InvokeCallback(0);
                return result;
            }
            if ((this.m_LeftToWrite >= 0L) && (size > this.m_LeftToWrite))
            {
                throw new ProtocolViolationException(SR.GetString("net_entitytoobig"));
            }
            flags |= (this.m_LeftToWrite == size) ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
            bool sentHeaders = this.m_HttpContext.Response.SentHeaders;
            HttpResponseStreamAsyncResult asyncResult = new HttpResponseStreamAsyncResult(this, state, callback, buffer, offset, size, this.m_HttpContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders);
            try
            {
                if (!sentHeaders)
                {
                    num = this.m_HttpContext.Response.SendHeaders(null, asyncResult, flags);
                }
                else
                {
                    this.m_HttpContext.EnsureBoundHandle();
                    num = UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody(this.m_HttpContext.RequestQueueHandle, this.m_HttpContext.RequestId, (uint) flags, asyncResult.dataChunkCount, asyncResult.pDataChunks, null, SafeLocalFree.Zero, 0, asyncResult.m_pOverlapped, null);
                }
            }
            catch (Exception exception)
            {
                if (Logging.On)
                {
                    Logging.Exception(Logging.HttpListener, this, "BeginWrite", exception);
                }
                asyncResult.InternalCleanup();
                this.m_HttpContext.Abort();
                throw;
            }
            switch (num)
            {
                case 0:
                case 0x3e5:
                    break;

                default:
                    asyncResult.InternalCleanup();
                    if (!this.m_HttpContext.Listener.IgnoreWriteExceptions || !sentHeaders)
                    {
                        Exception e = new HttpListenerException((int) num);
                        if (Logging.On)
                        {
                            Logging.Exception(Logging.HttpListener, this, "BeginWrite", e);
                        }
                        this.m_HttpContext.Abort();
                        throw e;
                    }
                    break;
            }
            if (Logging.On)
            {
                Logging.Exit(Logging.HttpListener, this, "BeginWrite", "");
            }
            return asyncResult;
        }
Exemplo n.º 21
0
        private IAsyncResult BeginWriteCore(byte[] buffer, int offset, int size, AsyncCallback?callback, object?state)
        {
            Interop.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
            if (_closed || (size == 0 && _leftToWrite != 0))
            {
                HttpResponseStreamAsyncResult result = new HttpResponseStreamAsyncResult(this, state, callback);
                result.InvokeCallback((uint)0);
                return(result);
            }
            if (_leftToWrite >= 0 && size > _leftToWrite)
            {
                throw new ProtocolViolationException(SR.net_entitytoobig);
            }

            uint statusCode;
            uint bytesSent = 0;

            flags |= _leftToWrite == size ? Interop.HttpApi.HTTP_FLAGS.NONE : Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
            bool sentHeaders = _httpContext.Response.SentHeaders;
            HttpResponseStreamAsyncResult asyncResult = new HttpResponseStreamAsyncResult(this, state, callback, buffer, offset, size, _httpContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders, _httpContext.RequestQueueBoundHandle);

            // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite.
            UpdateAfterWrite((uint)((_httpContext.Response.BoundaryType == BoundaryType.Chunked) ? 0 : size));

            try
            {
                if (!sentHeaders)
                {
                    statusCode = _httpContext.Response.SendHeaders(null, asyncResult, flags, false);
                }
                else
                {
                    if (NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Info(this, "Calling Interop.HttpApi.HttpSendResponseEntityBody");
                    }

                    statusCode =
                        Interop.HttpApi.HttpSendResponseEntityBody(
                            _httpContext.RequestQueueHandle,
                            _httpContext.RequestId,
                            (uint)flags,
                            asyncResult.dataChunkCount,
                            asyncResult.pDataChunks,
                            &bytesSent,
                            SafeLocalAllocHandle.Zero,
                            0,
                            asyncResult._pOverlapped,
                            null);

                    if (NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Info(this, "Call to Interop.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                    }
                }
            }
            catch (Exception e)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(this, e.ToString());
                }
                asyncResult.InternalCleanup();
                _closed = true;
                _httpContext.Abort();
                throw;
            }

            if (statusCode != Interop.HttpApi.ERROR_SUCCESS && statusCode != Interop.HttpApi.ERROR_IO_PENDING)
            {
                asyncResult.InternalCleanup();
                if (_httpContext.Listener !.IgnoreWriteExceptions && sentHeaders)
                {
                    if (NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Info(this, "BeginWrite() Suppressing error");
                    }
                }
                else
                {
                    Exception exception = new HttpListenerException((int)statusCode);
                    if (NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Error(this, exception.ToString());
                    }
                    _closed = true;
                    _httpContext.Abort();
                    throw exception;
                }
            }
Exemplo n.º 22
0
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
        {
            GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() buffer.Length:" + buffer.Length + " size:" + size + " offset:" + offset);
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (offset < 0 || offset > buffer.Length)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (size < 0 || size > buffer.Length - offset)
            {
                throw new ArgumentOutOfRangeException("size");
            }
            UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
            if (m_Closed || (size == 0 && m_LeftToWrite != 0))
            {
                if (Logging.On)
                {
                    Logging.Exit(Logging.HttpListener, this, "BeginWrite", "");
                }
                HttpResponseStreamAsyncResult result = new HttpResponseStreamAsyncResult(this, state, callback);
                result.InvokeCallback((uint)0);
                return(result);
            }
            if (m_LeftToWrite >= 0 && size > m_LeftToWrite)
            {
                throw new ProtocolViolationException(SR.GetString(SR.net_entitytoobig));
            }

            uint statusCode;
            uint bytesSent = 0;

            flags |= m_LeftToWrite == size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
            bool sentHeaders = m_HttpContext.Response.SentHeaders;
            HttpResponseStreamAsyncResult asyncResult = new HttpResponseStreamAsyncResult(this, state, callback, buffer, offset, size, m_HttpContext.Response.BoundaryType == BoundaryType.Chunked, sentHeaders);

            // Update m_LeftToWrite now so we can queue up additional BeginWrite's without waiting for EndWrite.
            UpdateAfterWrite((uint)((m_HttpContext.Response.BoundaryType == BoundaryType.Chunked) ? 0 : size));

            try {
                if (!sentHeaders)
                {
                    statusCode = m_HttpContext.Response.SendHeaders(null, asyncResult, flags, false);
                }
                else
                {
                    GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() calling UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody");

                    m_HttpContext.EnsureBoundHandle();
                    statusCode =
                        UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody(
                            m_HttpContext.RequestQueueHandle,
                            m_HttpContext.RequestId,
                            (uint)flags,
                            asyncResult.dataChunkCount,
                            asyncResult.pDataChunks,
                            &bytesSent,
                            SafeLocalFree.Zero,
                            0,
                            asyncResult.m_pOverlapped,
                            null);

                    GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() call to UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                }
            }
            catch (Exception e) {
                if (Logging.On)
                {
                    Logging.Exception(Logging.HttpListener, this, "BeginWrite", e);
                }
                asyncResult.InternalCleanup();
                m_Closed = true;
                m_HttpContext.Abort();
                throw;
            }

            if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
            {
                asyncResult.InternalCleanup();
                if (m_HttpContext.Listener.IgnoreWriteExceptions && sentHeaders)
                {
                    GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() suppressing error");
                }
                else
                {
                    Exception exception = new HttpListenerException((int)statusCode);
                    if (Logging.On)
                    {
                        Logging.Exception(Logging.HttpListener, this, "BeginWrite", exception);
                    }
                    m_Closed = true;
                    m_HttpContext.Abort();
                    throw exception;
                }
            }

            if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && HttpListener.SkipIOCPCallbackOnSuccess)
            {
                // IO operation completed synchronously - callback won't be called to signal completion.
                asyncResult.IOCompleted(statusCode, bytesSent);
            }

            // Last write, cache it for special cancelation handling.
            if ((flags & UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0)
            {
                m_LastWrite = asyncResult;
            }

            if (Logging.On)
            {
                Logging.Exit(Logging.HttpListener, this, "BeginWrite", "");
            }
            return(asyncResult);
        }
/*
12.3
HttpSendHttpResponse() and HttpSendResponseEntityBody() Flag Values.
The following flags can be used on calls to HttpSendHttpResponse() and HttpSendResponseEntityBody() API calls:

#define HTTP_SEND_RESPONSE_FLAG_DISCONNECT          0x00000001
#define HTTP_SEND_RESPONSE_FLAG_MORE_DATA           0x00000002
#define HTTP_SEND_RESPONSE_FLAG_RAW_HEADER          0x00000004
#define HTTP_SEND_RESPONSE_FLAG_VALID               0x00000007

HTTP_SEND_RESPONSE_FLAG_DISCONNECT:
    specifies that the network connection should be disconnected immediately after
    sending the response, overriding the HTTP protocol's persistent connection features.
HTTP_SEND_RESPONSE_FLAG_MORE_DATA:
    specifies that additional entity body data will be sent by the caller. Thus,
    the last call HttpSendResponseEntityBody for a RequestId, will have this flag reset.
HTTP_SEND_RESPONSE_RAW_HEADER:
    specifies that a caller of HttpSendResponseEntityBody() is intentionally omitting
    a call to HttpSendHttpResponse() in order to bypass normal header processing. The
    actual HTTP header will be generated by the application and sent as entity body.
    This flag should be passed on the first call to HttpSendResponseEntityBody, and
    not after. Thus, flag is not applicable to HttpSendHttpResponse.
*/
        internal unsafe uint SendHeaders(UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK* pDataChunk, 
            HttpResponseStreamAsyncResult asyncResult, 
            UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags,
            bool isWebSocketHandshake) {
            GlobalLog.Print("HttpListenerResponse#" + ValidationHelper.HashString(this) + "::SendHeaders() pDataChunk:" + ValidationHelper.ToString((IntPtr)pDataChunk) + " asyncResult:" + ValidationHelper.ToString(asyncResult));
            GlobalLog.Assert(!SentHeaders, "HttpListenerResponse#{0}::SendHeaders()|SentHeaders is true.", ValidationHelper.HashString(this));
            
            if (StatusCode == (int)HttpStatusCode.Unauthorized) { // User set 401
                // Using the configured Auth schemes, populate the auth challenge headers. This is for scenarios where 
                // Anonymous access is allowed for some resources, but the server later determines that authorization 
                // is required for this request.
                HttpListenerContext.SetAuthenticationHeaders();
            }
            
            // Log headers
            if(Logging.On) {
                StringBuilder sb = new StringBuilder("HttpListenerResponse Headers:\n");
                for (int i=0; i<Headers.Count; i++) {
                    sb.Append("\t");
                    sb.Append(Headers.GetKey(i));
                    sb.Append(" : ");
                    sb.Append(Headers.Get(i));
                    sb.Append("\n");
                }
                Logging.PrintInfo(Logging.HttpListener, this, ".ctor", sb.ToString());
            }
            m_ResponseState = ResponseState.SentHeaders;
            /*
            if (m_BoundaryType==BoundaryType.Raw) {
                use HTTP_SEND_RESPONSE_FLAG_RAW_HEADER;
            }
            */
            uint statusCode;
            uint bytesSent;
            List<GCHandle> pinnedHeaders = SerializeHeaders(ref m_NativeResponse.Headers, isWebSocketHandshake);
            try {
                if (pDataChunk!=null) {
                    m_NativeResponse.EntityChunkCount = 1;
                    m_NativeResponse.pEntityChunks = pDataChunk;
                }
                else if (asyncResult!=null && asyncResult.pDataChunks!=null) {
                    m_NativeResponse.EntityChunkCount = asyncResult.dataChunkCount;
                    m_NativeResponse.pEntityChunks = asyncResult.pDataChunks;
                } 
                else {
                    m_NativeResponse.EntityChunkCount = 0;
                    m_NativeResponse.pEntityChunks = null;
                }
                GlobalLog.Print("HttpListenerResponse#" + ValidationHelper.HashString(this) + "::SendHeaders() calling UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse flags:" + flags);
                if (StatusDescription.Length>0) {
                    byte[] statusDescriptionBytes = new byte[WebHeaderCollection.HeaderEncoding.GetByteCount(StatusDescription)];
                    fixed (byte* pStatusDescription = statusDescriptionBytes) {
                        m_NativeResponse.ReasonLength = (ushort)statusDescriptionBytes.Length;
                        WebHeaderCollection.HeaderEncoding.GetBytes(StatusDescription, 0, statusDescriptionBytes.Length, statusDescriptionBytes, 0);
                        m_NativeResponse.pReason = (sbyte*)pStatusDescription;
                        fixed (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE* pResponse = &m_NativeResponse) {
                            if (asyncResult != null)
                            {
                                HttpListenerContext.EnsureBoundHandle();
                            }
                            statusCode =
                                UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse(
                                    HttpListenerContext.RequestQueueHandle,
                                    HttpListenerRequest.RequestId,
                                    (uint)flags,
                                    pResponse,
                                    null,
                                    &bytesSent,
                                    SafeLocalFree.Zero,
                                    0,
                                    asyncResult==null ? null : asyncResult.m_pOverlapped,
                                    null );

                            if (asyncResult != null && 
                                statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
                                HttpListener.SkipIOCPCallbackOnSuccess)
                            {
                                asyncResult.IOCompleted(statusCode, bytesSent);
                                // IO operation completed synchronously - callback won't be called to signal completion.
                            }
                        }
                    }
                }
                else {
                    fixed (UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE* pResponse = &m_NativeResponse) {
                        if (asyncResult != null)
                        {
                            HttpListenerContext.EnsureBoundHandle();
                        }
                        statusCode =
                            UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse(
                                HttpListenerContext.RequestQueueHandle,
                                HttpListenerRequest.RequestId,
                                (uint)flags,
                                pResponse,
                                null,
                                &bytesSent,
                                SafeLocalFree.Zero,
                                0,
                                asyncResult==null ? null : asyncResult.m_pOverlapped,
                                null );

                        if (asyncResult != null && 
                            statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
                            HttpListener.SkipIOCPCallbackOnSuccess)
                        {
                            asyncResult.IOCompleted(statusCode, bytesSent);
                            // IO operation completed synchronously - callback won't be called to signal completion.
                        }
                    }
                }
                GlobalLog.Print("HttpListenerResponse#" + ValidationHelper.HashString(this) + "::SendHeaders() call to UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse returned:" + statusCode);
            }
            finally {
                FreePinnedHeaders(pinnedHeaders);
            }
            return statusCode;
        }
Exemplo n.º 24
0
 private static void IOCompleted(HttpResponseStreamAsyncResult asyncResult, uint errorCode, uint numBytes)
 {
     if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"errorCode:0x {errorCode.ToString("x8")} numBytes: {numBytes}");
     object result = null;
     try
     {
         if (errorCode != Interop.HttpApi.ERROR_SUCCESS && errorCode != Interop.HttpApi.ERROR_HANDLE_EOF)
         {
             asyncResult.ErrorCode = (int)errorCode;
             result = new HttpListenerException((int)errorCode);
         }
         else
         {
             // if we sent headers and body together, numBytes will be the total, but we need to only account for the data
             if (asyncResult._dataChunks == null)
             {
                 result = (uint)0;
                 if (NetEventSource.IsEnabled) { NetEventSource.DumpBuffer(null, IntPtr.Zero, 0); }
             }
             else
             {
                 result = asyncResult._dataChunks.Length == 1 ? asyncResult._dataChunks[0].BufferLength : 0;
                 if (NetEventSource.IsEnabled) { for (int i = 0; i < asyncResult._dataChunks.Length; i++) { NetEventSource.DumpBuffer(null, (IntPtr)asyncResult._dataChunks[0].pBuffer, (int)asyncResult._dataChunks[0].BufferLength); } }
             }
         }
         if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Calling Complete()");
     }
     catch (Exception e)
     {
         result = e;
     }
     asyncResult.InvokeCallback(result);
 }