Ejemplo n.º 1
0
 internal WinHttpRequestStream(SafeWinHttpHandle requestHandle, bool chunkedMode)
 {
     bool ignore = false;
     requestHandle.DangerousAddRef(ref ignore);
     _requestHandle = requestHandle;
     _chunkedMode = chunkedMode;
 }
Ejemplo n.º 2
0
 public static SafeWinHttpHandle WinHttpConnect(
     SafeWinHttpHandle sessionHandle,
     string serverName,
     ushort serverPort,
     uint reserved)
 {
     return new FakeSafeWinHttpHandle(true);
 }
Ejemplo n.º 3
0
        internal void SetChannelBinding(SafeWinHttpHandle requestHandle)
        {
            var channelBinding = new WinHttpChannelBinding(requestHandle);

            if (channelBinding.IsInvalid)
            {
                channelBinding.Dispose();
            }
            else
            {
                _channelBinding = channelBinding;
            }
        }
 internal WinHttpResponseStream(
     SafeWinHttpHandle sessionHandle,
     SafeWinHttpHandle connectHandle,
     SafeWinHttpHandle requestHandle)
 {
     // While we only use the requestHandle to do actual reads of the response body,
     // we need to keep the parent handles (connection, session) alive as well.
     bool ignore = false;
     sessionHandle.DangerousAddRef(ref ignore);
     connectHandle.DangerousAddRef(ref ignore);
     requestHandle.DangerousAddRef(ref ignore);
     _sessionHandle = sessionHandle;
     _connectHandle = connectHandle;
     _requestHandle = requestHandle;
 }
Ejemplo n.º 5
0
        internal WinHttpChannelBinding(SafeWinHttpHandle requestHandle)
        {
            IntPtr data = IntPtr.Zero;
            uint dataSize = 0;

            if (!Interop.WinHttp.WinHttpQueryOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_SERVER_CBT, null, ref dataSize))
            {
                if (Marshal.GetLastWin32Error() == Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER)
                {
                    data = Marshal.AllocHGlobal((int)dataSize);

                    if (Interop.WinHttp.WinHttpQueryOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_SERVER_CBT, data, ref dataSize))
                    {
                        SetHandle(data);
                        _size = (int)dataSize;
                    }
                    else
                    {
                        Marshal.FreeHGlobal(data);
                    }
                }
            }
        }
Ejemplo n.º 6
0
        public static HttpResponseMessage CreateResponseMessage(
            WinHttpRequestState state,
            bool doManualDecompressionCheck)
        {
            HttpRequestMessage request         = state.RequestMessage;
            SafeWinHttpHandle  requestHandle   = state.RequestHandle;
            CookieUsePolicy    cookieUsePolicy = state.Handler.CookieUsePolicy;
            CookieContainer    cookieContainer = state.Handler.CookieContainer;
            var  response             = new HttpResponseMessage();
            bool stripEncodingHeaders = false;

            // Create a single buffer to use for all subsequent WinHttpQueryHeaders string interop calls.
            // This buffer is the length needed for WINHTTP_QUERY_RAW_HEADERS_CRLF, which includes the status line
            // and all headers separated by CRLF, so it should be large enough for any individual status line or header queries.
            int bufferLength = GetResponseHeaderCharBufferLength(requestHandle, Interop.WinHttp.WINHTTP_QUERY_RAW_HEADERS_CRLF);

            char[] buffer = new char[bufferLength];

            // Get HTTP version, status code, reason phrase from the response headers.

            if (IsResponseHttp2(requestHandle))
            {
                response.Version = WinHttpHandler.HttpVersion20;
            }
            else
            {
                int versionLength = GetResponseHeader(requestHandle, Interop.WinHttp.WINHTTP_QUERY_VERSION, buffer);
                response.Version =
                    CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase("HTTP/1.1", buffer, 0, versionLength) ? HttpVersion.Version11 :
                    CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase("HTTP/1.0", buffer, 0, versionLength) ? HttpVersion.Version10 :
                    WinHttpHandler.HttpVersionUnknown;
            }

            response.StatusCode = (HttpStatusCode)GetResponseHeaderNumberInfo(
                requestHandle,
                Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE);

            int reasonPhraseLength = GetResponseHeader(requestHandle, Interop.WinHttp.WINHTTP_QUERY_STATUS_TEXT, buffer);

            response.ReasonPhrase = reasonPhraseLength > 0 ?
                                    GetReasonPhrase(response.StatusCode, buffer, reasonPhraseLength) :
                                    string.Empty;

            // Create response stream and wrap it in a StreamContent object.
            var responseStream = new WinHttpResponseStream(requestHandle, state);

            state.RequestHandle = null; // ownership successfully transfered to WinHttpResponseStram.
            Stream decompressedStream = responseStream;

            if (doManualDecompressionCheck)
            {
                int contentEncodingStartIndex = 0;
                int contentEncodingLength     = GetResponseHeader(
                    requestHandle,
                    Interop.WinHttp.WINHTTP_QUERY_CONTENT_ENCODING,
                    buffer);

                CharArrayHelpers.Trim(buffer, ref contentEncodingStartIndex, ref contentEncodingLength);

                if (contentEncodingLength > 0)
                {
                    if (CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase(
                            EncodingNameGzip, buffer, contentEncodingStartIndex, contentEncodingLength))
                    {
                        decompressedStream   = new GZipStream(responseStream, CompressionMode.Decompress);
                        stripEncodingHeaders = true;
                    }
                    else if (CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase(
                                 EncodingNameDeflate, buffer, contentEncodingStartIndex, contentEncodingLength))
                    {
                        decompressedStream   = new DeflateStream(responseStream, CompressionMode.Decompress);
                        stripEncodingHeaders = true;
                    }
                }
            }

#if HTTP_DLL
            var content = new StreamContent(decompressedStream, state.CancellationToken);
#else
            // TODO: Issue https://github.com/dotnet/corefx/issues/9071
            // We'd like to be able to pass state.CancellationToken into the StreamContent so that its
            // SerializeToStreamAsync method can use it, but that ctor isn't public, nor is there a
            // SerializeToStreamAsync override that takes a CancellationToken.
            var content = new StreamContent(decompressedStream);
#endif

            response.Content        = content;
            response.RequestMessage = request;

            // Parse raw response headers and place them into response message.
            ParseResponseHeaders(requestHandle, response, buffer, stripEncodingHeaders);

            if (response.RequestMessage.Method != HttpMethod.Head)
            {
                state.ExpectedBytesToRead = response.Content.Headers.ContentLength;
            }

            return(response);
        }
Ejemplo n.º 7
0
        private 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;
        }
Ejemplo n.º 8
0
 private void SetRequestHandleCookieOptions(SafeWinHttpHandle requestHandle)
 {
     if (_cookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer ||
         _cookieUsePolicy == CookieUsePolicy.IgnoreCookies)
     {
         uint optionData = Interop.WinHttp.WINHTTP_DISABLE_COOKIES;
         SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_DISABLE_FEATURE, ref optionData);
     }
 }
