ThrowExceptionUsingLastError() public static method

public static ThrowExceptionUsingLastError ( ) : void
return void
Beispiel #1
0
 private void ThrowOnInvalidHandle(SafeWinHttpHandle handle)
 {
     if (handle.IsInvalid)
     {
         WinHttpException.ThrowExceptionUsingLastError();
     }
 }
Beispiel #2
0
        private void SetWinHttpCredential(
            SafeWinHttpHandle requestHandle,
            ICredentials credentials,
            Uri uri,
            uint authScheme,
            uint authTarget)
        {
            string userName;
            string password;

            Debug.Assert(credentials != null);
            Debug.Assert(authScheme != 0);
            Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY || 
                         authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);

            NetworkCredential networkCredential = credentials.GetCredential(uri, s_authSchemeStringMapping[authScheme]);

            if (networkCredential == null)
            {
                return;
            }

            if (networkCredential == CredentialCache.DefaultNetworkCredentials)
            {
                // Allow WinHTTP to transmit the default credentials.
                ChangeDefaultCredentialsPolicy(requestHandle, authTarget, allowDefaultCredentials:true);
                userName = null;
                password = null;
            }
            else
            {
                userName = networkCredential.UserName;
                password = networkCredential.Password;
                string domain = networkCredential.Domain;

                // WinHTTP does not support a blank username.  So, we will throw an exception.
                if (string.IsNullOrEmpty(userName))
                {
                    throw new InvalidOperationException(SR.net_http_username_empty_string);
                }

                if (!string.IsNullOrEmpty(domain))
                {
                    userName = domain + "\\" + userName;
                }
            }

            if (!Interop.WinHttp.WinHttpSetCredentials(
                requestHandle,
                authTarget,
                authScheme,
                userName,
                password,
                IntPtr.Zero))
            {
                WinHttpException.ThrowExceptionUsingLastError();
            }
        }
Beispiel #3
0
 private void SetWinHttpOption(SafeWinHttpHandle handle, uint option, ref uint optionData)
 {
     if (!Interop.WinHttp.WinHttpSetOption(
             handle,
             option,
             ref optionData))
     {
         WinHttpException.ThrowExceptionUsingLastError();
     }
 }
Beispiel #4
0
 private void SetWinHttpOption(SafeWinHttpHandle handle, uint option, string optionData)
 {
     if (!Interop.WinHttp.WinHttpSetOption(
             handle,
             option,
             optionData,
             (uint)optionData.Length))
     {
         WinHttpException.ThrowExceptionUsingLastError();
     }
 }
Beispiel #5
0
 private void SetSessionHandleTimeoutOptions()
 {
     if (!Interop.WinHttp.WinHttpSetTimeouts(
             _sessionHandle,
             0,
             (int)_connectTimeout.TotalMilliseconds,
             (int)_sendTimeout.TotalMilliseconds,
             (int)_receiveHeadersTimeout.TotalMilliseconds))
     {
         WinHttpException.ThrowExceptionUsingLastError();
     }
 }
Beispiel #6
0
 private static void SetWinHttpOption(
     SafeWinHttpHandle handle,
     uint option,
     IntPtr optionData,
     uint optionSize)
 {
     if (!Interop.WinHttp.WinHttpSetOption(
             handle,
             option,
             optionData,
             optionSize))
     {
         WinHttpException.ThrowExceptionUsingLastError();
     }
 }
