unsigned long open()

in Release/src/http/client/http_client_winhttp.cpp [791:959]


    unsigned long open()
    {
        if (m_opened)
        {
            return 0;
        }

        pplx::extensibility::scoped_critical_section_t l(m_client_lock);
        if (m_opened)
        {
            return 0;
        }

        // This object have lifetime greater than proxy_name and proxy_bypass
        // which may point to its elements.
        ie_proxy_config proxyIE;

        DWORD access_type;
        LPCTSTR proxy_name = WINHTTP_NO_PROXY_NAME;
        LPCTSTR proxy_bypass = WINHTTP_NO_PROXY_BYPASS;
        m_proxy_auto_config = false;
        utility::string_t proxy_str;
        http::uri uri;

        const auto& config = client_config();
        const auto& proxy = config.proxy();
        if (proxy.is_default())
        {
            access_type = WinHttpDefaultProxyConstant();
        }
        else if (proxy.is_disabled())
        {
            access_type = WINHTTP_ACCESS_TYPE_NO_PROXY;
        }
        else if (proxy.is_auto_discovery())
        {
            access_type = WinHttpDefaultProxyConstant();
            if (access_type != WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY)
            {
                // Windows 8 or earlier, do proxy autodetection ourselves
                m_proxy_auto_config = true;

                proxy_info proxyDefault;
                if (!WinHttpGetDefaultProxyConfiguration(&proxyDefault) ||
                    proxyDefault.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY)
                {
                    // ... then try to fall back on the default WinINET proxy, as
                    // recommended for the desktop applications (if we're not
                    // running under a user account, the function below will just
                    // fail, so there is no real need to check for this explicitly)
                    if (WinHttpGetIEProxyConfigForCurrentUser(&proxyIE))
                    {
                        if (proxyIE.fAutoDetect)
                        {
                            m_proxy_auto_config = true;
                        }
                        else if (proxyIE.lpszAutoConfigUrl)
                        {
                            m_proxy_auto_config = true;
                            m_proxy_auto_config_url = proxyIE.lpszAutoConfigUrl;
                        }
                        else if (proxyIE.lpszProxy)
                        {
                            access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
                            proxy_name = proxyIE.lpszProxy;

                            if (proxyIE.lpszProxyBypass)
                            {
                                proxy_bypass = proxyIE.lpszProxyBypass;
                            }
                        }
                    }
                }
            }
        }
        else
        {
            _ASSERTE(config.proxy().is_specified());
            access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
            // WinHttpOpen cannot handle trailing slash in the name, so here is some string gymnastics to keep
            // WinHttpOpen happy proxy_str is intentionally declared at the function level to avoid pointing to the
            // string in the destructed object
            uri = config.proxy().address();
            if (uri.is_port_default())
            {
                proxy_name = uri.host().c_str();
            }
            else
            {
                proxy_str = uri.host();
                if (uri.port() > 0)
                {
                    proxy_str.push_back(_XPLATSTR(':'));
                    proxy_str.append(::utility::conversions::details::to_string_t(uri.port()));
                }

                proxy_name = proxy_str.c_str();
            }
        }

        // Open session.
        m_hSession = WinHttpOpen(NULL, access_type, proxy_name, proxy_bypass, WINHTTP_FLAG_ASYNC);
        if (!m_hSession)
        {
            return GetLastError();
        }

        {
            // Set timeouts.
            const int milliseconds =
                (std::max)(static_cast<int>(config.timeout<std::chrono::milliseconds>().count()), 1);
            if (!WinHttpSetTimeouts(m_hSession, milliseconds, milliseconds, milliseconds, milliseconds))
            {
                return GetLastError();
            }
        }

        if (config.guarantee_order())
        {
            // Set max connection to use per server to 1.
            DWORD maxConnections = 1;
            if (!WinHttpSetOption(
                    m_hSession, WINHTTP_OPTION_MAX_CONNS_PER_SERVER, &maxConnections, sizeof(maxConnections)))
            {
                return GetLastError();
            }
        }

        {
            // Enable TLS 1.1 and 1.2
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
            DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
                                   WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2);
            if (!WinHttpSetOption(
                m_hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols)))
            {
                return GetLastError();
            }
#endif
        }

        config._invoke_nativesessionhandle_options(m_hSession);

        // Register asynchronous callback.
        if (WINHTTP_INVALID_STATUS_CALLBACK ==
            WinHttpSetStatusCallback(m_hSession,
                                     &winhttp_client::completion_callback,
                                     WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | WINHTTP_CALLBACK_FLAG_HANDLES |
                                         WINHTTP_CALLBACK_FLAG_SECURE_FAILURE | WINHTTP_CALLBACK_FLAG_SEND_REQUEST |
                                         WINHTTP_CALLBACK_STATUS_REDIRECT,
                                     0))
        {
            return GetLastError();
        }

        // Open connection.
        unsigned int port = m_uri.is_port_default()
                                ? (m_secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT)
                                : m_uri.port();
        m_hConnection = WinHttpConnect(m_hSession, m_uri.host().c_str(), (INTERNET_PORT)port, 0);

        if (m_hConnection == nullptr)
        {
            return GetLastError();
        }

        m_opened = true;
        return S_OK;
    }