Ejemplo n.º 9
0
        private void SetRequestHandleClientCertificateOptions(SafeWinHttpHandle requestHandle, Uri requestUri)
        {
            // Must be HTTPS scheme to use client certificates.
            if (requestUri.Scheme != UriSchemeHttps)
            {
                return;
            }

            // Get candidate list for client certificates.
            X509Certificate2Collection certs;
            if (_clientCertificateOption == ClientCertificateOption.Manual)
            {
                certs = ClientCertificates;
            }
            else
            {
                using (var myStore = new X509Store())
                {
                    myStore.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
                    certs = myStore.Certificates;
                }
            }

            // Check for no certs now as a performance optimization.
            if (certs.Count == 0)
            {
                SetNoClientCertificate(requestHandle);
                return;
            }

            // Reduce the set of certificates to match the proper 'Client Authentication' criteria.
            certs = certs.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, true);
            certs = certs.Find(X509FindType.FindByApplicationPolicy, ClientAuthenticationOID, true);

            // Build a new collection with certs that have a private key. Need to do this
            // manually because there is no X509FindType to match this criteria.
            var clientCerts = new X509Certificate2Collection();
            foreach (var cert in certs)
            {
                if (cert.HasPrivateKey)
                {
                    clientCerts.Add(cert);
                }
            }

            // TOOD: Filter the list based on TrustedIssuerList info from WINHTTP.

            // Set the client certificate.
            if (certs.Count == 0)
            {
                SetNoClientCertificate(requestHandle);
            }
            else
            {
                SetWinHttpOption(
                    requestHandle,
                    Interop.WinHttp.WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
                    clientCerts[0].Handle,
                    (uint)Marshal.SizeOf<Interop.Crypt32.CERT_CONTEXT>());
            }
        }
Ejemplo n.º 10
0
        private void ProcessResponse(
            RequestState state,
            SafeWinHttpHandle requestHandle,
            ref uint proxyAuthScheme,
            ref uint serverAuthScheme,
            out bool retryRequest)
        {
            retryRequest = false;

            // Check the status code and retry the request applying credentials if needed.
            var statusCode = (HttpStatusCode)GetResponseHeaderNumberInfo(
                requestHandle,
                Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE);
            uint supportedSchemes = 0;
            uint firstSchemeIgnored = 0;
            uint authTarget = 0;
            Uri uri = state.RequestMessage.RequestUri;

            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(
                        requestHandle,
                        out supportedSchemes,
                        out firstSchemeIgnored,
                        out authTarget))
                    {
                        WinHttpException.ThrowExceptionUsingLastError();
                    }

                    // Verify the authTarget is for server authentication only.
                    if (authTarget != Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER)
                    {
                        // TODO: Protocol violation. Add detailed error message.
                        throw new InvalidOperationException();
                    }

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

                        retryRequest = true;
                    }
                    break;

                case HttpStatusCode.ProxyAuthenticationRequired:
                    if (state.LastStatusCode == HttpStatusCode.ProxyAuthenticationRequired)
                    {
                        // We tried already to set the credentials.
                        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(
                        requestHandle,
                        out supportedSchemes,
                        out firstSchemeIgnored,
                        out authTarget))
                    {
                        WinHttpException.ThrowExceptionUsingLastError();
                    }

                    // Verify the authTarget is for proxy authentication only.
                    if (authTarget != Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY)
                    {
                        // TODO: Protocol violation. Add detailed error message.
                        throw new InvalidOperationException();
                    }

                    proxyAuthScheme = ChooseAuthScheme(supportedSchemes);

                    retryRequest = true;
                    break;

                default:
                    if (_preAuthenticate && serverAuthScheme != 0)
                    {
                        SaveServerCredentialsToCache(uri, serverAuthScheme, state.ServerCredentials);
                    }
                    break;
            }
        }
Ejemplo n.º 11
0
        private void SetRequestHandleDecompressionOptions(SafeWinHttpHandle requestHandle)
        {
            uint optionData = 0;

            if (_automaticDecompression != DecompressionMethods.None)
            {
                if ((_automaticDecompression & DecompressionMethods.GZip) != 0)
                {
                    optionData |= Interop.WinHttp.WINHTTP_DECOMPRESSION_FLAG_GZIP;
                }

                if ((_automaticDecompression & DecompressionMethods.Deflate) != 0)
                {
                    optionData |= Interop.WinHttp.WINHTTP_DECOMPRESSION_FLAG_DEFLATE;
                }

                try
                {
                    SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_DECOMPRESSION, ref optionData);
                }
                catch (WinHttpException ex)
                {
                    if (ex.NativeErrorCode != (int)Interop.WinHttp.ERROR_WINHTTP_INVALID_OPTION)
                    {
                        throw;
                    }

                    // We are running on a platform earlier than Win8.1 for which WINHTTP.DLL
                    // doesn't support this option.  So, we'll have to do the decompression
                    // manually.
                    _doManualDecompressionCheck = true;
                }
            }
        }
Ejemplo n.º 12
0
        public bool GetProxyForUrl(
            SafeWinHttpHandle sessionHandle,
            Uri uri,
            out Interop.WinHttp.WINHTTP_PROXY_INFO proxyInfo)
        {
            proxyInfo.AccessType  = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NO_PROXY;
            proxyInfo.Proxy       = IntPtr.Zero;
            proxyInfo.ProxyBypass = IntPtr.Zero;

            if (!_useProxy)
            {
                return(false);
            }

            bool useProxy = false;

            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.
            // https://docs.microsoft.com/en-us/windows/desktop/WinHttp/autoproxy-cache
            // 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.
            //
            // We match behavior of WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY and ignore errors.
            var repeat = false;

            do
            {
                _autoDetectionFailed = false;
                if (Interop.WinHttp.WinHttpGetProxyForUrl(
                        sessionHandle,
                        uri.AbsoluteUri,
                        ref autoProxyOptions,
                        out proxyInfo))
                {
                    if (NetEventSource.IsEnabled)
                    {
                        NetEventSource.Info(this, "Using autoconfig proxy settings");
                    }
                    useProxy = true;

                    break;
                }
                else
                {
                    var lastError = Marshal.GetLastWin32Error();
                    if (NetEventSource.IsEnabled)
                    {
                        NetEventSource.Error(this, $"error={lastError}");
                    }

                    if (lastError == Interop.WinHttp.ERROR_WINHTTP_LOGIN_FAILURE)
                    {
                        if (repeat)
                        {
                            // We don't retry more than once.
                            break;
                        }
                        else
                        {
                            repeat = true;
                            autoProxyOptions.AutoLoginIfChallenged = true;
                        }
                    }
                    else
                    {
                        if (lastError == Interop.WinHttp.ERROR_WINHTTP_AUTODETECTION_FAILED)
                        {
                            _autoDetectionFailed         = true;
                            _lastTimeAutoDetectionFailed = Environment.TickCount;
                        }

                        break;
                    }
                }
            } while (repeat);

            // Fall back to manual settings if available.
            if (!useProxy && !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);

                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(this, $"Fallback to Proxy={Proxy}, ProxyBypass={ProxyBypass}");
                }
                useProxy = true;
            }

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Info(this, $"useProxy={useProxy}");
            }

            return(useProxy);
        }