Beispiel #7
0
        private static string GetResponseHeaderStringHelper(
            SafeWinHttpHandle requestHandle,
            uint infoLevel,
            ref uint index)
        {
            uint bytesNeeded = 0;
            bool results     = false;

            // Call WinHttpQueryHeaders once to obtain the size of the buffer needed.  The size is returned in
            // bytes but the API actually returns Unicode characters.
            if (!Interop.WinHttp.WinHttpQueryHeaders(
                    requestHandle,
                    infoLevel,
                    Interop.WinHttp.WINHTTP_HEADER_NAME_BY_INDEX,
                    null,
                    ref bytesNeeded,
                    ref index))
            {
                int lastError = Marshal.GetLastWin32Error();
                if (lastError == Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
                {
                    return(null);
                }

                if (lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER)
                {
                    throw WinHttpException.CreateExceptionUsingError(lastError);
                }
            }

            // Allocate space for the buffer.
            int charsNeeded = (int)bytesNeeded / sizeof(char);
            var buffer      = new StringBuilder(charsNeeded, charsNeeded);

            results = Interop.WinHttp.WinHttpQueryHeaders(
                requestHandle,
                infoLevel,
                Interop.WinHttp.WINHTTP_HEADER_NAME_BY_INDEX,
                buffer,
                ref bytesNeeded,
                ref index);
            if (!results)
            {
                WinHttpException.ThrowExceptionUsingLastError();
            }

            return(buffer.ToString());
        }
Beispiel #8
0
        private static void AddRequestHeaders(
            SafeWinHttpHandle requestHandle,
            HttpRequestMessage requestMessage,
            CookieContainer cookies)
        {
            var requestHeadersBuffer = new StringBuilder();

            // Manually add cookies.
            if (cookies != null)
            {
                string cookieHeader = GetCookieHeader(requestMessage.RequestUri, cookies);
                if (!string.IsNullOrEmpty(cookieHeader))
                {
                    requestHeadersBuffer.AppendLine(cookieHeader);
                }
            }

            // Serialize general request headers.
            requestHeadersBuffer.AppendLine(requestMessage.Headers.ToString());

            // Serialize entity-body (content) headers.
            if (requestMessage.Content != null)
            {
                // TODO: Content-Length header isn't getting correctly placed using ToString()
                // This is a bug in HttpContentHeaders that needs to be fixed.
                if (requestMessage.Content.Headers.ContentLength.HasValue)
                {
                    long contentLength = requestMessage.Content.Headers.ContentLength.Value;
                    requestMessage.Content.Headers.ContentLength = null;
                    requestMessage.Content.Headers.ContentLength = contentLength;
                }

                requestHeadersBuffer.AppendLine(requestMessage.Content.Headers.ToString());
            }

            // Add request headers to WinHTTP request handle.
            if (!Interop.WinHttp.WinHttpAddRequestHeaders(
                    requestHandle,
                    requestHeadersBuffer,
                    (uint)requestHeadersBuffer.Length,
                    Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
            {
                WinHttpException.ThrowExceptionUsingLastError();
            }
        }
Beispiel #9
0
        /// <summary>
        /// Returns the first header or throws if the header isn't found.
        /// </summary>
        public static uint GetResponseHeaderNumberInfo(SafeWinHttpHandle requestHandle, uint infoLevel)
        {
            uint result     = 0;
            uint resultSize = sizeof(uint);

            if (!Interop.WinHttp.WinHttpQueryHeaders(
                    requestHandle,
                    infoLevel | Interop.WinHttp.WINHTTP_QUERY_FLAG_NUMBER,
                    Interop.WinHttp.WINHTTP_HEADER_NAME_BY_INDEX,
                    ref result,
                    ref resultSize,
                    IntPtr.Zero))
            {
                WinHttpException.ThrowExceptionUsingLastError();
            }

            return(result);
        }
Beispiel #10
0
        private Task <bool> InternalSendRequestAsync(WinHttpRequestState state)
        {
            state.TcsSendRequest = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);

            lock (state.Lock)
            {
                if (!Interop.WinHttp.WinHttpSendRequest(
                        state.RequestHandle,
                        null,
                        0,
                        IntPtr.Zero,
                        0,
                        0,
                        state.ToIntPtr()))
                {
                    WinHttpException.ThrowExceptionUsingLastError();
                }
            }

            return(state.TcsSendRequest.Task);
        }
        public static void ResetCookieRequestHeaders(WinHttpRequestState state, Uri redirectUri)
        {
            SafeWinHttpHandle?requestHandle = state.RequestHandle;

            Debug.Assert(state.Handler != null);
            Debug.Assert(state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer);
            Debug.Assert(state.Handler.CookieContainer != null);
            Debug.Assert(requestHandle != null);

            // Clear cookies.
            if (!Interop.WinHttp.WinHttpAddRequestHeaders(
                    requestHandle,
                    CookieHeaderNameWithColon,
                    (uint)CookieHeaderNameWithColon.Length,
                    Interop.WinHttp.WINHTTP_ADDREQ_FLAG_REPLACE))
            {
                int lastError = Marshal.GetLastWin32Error();
                if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
                {
                    throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
                }
            }

            // Re-add cookies. The GetCookieHeader() method will return the correct set of
            // cookies based on the redirectUri.
            string?cookieHeader = GetCookieHeader(redirectUri, state.Handler.CookieContainer);

            if (!string.IsNullOrEmpty(cookieHeader))
            {
                if (!Interop.WinHttp.WinHttpAddRequestHeaders(
                        requestHandle,
                        cookieHeader,
                        (uint)cookieHeader.Length,
                        Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
                {
                    WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
                }
            }
        }
Beispiel #12
0
        public void ChangeDefaultCredentialsPolicy(
            SafeWinHttpHandle requestHandle,
            uint authTarget,
            bool allowDefaultCredentials)
        {
            Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY ||
                         authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);

            uint optionData = allowDefaultCredentials ?
                              (authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY ?
                               Interop.WinHttp.WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM :
                               Interop.WinHttp.WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW) :
                              Interop.WinHttp.WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH;

            if (!Interop.WinHttp.WinHttpSetOption(
                    requestHandle,
                    Interop.WinHttp.WINHTTP_OPTION_AUTOLOGON_POLICY,
                    ref optionData))
            {
                WinHttpException.ThrowExceptionUsingLastError();
            }
        }
Beispiel #13
0
        public void GetProxyForUrl(SafeWinHttpHandle sessionHandle, Uri uri, out Interop.WinHttp.WINHTTP_PROXY_INFO proxyInfo)
        {
            Interop.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions;
            autoProxyOptions.AutoConfigUrl         = AutoConfigUrl;
            autoProxyOptions.AutoDetectFlags       = AutoDetect ? (Interop.WinHttp.WINHTTP_AUTO_DETECT_TYPE_DHCP | Interop.WinHttp.WINHTTP_AUTO_DETECT_TYPE_DNS_A) : 0;
            autoProxyOptions.AutoLoginIfChallenged = false;
            autoProxyOptions.Flags =
                (AutoDetect ? Interop.WinHttp.WINHTTP_AUTOPROXY_AUTO_DETECT : 0) |
                (!string.IsNullOrEmpty(AutoConfigUrl) ? Interop.WinHttp.WINHTTP_AUTOPROXY_CONFIG_URL : 0);
            autoProxyOptions.Reserved1 = IntPtr.Zero;
            autoProxyOptions.Reserved2 = 0;

            // AutoProxy Cache.
            // http://msdn.microsoft.com/en-us/library/windows/desktop/aa383153(v=vs.85).aspx
            // If the out-of-process service is active when WinHttpGetProxyForUrl is called, the cached autoproxy
            // URL and script are available to the whole computer. However, if the out-of-process service is used,
            // and the fAutoLogonIfChallenged flag in the pAutoProxyOptions structure is true, then the autoproxy
            // URL and script are not cached. Therefore, calling WinHttpGetProxyForUrl with the fAutoLogonIfChallenged
            // member set to TRUE results in additional overhead operations that may affect performance.
            // The following steps can be used to improve performance:
            // 1. Call WinHttpGetProxyForUrl with the fAutoLogonIfChallenged parameter set to false. The autoproxy
            //    URL and script are cached for future calls to WinHttpGetProxyForUrl.
            // 2. If Step 1 fails, with ERROR_WINHTTP_LOGIN_FAILURE, then call WinHttpGetProxyForUrl with the
            //    fAutoLogonIfChallenged member set to TRUE.
            var repeat = false;

            do
            {
                if (Interop.WinHttp.WinHttpGetProxyForUrl(sessionHandle, uri.AbsoluteUri, ref autoProxyOptions, out proxyInfo))
                {
                    repeat = false;
                }
                else
                {
                    var lastError = Marshal.GetLastWin32Error();
                    if (lastError == Interop.WinHttp.ERROR_WINHTTP_AUTODETECTION_FAILED)
                    {
                        // Fall back to manual settings if available.
                        if (!string.IsNullOrEmpty(Proxy))
                        {
                            proxyInfo.AccessType  = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NAMED_PROXY;
                            proxyInfo.Proxy       = Marshal.StringToHGlobalUni(Proxy);
                            proxyInfo.ProxyBypass = string.IsNullOrEmpty(ProxyBypass) ? IntPtr.Zero : Marshal.StringToHGlobalUni(ProxyBypass);
                        }
                        else
                        {
                            proxyInfo.AccessType  = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NO_PROXY;
                            proxyInfo.Proxy       = IntPtr.Zero;
                            proxyInfo.ProxyBypass = IntPtr.Zero;
                        }

                        repeat = false;
                    }
                    else if (lastError == Interop.WinHttp.ERROR_WINHTTP_LOGIN_FAILURE)
                    {
                        if (repeat)
                        {
                            throw WinHttpException.CreateExceptionUsingError(lastError);
                        }

                        repeat = true;
                        autoProxyOptions.AutoLoginIfChallenged = true;
                    }
                    else
                    {
                        WinHttpException.ThrowExceptionUsingLastError();
                    }
                }
            } while (repeat);
        }
        private static void OnRequestRedirect(WinHttpRequestState state, Uri redirectUri)
        {
            const string EmptyCookieHeader = "Cookie:";

            Debug.Assert(state != null, "OnRequestRedirect: state is null");
            Debug.Assert(redirectUri != null, "OnRequestRedirect: redirectUri is null");
            Debug.Assert(state.TcsReceiveResponseHeaders != null, "TcsReceiveResponseHeaders is null");
            Debug.Assert(!state.TcsReceiveResponseHeaders.Task.IsCompleted, "TcsReceiveResponseHeaders.Task is completed");

            // If we're manually handling cookies, we need to reset them based on the new URI.
            if (state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer)
            {
                // Clear cookies.
                if (!Interop.WinHttp.WinHttpAddRequestHeaders(
                        state.RequestHandle,
                        EmptyCookieHeader,
                        (uint)EmptyCookieHeader.Length,
                        Interop.WinHttp.WINHTTP_ADDREQ_FLAG_REPLACE))
                {
                    int lastError = Marshal.GetLastWin32Error();
                    if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
                    {
                        throw WinHttpException.CreateExceptionUsingError(lastError);
                    }
                }

                // Re-add cookies. The GetCookieHeader() method will return the correct set of
                // cookies based on the redirectUri.
                string cookieHeader = WinHttpHandler.GetCookieHeader(redirectUri, state.Handler.CookieContainer);
                if (!string.IsNullOrEmpty(cookieHeader))
                {
                    if (!Interop.WinHttp.WinHttpAddRequestHeaders(
                            state.RequestHandle,
                            cookieHeader,
                            (uint)cookieHeader.Length,
                            Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
                    {
                        WinHttpException.ThrowExceptionUsingLastError();
                    }
                }
            }

            state.RequestMessage.RequestUri = redirectUri;

            // Redirection to a new uri may require a new connection through a potentially different proxy.
            // If so, we will need to respond to additional 407 proxy auth demands and re-attach any
            // proxy credentials. The ProcessResponse() method looks at the state.LastStatusCode
            // before attaching proxy credentials and marking the HTTP request to be re-submitted.
            // So we need to reset the LastStatusCode remembered. Otherwise, it will see additional 407
            // responses as an indication that proxy auth failed and won't retry the HTTP request.
            if (state.LastStatusCode == HttpStatusCode.ProxyAuthenticationRequired)
            {
                state.LastStatusCode = 0;
            }

            // For security reasons, we drop the server credential if it is a
            // NetworkCredential.  But we allow credentials in a CredentialCache
            // since they are specifically tied to URI's.
            if (!(state.ServerCredentials is CredentialCache))
            {
                state.ServerCredentials = null;
            }
        }
Beispiel #15
0
        private bool SetWinHttpCredential(
            SafeWinHttpHandle requestHandle,
            ICredentials credentials,
            Uri uri,
            uint authScheme,
            uint authTarget)
        {
            string?userName;
            string?password;

            Debug.Assert(credentials != null);
            Debug.Assert(authScheme != 0);
            Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY ||
                         authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);

            string?authType = s_authSchemeStringMapping[authScheme];

            Debug.Assert(!string.IsNullOrEmpty(authType));
            NetworkCredential?networkCredential = credentials.GetCredential(uri, authType);

            if (networkCredential == null)
            {
                return(false);
            }

            if (networkCredential == CredentialCache.DefaultNetworkCredentials)
            {
                // Only Negotiate and NTLM can use default credentials. Otherwise,
                // behave as-if there were no credentials.
                if (authScheme == Interop.WinHttp.WINHTTP_AUTH_SCHEME_NEGOTIATE ||
                    authScheme == Interop.WinHttp.WINHTTP_AUTH_SCHEME_NTLM)
                {
                    // Allow WinHTTP to transmit the default credentials.
                    ChangeDefaultCredentialsPolicy(requestHandle, authTarget, allowDefaultCredentials: true);
                    userName = null;
                    password = null;
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                userName = networkCredential.UserName;
                password = networkCredential.Password;
                string domain = networkCredential.Domain;

                // WinHTTP does not support a blank username.  So, we will throw an exception.
                if (string.IsNullOrEmpty(userName))
                {
                    throw new InvalidOperationException(SR.net_http_username_empty_string);
                }

                if (!string.IsNullOrEmpty(domain))
                {
                    userName = domain + "\\" + userName;
                }
            }

            if (!Interop.WinHttp.WinHttpSetCredentials(
                    requestHandle,
                    authTarget,
                    authScheme,
                    userName,
                    password,
                    IntPtr.Zero))
            {
                WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetCredentials));
            }

            return(true);
        }
Beispiel #16
0
        public void CheckResponseForAuthentication(
            WinHttpRequestState state,
            ref uint proxyAuthScheme,
            ref uint serverAuthScheme)
        {
            uint supportedSchemes   = 0;
            uint firstSchemeIgnored = 0;
            uint authTarget         = 0;
            Uri  uri = state.RequestMessage.RequestUri;

            state.RetryRequest = false;

            // Check the status code and retry the request applying credentials if needed.
            var statusCode = (HttpStatusCode)WinHttpResponseParser.GetResponseHeaderNumberInfo(
                state.RequestHandle,
                Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE);

            switch (statusCode)
            {
            case HttpStatusCode.Unauthorized:
                if (state.ServerCredentials == null || state.LastStatusCode == HttpStatusCode.Unauthorized)
                {
                    // Either we don't have server credentials or we already tried
                    // to set the credentials and it failed before.
                    // So we will let the 401 be the final status code returned.
                    break;
                }

                state.LastStatusCode = statusCode;

                // Determine authorization scheme to use. We ignore the firstScheme
                // parameter which is included in the supportedSchemes flags already.
                // We pass the schemes to ChooseAuthScheme which will pick the scheme
                // based on most secure scheme to least secure scheme ordering.
                if (!Interop.WinHttp.WinHttpQueryAuthSchemes(
                        state.RequestHandle,
                        out supportedSchemes,
                        out firstSchemeIgnored,
                        out authTarget))
                {
                    WinHttpException.ThrowExceptionUsingLastError();
                }

                // WinHTTP returns the proper authTarget based on the status code (401, 407).
                // But we can validate with assert.
                Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);

                serverAuthScheme = ChooseAuthScheme(supportedSchemes);
                if (serverAuthScheme != 0)
                {
                    SetWinHttpCredential(
                        state.RequestHandle,
                        state.ServerCredentials,
                        uri,
                        serverAuthScheme,
                        authTarget);

                    state.RetryRequest = true;
                }

                break;

            case HttpStatusCode.ProxyAuthenticationRequired:
                if (state.LastStatusCode == HttpStatusCode.ProxyAuthenticationRequired)
                {
                    // We tried already to set the credentials.
                    break;
                }

                state.LastStatusCode = statusCode;

                // If we don't have any proxy credentials to try, then we end up with 407.
                ICredentials proxyCreds = state.Proxy == null ?
                                          state.DefaultProxyCredentials :
                                          state.Proxy.Credentials;
                if (proxyCreds == null)
                {
                    break;
                }

                // Determine authorization scheme to use. We ignore the firstScheme
                // parameter which is included in the supportedSchemes flags already.
                // We pass the schemes to ChooseAuthScheme which will pick the scheme
                // based on most secure scheme to least secure scheme ordering.
                if (!Interop.WinHttp.WinHttpQueryAuthSchemes(
                        state.RequestHandle,
                        out supportedSchemes,
                        out firstSchemeIgnored,
                        out authTarget))
                {
                    WinHttpException.ThrowExceptionUsingLastError();
                }

                // WinHTTP returns the proper authTarget based on the status code (401, 407).
                // But we can validate with assert.
                Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY);

                proxyAuthScheme    = ChooseAuthScheme(supportedSchemes);
                state.RetryRequest = true;
                break;

            default:
                if (state.PreAuthenticate && serverAuthScheme != 0)
                {
                    SaveServerCredentialsToCache(uri, serverAuthScheme, state.ServerCredentials);
                }
                break;
            }
        }
Beispiel #17
0
        private void EnsureSessionHandleExists(WinHttpRequestState state)
        {
            if (_sessionHandle == null)
            {
                lock (_lockObject)
                {
                    if (_sessionHandle == null)
                    {
                        uint accessType;

                        // If a custom proxy is specified and it is really the system web proxy
                        // (initial WebRequest.DefaultWebProxy) then we need to update the settings
                        // since that object is only a sentinel.
                        if (state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseCustomProxy)
                        {
                            Debug.Assert(state.Proxy != null);
                            try
                            {
                                state.Proxy.GetProxy(state.RequestMessage.RequestUri);
                            }
                            catch (PlatformNotSupportedException)
                            {
                                // This is the system web proxy.
                                state.WindowsProxyUsePolicy = WindowsProxyUsePolicy.UseWinInetProxy;
                                state.Proxy = null;
                            }
                        }

                        if (state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.DoNotUseProxy ||
                            state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseCustomProxy)
                        {
                            // Either no proxy at all or a custom IWebProxy proxy is specified.
                            // For a custom IWebProxy, we'll need to calculate and set the proxy
                            // on a per request handle basis using the request Uri.  For now,
                            // we set the session handle to have no proxy.
                            accessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NO_PROXY;
                        }
                        else if (state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseWinHttpProxy)
                        {
                            // Use WinHTTP per-machine proxy settings which are set using the "netsh winhttp" command.
                            accessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
                        }
                        else
                        {
                            // Use WinInet per-user proxy settings.
                            accessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY;
                        }

                        _sessionHandle = Interop.WinHttp.WinHttpOpen(
                            IntPtr.Zero,
                            accessType,
                            Interop.WinHttp.WINHTTP_NO_PROXY_NAME,
                            Interop.WinHttp.WINHTTP_NO_PROXY_BYPASS,
                            (int)Interop.WinHttp.WINHTTP_FLAG_ASYNC);

                        if (_sessionHandle.IsInvalid)
                        {
                            int lastError = Marshal.GetLastWin32Error();
                            if (lastError != Interop.WinHttp.ERROR_INVALID_PARAMETER)
                            {
                                ThrowOnInvalidHandle(_sessionHandle);
                            }

                            // We must be running on a platform earlier than Win8.1/Win2K12R2 which doesn't support
                            // WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY.  So, we'll need to read the Wininet style proxy
                            // settings ourself using our WinInetProxyHelper object.
                            _proxyHelper   = new WinInetProxyHelper();
                            _sessionHandle = Interop.WinHttp.WinHttpOpen(
                                IntPtr.Zero,
                                _proxyHelper.ManualSettingsOnly ? Interop.WinHttp.WINHTTP_ACCESS_TYPE_NAMED_PROXY : Interop.WinHttp.WINHTTP_ACCESS_TYPE_NO_PROXY,
                                _proxyHelper.ManualSettingsOnly ? _proxyHelper.Proxy : Interop.WinHttp.WINHTTP_NO_PROXY_NAME,
                                _proxyHelper.ManualSettingsOnly ? _proxyHelper.ProxyBypass : Interop.WinHttp.WINHTTP_NO_PROXY_BYPASS,
                                (int)Interop.WinHttp.WINHTTP_FLAG_ASYNC);
                            ThrowOnInvalidHandle(_sessionHandle);
                        }

                        uint optionAssuredNonBlockingTrue = 1; // TRUE

                        if (!Interop.WinHttp.WinHttpSetOption(
                                _sessionHandle,
                                Interop.WinHttp.WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS,
                                ref optionAssuredNonBlockingTrue,
                                (uint)Marshal.SizeOf <uint>()))
                        {
                            WinHttpException.ThrowExceptionUsingLastError();
                        }
                    }
                }
            }
        }