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
- DataGridState.cs
- BitmapEffectInputConnector.cs
- WebControlAdapter.cs
- MarkupWriter.cs
- ScrollData.cs
- LinkDesigner.cs
- ChildTable.cs
- TemplateControlParser.cs
- CharacterHit.cs
- BuilderPropertyEntry.cs
- TrackingConditionCollection.cs
- odbcmetadatacollectionnames.cs
- QueryReaderSettings.cs
- HttpInputStream.cs
- Viewport2DVisual3D.cs
- SqlProcedureAttribute.cs
- DropAnimation.xaml.cs
- HotSpotCollection.cs
- TransformValueSerializer.cs
- XPathNodeIterator.cs
- TimeSpanConverter.cs
- MaterialGroup.cs
- OleDbConnection.cs
- XmlExpressionDumper.cs
- XmlLanguageConverter.cs
- OverrideMode.cs
- StackBuilderSink.cs
- SelectionItemPattern.cs
- DragDropHelper.cs
- CaseInsensitiveComparer.cs
- TextServicesCompartment.cs
- EncoderNLS.cs
- EnumerableWrapperWeakToStrong.cs
- WebPartsPersonalizationAuthorization.cs
- EntityUtil.cs
- WindowsUpDown.cs
- EventMap.cs
- TempFiles.cs
- ConsumerConnectionPoint.cs
- sitestring.cs
- XmlHierarchyData.cs
- MarkupExtensionParser.cs
- JsonServiceDocumentSerializer.cs
- ItemCollection.cs
- TextEditorCharacters.cs
- EventLogEntryCollection.cs
- XmlSerializerSection.cs
- DelegatingTypeDescriptionProvider.cs
- KeyFrames.cs
- DataGridViewControlCollection.cs
- AnonymousIdentificationSection.cs
- PermissionSet.cs
- RegexRunner.cs
- Pkcs7Recipient.cs
- Internal.cs
- WebPartAddingEventArgs.cs
- DefaultBindingPropertyAttribute.cs
- DockingAttribute.cs
- _HeaderInfoTable.cs
- MenuItemCollectionEditor.cs
- RuleConditionDialog.Designer.cs
- OperationCanceledException.cs
- TrackingExtract.cs
- GridSplitterAutomationPeer.cs
- CookielessData.cs
- FtpRequestCacheValidator.cs
- HttpHandlerAction.cs
- _SpnDictionary.cs
- AdapterDictionary.cs
- ObjectStateEntryBaseUpdatableDataRecord.cs
- HttpChannelBindingToken.cs
- DataSetViewSchema.cs
- CacheVirtualItemsEvent.cs
- XmlSchemaSimpleContentRestriction.cs
- SqlGenericUtil.cs
- MessageSecurityProtocolFactory.cs
- WebPartAuthorizationEventArgs.cs
- ClassImporter.cs
- StringValidator.cs
- DesignerListAdapter.cs
- ListSortDescriptionCollection.cs
- TextBoxDesigner.cs
- OutputCacheSettings.cs
- FormParameter.cs
- ComponentCollection.cs
- PlacementWorkspace.cs
- PriorityChain.cs
- MsmqChannelListenerBase.cs
- ListSortDescriptionCollection.cs
- WindowsFormsSectionHandler.cs
- XmlSchemaException.cs
- TreeNodeCollection.cs
- UnmanagedBitmapWrapper.cs
- TracePayload.cs
- WebPartMenu.cs
- MemberRelationshipService.cs
- QueryableDataSourceView.cs
- DataGridViewCellCancelEventArgs.cs
- TypeConstant.cs
- DbProviderFactories.cs