Ejemplo n.º 13
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>()))
                        {
                            // This option is not available on downlevel Windows versions. While it improves
                            // performance, we can ignore the error that the option is not available.
                            int lastError = Marshal.GetLastWin32Error();
                            if (lastError != Interop.WinHttp.ERROR_WINHTTP_INVALID_OPTION)
                            {
                                throw WinHttpException.CreateExceptionUsingError(lastError);
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 14
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);
        }
Ejemplo n.º 15
0
        public static HttpResponseMessage CreateResponseMessage(
            WinHttpRequestState state,
            bool doManualDecompressionCheck)
        {
            HttpRequestMessage request         = state.RequestMessage;
            SafeWinHttpHandle  requestHandle   = state.RequestHandle;
            CookieUsePolicy    cookieUsePolicy = state.Handler.CookieUsePolicy;
            CookieContainer    cookieContainer = state.Handler.CookieContainer;
            var  response             = new HttpResponseMessage();
            bool stripEncodingHeaders = false;

            // Create a single buffer to use for all subsequent WinHttpQueryHeaders string interop calls.
            // This buffer is the length needed for WINHTTP_QUERY_RAW_HEADERS_CRLF, which includes the status line
            // and all headers separated by CRLF, so it should be large enough for any individual status line or header queries.
            int bufferLength = GetResponseHeaderCharBufferLength(requestHandle, Interop.WinHttp.WINHTTP_QUERY_RAW_HEADERS_CRLF);

            char[] buffer = new char[bufferLength];

            // Get HTTP version, status code, reason phrase from the response headers.

            int versionLength = GetResponseHeader(requestHandle, Interop.WinHttp.WINHTTP_QUERY_VERSION, buffer);

            response.Version =
                CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase("HTTP/1.1", buffer, 0, versionLength) ? HttpVersion.Version11 :
                CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase("HTTP/1.0", buffer, 0, versionLength) ? HttpVersion.Version10 :
                HttpVersion.Unknown;

            response.StatusCode = (HttpStatusCode)GetResponseHeaderNumberInfo(
                requestHandle,
                Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE);

            int reasonPhraseLength = GetResponseHeader(requestHandle, Interop.WinHttp.WINHTTP_QUERY_STATUS_TEXT, buffer);

            if (reasonPhraseLength > 0)
            {
                response.ReasonPhrase = GetReasonPhrase(response.StatusCode, buffer, reasonPhraseLength);
            }

            // Create response stream and wrap it in a StreamContent object.
            var    responseStream     = new WinHttpResponseStream(requestHandle, state);
            Stream decompressedStream = responseStream;

            if (doManualDecompressionCheck)
            {
                int contentEncodingStartIndex = 0;
                int contentEncodingLength     = GetResponseHeader(
                    requestHandle,
                    Interop.WinHttp.WINHTTP_QUERY_CONTENT_ENCODING,
                    buffer);

                CharArrayHelpers.Trim(buffer, ref contentEncodingStartIndex, ref contentEncodingLength);

                if (contentEncodingLength > 0)
                {
                    if (CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase(
                            EncodingNameGzip, buffer, contentEncodingStartIndex, contentEncodingLength))
                    {
                        decompressedStream   = new GZipStream(responseStream, CompressionMode.Decompress);
                        stripEncodingHeaders = true;
                    }
                    else if (CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase(
                                 EncodingNameDeflate, buffer, contentEncodingStartIndex, contentEncodingLength))
                    {
                        decompressedStream   = new DeflateStream(responseStream, CompressionMode.Decompress);
                        stripEncodingHeaders = true;
                    }
                }
            }

            var content = new StreamContent(decompressedStream);

            response.Content        = content;
            response.RequestMessage = request;

            // Parse raw response headers and place them into response message.
            ParseResponseHeaders(requestHandle, response, buffer, stripEncodingHeaders);

            if (response.RequestMessage.Method != HttpMethod.Head)
            {
                state.ExpectedBytesToRead = response.Content.Headers.ContentLength;
            }

            return(response);
        }
Ejemplo n.º 16
0
 public static bool WinHttpQueryDataAvailable(SafeWinHttpHandle requestHandle, out uint bytesAvailable)
 {
     bytesAvailable = 0;
     return(true);
 }
