Exemplo n.º 1
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);
        }
Exemplo n.º 2
0
        protected override void Dispose(bool disposing)
        {
            if (Logging.On)
            {
                Logging.Enter(Logging.HttpListener, this, "Close", "");
            }

            try {
                if (disposing)
                {
                    GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Close() m_Closed:" + m_Closed);
                    if (m_Closed)
                    {
                        if (Logging.On)
                        {
                            Logging.Exit(Logging.HttpListener, this, "Close", "");
                        }
                        return;
                    }
                    m_Closed = true;
                    UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
                    if (m_LeftToWrite > 0 && !m_InOpaqueMode)
                    {
                        throw new InvalidOperationException(SR.GetString(SR.net_io_notenoughbyteswritten));
                    }
                    bool sentHeaders = m_HttpContext.Response.SentHeaders;
                    if (sentHeaders && m_LeftToWrite == 0)
                    {
                        if (Logging.On)
                        {
                            Logging.Exit(Logging.HttpListener, this, "Close", "");
                        }
                        return;
                    }

                    uint statusCode = 0;
                    if ((m_HttpContext.Response.BoundaryType == BoundaryType.Chunked || m_HttpContext.Response.BoundaryType == BoundaryType.None) && (String.Compare(m_HttpContext.Request.HttpMethod, "HEAD", StringComparison.OrdinalIgnoreCase) != 0))
                    {
                        if (m_HttpContext.Response.BoundaryType == BoundaryType.None)
                        {
                            flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT;
                        }
                        fixed(void *pBuffer = NclConstants.ChunkTerminator)
                        {
                            UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK *pDataChunk = null;
                            if (m_HttpContext.Response.BoundaryType == BoundaryType.Chunked)
                            {
                                UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK dataChunk = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK();
                                dataChunk.DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                                dataChunk.pBuffer       = (byte *)pBuffer;
                                dataChunk.BufferLength  = (uint)NclConstants.ChunkTerminator.Length;
                                pDataChunk = &dataChunk;
                            }
                            if (!sentHeaders)
                            {
                                statusCode = m_HttpContext.Response.SendHeaders(pDataChunk, null, flags, false);
                            }
                            else
                            {
                                GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Close() calling UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody");

                                statusCode =
                                    UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody(
                                        m_HttpContext.RequestQueueHandle,
                                        m_HttpContext.RequestId,
                                        (uint)flags,
                                        pDataChunk != null ? (ushort)1 : (ushort)0,
                                        pDataChunk,
                                        null,
                                        SafeLocalFree.Zero,
                                        0,
                                        null,
                                        null);

                                GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Close() call to UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                                if (m_HttpContext.Listener.IgnoreWriteExceptions)
                                {
                                    GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Close() suppressing error");
                                    statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS;
                                }
                            }
                        }
                    }
                    else
                    {
                        if (!sentHeaders)
                        {
                            statusCode = m_HttpContext.Response.SendHeaders(null, null, flags, false);
                        }
                    }
                    if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
                    {
                        Exception exception = new HttpListenerException((int)statusCode);
                        if (Logging.On)
                        {
                            Logging.Exception(Logging.HttpListener, this, "Close", exception);
                        }
                        m_HttpContext.Abort();
                        throw exception;
                    }
                    m_LeftToWrite = 0;
                }
            }
            finally {
                base.Dispose(disposing);
            }
            if (Logging.On)
            {
                Logging.Exit(Logging.HttpListener, this, "Dispose", "");
            }
        }
Exemplo n.º 3
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);
                }
            }