/* * 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); }
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", ""); } }
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); } }