Ejemplo n.º 17
0
        public static HttpResponseMessage CreateResponseMessage(
            WinHttpRequestState state,
            bool doManualDecompressionCheck)
        {
            HttpRequestMessage request         = state.RequestMessage;
            SafeWinHttpHandle  requestHandle   = state.RequestHandle;
            CookieUsePolicy    cookieUsePolicy = state.Handler.CookieUsePolicy;
            CookieContainer    cookieContainer = state.Handler.CookieContainer;
            var  response             = new HttpResponseMessage();
            bool stripEncodingHeaders = false;

            // Get HTTP version, status code, reason phrase from the response headers.
            string version = GetResponseHeaderStringInfo(requestHandle, Interop.WinHttp.WINHTTP_QUERY_VERSION);

            if (string.Compare("HTTP/1.1", version, StringComparison.OrdinalIgnoreCase) == 0)
            {
                response.Version = HttpVersion.Version11;
            }
            else if (string.Compare("HTTP/1.0", version, StringComparison.OrdinalIgnoreCase) == 0)
            {
                response.Version = HttpVersion.Version10;
            }
            else
            {
                response.Version = HttpVersion.Unknown;
            }

            response.StatusCode = (HttpStatusCode)GetResponseHeaderNumberInfo(
                requestHandle,
                Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE);
            response.ReasonPhrase = GetResponseHeaderStringInfo(
                requestHandle,
                Interop.WinHttp.WINHTTP_QUERY_STATUS_TEXT);

            // Create response stream and wrap it in a StreamContent object.
            var    responseStream     = new WinHttpResponseStream(state);
            Stream decompressedStream = responseStream;

            if (doManualDecompressionCheck)
            {
                string contentEncoding = GetResponseHeaderStringInfo(
                    requestHandle,
                    Interop.WinHttp.WINHTTP_QUERY_CONTENT_ENCODING);
                if (!string.IsNullOrEmpty(contentEncoding))
                {
                    if (contentEncoding.IndexOf(EncodingNameDeflate, StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        decompressedStream   = new DeflateStream(responseStream, CompressionMode.Decompress);
                        stripEncodingHeaders = true;
                    }
                    else if (contentEncoding.IndexOf(EncodingNameGzip, StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        decompressedStream   = new GZipStream(responseStream, CompressionMode.Decompress);
                        stripEncodingHeaders = true;
                    }
                }
            }

            var content = new StreamContent(decompressedStream);

            response.Content        = content;
            response.RequestMessage = request;

            // Parse raw response headers and place them into response message.
            ParseResponseHeaders(requestHandle, response, stripEncodingHeaders);

            return(response);
        }
Ejemplo n.º 18
0
        // Returns the first header or null if header isn't found.
        public static string GetResponseHeaderStringInfo(SafeWinHttpHandle requestHandle, uint infoLevel)
        {
            uint index = 0;

            return(GetResponseHeaderStringHelper(requestHandle, infoLevel, ref index));
        }
Ejemplo n.º 19
0
        private void ParseResponseHeaders(
            SafeWinHttpHandle requestHandle,
            HttpResponseMessage response,
            bool stripEncodingHeaders)
        {
            string rawResponseHeaders = GetResponseHeaderStringInfo(
                requestHandle,
                Interop.WinHttp.WINHTTP_QUERY_RAW_HEADERS_CRLF);
            string[] responseHeaderArray = rawResponseHeaders.Split(
                s_httpHeadersSeparator,
                StringSplitOptions.RemoveEmptyEntries);

            // Parse the array of headers and split them between Content headers and Response headers.
            // Skip the first line which contains status code, etc. information that we already parsed.
            for (int i = 1; i < responseHeaderArray.Length; i++)
            {
                int colonIndex = responseHeaderArray[i].IndexOf(':');

                // Skip malformed header lines that are missing the colon character.
                if (colonIndex > 0)
                {
                    string headerName = responseHeaderArray[i].Substring(0, colonIndex);
                    string headerValue = responseHeaderArray[i].Substring(colonIndex + 1).Trim(); // Normalize header value by trimming white space.

                    if (!response.Headers.TryAddWithoutValidation(headerName, headerValue))
                    {
                        if (stripEncodingHeaders)
                        {
                            // Remove Content-Length and Content-Encoding headers if we are
                            // decompressing the response stream in the handler (due to 
                            // WINHTTP not supporting it in a particular downlevel platform). 
                            // This matches the behavior of WINHTTP when it does decompression iself.
                            if (string.Equals(
                                HeaderNameContentLength,
                                headerName,
                                StringComparison.OrdinalIgnoreCase))
                            {
                                continue;
                            }

                            if (string.Equals(
                                HeaderNameContentEncoding,
                                headerName,
                                StringComparison.OrdinalIgnoreCase))
                            {
                                continue;
                            }
                        }

                        // TODO: Should we log if there is an error here?
                        response.Content.Headers.TryAddWithoutValidation(headerName, headerValue);
                    }
                }
            }
        }
Ejemplo n.º 20
0
 internal WinHttpResponseStream(SafeWinHttpHandle requestHandle, WinHttpRequestState state, HttpResponseMessage responseMessage)
 {
     _state           = state;
     _responseMessage = responseMessage;
     _requestHandle   = requestHandle;
 }
Ejemplo n.º 21
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();
            }
        }
Ejemplo n.º 22
0
        private HttpSystemProxy(WinInetProxyHelper proxyHelper, SafeWinHttpHandle sessionHandle)
        {
            _proxyHelper   = proxyHelper;
            _sessionHandle = sessionHandle;

            if (proxyHelper.ManualSettingsOnly)
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(proxyHelper, $"ManualSettingsUsed, {proxyHelper.Proxy}");
                }
                ParseProxyConfig(proxyHelper.Proxy, out _insecureProxyUri, out _secureProxyUri);
                if (_insecureProxyUri == null && _secureProxyUri == null)
                {
                    // If advanced parsing by protocol fails, fall-back to simplified parsing.
                    _insecureProxyUri = _secureProxyUri = GetUriFromString(proxyHelper.Proxy);
                }

                if (!string.IsNullOrWhiteSpace(proxyHelper.ProxyBypass))
                {
                    int    idx   = 0;
                    int    start = 0;
                    string tmp;

                    // Process bypass list for manual setting.
                    // Initial list size is best guess based on string length assuming each entry is at least 5 characters on average.
                    _bypass = new List <Regex>(proxyHelper.ProxyBypass.Length / 5);

                    while (idx < proxyHelper.ProxyBypass.Length)
                    {
                        // Strip leading spaces and scheme if any.
                        while (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] == ' ')
                        {
                            idx += 1;
                        }
                        ;
                        if (string.Compare(proxyHelper.ProxyBypass, idx, "http://", 0, 7, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            idx += 7;
                        }
                        else if (string.Compare(proxyHelper.ProxyBypass, idx, "https://", 0, 8, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            idx += 8;
                        }

                        if (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] == '[')
                        {
                            // Strip [] from IPv6 so we can use IdnHost laster for matching.
                            idx += 1;
                        }

                        start = idx;
                        while (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] != ' ' && proxyHelper.ProxyBypass[idx] != ';' && proxyHelper.ProxyBypass[idx] != ']')
                        {
                            idx += 1;
                        }
                        ;

                        if (idx == start)
                        {
                            // Empty string.
                            tmp = null;
                        }
                        else if (string.Compare(proxyHelper.ProxyBypass, start, "<local>", 0, 7, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            _bypassLocal = true;
                            tmp          = null;
                        }
                        else
                        {
                            tmp = proxyHelper.ProxyBypass.Substring(start, idx - start);
                        }

                        // Skip trailing characters if any.
                        if (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] != ';')
                        {
                            // Got stopped at space or ']'. Strip until next ';' or end.
                            while (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] != ';')
                            {
                                idx += 1;
                            }
                            ;
                        }
                        if (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] == ';')
                        {
                            idx++;
                        }
                        if (tmp == null)
                        {
                            continue;
                        }

                        try
                        {
                            // Escape any special characters and unescape * to get wildcard pattern match.
                            Regex re = new Regex(Regex.Escape(tmp).Replace("\\*", ".*?") + "$",
                                                 RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
                            _bypass.Add(re);
                        }
                        catch (Exception ex)
                        {
                            if (NetEventSource.IsEnabled)
                            {
                                NetEventSource.Error(this, $"Failed to process {tmp} from bypass list: {ex}");
                            }
                        }
                    }
                    if (_bypass.Count == 0)
                    {
                        // Bypass string only had garbage we did not parse.
                        _bypass = null;
                    }
                }

                if (_bypassLocal)
                {
                    _localIp = new List <IPAddress>();
                    foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
                    {
                        IPInterfaceProperties ipProps = netInterface.GetIPProperties();
                        foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
                        {
                            _localIp.Add(addr.Address);
                        }
                    }
                }
            }
        }
