Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / HttpListenerRequest.cs / 1305376 / HttpListenerRequest.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Net { using System; using System.Collections; using System.Collections.Specialized; using System.IO; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Security.Authentication.ExtendedProtection; using System.Security.Permissions; using System.Globalization; using System.Text; using System.Threading; using System.ComponentModel; using System.Diagnostics; using System.Security; using System.Security.Principal; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; internal enum ListenerClientCertState { NotInitialized, InProgress, Completed } unsafe internal class ListenerClientCertAsyncResult : LazyAsyncResult { private NativeOverlapped* m_pOverlapped; private byte[] m_BackingBuffer; private UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* m_MemoryBlob; private uint m_Size; internal NativeOverlapped* NativeOverlapped { get { return m_pOverlapped; } } internal UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* RequestBlob { get { return m_MemoryBlob; } } private static readonly IOCompletionCallback s_IOCallback = new IOCompletionCallback(WaitCallback); internal ListenerClientCertAsyncResult(object asyncObject, object userState, AsyncCallback callback, uint size) : base(asyncObject, userState, callback) { // we will use this overlapped structure to issue async IO to ul // the event handle will be put in by the BeginHttpApi2.ERROR_SUCCESS() method Reset(size); } internal void Reset(uint size) { if (size == m_Size) { return; } if (m_Size != 0) { Overlapped.Free(m_pOverlapped); } m_Size = size; if (size == 0) { m_pOverlapped = null; m_MemoryBlob = null; m_BackingBuffer = null; return; } m_BackingBuffer = new byte[checked((int) size)]; Overlapped overlapped = new Overlapped(); overlapped.AsyncResult = this; m_pOverlapped = overlapped.Pack(s_IOCallback, m_BackingBuffer); m_MemoryBlob = (UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*) Marshal.UnsafeAddrOfPinnedArrayElement(m_BackingBuffer, 0); } private static unsafe void WaitCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { // take the ListenerClientCertAsyncResult object from the state Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); ListenerClientCertAsyncResult asyncResult = (ListenerClientCertAsyncResult) callbackOverlapped.AsyncResult; GlobalLog.Print("ListenerClientCertAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::WaitCallback() errorCode:[" + errorCode.ToString() + "] numBytes:[" + numBytes.ToString() + "] nativeOverlapped:[" + ((long)nativeOverlapped).ToString() + "]"); HttpListenerRequest httpListenerRequest = (HttpListenerRequest) asyncResult.AsyncObject; object result = null; try { if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) { //There is a bug that has existed in http.sys since w2k3. Bytesreceived will only //return the size of the inital cert structure. To get the full size, //we need to add the certificate encoding size as well. UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.RequestBlob; asyncResult.Reset(numBytes + pClientCertInfo->CertEncodedSize); uint bytesReceived = 0; errorCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate( httpListenerRequest.HttpListenerContext.RequestQueueHandle, httpListenerRequest.m_ConnectionId, (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE, asyncResult.m_MemoryBlob, asyncResult.m_Size, &bytesReceived, asyncResult.m_pOverlapped); if(errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING || errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { return; } } if (errorCode!=UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { asyncResult.ErrorCode = (int)errorCode; result = new HttpListenerException((int)errorCode); } else { UnsafeNclNativeMethods.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.m_MemoryBlob; if (pClientCertInfo!=null) { GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(httpListenerRequest) + "::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); result = httpListenerRequest.ClientCertificate = new X509Certificate2(certEncoded); } catch (CryptographicException exception) { GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(httpListenerRequest) + "::ProcessClientCertificate() caught CryptographicException in X509Certificate2..ctor():" + ValidationHelper.ToString(exception)); result = exception; } catch (SecurityException exception) { GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(httpListenerRequest) + "::ProcessClientCertificate() caught SecurityException in X509Certificate2..ctor():" + ValidationHelper.ToString(exception)); result = exception; } } httpListenerRequest.SetClientCertificateError((int)pClientCertInfo->CertFlags); } } // complete the async IO and invoke the callback GlobalLog.Print("ListenerClientCertAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::WaitCallback() calling Complete()"); } catch (Exception exception) { if (NclUtilities.IsFatal(exception)) throw; result = exception; } finally { if(errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING){ httpListenerRequest.ClientCertState = ListenerClientCertState.Completed; } } asyncResult.InvokeCallback(result); } // Will be called from the base class upon InvokeCallback() protected override void Cleanup() { if (m_pOverlapped != null) { m_MemoryBlob = null; Overlapped.Free(m_pOverlapped); m_pOverlapped = null; } GC.SuppressFinalize(this); base.Cleanup(); } ~ListenerClientCertAsyncResult() { if (m_pOverlapped != null && !NclUtilities.HasShutdownStarted) { Overlapped.Free(m_pOverlapped); m_pOverlapped = null; // Must do this in case application calls GC.ReRegisterForFinalize(). } } } public sealed unsafe class HttpListenerRequest/* BaseHttpRequest, */ { private Uri m_RequestUri; private ulong m_RequestId; internal ulong m_ConnectionId; private SslStatus m_SslStatus; private string m_RawUrl; private string m_CookedUrlHost; private string m_CookedUrlPath; private string m_CookedUrlQuery; private long m_ContentLength; private Stream m_RequestStream; private string m_HttpMethod; private TriState m_KeepAlive; private Version m_Version; private WebHeaderCollection m_WebHeaders; private IPEndPoint m_LocalEndPoint; private IPEndPoint m_RemoteEndPoint; private BoundaryType m_BoundaryType; private ListenerClientCertState m_ClientCertState; private X509Certificate2 m_ClientCertificate; private int m_ClientCertificateError; private RequestContextBase m_MemoryBlob; private CookieCollection m_Cookies; private HttpListenerContext m_HttpContext; private bool m_IsDisposed = false; internal const uint CertBoblSize = 1500; private string m_ServiceName; private enum SslStatus : byte { Insecure, NoClientCert, ClientCert } 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; i0) { try { return Encoding.GetEncoding(postDataCharset); } catch (ArgumentException) { } } } if (HasEntityBody) { if (ContentType!=null) { string charSet = Helpers.GetAttributeFromHeader(ContentType, "charset"); if (charSet!=null) { try { return Encoding.GetEncoding(charSet); } catch (ArgumentException) { } } } } return Encoding.Default; } } public /* override */ long ContentLength64 { get { if (m_BoundaryType==BoundaryType.None) { if (GetKnownHeader(HttpRequestHeader.TransferEncoding)==HttpWebRequest.ChunkedHeader) { m_BoundaryType = BoundaryType.Chunked; m_ContentLength = -1; } else { m_ContentLength = 0; m_BoundaryType = BoundaryType.ContentLength; string length = GetKnownHeader(HttpRequestHeader.ContentLength); if (length!=null) { bool success = long.TryParse(length, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out m_ContentLength); if (!success) { m_ContentLength = 0; m_BoundaryType = BoundaryType.Invalid; } } } } GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ContentLength_get() returning m_ContentLength:" + m_ContentLength + " m_BoundaryType:" + m_BoundaryType); return m_ContentLength; } } public /* override */ string ContentType { get { return GetKnownHeader(HttpRequestHeader.ContentType); } } public /* override */ NameValueCollection Headers { get { if (m_WebHeaders==null) { m_WebHeaders = UnsafeNclNativeMethods.HttpApi.GetHeaders(RequestBuffer, OriginalBlobAddress); } GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::Headers_get() returning#" + ValidationHelper.HashString(m_WebHeaders)); return m_WebHeaders; } } public /* override */ string HttpMethod { get { if (m_HttpMethod==null) { m_HttpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, OriginalBlobAddress); } GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::HttpMethod_get() returning m_HttpMethod:" + ValidationHelper.ToString(m_HttpMethod)); return m_HttpMethod; } } public /* override */ Stream InputStream { get { if(Logging.On)Logging.Enter(Logging.HttpListener, this, "InputStream_get", ""); if (m_RequestStream==null) { m_RequestStream = HasEntityBody ? new HttpRequestStream(HttpListenerContext) : Stream.Null; } if(Logging.On)Logging.Exit(Logging.HttpListener, this, "InputStream_get", ""); return m_RequestStream; } } // Requires ControlPrincipal permission if the request was authenticated with Negotiate, NTLM, or Digest. public /* override */ bool IsAuthenticated { get { IPrincipal user = HttpListenerContext.User; return user != null && user.Identity != null && user.Identity.IsAuthenticated; } } public /* override */ bool IsLocal { get { return LocalEndPoint.Address.Equals(RemoteEndPoint.Address); } } internal bool InternalIsLocal { get { return LocalEndPoint.Address.Equals(RemoteEndPoint.Address); } } public /* override */ bool IsSecureConnection { get { return m_SslStatus != SslStatus.Insecure; } } public /* override */ NameValueCollection QueryString { get { NameValueCollection queryString = new NameValueCollection(); Helpers.FillFromString(queryString, Url.Query, true, ContentEncoding); return queryString; } } public /* override */ string RawUrl { get { return m_RawUrl; } } public string ServiceName { get { return m_ServiceName; } internal set { m_ServiceName = value; } } public /* override */ Uri Url { get { return RequestUri; } } public /* override */ Uri UrlReferrer { get { string referrer = GetKnownHeader(HttpRequestHeader.Referer); if (referrer==null) { return null; } Uri urlReferrer; bool success = Uri.TryCreate(referrer, UriKind.RelativeOrAbsolute, out urlReferrer); return success ? urlReferrer : null; } } public /* override */ string UserAgent { get { return GetKnownHeader(HttpRequestHeader.UserAgent); } } public /* override */ string UserHostAddress { get { return LocalEndPoint.ToString(); } } public /* override */ string UserHostName { get { return GetKnownHeader(HttpRequestHeader.Host); } } public /* override */ string[] UserLanguages { get { return Helpers.ParseMultivalueHeader(GetKnownHeader(HttpRequestHeader.AcceptLanguage)); } } public int ClientCertificateError { get { if (m_ClientCertState == ListenerClientCertState.NotInitialized) throw new InvalidOperationException(SR.GetString(SR.net_listener_mustcall, "GetClientCertificate()/BeginGetClientCertificate()")); else if (m_ClientCertState == ListenerClientCertState.InProgress) throw new InvalidOperationException(SR.GetString(SR.net_listener_mustcompletecall, "GetClientCertificate()/BeginGetClientCertificate()")); GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ClientCertificateError_get() returning ClientCertificateError:" + ValidationHelper.ToString(m_ClientCertificateError)); return m_ClientCertificateError; } } internal X509Certificate2 ClientCertificate { set { m_ClientCertificate = value; } } internal ListenerClientCertState ClientCertState { set { m_ClientCertState = value; } } internal void SetClientCertificateError(int clientCertificateError) { m_ClientCertificateError = clientCertificateError; } public X509Certificate2 GetClientCertificate() { if(Logging.On)Logging.Enter(Logging.HttpListener, this, "GetClientCertificate", ""); try { ProcessClientCertificate(); GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::GetClientCertificate() returning m_ClientCertificate:" + ValidationHelper.ToString(m_ClientCertificate)); } finally { if(Logging.On)Logging.Exit(Logging.HttpListener, this, "GetClientCertificate", ValidationHelper.ToString(m_ClientCertificate)); } return m_ClientCertificate; } public IAsyncResult BeginGetClientCertificate(AsyncCallback requestCallback, object state) { if(Logging.On)Logging.PrintInfo(Logging.HttpListener, this, "BeginGetClientCertificate", ""); return AsyncProcessClientCertificate(requestCallback, state); } public X509Certificate2 EndGetClientCertificate(IAsyncResult asyncResult) { if(Logging.On)Logging.Enter(Logging.HttpListener, this, "EndGetClientCertificate", ""); X509Certificate2 clientCertificate = null; try { if (asyncResult==null) { throw new ArgumentNullException("asyncResult"); } ListenerClientCertAsyncResult clientCertAsyncResult = asyncResult as ListenerClientCertAsyncResult; if (clientCertAsyncResult==null || clientCertAsyncResult.AsyncObject!=this) { throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult"); } if (clientCertAsyncResult.EndCalled) { throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetClientCertificate")); } clientCertAsyncResult.EndCalled = true; clientCertificate = clientCertAsyncResult.InternalWaitForCompletion() as X509Certificate2; GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::EndGetClientCertificate() returning m_ClientCertificate:" + ValidationHelper.ToString(m_ClientCertificate)); } finally { if(Logging.On)Logging.Exit(Logging.HttpListener, this, "EndGetClientCertificate", ValidationHelper.HashString(clientCertificate)); } return clientCertificate; } public TransportContext TransportContext { get { return new HttpListenerRequestContext(this); } } private CookieCollection ParseCookies(Uri uri, string setCookieHeader) { GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ParseCookies() uri:" + uri + " setCookieHeader:" + setCookieHeader); CookieCollection cookies = new CookieCollection(); CookieParser parser = new CookieParser(setCookieHeader); for (;;) { Cookie cookie = parser.GetServer(); GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::ParseCookies() CookieParser returned cookie:" + ValidationHelper.ToString(cookie)); if (cookie==null) { // EOF, done. break; } if (cookie.Name.Length==0) { continue; } cookies.InternalAdd(cookie, true); } return cookies; } public CookieCollection Cookies { get { if (m_Cookies==null) { string cookieString = GetKnownHeader(HttpRequestHeader.Cookie); if (cookieString!=null && cookieString.Length>0) { m_Cookies = ParseCookies(RequestUri, cookieString); } if (m_Cookies==null) { m_Cookies = new CookieCollection(); } if (HttpListenerContext.PromoteCookiesToRfc2965) { for (int index=0; index 0 && m_BoundaryType == BoundaryType.ContentLength) || m_BoundaryType == BoundaryType.Chunked || m_BoundaryType == BoundaryType.Multipart; } } public /* override */ bool KeepAlive { get { if (m_KeepAlive == TriState.Unspecified) { string header = Headers[HttpKnownHeaderNames.ProxyConnection]; if (string.IsNullOrEmpty(header)) { header = GetKnownHeader(HttpRequestHeader.Connection); } if (string.IsNullOrEmpty(header)) { if (ProtocolVersion >= HttpVersion.Version11) { m_KeepAlive = TriState.True; } else { header = GetKnownHeader(HttpRequestHeader.KeepAlive); m_KeepAlive = string.IsNullOrEmpty(header) ? TriState.False : TriState.True; } } else { header = header.ToLower(CultureInfo.InvariantCulture); m_KeepAlive = header.IndexOf("close") < 0 || header.IndexOf("keep-alive") >= 0 ? TriState.True : TriState.False; } } GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::KeepAlive_get() returning:" + m_KeepAlive); return m_KeepAlive == TriState.True; } } public /* override */ IPEndPoint RemoteEndPoint { get { if (m_RemoteEndPoint==null) { m_RemoteEndPoint = UnsafeNclNativeMethods.HttpApi.GetRemoteEndPoint(RequestBuffer, OriginalBlobAddress); } GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::RemoteEndPoint_get() returning:" + m_RemoteEndPoint); return m_RemoteEndPoint; } } public /* override */ IPEndPoint LocalEndPoint { get { if (m_LocalEndPoint==null) { m_LocalEndPoint = UnsafeNclNativeMethods.HttpApi.GetLocalEndPoint(RequestBuffer, OriginalBlobAddress); } GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::LocalEndPoint_get() returning:" + m_LocalEndPoint); return m_LocalEndPoint; } } //should only be called from httplistenercontext internal void Close() { if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Close", ""); RequestContextBase memoryBlob = m_MemoryBlob; if (memoryBlob != null) { memoryBlob.Close(); m_MemoryBlob = null; } m_IsDisposed = true; if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Close", ""); } 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); } break; } } catch { if (asyncResult!=null) { asyncResult.InternalCleanup(); } throw; } } else { asyncResult = new ListenerClientCertAsyncResult(this, state, requestCallback, 0); asyncResult.InvokeCallback(); } return asyncResult; } 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 string RequestScheme { get { return IsSecureConnection ? "https" : "http"; } } private Uri RequestUri { get { if (m_RequestUri == null) { m_RequestUri = HttpListenerRequestUriBuilder.GetRequestUri( m_RawUrl, RequestScheme, m_CookedUrlHost, m_CookedUrlPath, m_CookedUrlQuery); } GlobalLog.Print("HttpListenerRequest#" + ValidationHelper.HashString(this) + "::RequestUri_get() returning m_RequestUri:" + ValidationHelper.ToString(m_RequestUri)); return m_RequestUri; } } /* private DateTime IfModifiedSince { get { string headerValue = GetKnownHeader(HttpRequestHeader.IfModifiedSince); if (headerValue==null) { return DateTime.Now; } return DateTime.Parse(headerValue, CultureInfo.InvariantCulture); } } */ private string GetKnownHeader(HttpRequestHeader header) { return UnsafeNclNativeMethods.HttpApi.GetKnownHeader(RequestBuffer, OriginalBlobAddress, (int) header); } internal ChannelBinding GetChannelBinding() { return HttpListenerContext.Listener.GetChannelBindingFromTls(m_ConnectionId); } internal void CheckDisposed() { if (m_IsDisposed) { throw new ObjectDisposedException(this.GetType().FullName); } } // < static class Helpers { // // Get attribute off header value // internal static String GetAttributeFromHeader(String headerValue, String attrName) { if (headerValue == null) return null; int l = headerValue.Length; int k = attrName.Length; // find properly separated attribute name int i = 1; // start searching from 1 while (i < l) { i = CultureInfo.InvariantCulture.CompareInfo.IndexOf(headerValue, attrName, i, CompareOptions.IgnoreCase); if (i < 0) break; if (i+k >= l) break; char chPrev = headerValue[i-1]; char chNext = headerValue[i+k]; if ((chPrev == ';' || chPrev == ',' || Char.IsWhiteSpace(chPrev)) && (chNext == '=' || Char.IsWhiteSpace(chNext))) break; i += k; } if (i < 0 || i >= l) return null; // skip to '=' and the following whitespaces i += k; while (i < l && Char.IsWhiteSpace(headerValue[i])) i++; if (i >= l || headerValue[i] != '=') return null; i++; while (i < l && Char.IsWhiteSpace(headerValue[i])) i++; if (i >= l) return null; // parse the value String attrValue = null; int j; if (i < l && headerValue[i] == '"') { if (i == l-1) return null; j = headerValue.IndexOf('"', i+1); if (j < 0 || j == i+1) return null; attrValue = headerValue.Substring(i+1, j-i-1).Trim(); } else { for (j = i; j < l; j++) { if (headerValue[j] == ' ' || headerValue[j] == ',') break; } if (j == i) return null; attrValue = headerValue.Substring(i, j-i).Trim(); } return attrValue; } internal static String[] ParseMultivalueHeader(String s) { if (s == null) return null; int l = s.Length; // collect comma-separated values into list ArrayList values = new ArrayList(); int i = 0; while (i < l) { // find next , int ci = s.IndexOf(',', i); if (ci < 0) ci = l; // append corresponding server value values.Add(s.Substring(i, ci-i)); // move to next i = ci+1; // skip leading space if (i < l && s[i] == ' ') i++; } // return list as array of strings int n = values.Count; String[] strings; // if n is 0 that means s was empty string if (n == 0) { strings = new String[1]; strings[0] = String.Empty; } else { strings = new String[n]; values.CopyTo(0, strings, 0, n); } return strings; } private static string UrlDecodeStringFromStringInternal(string s, Encoding e) { int count = s.Length; UrlDecoder helper = new UrlDecoder(count, e); // go through the string's chars collapsing %XX and %uXXXX and // appending each char as char, with exception of %XX constructs // that are appended as bytes for (int pos = 0; pos < count; pos++) { char ch = s[pos]; if (ch == '+') { ch = ' '; } else if (ch == '%' && pos < count-2) { if (s[pos+1] == 'u' && pos < count-5) { int h1 = HexToInt(s[pos+2]); int h2 = HexToInt(s[pos+3]); int h3 = HexToInt(s[pos+4]); int h4 = HexToInt(s[pos+5]); if (h1 >= 0 && h2 >= 0 && h3 >= 0 && h4 >= 0) { // valid 4 hex chars ch = (char)((h1 << 12) | (h2 << 8) | (h3 << 4) | h4); pos += 5; // only add as char helper.AddChar(ch); continue; } } else { int h1 = HexToInt(s[pos+1]); int h2 = HexToInt(s[pos+2]); if (h1 >= 0 && h2 >= 0) { // valid 2 hex chars byte b = (byte)((h1 << 4) | h2); pos += 2; // don't add as char helper.AddByte(b); continue; } } } if ((ch & 0xFF80) == 0) helper.AddByte((byte)ch); // 7 bit have to go as bytes because of Unicode else helper.AddChar(ch); } return helper.GetString(); } private static int HexToInt(char h) { return( h >= '0' && h <= '9' ) ? h - '0' : ( h >= 'a' && h <= 'f' ) ? h - 'a' + 10 : ( h >= 'A' && h <= 'F' ) ? h - 'A' + 10 : -1; } private class UrlDecoder { private int _bufferSize; // Accumulate characters in a special array private int _numChars; private char[] _charBuffer; // Accumulate bytes for decoding into characters in a special array private int _numBytes; private byte[] _byteBuffer; // Encoding to convert chars to bytes private Encoding _encoding; private void FlushBytes() { if (_numBytes > 0) { _numChars += _encoding.GetChars(_byteBuffer, 0, _numBytes, _charBuffer, _numChars); _numBytes = 0; } } internal UrlDecoder(int bufferSize, Encoding encoding) { _bufferSize = bufferSize; _encoding = encoding; _charBuffer = new char[bufferSize]; // byte buffer created on demand } internal void AddChar(char ch) { if (_numBytes > 0) FlushBytes(); _charBuffer[_numChars++] = ch; } internal void AddByte(byte b) { // if there are no pending bytes treat 7 bit bytes as characters // this optimization is temp disable as it doesn't work for some encodings /* if (_numBytes == 0 && ((b & 0x80) == 0)) { AddChar((char)b); } else */ { if (_byteBuffer == null) _byteBuffer = new byte[_bufferSize]; _byteBuffer[_numBytes++] = b; } } internal String GetString() { if (_numBytes > 0) FlushBytes(); if (_numChars > 0) return new String(_charBuffer, 0, _numChars); else return String.Empty; } } internal static void FillFromString(NameValueCollection nvc, String s, bool urlencoded, Encoding encoding) { int l = (s != null) ? s.Length : 0; int i = (s.Length>0 && s[0]=='?') ? 1 : 0; while (i < l) { // find next & while noting first = on the way (and if there are more) int si = i; int ti = -1; while (i < l) { char ch = s[i]; if (ch == '=') { if (ti < 0) ti = i; } else if (ch == '&') { break; } i++; } // extract the name / value pair String name = null; String value = null; if (ti >= 0) { name = s.Substring(si, ti-si); value = s.Substring(ti+1, i-ti-1); } else { value = s.Substring(si, i-si); } // add name / value pair to the collection if (urlencoded) nvc.Add( name == null ? null : UrlDecodeStringFromStringInternal(name, encoding), UrlDecodeStringFromStringInternal(value, encoding)); else nvc.Add(name, value); // trailing '&' if (i == l-1 && s[i] == '&') nvc.Add(null, ""); i++; } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FreeIndexList.cs
- SqlDataSourceEnumerator.cs
- TextSelectionHelper.cs
- XmlValueConverter.cs
- DataGridParentRows.cs
- FileUpload.cs
- DefaultEventAttribute.cs
- CompiledQueryCacheKey.cs
- Processor.cs
- ReachDocumentSequenceSerializerAsync.cs
- SelectorAutomationPeer.cs
- HttpRequestCacheValidator.cs
- Matrix.cs
- DeferredTextReference.cs
- UrlAuthFailedErrorFormatter.cs
- ExpressionList.cs
- ExpandedWrapper.cs
- FormatStringEditor.cs
- SHA512.cs
- ResXFileRef.cs
- TraceInternal.cs
- Freezable.cs
- UnmanagedMemoryAccessor.cs
- BooleanExpr.cs
- AutoResetEvent.cs
- ChameleonKey.cs
- ProcessThreadCollection.cs
- ExpandCollapsePatternIdentifiers.cs
- StyleTypedPropertyAttribute.cs
- XmlChildNodes.cs
- UserNamePasswordValidationMode.cs
- SqlServer2KCompatibilityAnnotation.cs
- ResourceAssociationTypeEnd.cs
- _NetworkingPerfCounters.cs
- EventBuilder.cs
- WebUtil.cs
- TypedCompletedAsyncResult.cs
- Schema.cs
- ConnectionConsumerAttribute.cs
- SessionIDManager.cs
- ResourceExpressionEditorSheet.cs
- SelectionListDesigner.cs
- SmiContext.cs
- ListSourceHelper.cs
- CatalogZoneBase.cs
- PropertyMapper.cs
- SQLDecimal.cs
- AttributeAction.cs
- XmlSchemaDocumentation.cs
- HtmlMobileTextWriter.cs
- FieldToken.cs
- InteropAutomationProvider.cs
- Pointer.cs
- XmlDataSourceView.cs
- NamespaceCollection.cs
- WebRequestModuleElement.cs
- AnimationLayer.cs
- WebServiceFaultDesigner.cs
- formatstringdialog.cs
- ListViewItem.cs
- LiteralSubsegment.cs
- ScriptDescriptor.cs
- DataControlExtensions.cs
- ElementFactory.cs
- TextDecorationCollection.cs
- DescendantOverDescendantQuery.cs
- WebSysDisplayNameAttribute.cs
- BasicCellRelation.cs
- NativeWindow.cs
- DelegateSerializationHolder.cs
- TypeDependencyAttribute.cs
- SafeMarshalContext.cs
- AutomationPatternInfo.cs
- EndpointBehaviorElementCollection.cs
- TextPattern.cs
- EtwTrace.cs
- CheckBoxFlatAdapter.cs
- LabelDesigner.cs
- PersonalizationStateQuery.cs
- wgx_sdk_version.cs
- ScriptComponentDescriptor.cs
- DbDataSourceEnumerator.cs
- TextEditorSelection.cs
- DBBindings.cs
- MetadataWorkspace.cs
- SafeProcessHandle.cs
- Int32Rect.cs
- MembershipSection.cs
- ParentQuery.cs
- SystemInfo.cs
- AuthenticationManager.cs
- CopyNodeSetAction.cs
- DbUpdateCommandTree.cs
- ChangeDirector.cs
- ProgressBarBrushConverter.cs
- EntityKeyElement.cs
- ControlBindingsConverter.cs
- MonthCalendar.cs
- XPathItem.cs
- TCPClient.cs