internal HttpListenerRequest(HttpListenerContext httpContext, RequestContextBase memoryBlob) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"httpContext:${httpContext} memoryBlob {((IntPtr)memoryBlob.RequestBlob)}"); NetEventSource.Associate(this, httpContext); } _httpContext = httpContext; _memoryBlob = memoryBlob; _boundaryType = BoundaryType.None; // Set up some of these now to avoid refcounting on memory blob later. _requestId = memoryBlob.RequestBlob->RequestId; _connectionId = memoryBlob.RequestBlob->ConnectionId; _sslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure : memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert : SslStatus.ClientCert; if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0) { _rawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength); } Interop.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl; if (cookedUrl.pHost != null && cookedUrl.HostLength > 0) { _cookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2); } if (cookedUrl.pAbsPath != null && cookedUrl.AbsPathLength > 0) { _cookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2); } if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0) { _cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } _version = new Version(memoryBlob.RequestBlob->Version.MajorVersion, memoryBlob.RequestBlob->Version.MinorVersion); _clientCertState = ListenerClientCertState.NotInitialized; _keepAlive = null; if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"RequestId:{RequestId} ConnectionId:{_connectionId} RawConnectionId:{memoryBlob.RequestBlob->RawConnectionId} UrlContext:{memoryBlob.RequestBlob->UrlContext} RawUrl:{_rawUrl} Version:{_version} Secure:{_sslStatus}"); NetEventSource.Info(this, $"httpContext:${httpContext} RequestUri:{RequestUri} Content-Length:{ContentLength64} HTTP Method:{HttpMethod}"); } // Log headers if (NetEventSource.IsEnabled) { StringBuilder sb = new StringBuilder("HttpListenerRequest 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"); } NetEventSource.Info(this, sb.ToString()); } }
internal unsafe HttpListenerRequest(System.Net.HttpListenerContext httpContext, RequestContextBase memoryBlob) { if (Logging.On) { Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#" + ValidationHelper.HashString(httpContext) + " memoryBlob# " + ValidationHelper.HashString((IntPtr) memoryBlob.RequestBlob)); } if (Logging.On) { Logging.Associate(Logging.HttpListener, this, httpContext); } this.m_HttpContext = httpContext; this.m_MemoryBlob = memoryBlob; this.m_BoundaryType = BoundaryType.None; this.m_RequestId = memoryBlob.RequestBlob.RequestId; this.m_ConnectionId = memoryBlob.RequestBlob.ConnectionId; this.m_SslStatus = (memoryBlob.RequestBlob.pSslInfo == null) ? SslStatus.Insecure : ((memoryBlob.RequestBlob.pSslInfo.SslClientCertNegotiated == 0) ? SslStatus.NoClientCert : SslStatus.ClientCert); if ((memoryBlob.RequestBlob.pRawUrl != null) && (memoryBlob.RequestBlob.RawUrlLength > 0)) { this.m_RawUrl = Marshal.PtrToStringAnsi((IntPtr) memoryBlob.RequestBlob.pRawUrl, memoryBlob.RequestBlob.RawUrlLength); } UnsafeNclNativeMethods.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob.CookedUrl; if ((cookedUrl.pHost != null) && (cookedUrl.HostLength > 0)) { this.m_CookedUrlHost = Marshal.PtrToStringUni((IntPtr) cookedUrl.pHost, cookedUrl.HostLength / 2); } if ((cookedUrl.pAbsPath != null) && (cookedUrl.AbsPathLength > 0)) { this.m_CookedUrlPath = Marshal.PtrToStringUni((IntPtr) cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2); } if ((cookedUrl.pQueryString != null) && (cookedUrl.QueryStringLength > 0)) { this.m_CookedUrlQuery = Marshal.PtrToStringUni((IntPtr) cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } this.m_Version = new Version(memoryBlob.RequestBlob.Version.MajorVersion, memoryBlob.RequestBlob.Version.MinorVersion); this.m_ClientCertState = ListenerClientCertState.NotInitialized; this.m_KeepAlive = TriState.Unspecified; if (Logging.On) { Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#" + ValidationHelper.HashString(httpContext) + " RequestUri:" + ValidationHelper.ToString(this.RequestUri) + " Content-Length:" + ValidationHelper.ToString(this.ContentLength64) + " HTTP Method:" + ValidationHelper.ToString(this.HttpMethod)); } if (Logging.On) { StringBuilder builder = new StringBuilder("HttpListenerRequest 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()); } }
internal unsafe HttpListenerRequest(System.Net.HttpListenerContext httpContext, RequestContextBase memoryBlob) { if (Logging.On) { Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#" + ValidationHelper.HashString(httpContext) + " memoryBlob# " + ValidationHelper.HashString((IntPtr)memoryBlob.RequestBlob)); } if (Logging.On) { Logging.Associate(Logging.HttpListener, this, httpContext); } this.m_HttpContext = httpContext; this.m_MemoryBlob = memoryBlob; this.m_BoundaryType = BoundaryType.None; this.m_RequestId = memoryBlob.RequestBlob.RequestId; this.m_ConnectionId = memoryBlob.RequestBlob.ConnectionId; this.m_SslStatus = (memoryBlob.RequestBlob.pSslInfo == null) ? SslStatus.Insecure : ((memoryBlob.RequestBlob.pSslInfo.SslClientCertNegotiated == 0) ? SslStatus.NoClientCert : SslStatus.ClientCert); if ((memoryBlob.RequestBlob.pRawUrl != null) && (memoryBlob.RequestBlob.RawUrlLength > 0)) { this.m_RawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob.pRawUrl, memoryBlob.RequestBlob.RawUrlLength); } UnsafeNclNativeMethods.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob.CookedUrl; if ((cookedUrl.pHost != null) && (cookedUrl.HostLength > 0)) { this.m_CookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2); } if ((cookedUrl.pAbsPath != null) && (cookedUrl.AbsPathLength > 0)) { this.m_CookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2); } if ((cookedUrl.pQueryString != null) && (cookedUrl.QueryStringLength > 0)) { this.m_CookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } this.m_Version = new Version(memoryBlob.RequestBlob.Version.MajorVersion, memoryBlob.RequestBlob.Version.MinorVersion); this.m_ClientCertState = ListenerClientCertState.NotInitialized; this.m_KeepAlive = TriState.Unspecified; if (Logging.On) { Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#" + ValidationHelper.HashString(httpContext) + " RequestUri:" + ValidationHelper.ToString(this.RequestUri) + " Content-Length:" + ValidationHelper.ToString(this.ContentLength64) + " HTTP Method:" + ValidationHelper.ToString(this.HttpMethod)); } if (Logging.On) { StringBuilder builder = new StringBuilder("HttpListenerRequest 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()); } }
private unsafe void ProcessClientCertificate() { byte[] buffer; if (this.m_ClientCertState == ListenerClientCertState.InProgress) { throw new InvalidOperationException(SR.GetString("net_listener_callinprogress", new object[] { "GetClientCertificate()/BeginGetClientCertificate()" })); } this.m_ClientCertState = ListenerClientCertState.InProgress; if (this.m_SslStatus == SslStatus.Insecure) { goto Label_00FD; } uint sslClientCertInfoSize = 0x5dc; Label_0044: buffer = new byte[sslClientCertInfoSize]; fixed(byte *numRef = buffer) { UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *pSslClientCertInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *)numRef; uint pBytesReceived = 0; uint num3 = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate(this.HttpListenerContext.RequestQueueHandle, this.m_ConnectionId, 0, pSslClientCertInfo, sslClientCertInfoSize, &pBytesReceived, null); if (num3 == 0xea) { sslClientCertInfoSize = pBytesReceived + pSslClientCertInfo->CertEncodedSize; goto Label_0044; } if ((num3 == 0) && (pSslClientCertInfo != null)) { if (pSslClientCertInfo->pCertEncoded != null) { try { byte[] destination = new byte[pSslClientCertInfo->CertEncodedSize]; Marshal.Copy((IntPtr)pSslClientCertInfo->pCertEncoded, destination, 0, destination.Length); this.m_ClientCertificate = new X509Certificate2(destination); } catch (CryptographicException) { } catch (SecurityException) { } } this.m_ClientCertificateError = (int)pSslClientCertInfo->CertFlags; } } Label_00FD: this.m_ClientCertState = ListenerClientCertState.Completed; }
private unsafe ListenerClientCertAsyncResult AsyncProcessClientCertificate(AsyncCallback requestCallback, object state) { if (this.m_ClientCertState == ListenerClientCertState.InProgress) { throw new InvalidOperationException(SR.GetString("net_listener_callinprogress", new object[] { "GetClientCertificate()/BeginGetClientCertificate()" })); } this.m_ClientCertState = ListenerClientCertState.InProgress; this.HttpListenerContext.EnsureBoundHandle(); ListenerClientCertAsyncResult result = null; if (this.m_SslStatus != SslStatus.Insecure) { uint size = 0x5dc; result = new ListenerClientCertAsyncResult(this, state, requestCallback, size); try { uint num2; Label_0058: num2 = 0; uint num3 = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate(this.HttpListenerContext.RequestQueueHandle, this.m_ConnectionId, 0, result.RequestBlob, size, &num2, result.NativeOverlapped); if (num3 == 0xea) { UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *requestBlob = result.RequestBlob; size = num2 + requestBlob->CertEncodedSize; result.Reset(size); goto Label_0058; } if ((num3 != 0) && (num3 != 0x3e5)) { throw new HttpListenerException((int)num3); } return(result); } catch { if (result != null) { result.InternalCleanup(); } throw; } } result = new ListenerClientCertAsyncResult(this, state, requestCallback, 0); result.InvokeCallback(); return(result); }
private void ProcessClientCertificate() { if (_clientCertState == ListenerClientCertState.InProgress) { throw new InvalidOperationException(SR.Format(SR.net_listener_callinprogress, "GetClientCertificate()/BeginGetClientCertificate()")); } _clientCertState = ListenerClientCertState.InProgress; if (NetEventSource.IsEnabled) { NetEventSource.Info(this); } //-------------------------------------------------------------------- //When you configure the HTTP.SYS with a flag value 2 //which means require client certificates, when the client makes the //initial SSL connection, server (HTTP.SYS) demands the client certificate // //Some apps may not want to demand the client cert at the beginning //perhaps server the default.htm. In this case the HTTP.SYS is configured //with a flag value other than 2, whcih means that the client certificate is //optional.So initially when SSL is established HTTP.SYS won't ask for client //certificate. This works fine for the default.htm in the case above //However, if the app wants to demand a client certficate at a later time //perhaps showing "YOUR ORDERS" page, then the server wans to demand //Client certs. this will inturn makes HTTP.SYS to do the //SEC_I_RENOGOTIATE through which the client cert demand is made // //THE BUG HERE IS THAT PRIOR TO QFE 4796, we call //GET Client certificate native API ONLY WHEN THE HTTP.SYS is configured with //flag = 2. Which means that apps using HTTPListener will not be able to //demand a client cert at a later point // //The fix here is to demand the client cert when the channel is NOT INSECURE //which means whether the client certs are requried at the beginning or not, //if this is an SSL connection, Call HttpReceiveClientCertificate, thus //starting the cert negotiation at that point // //NOTE: WHEN CALLING THE HttpReceiveClientCertificate, you can get //ERROR_NOT_FOUND - which means the client did not provide the cert //If this is important, the server should respond with 403 forbidden //HTTP.SYS will not do this for you automatically *** //-------------------------------------------------------------------- if (_sslStatus != SslStatus.Insecure) { // at this point we know that DefaultFlags has the 2 bit set (Negotiate Client certificate) // the cert, though might or might not be there. try to retrieve it // this number is the same that IIS decided to use uint size = CertBoblSize; while (true) { byte[] clientCertInfoBlob = new byte[checked ((int)size)]; fixed(byte *pClientCertInfoBlob = &clientCertInfoBlob[0]) { Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *pClientCertInfo = (Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *)pClientCertInfoBlob; if (NetEventSource.IsEnabled) { NetEventSource.Info(this, "Calling Interop.HttpApi.HttpReceiveClientCertificate size:" + size); } uint bytesReceived = 0; uint statusCode = Interop.HttpApi.HttpReceiveClientCertificate( HttpListenerContext.RequestQueueHandle, _connectionId, (uint)Interop.HttpApi.HTTP_FLAGS.NONE, pClientCertInfo, size, &bytesReceived, null); if (NetEventSource.IsEnabled) { NetEventSource.Info(this, "Call to Interop.HttpApi.HttpReceiveClientCertificate returned:" + statusCode + " bytesReceived:" + bytesReceived); } if (statusCode == Interop.HttpApi.ERROR_MORE_DATA) { size = bytesReceived + pClientCertInfo->CertEncodedSize; continue; } else if (statusCode == Interop.HttpApi.ERROR_SUCCESS) { if (pClientCertInfo != null) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"pClientCertInfo:{(IntPtr)pClientCertInfo} pClientCertInfo->CertFlags: {pClientCertInfo->CertFlags} pClientCertInfo->CertEncodedSize: {pClientCertInfo->CertEncodedSize} pClientCertInfo->pCertEncoded: {(IntPtr)pClientCertInfo->pCertEncoded} pClientCertInfo->Token: {(IntPtr)pClientCertInfo->Token} pClientCertInfo->CertDeniedByMapper: {pClientCertInfo->CertDeniedByMapper}"); } if (pClientCertInfo->pCertEncoded != null) { try { byte[] certEncoded = new byte[pClientCertInfo->CertEncodedSize]; Marshal.Copy((IntPtr)pClientCertInfo->pCertEncoded, certEncoded, 0, certEncoded.Length); _clientCertificate = new X509Certificate2(certEncoded); } catch (CryptographicException exception) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"CryptographicException={exception}"); } } catch (SecurityException exception) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"SecurityException={exception}"); } } } _clientCertificateError = (int)pClientCertInfo->CertFlags; } } else { Debug.Assert(statusCode == Interop.HttpApi.ERROR_NOT_FOUND, $"Call to Interop.HttpApi.HttpReceiveClientCertificate() failed with statusCode {statusCode}."); } } break; } } _clientCertState = ListenerClientCertState.Completed; }
private ListenerClientCertAsyncResult AsyncProcessClientCertificate(AsyncCallback requestCallback, object state) { if (_clientCertState == ListenerClientCertState.InProgress) { throw new InvalidOperationException(SR.Format(SR.net_listener_callinprogress, "GetClientCertificate()/BeginGetClientCertificate()")); } _clientCertState = ListenerClientCertState.InProgress; ListenerClientCertAsyncResult asyncResult = null; //-------------------------------------------------------------------- //When you configure the HTTP.SYS with a flag value 2 //which means require client certificates, when the client makes the //initial SSL connection, server (HTTP.SYS) demands the client certificate // //Some apps may not want to demand the client cert at the beginning //perhaps server the default.htm. In this case the HTTP.SYS is configured //with a flag value other than 2, whcih means that the client certificate is //optional.So initially when SSL is established HTTP.SYS won't ask for client //certificate. This works fine for the default.htm in the case above //However, if the app wants to demand a client certficate at a later time //perhaps showing "YOUR ORDERS" page, then the server wans to demand //Client certs. this will inturn makes HTTP.SYS to do the //SEC_I_RENOGOTIATE through which the client cert demand is made // //THE BUG HERE IS THAT PRIOR TO QFE 4796, we call //GET Client certificate native API ONLY WHEN THE HTTP.SYS is configured with //flag = 2. Which means that apps using HTTPListener will not be able to //demand a client cert at a later point // //The fix here is to demand the client cert when the channel is NOT INSECURE //which means whether the client certs are requried at the beginning or not, //if this is an SSL connection, Call HttpReceiveClientCertificate, thus //starting the cert negotiation at that point // //NOTE: WHEN CALLING THE HttpReceiveClientCertificate, you can get //ERROR_NOT_FOUND - which means the client did not provide the cert //If this is important, the server should respond with 403 forbidden //HTTP.SYS will not do this for you automatically *** //-------------------------------------------------------------------- if (_sslStatus != SslStatus.Insecure) { // at this point we know that DefaultFlags has the 2 bit set (Negotiate Client certificate) // the cert, though might or might not be there. try to retrieve it // this number is the same that IIS decided to use uint size = CertBoblSize; asyncResult = new ListenerClientCertAsyncResult(HttpListenerContext.RequestQueueBoundHandle, this, state, requestCallback, size); try { while (true) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, "Calling Interop.HttpApi.HttpReceiveClientCertificate size:" + size); } uint bytesReceived = 0; uint statusCode = Interop.HttpApi.HttpReceiveClientCertificate( HttpListenerContext.RequestQueueHandle, _connectionId, (uint)Interop.HttpApi.HTTP_FLAGS.NONE, asyncResult.RequestBlob, size, &bytesReceived, asyncResult.NativeOverlapped); if (NetEventSource.IsEnabled) { NetEventSource.Info(this, "Call to Interop.HttpApi.HttpReceiveClientCertificate returned:" + statusCode + " bytesReceived:" + bytesReceived); } if (statusCode == Interop.HttpApi.ERROR_MORE_DATA) { Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *pClientCertInfo = asyncResult.RequestBlob; size = bytesReceived + pClientCertInfo->CertEncodedSize; asyncResult.Reset(size); continue; } if (statusCode != Interop.HttpApi.ERROR_SUCCESS && statusCode != Interop.HttpApi.ERROR_IO_PENDING) { // someother bad error, possible return values are: // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED // Also ERROR_BAD_DATA if we got it twice or it reported smaller size buffer required. throw new HttpListenerException((int)statusCode); } if (statusCode == Interop.HttpApi.ERROR_SUCCESS && HttpListener.SkipIOCPCallbackOnSuccess) { asyncResult.IOCompleted(statusCode, bytesReceived); } break; } } catch { asyncResult?.InternalCleanup(); throw; } } else { asyncResult = new ListenerClientCertAsyncResult(HttpListenerContext.RequestQueueBoundHandle, this, state, requestCallback, 0); asyncResult.InvokeCallback(); } return(asyncResult); }
private void ProcessClientCertificate() { if (_clientCertState == ListenerClientCertState.InProgress) throw new InvalidOperationException(SR.Format(SR.net_listener_callinprogress, "GetClientCertificate()/BeginGetClientCertificate()")); _clientCertState = ListenerClientCertState.InProgress; if (NetEventSource.IsEnabled) NetEventSource.Info(this); //-------------------------------------------------------------------- //When you configure the HTTP.SYS with a flag value 2 //which means require client certificates, when the client makes the //initial SSL connection, server (HTTP.SYS) demands the client certificate // //Some apps may not want to demand the client cert at the beginning //perhaps server the default.htm. In this case the HTTP.SYS is configured //with a flag value other than 2, whcih means that the client certificate is //optional.So intially when SSL is established HTTP.SYS won't ask for client //certificate. This works fine for the default.htm in the case above //However, if the app wants to demand a client certficate at a later time //perhaps showing "YOUR ORDERS" page, then the server wans to demand //Client certs. this will inturn makes HTTP.SYS to do the //SEC_I_RENOGOTIATE through which the client cert demand is made // //THE BUG HERE IS THAT PRIOR TO QFE 4796, we call //GET Client certificate native API ONLY WHEN THE HTTP.SYS is configured with //flag = 2. Which means that apps using HTTPListener will not be able to //demand a client cert at a later point // //The fix here is to demand the client cert when the channel is NOT INSECURE //which means whether the client certs are requried at the beginning or not, //if this is an SSL connection, Call HttpReceiveClientCertificate, thus //starting the cert negotiation at that point // //NOTE: WHEN CALLING THE HttpReceiveClientCertificate, you can get //ERROR_NOT_FOUND - which means the client did not provide the cert //If this is important, the server should respond with 403 forbidden //HTTP.SYS will not do this for you automatically *** //-------------------------------------------------------------------- if (_sslStatus != SslStatus.Insecure) { // at this point we know that DefaultFlags has the 2 bit set (Negotiate Client certificate) // the cert, though might or might not be there. try to retrieve it // this number is the same that IIS decided to use uint size = CertBoblSize; while (true) { byte[] clientCertInfoBlob = new byte[checked((int)size)]; fixed (byte* pClientCertInfoBlob = clientCertInfoBlob) { Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = (Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)pClientCertInfoBlob; if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Calling Interop.HttpApi.HttpReceiveClientCertificate size:" + size); uint bytesReceived = 0; uint statusCode = Interop.HttpApi.HttpReceiveClientCertificate( HttpListenerContext.RequestQueueHandle, _connectionId, (uint)Interop.HttpApi.HTTP_FLAGS.NONE, pClientCertInfo, size, &bytesReceived, null); if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Call to Interop.HttpApi.HttpReceiveClientCertificate returned:" + statusCode + " bytesReceived:" + bytesReceived); if (statusCode == Interop.HttpApi.ERROR_MORE_DATA) { size = bytesReceived + pClientCertInfo->CertEncodedSize; continue; } else if (statusCode == Interop.HttpApi.ERROR_SUCCESS) { if (pClientCertInfo != null) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"pClientCertInfo:{(IntPtr)pClientCertInfo} pClientCertInfo->CertFlags: {pClientCertInfo->CertFlags} pClientCertInfo->CertEncodedSize: {pClientCertInfo->CertEncodedSize} pClientCertInfo->pCertEncoded: {(IntPtr)pClientCertInfo->pCertEncoded} pClientCertInfo->Token: {(IntPtr)pClientCertInfo->Token} pClientCertInfo->CertDeniedByMapper: {pClientCertInfo->CertDeniedByMapper}"); if (pClientCertInfo->pCertEncoded != null) { try { byte[] certEncoded = new byte[pClientCertInfo->CertEncodedSize]; Marshal.Copy((IntPtr)pClientCertInfo->pCertEncoded, certEncoded, 0, certEncoded.Length); _clientCertificate = new X509Certificate2(certEncoded); } catch (CryptographicException exception) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"CryptographicException={exception}"); } catch (SecurityException exception) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"SecurityException={exception}"); } } _clientCertificateError = (int)pClientCertInfo->CertFlags; } } else { Debug.Assert(statusCode == Interop.HttpApi.ERROR_NOT_FOUND, $"Call to Interop.HttpApi.HttpReceiveClientCertificate() failed with statusCode {statusCode}."); } } break; } } _clientCertState = ListenerClientCertState.Completed; }
private ListenerClientCertAsyncResult AsyncProcessClientCertificate(AsyncCallback requestCallback, object state) { if (_clientCertState == ListenerClientCertState.InProgress) throw new InvalidOperationException(SR.Format(SR.net_listener_callinprogress, "GetClientCertificate()/BeginGetClientCertificate()")); _clientCertState = ListenerClientCertState.InProgress; ListenerClientCertAsyncResult asyncResult = null; //-------------------------------------------------------------------- //When you configure the HTTP.SYS with a flag value 2 //which means require client certificates, when the client makes the //initial SSL connection, server (HTTP.SYS) demands the client certificate // //Some apps may not want to demand the client cert at the beginning //perhaps server the default.htm. In this case the HTTP.SYS is configured //with a flag value other than 2, whcih means that the client certificate is //optional.So intially when SSL is established HTTP.SYS won't ask for client //certificate. This works fine for the default.htm in the case above //However, if the app wants to demand a client certficate at a later time //perhaps showing "YOUR ORDERS" page, then the server wans to demand //Client certs. this will inturn makes HTTP.SYS to do the //SEC_I_RENOGOTIATE through which the client cert demand is made // //THE BUG HERE IS THAT PRIOR TO QFE 4796, we call //GET Client certificate native API ONLY WHEN THE HTTP.SYS is configured with //flag = 2. Which means that apps using HTTPListener will not be able to //demand a client cert at a later point // //The fix here is to demand the client cert when the channel is NOT INSECURE //which means whether the client certs are requried at the beginning or not, //if this is an SSL connection, Call HttpReceiveClientCertificate, thus //starting the cert negotiation at that point // //NOTE: WHEN CALLING THE HttpReceiveClientCertificate, you can get //ERROR_NOT_FOUND - which means the client did not provide the cert //If this is important, the server should respond with 403 forbidden //HTTP.SYS will not do this for you automatically *** //-------------------------------------------------------------------- if (_sslStatus != SslStatus.Insecure) { // at this point we know that DefaultFlags has the 2 bit set (Negotiate Client certificate) // the cert, though might or might not be there. try to retrieve it // this number is the same that IIS decided to use uint size = CertBoblSize; asyncResult = new ListenerClientCertAsyncResult(HttpListenerContext.RequestQueueBoundHandle, this, state, requestCallback, size); try { while (true) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Calling Interop.HttpApi.HttpReceiveClientCertificate size:" + size); uint bytesReceived = 0; uint statusCode = Interop.HttpApi.HttpReceiveClientCertificate( HttpListenerContext.RequestQueueHandle, _connectionId, (uint)Interop.HttpApi.HTTP_FLAGS.NONE, asyncResult.RequestBlob, size, &bytesReceived, asyncResult.NativeOverlapped); if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Call to Interop.HttpApi.HttpReceiveClientCertificate returned:" + statusCode + " bytesReceived:" + bytesReceived); if (statusCode == Interop.HttpApi.ERROR_MORE_DATA) { Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.RequestBlob; size = bytesReceived + pClientCertInfo->CertEncodedSize; asyncResult.Reset(size); continue; } if (statusCode != Interop.HttpApi.ERROR_SUCCESS && statusCode != Interop.HttpApi.ERROR_IO_PENDING) { // someother bad error, possible return values are: // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED // Also ERROR_BAD_DATA if we got it twice or it reported smaller size buffer required. throw new HttpListenerException((int)statusCode); } if (statusCode == Interop.HttpApi.ERROR_SUCCESS && HttpListener.SkipIOCPCallbackOnSuccess) { asyncResult.IOCompleted(statusCode, bytesReceived); } break; } } catch { asyncResult?.InternalCleanup(); throw; } } else { asyncResult = new ListenerClientCertAsyncResult(HttpListenerContext.RequestQueueBoundHandle, this, state, requestCallback, 0); asyncResult.InvokeCallback(); } return asyncResult; }
internal HttpListenerRequest(HttpListenerContext httpContext, RequestContextBase memoryBlob) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"httpContext:${httpContext} memoryBlob {((IntPtr)memoryBlob.RequestBlob)}"); NetEventSource.Associate(this, httpContext); } _httpContext = httpContext; _memoryBlob = memoryBlob; _boundaryType = BoundaryType.None; // Set up some of these now to avoid refcounting on memory blob later. _requestId = memoryBlob.RequestBlob->RequestId; _connectionId = memoryBlob.RequestBlob->ConnectionId; _sslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure : memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert : SslStatus.ClientCert; if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0) { _rawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength); } Interop.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl; if (cookedUrl.pHost != null && cookedUrl.HostLength > 0) { _cookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2); } if (cookedUrl.pAbsPath != null && cookedUrl.AbsPathLength > 0) { _cookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2); } if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0) { _cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } _version = new Version(memoryBlob.RequestBlob->Version.MajorVersion, memoryBlob.RequestBlob->Version.MinorVersion); _clientCertState = ListenerClientCertState.NotInitialized; _keepAlive = null; if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"RequestId:{RequestId} ConnectionId:{_connectionId} RawConnectionId:{memoryBlob.RequestBlob->RawConnectionId} UrlContext:{memoryBlob.RequestBlob->UrlContext} RawUrl:{_rawUrl} Version:{_version} Secure:{_sslStatus}"); NetEventSource.Info(this, $"httpContext:${httpContext} RequestUri:{RequestUri} Content-Length:{ContentLength64} HTTP Method:{HttpMethod}"); } // Log headers if (NetEventSource.IsEnabled) { StringBuilder sb = new StringBuilder("HttpListenerRequest 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"); } NetEventSource.Info(this, sb.ToString()); } }
private unsafe ListenerClientCertAsyncResult AsyncProcessClientCertificate(AsyncCallback requestCallback, object state) { if (this.m_ClientCertState == ListenerClientCertState.InProgress) { throw new InvalidOperationException(SR.GetString("net_listener_callinprogress", new object[] { "GetClientCertificate()/BeginGetClientCertificate()" })); } this.m_ClientCertState = ListenerClientCertState.InProgress; this.HttpListenerContext.EnsureBoundHandle(); ListenerClientCertAsyncResult result = null; if (this.m_SslStatus != SslStatus.Insecure) { uint size = 0x5dc; result = new ListenerClientCertAsyncResult(this, state, requestCallback, size); try { uint num2; Label_0058: num2 = 0; uint num3 = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate(this.HttpListenerContext.RequestQueueHandle, this.m_ConnectionId, 0, result.RequestBlob, size, &num2, result.NativeOverlapped); if (num3 == 0xea) { UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* requestBlob = result.RequestBlob; size = num2 + requestBlob->CertEncodedSize; result.Reset(size); goto Label_0058; } if ((num3 != 0) && (num3 != 0x3e5)) { throw new HttpListenerException((int) num3); } return result; } catch { if (result != null) { result.InternalCleanup(); } throw; } } result = new ListenerClientCertAsyncResult(this, state, requestCallback, 0); result.InvokeCallback(); return result; }
private unsafe void ProcessClientCertificate() { byte[] buffer; if (this.m_ClientCertState == ListenerClientCertState.InProgress) { throw new InvalidOperationException(SR.GetString("net_listener_callinprogress", new object[] { "GetClientCertificate()/BeginGetClientCertificate()" })); } this.m_ClientCertState = ListenerClientCertState.InProgress; if (this.m_SslStatus == SslStatus.Insecure) { goto Label_00FD; } uint sslClientCertInfoSize = 0x5dc; Label_0044: buffer = new byte[sslClientCertInfoSize]; fixed (byte* numRef = buffer) { UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pSslClientCertInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*) numRef; uint pBytesReceived = 0; uint num3 = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate(this.HttpListenerContext.RequestQueueHandle, this.m_ConnectionId, 0, pSslClientCertInfo, sslClientCertInfoSize, &pBytesReceived, null); if (num3 == 0xea) { sslClientCertInfoSize = pBytesReceived + pSslClientCertInfo->CertEncodedSize; goto Label_0044; } if ((num3 == 0) && (pSslClientCertInfo != null)) { if (pSslClientCertInfo->pCertEncoded != null) { try { byte[] destination = new byte[pSslClientCertInfo->CertEncodedSize]; Marshal.Copy((IntPtr) pSslClientCertInfo->pCertEncoded, destination, 0, destination.Length); this.m_ClientCertificate = new X509Certificate2(destination); } catch (CryptographicException) { } catch (SecurityException) { } } this.m_ClientCertificateError = (int) pSslClientCertInfo->CertFlags; } } Label_00FD: this.m_ClientCertState = ListenerClientCertState.Completed; }
private void ProcessClientCertificate() { if (m_ClientCertState == ListenerClientCertState.InProgress) throw new InvalidOperationException(SR.GetString(SR.net_listener_callinprogress, "GetClientCertificate()/BeginGetClientCertificate()")); m_ClientCertState = ListenerClientCertState.InProgress; GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ProcessClientCertificate()"); //-------------------------------------------------------------------- //When you configure the HTTP.SYS with a flag value 2 //which means require client certificates, when the client makes the //initial SSL connection, server (HTTP.SYS) demands the client certificate // //Some apps may not want to demand the client cert at the beginning //perhaps server the default.htm. In this case the HTTP.SYS is configured //with a flag value other than 2, whcih means that the client certificate is //optional.So intially when SSL is established HTTP.SYS won't ask for client //certificate. This works fine for the default.htm in the case above //However, if the app wants to demand a client certficate at a later time //perhaps showing "YOUR ORDERS" page, then the server wans to demand //Client certs. this will inturn makes HTTP.SYS to do the //SEC_I_RENOGOTIATE through which the client cert demand is made // //THE if (m_SslStatus != SslStatus.Insecure) { // at this point we know that DefaultFlags has the 2 bit set (Negotiate Client certificate) // the cert, though might or might not be there. try to retrieve it // this number is the same that IIS decided to use uint size = CertBoblSize; while (true) { byte[] clientCertInfoBlob = new byte[checked((int) size)]; fixed (byte* pClientCertInfoBlob = clientCertInfoBlob) { UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = (UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*) pClientCertInfoBlob; GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ProcessClientCertificate() calling UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate size:" + size); uint bytesReceived = 0; uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( HttpListenerContext.RequestQueueHandle, m_ConnectionId, (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE, pClientCertInfo, size, &bytesReceived, null); GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ProcessClientCertificate() call to UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate returned:" + statusCode + " bytesReceived:" + bytesReceived); if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) { size = bytesReceived + pClientCertInfo->CertEncodedSize; continue; } else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { if (pClientCertInfo!=null) { GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ProcessClientCertificate() pClientCertInfo:" + ValidationHelper.ToString((IntPtr)pClientCertInfo) + " pClientCertInfo->CertFlags:" + ValidationHelper.ToString(pClientCertInfo->CertFlags) + " pClientCertInfo->CertEncodedSize:" + ValidationHelper.ToString(pClientCertInfo->CertEncodedSize) + " pClientCertInfo->pCertEncoded:" + ValidationHelper.ToString((IntPtr)pClientCertInfo->pCertEncoded) + " pClientCertInfo->Token:" + ValidationHelper.ToString((IntPtr)pClientCertInfo->Token) + " pClientCertInfo->CertDeniedByMapper:" + ValidationHelper.ToString(pClientCertInfo->CertDeniedByMapper)); if (pClientCertInfo->pCertEncoded!=null) { try { byte[] certEncoded = new byte[pClientCertInfo->CertEncodedSize]; Marshal.Copy((IntPtr)pClientCertInfo->pCertEncoded, certEncoded, 0, certEncoded.Length); m_ClientCertificate = new X509Certificate2(certEncoded); } catch (CryptographicException exception) { GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ProcessClientCertificate() caught CryptographicException in X509Certificate2..ctor():" + ValidationHelper.ToString(exception)); } catch (SecurityException exception) { GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ProcessClientCertificate() caught SecurityException in X509Certificate2..ctor():" + ValidationHelper.ToString(exception)); } } m_ClientCertificateError = (int)pClientCertInfo->CertFlags; } } else { GlobalLog.Assert(statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND, "HttpListenerRequest#{0}::ProcessClientCertificate()|Call to UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate() failed with statusCode {1}.", ValidationHelper.HashString(this), statusCode); } } break; } } m_ClientCertState = ListenerClientCertState.Completed; }
private ListenerClientCertAsyncResult AsyncProcessClientCertificate(AsyncCallback requestCallback, object state) { if (m_ClientCertState == ListenerClientCertState.InProgress) throw new InvalidOperationException(SR.GetString(SR.net_listener_callinprogress, "GetClientCertificate()/BeginGetClientCertificate()")); m_ClientCertState = ListenerClientCertState.InProgress; HttpListenerContext.EnsureBoundHandle(); ListenerClientCertAsyncResult asyncResult = null; //-------------------------------------------------------------------- //When you configure the HTTP.SYS with a flag value 2 //which means require client certificates, when the client makes the //initial SSL connection, server (HTTP.SYS) demands the client certificate // //Some apps may not want to demand the client cert at the beginning //perhaps server the default.htm. In this case the HTTP.SYS is configured //with a flag value other than 2, whcih means that the client certificate is //optional.So intially when SSL is established HTTP.SYS won't ask for client //certificate. This works fine for the default.htm in the case above //However, if the app wants to demand a client certficate at a later time //perhaps showing "YOUR ORDERS" page, then the server wans to demand //Client certs. this will inturn makes HTTP.SYS to do the //SEC_I_RENOGOTIATE through which the client cert demand is made // //THE if (m_SslStatus != SslStatus.Insecure) { // at this point we know that DefaultFlags has the 2 bit set (Negotiate Client certificate) // the cert, though might or might not be there. try to retrieve it // this number is the same that IIS decided to use uint size = CertBoblSize; asyncResult = new ListenerClientCertAsyncResult(this, state, requestCallback, size); try { while (true) { GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ProcessClientCertificate() calling UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate size:" + size); uint bytesReceived = 0; uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( HttpListenerContext.RequestQueueHandle, m_ConnectionId, (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE, asyncResult.RequestBlob, size, &bytesReceived, asyncResult.NativeOverlapped); GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ProcessClientCertificate() call to UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate returned:" + statusCode + " bytesReceived:" + bytesReceived); if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) { UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.RequestBlob; size = bytesReceived + pClientCertInfo->CertEncodedSize; asyncResult.Reset(size); continue; } if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) { // someother bad error, possible(?) return values are: // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED // Also ERROR_BAD_DATA if we got it twice or it reported smaller size buffer required. throw new HttpListenerException((int)statusCode); } if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && HttpListener.SkipIOCPCallbackOnSuccess) { asyncResult.IOCompleted(statusCode, bytesReceived); } break; } } catch { if (asyncResult!=null) { asyncResult.InternalCleanup(); } throw; } } else { asyncResult = new ListenerClientCertAsyncResult(this, state, requestCallback, 0); asyncResult.InvokeCallback(); } return asyncResult; }
internal HttpListenerRequest(HttpListenerContext httpContext, RequestContextBase memoryBlob) { if (Logging.On) Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#" + ValidationHelper.HashString(httpContext) + " memoryBlob# " + ValidationHelper.HashString((IntPtr) memoryBlob.RequestBlob)); if(Logging.On)Logging.Associate(Logging.HttpListener, this, httpContext); m_HttpContext = httpContext; m_MemoryBlob = memoryBlob; m_BoundaryType = BoundaryType.None; // Set up some of these now to avoid refcounting on memory blob later. m_RequestId = memoryBlob.RequestBlob->RequestId; m_ConnectionId = memoryBlob.RequestBlob->ConnectionId; m_SslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure : memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert : SslStatus.ClientCert; if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0) { m_RawUrl = Marshal.PtrToStringAnsi((IntPtr) memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength); } UnsafeNclNativeMethods.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl; if (cookedUrl.pHost != null && cookedUrl.HostLength > 0) { m_CookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2); } if (cookedUrl.pAbsPath != null && cookedUrl.AbsPathLength > 0) { m_CookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2); } if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0) { m_CookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2); } m_Version = new Version(memoryBlob.RequestBlob->Version.MajorVersion, memoryBlob.RequestBlob->Version.MinorVersion); m_ClientCertState = ListenerClientCertState.NotInitialized; m_KeepAlive = TriState.Unspecified; GlobalLog.Print("HttpListenerContext#" + ValidationHelper.HashString(this) + "::.ctor() RequestId:" + RequestId + " ConnectionId:" + m_ConnectionId + " RawConnectionId:" + memoryBlob.RequestBlob->RawConnectionId + " UrlContext:" + memoryBlob.RequestBlob->UrlContext + " RawUrl:" + m_RawUrl + " Version:" + m_Version.ToString() + " Secure:" + m_SslStatus.ToString()); if(Logging.On)Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#"+ ValidationHelper.HashString(httpContext)+ " RequestUri:" + ValidationHelper.ToString(RequestUri) + " Content-Length:" + ValidationHelper.ToString(ContentLength64) + " HTTP Method:" + ValidationHelper.ToString(HttpMethod)); // Log headers if(Logging.On) { StringBuilder sb = new StringBuilder("HttpListenerRequest 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()); } }