Ejemplo n.º 23
0
        private async void StartRequest(object obj)
        {
            WinHttpRequestState state           = (WinHttpRequestState)obj;
            bool secureConnection               = false;
            HttpResponseMessage responseMessage = null;
            Exception           savedException  = null;
            SafeWinHttpHandle   connectHandle   = null;

            if (state.CancellationToken.IsCancellationRequested)
            {
                state.Tcs.TrySetCanceled(state.CancellationToken);
                return;
            }

            try
            {
                EnsureSessionHandleExists(state);

                SetSessionHandleOptions();

                // Specify an HTTP server.
                connectHandle = Interop.WinHttp.WinHttpConnect(
                    _sessionHandle,
                    state.RequestMessage.RequestUri.Host,
                    (ushort)state.RequestMessage.RequestUri.Port,
                    0);
                ThrowOnInvalidHandle(connectHandle);
                connectHandle.SetParentHandle(_sessionHandle);

                if (state.RequestMessage.RequestUri.Scheme == UriScheme.Https)
                {
                    secureConnection = true;
                }
                else
                {
                    secureConnection = false;
                }

                // Try to use the requested version if a known/supported version was explicitly requested.
                // Otherwise, we simply use winhttp's default.
                string httpVersion = null;
                if (state.RequestMessage.Version == HttpVersion.Version10)
                {
                    httpVersion = "HTTP/1.0";
                }
                else if (state.RequestMessage.Version == HttpVersion.Version11)
                {
                    httpVersion = "HTTP/1.1";
                }

                // Create an HTTP request handle.
                state.RequestHandle = Interop.WinHttp.WinHttpOpenRequest(
                    connectHandle,
                    state.RequestMessage.Method.Method,
                    state.RequestMessage.RequestUri.PathAndQuery,
                    httpVersion,
                    Interop.WinHttp.WINHTTP_NO_REFERER,
                    Interop.WinHttp.WINHTTP_DEFAULT_ACCEPT_TYPES,
                    secureConnection ? Interop.WinHttp.WINHTTP_FLAG_SECURE : 0);
                ThrowOnInvalidHandle(state.RequestHandle);
                state.RequestHandle.SetParentHandle(connectHandle);

                // Set callback function.
                SetStatusCallback(state.RequestHandle, WinHttpRequestCallback.StaticCallbackDelegate);

                // Set needed options on the request handle.
                SetRequestHandleOptions(state);

                bool chunkedModeForSend = IsChunkedModeForSend(state.RequestMessage);

                AddRequestHeaders(
                    state.RequestHandle,
                    state.RequestMessage,
                    _cookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer ? _cookieContainer : null);

                uint proxyAuthScheme  = 0;
                uint serverAuthScheme = 0;
                state.RetryRequest = false;

                // The only way to abort pending async operations in WinHTTP is to close the WinHTTP handle.
                // We will detect a cancellation request on the cancellation token by registering a callback.
                // If the callback is invoked, then we begin the abort process by disposing the handle. This
                // will have the side-effect of WinHTTP cancelling any pending I/O and accelerating its callbacks
                // on the handle and thus releasing the awaiting tasks in the loop below. This helps to provide
                // a more timely, cooperative, cancellation pattern.
                using (state.CancellationToken.Register(s => ((WinHttpRequestState)s).RequestHandle.Dispose(), state))
                {
                    do
                    {
                        _authHelper.PreAuthenticateRequest(state, proxyAuthScheme);

                        await InternalSendRequestAsync(state).ConfigureAwait(false);

                        if (state.RequestMessage.Content != null)
                        {
                            await InternalSendRequestBodyAsync(state, chunkedModeForSend).ConfigureAwait(false);
                        }

                        bool receivedResponse = await InternalReceiveResponseHeadersAsync(state).ConfigureAwait(false);

                        if (receivedResponse)
                        {
                            // If we're manually handling cookies, we need to add them to the container after
                            // each response has been received.
                            if (state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer)
                            {
                                WinHttpCookieContainerAdapter.AddResponseCookiesToContainer(state);
                            }

                            _authHelper.CheckResponseForAuthentication(
                                state,
                                ref proxyAuthScheme,
                                ref serverAuthScheme);
                        }
                    } while (state.RetryRequest);
                }

                state.CancellationToken.ThrowIfCancellationRequested();

                responseMessage = WinHttpResponseParser.CreateResponseMessage(state, _doManualDecompressionCheck);

                // Since the headers have been read, set the "receive" timeout to be based on each read
                // call of the response body data. WINHTTP_OPTION_RECEIVE_TIMEOUT sets a timeout on each
                // lower layer winsock read.
                uint optionData = (uint)_receiveDataTimeout.TotalMilliseconds;
                SetWinHttpOption(state.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_RECEIVE_TIMEOUT, ref optionData);
            }
            catch (Exception ex)
            {
                if (state.SavedException != null)
                {
                    savedException = state.SavedException;
                }
                else
                {
                    savedException = ex;
                }
            }
            finally
            {
                SafeWinHttpHandle.DisposeAndClearHandle(ref connectHandle);
            }

            // Move the main task to a terminal state. This releases any callers of SendAsync() that are awaiting.
            if (responseMessage != null)
            {
                state.Tcs.TrySetResult(responseMessage);
            }
            else
            {
                HandleAsyncException(state, savedException);
            }
        }
Ejemplo n.º 24
0
        public static HttpResponseMessage CreateResponseMessage(
            WinHttpRequestState state,
            DecompressionMethods manuallyProcessedDecompressionMethods)
        {
            HttpRequestMessage request       = state.RequestMessage;
            SafeWinHttpHandle  requestHandle = state.RequestHandle;
            var  response             = new HttpResponseMessage();
            bool stripEncodingHeaders = false;

            // Create a single buffer to use for all subsequent WinHttpQueryHeaders string interop calls.
            // This buffer is the length needed for WINHTTP_QUERY_RAW_HEADERS_CRLF, which includes the status line
            // and all headers separated by CRLF, so it should be large enough for any individual status line or header queries.
            int bufferLength = GetResponseHeaderCharBufferLength(requestHandle, Interop.WinHttp.WINHTTP_QUERY_RAW_HEADERS_CRLF);

            char[] buffer = ArrayPool <char> .Shared.Rent(bufferLength);

            try
            {
                // Get HTTP version, status code, reason phrase from the response headers.

                if (IsResponseHttp2(requestHandle))
                {
                    response.Version = WinHttpHandler.HttpVersion20;
                }
                else
                {
                    int versionLength = GetResponseHeader(requestHandle, Interop.WinHttp.WINHTTP_QUERY_VERSION, buffer);
                    response.Version =
                        CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase("HTTP/1.1", buffer, 0, versionLength) ? HttpVersion.Version11 :
                        CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase("HTTP/1.0", buffer, 0, versionLength) ? HttpVersion.Version10 :
                        WinHttpHandler.HttpVersionUnknown;
                }

                response.StatusCode = (HttpStatusCode)GetResponseHeaderNumberInfo(
                    requestHandle,
                    Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE);

                int reasonPhraseLength = GetResponseHeader(requestHandle, Interop.WinHttp.WINHTTP_QUERY_STATUS_TEXT, buffer);
                response.ReasonPhrase = reasonPhraseLength > 0 ?
                                        GetReasonPhrase(response.StatusCode, buffer, reasonPhraseLength) :
                                        string.Empty;

                // Create response stream and wrap it in a StreamContent object.
                var responseStream = new WinHttpResponseStream(requestHandle, state);
                state.RequestHandle = null; // ownership successfully transfered to WinHttpResponseStram.
                Stream decompressedStream = responseStream;

                if (manuallyProcessedDecompressionMethods != DecompressionMethods.None)
                {
                    int contentEncodingStartIndex = 0;
                    int contentEncodingLength     = GetResponseHeader(
                        requestHandle,
                        Interop.WinHttp.WINHTTP_QUERY_CONTENT_ENCODING,
                        buffer);

                    CharArrayHelpers.Trim(buffer, ref contentEncodingStartIndex, ref contentEncodingLength);

                    if (contentEncodingLength > 0)
                    {
                        if ((manuallyProcessedDecompressionMethods & DecompressionMethods.GZip) == DecompressionMethods.GZip &&
                            CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase(EncodingNameGzip, buffer, contentEncodingStartIndex, contentEncodingLength))
                        {
                            decompressedStream   = new GZipStream(responseStream, CompressionMode.Decompress);
                            stripEncodingHeaders = true;
                        }
                        else if ((manuallyProcessedDecompressionMethods & DecompressionMethods.Deflate) == DecompressionMethods.Deflate &&
                                 CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase(EncodingNameDeflate, buffer, contentEncodingStartIndex, contentEncodingLength))
                        {
                            decompressedStream   = new DeflateStream(responseStream, CompressionMode.Decompress);
                            stripEncodingHeaders = true;
                        }
                    }
                }

                response.Content        = new NoWriteNoSeekStreamContent(decompressedStream);
                response.RequestMessage = request;

                // Parse raw response headers and place them into response message.
                ParseResponseHeaders(requestHandle, response, buffer, stripEncodingHeaders);

                if (response.RequestMessage.Method != HttpMethod.Head)
                {
                    state.ExpectedBytesToRead = response.Content.Headers.ContentLength;
                }

                return(response);
            }
            finally
            {
                ArrayPool <char> .Shared.Return(buffer);
            }
        }
Ejemplo n.º 25
0
        private void PreAuthenticateRequest(
            RequestState state,
            SafeWinHttpHandle requestHandle,
            uint proxyAuthScheme)
        {
            // Set proxy credentials if we have them.
            // If a proxy authentication challenge was responded to, reset
            // those credentials before each SendRequest, because the proxy  
            // may require re-authentication after responding to a 401 or  
            // to a redirect. If you don't, you can get into a 
            // 407-401-407-401- loop.
            if (proxyAuthScheme != 0)
            {
                SetWinHttpCredential(
                    requestHandle,
                    state.Proxy == null ? _defaultProxyCredentials : state.Proxy.Credentials,
                    state.RequestMessage.RequestUri,
                    proxyAuthScheme,
                    Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY);
            }

            // Apply pre-authentication headers for server authentication?
            if (_preAuthenticate)
            {
                uint authScheme;
                NetworkCredential serverCredentials;
                if (GetServerCredentialsFromCache(
                    state.RequestMessage.RequestUri,
                    out authScheme,
                    out serverCredentials))
                {
                    SetWinHttpCredential(
                        requestHandle,
                        serverCredentials,
                        state.RequestMessage.RequestUri,
                        authScheme,
                        Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);
                    state.LastStatusCode = HttpStatusCode.Unauthorized; // Remember we already set the creds.
                }
            }
        }
Ejemplo n.º 26
0
 private void SetRequestHandleBufferingOptions(SafeWinHttpHandle requestHandle)
 {
     uint optionData = (uint)_maxResponseHeadersLength;
     SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE, ref optionData);
     optionData = (uint)_maxResponseDrainSize;
     SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE, ref optionData);
 }
Ejemplo n.º 27
0
        private void SetRequestHandleRedirectionOptions(SafeWinHttpHandle requestHandle)
        {
            uint optionData = 0;

            if (_automaticRedirection)
            {
                optionData = (uint)_maxAutomaticRedirections;
                SetWinHttpOption(
                    requestHandle,
                    Interop.WinHttp.WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS,
                    ref optionData);
            }

            optionData = _automaticRedirection ? 
                Interop.WinHttp.WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP :
                Interop.WinHttp.WINHTTP_OPTION_REDIRECT_POLICY_NEVER;
            SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_REDIRECT_POLICY, ref optionData);
        }
Ejemplo n.º 28
0
 private void SetWinHttpOption(SafeWinHttpHandle handle, uint option, ref uint optionData)
 {
     if (!Interop.WinHttp.WinHttpSetOption(
         handle,
         option,
         ref optionData))
     {
         WinHttpException.ThrowExceptionUsingLastError();
     }
 }
Ejemplo n.º 29
0
 private void SetRequestHandleTlsOptions(SafeWinHttpHandle requestHandle)
 {
     // If we have a custom server certificate validation callback method then 
     // we need to have WinHTTP ignore some errors so that the callback method
     // will have a chance to be called.
     uint optionData;
     if (_serverCertificateValidationCallback != null)
     {
         optionData =
             Interop.WinHttp.SECURITY_FLAG_IGNORE_UNKNOWN_CA |
             Interop.WinHttp.SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE |
             Interop.WinHttp.SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
             Interop.WinHttp.SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
         SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_SECURITY_FLAGS, ref optionData);
     }
     else if (_checkCertificateRevocationList)
     {
         // If no custom validation method, then we let WinHTTP do the revocation check itself.
         optionData = Interop.WinHttp.WINHTTP_ENABLE_SSL_REVOCATION;
         SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_ENABLE_FEATURE, ref optionData);
     }
 }
Ejemplo n.º 30
0
 private static void SetWinHttpOption(
     SafeWinHttpHandle handle,
     uint option,
     IntPtr optionData,
     uint optionSize)
 {
     if (!Interop.WinHttp.WinHttpSetOption(
         handle,
         option,
         optionData,
         optionSize))
     {
         WinHttpException.ThrowExceptionUsingLastError();
     }
 }
Ejemplo n.º 31
0
 private static void SetNoClientCertificate(SafeWinHttpHandle requestHandle)
 {
     SetWinHttpOption(
         requestHandle,
         Interop.WinHttp.WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
         IntPtr.Zero,
         0);
 }
Ejemplo n.º 32
0
        public static bool WinHttpQueryHeaders(
            SafeWinHttpHandle requestHandle,
            uint infoLevel, string name,
            StringBuilder buffer,
            ref uint bufferLength,
            IntPtr index)
        {
            string httpVersion = "HTTP/1.1";
            string statusText  = "OK";

            if (infoLevel == Interop.WinHttp.WINHTTP_QUERY_VERSION)
            {
                if (buffer == null)
                {
                    bufferLength = ((uint)httpVersion.Length + 1) * 2;
                    TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER;
                    return(false);
                }

                buffer.Append(httpVersion);
                return(true);
            }

            if (infoLevel == Interop.WinHttp.WINHTTP_QUERY_STATUS_TEXT)
            {
                if (buffer == null)
                {
                    bufferLength = ((uint)statusText.Length + 1) * 2;
                    TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER;
                    return(false);
                }

                buffer.Append(statusText);
                return(true);
            }

            if (infoLevel == Interop.WinHttp.WINHTTP_QUERY_CONTENT_ENCODING)
            {
                string compression = null;

                if (TestServer.ResponseHeaders.Contains("Content-Encoding: deflate"))
                {
                    compression = "deflate";
                }
                else if (TestServer.ResponseHeaders.Contains("Content-Encoding: gzip"))
                {
                    compression = "gzip";
                }

                if (compression == null)
                {
                    TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND;
                    return(false);
                }

                if (buffer == null)
                {
                    bufferLength = ((uint)compression.Length + 1) * 2;
                    TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER;
                    return(false);
                }

                buffer.Append(compression);
                return(true);
            }

            if (infoLevel == Interop.WinHttp.WINHTTP_QUERY_RAW_HEADERS_CRLF)
            {
                if (buffer == null)
                {
                    bufferLength = ((uint)TestServer.ResponseHeaders.Length + 1) * 2;
                    TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER;
                    return(false);
                }

                buffer.Append(TestServer.ResponseHeaders);
                return(true);
            }

            return(false);
        }
Ejemplo n.º 33
0
        private void SetWinHttpCredential(
            SafeWinHttpHandle requestHandle,
            ICredentials credentials,
            Uri uri,
            uint authScheme,
            uint authTarget)
        {
            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]);

            // Skip if no credentials or this is the default credential.
            if (networkCredential == null || networkCredential == CredentialCache.DefaultNetworkCredentials)
            {
                return;
            }

            string userName = networkCredential.UserName;
            string password = networkCredential.Password;
            string domain = networkCredential.Domain;

            // WinHTTP does not support a blank username.  So, we will throw an exception.
            if (string.IsNullOrEmpty(userName))
            {
                // TODO: Add error message.
                throw new InvalidOperationException();
            }

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

            if (!Interop.WinHttp.WinHttpSetCredentials(
                requestHandle,
                authTarget,
                authScheme,
                userName,
                password,
                IntPtr.Zero))
            {
                WinHttpException.ThrowExceptionUsingLastError();
            }
        }
Ejemplo n.º 34
0
        public static bool WinHttpQueryAuthSchemes(
            SafeWinHttpHandle requestHandle,
            out uint supportedSchemes,
            out uint firstScheme,
            out uint authTarget)
        {
            supportedSchemes = 0;
            firstScheme = 0;
            authTarget = 0;

            return true;
        }
Ejemplo n.º 35
0
 private void SetWinHttpOption(SafeWinHttpHandle handle, uint option, string optionData)
 {
     if (!Interop.WinHttp.WinHttpSetOption(
         handle,
         option,
         optionData,
         (uint)optionData.Length))
     {
         WinHttpException.ThrowExceptionUsingLastError();
     }
 }
Ejemplo n.º 36
0
 public static bool WinHttpSetTimeouts(
     SafeWinHttpHandle handle,
     int resolveTimeout,
     int connectTimeout,
     int sendTimeout,
     int receiveTimeout)
 {
     return true;
 }
Ejemplo n.º 37
0
        private HttpResponseMessage CreateResponseMessage(SafeWinHttpHandle requestHandle, HttpRequestMessage request)
        {
            var response = new HttpResponseMessage();
            bool useDeflateDecompression = false;
            bool useGzipDecompression = false;

            // Get HTTP version, status code, reason phrase from the response headers.
            string version = GetResponseHeaderStringInfo(requestHandle, Interop.WinHttp.WINHTTP_QUERY_VERSION);
            if (string.Compare("HTTP/1.1", version, StringComparison.OrdinalIgnoreCase) == 0)
            {
                response.Version = new Version(1, 1);
            }
            else if (string.Compare("HTTP/1.0", version, StringComparison.OrdinalIgnoreCase) == 0)
            {
                response.Version = new Version(1, 0);
            }
            else
            {
                response.Version = null;
            }

            response.StatusCode = (HttpStatusCode)GetResponseHeaderNumberInfo(
                requestHandle,
                Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE);
            response.ReasonPhrase = GetResponseHeaderStringInfo(
                requestHandle,
                Interop.WinHttp.WINHTTP_QUERY_STATUS_TEXT);

            if (_doManualDecompressionCheck)
            {
                string contentEncoding = GetResponseHeaderStringInfo(
                    requestHandle,
                    Interop.WinHttp.WINHTTP_QUERY_CONTENT_ENCODING);
                if (!string.IsNullOrEmpty(contentEncoding))
                {
                    if (contentEncoding.IndexOf(EncodingNameDeflate, StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        useDeflateDecompression = true;
                    }
                    else if (contentEncoding.IndexOf(EncodingNameGzip, StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        useGzipDecompression = true;
                    }
                }
            }

            // Create response stream and wrap it in a StreamContent object.
            var responseStream = new WinHttpResponseStream(requestHandle);
            Stream decompressedStream = responseStream;
            if (_doManualDecompressionCheck)
            {
                if (useDeflateDecompression)
                {
                    decompressedStream = new DeflateStream(responseStream, CompressionMode.Decompress);
                }
                else if (useGzipDecompression)
                {
                    decompressedStream = new GZipStream(responseStream, CompressionMode.Decompress);
                }
            }

            var content = new StreamContent(decompressedStream);

            response.Content = content;
            response.RequestMessage = request;

            // Parse raw response headers and place them into response message.
            ParseResponseHeaders(requestHandle, response, useDeflateDecompression || useGzipDecompression);

            // Store response header cookies into custom CookieContainer.
            if (_cookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer)
            {
                Debug.Assert(_cookieContainer != null);

                if (response.Headers.Contains(HeaderNameSetCookie))
                {
                    IEnumerable<string> cookieHeaders = response.Headers.GetValues(HeaderNameSetCookie);
                    foreach (var cookieHeader in cookieHeaders)
                    {
                        try
                        {
                            _cookieContainer.SetCookies(request.RequestUri, cookieHeader);
                        }
                        catch (CookieException)
                        {
                            // We ignore malformed cookies in the response.
                        }
                    }
                }
            }

            // Since the headers have been read, set the "receive" timeout to be based on each read
            // call of the response body data. WINHTTP_OPTION_RECEIVE_TIMEOUT sets a timeout on each
            // lower layer winsock read.
            uint optionData = (uint)_receiveDataTimeout.TotalMilliseconds;
            SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_RECEIVE_TIMEOUT, ref optionData);

            return response;
        }
Ejemplo n.º 38
0
        public static bool WinHttpGetProxyForUrl(
            SafeWinHttpHandle sessionHandle,
            string url,
            ref Interop.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions,
            out Interop.WinHttp.WINHTTP_PROXY_INFO proxyInfo)
        {
            if (TestControl.PACFileNotDetectedOnNetwork)
            {
                proxyInfo.AccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
                proxyInfo.Proxy = IntPtr.Zero;
                proxyInfo.ProxyBypass = IntPtr.Zero;

                TestControl.LastWin32Error = (int)Interop.WinHttp.ERROR_WINHTTP_AUTODETECTION_FAILED;
                return false;
            }

            proxyInfo.AccessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NAMED_PROXY;
            proxyInfo.Proxy = Marshal.StringToHGlobalUni(FakeRegistry.WinInetProxySettings.Proxy);
            proxyInfo.ProxyBypass = IntPtr.Zero;

            return true;
        }
Ejemplo n.º 39
0
        private string GetResponseHeaderStringInfo(SafeWinHttpHandle requestHandle, uint infoLevel)
        {
            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,
                IntPtr.Zero))
            {
                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 / 2;
            var buffer = new StringBuilder(charsNeeded, charsNeeded);

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

            return buffer.ToString();
        }
Ejemplo n.º 40
0
 public static IntPtr WinHttpSetStatusCallback(
     SafeWinHttpHandle handle,
     Interop.WinHttp.WINHTTP_STATUS_CALLBACK callback,
     uint notificationFlags,
     IntPtr reserved)
 {
     if (handle == null)
     {
         throw new ArgumentNullException("handle");
     }
     
     return IntPtr.Zero;
 }
Ejemplo n.º 41
0
        private void SetStatusCallback(
            SafeWinHttpHandle requestHandle,
            Interop.WinHttp.WINHTTP_STATUS_CALLBACK callback)
        {
            IntPtr oldCallback = Interop.WinHttp.WinHttpSetStatusCallback(
                requestHandle,
                callback,
                Interop.WinHttp.WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,
                IntPtr.Zero);

            if (oldCallback == new IntPtr(Interop.WinHttp.WINHTTP_INVALID_STATUS_CALLBACK))
            {
                int lastError = Marshal.GetLastWin32Error();
                if (lastError != Interop.WinHttp.ERROR_INVALID_HANDLE) // Ignore error if handle was already closed.
                {
                    throw WinHttpException.CreateExceptionUsingError(lastError);
                }
            }
        }
Ejemplo n.º 42
0
 public static bool WinHttpAddRequestHeaders(
     SafeWinHttpHandle requestHandle,
     StringBuilder headers,
     uint headersLength,
     uint modifiers)
 {
     return true;
 }
Ejemplo n.º 43
0
        private void EnsureSessionHandleExists(RequestState 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,
                            0);
                        if (!_sessionHandle.IsInvalid)
                        {
                            return;
                        }

                        int lastError = Marshal.GetLastWin32Error();
                        if (lastError != Interop.WinHttp.ERROR_INVALID_PARAMETER)
                        {
                            throw new HttpRequestException(
                                SR.net_http_client_execution_error,
                                WinHttpException.CreateExceptionUsingError(lastError));
                        }

                        // 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,
                            0);
                        if (_sessionHandle.IsInvalid)
                        {
                            throw new HttpRequestException(
                                SR.net_http_client_execution_error,
                                WinHttpException.CreateExceptionUsingLastError());
                        }
                    }
                }
            }
        }
Ejemplo n.º 44
0
        private HttpWindowsProxy(WinInetProxyHelper proxyHelper, SafeWinHttpHandle sessionHandle)
        {
            _proxyHelper   = proxyHelper;
            _sessionHandle = sessionHandle;

            if (proxyHelper.ManualSettingsUsed)
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(proxyHelper, $"ManualSettingsUsed, {proxyHelper.Proxy}");
                }

                _secureProxy   = MultiProxy.Parse(_failedProxies, proxyHelper.Proxy, true);
                _insecureProxy = MultiProxy.Parse(_failedProxies, proxyHelper.Proxy, false);

                if (!string.IsNullOrWhiteSpace(proxyHelper.ProxyBypass))
                {
                    int    idx   = 0;
                    int    start = 0;
                    string tmp;

                    // Process bypass list for manual setting.
                    // Initial list size is best guess based on string length assuming each entry is at least 5 characters on average.
                    _bypass = new List <string>(proxyHelper.ProxyBypass.Length / 5);

                    while (idx < proxyHelper.ProxyBypass.Length)
                    {
                        // Strip leading spaces and scheme if any.
                        while (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] == ' ')
                        {
                            idx += 1;
                        }
                        ;
                        if (string.Compare(proxyHelper.ProxyBypass, idx, "http://", 0, 7, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            idx += 7;
                        }
                        else if (string.Compare(proxyHelper.ProxyBypass, idx, "https://", 0, 8, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            idx += 8;
                        }

                        if (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] == '[')
                        {
                            // Strip [] from IPv6 so we can use IdnHost laster for matching.
                            idx += 1;
                        }

                        start = idx;
                        while (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] != ' ' && proxyHelper.ProxyBypass[idx] != ';' && proxyHelper.ProxyBypass[idx] != ']')
                        {
                            idx += 1;
                        }
                        ;

                        if (idx == start)
                        {
                            // Empty string.
                            tmp = null;
                        }
                        else if (string.Compare(proxyHelper.ProxyBypass, start, "<local>", 0, 7, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            _bypassLocal = true;
                            tmp          = null;
                        }
                        else
                        {
                            tmp = proxyHelper.ProxyBypass.Substring(start, idx - start);
                        }

                        // Skip trailing characters if any.
                        if (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] != ';')
                        {
                            // Got stopped at space or ']'. Strip until next ';' or end.
                            while (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] != ';')
                            {
                                idx += 1;
                            }
                            ;
                        }
                        if (idx < proxyHelper.ProxyBypass.Length && proxyHelper.ProxyBypass[idx] == ';')
                        {
                            idx++;
                        }
                        if (tmp == null)
                        {
                            continue;
                        }

                        _bypass.Add(tmp);
                    }
                    if (_bypass.Count == 0)
                    {
                        // Bypass string only had garbage we did not parse.
                        _bypass = null;
                    }
                }

                if (_bypassLocal)
                {
                    _localIp = new List <IPAddress>();
                    foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
                    {
                        IPInterfaceProperties ipProps = netInterface.GetIPProperties();
                        foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
                        {
                            _localIp.Add(addr.Address);
                        }
                    }
                }
            }
        }