HRESULT WinHttpConnection::Initialize()

in Source/HTTP/WinHttp/winhttp_connection.cpp [142:287]


HRESULT WinHttpConnection::Initialize()
{
    try
    {
        const char* url = nullptr;
        const char* method = nullptr;
        RETURN_IF_FAILED(HCHttpCallRequestGetUrl(m_call, &method, &url));

        m_uri = Uri{ url };
        unsigned int port = m_uri.IsPortDefault() ? (m_uri.IsSecure() ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT) : m_uri.Port();

        http_internal_wstring wUrlHost = utf16_from_utf8(m_uri.Host());
        m_hConnection = WinHttpConnect(
            m_hSession,
            wUrlHost.c_str(),
            (INTERNET_PORT)port,
            0);

        if (m_hConnection == nullptr)
        {
            DWORD dwError = GetLastError();
            HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection [ID %llu] [TID %ul] WinHttpConnect errorcode %d", TO_ULL(HCHttpCallGetId(m_call)), GetCurrentThreadId(), dwError);
            return HRESULT_FROM_WIN32(dwError);
        }

        // Need to form uri path, query, and fragment for this request.
        http_internal_wstring wEncodedResource = utf16_from_utf8(m_uri.Resource());
        http_internal_wstring wMethod = utf16_from_utf8(method);

        // Open the request.
        m_hRequest = WinHttpOpenRequest(
            m_hConnection,
            wMethod.c_str(),
            wEncodedResource.c_str(),
            nullptr,
            WINHTTP_NO_REFERER,
            WINHTTP_DEFAULT_ACCEPT_TYPES,
            WINHTTP_FLAG_ESCAPE_DISABLE | (m_uri.IsSecure() ? WINHTTP_FLAG_SECURE : 0));

        if (m_hRequest == nullptr)
        {
            DWORD dwError = GetLastError();
            HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection [ID %llu] [TID %ul] WinHttpOpenRequest errorcode %d", TO_ULL(HCHttpCallGetId(m_call)), GetCurrentThreadId(), dwError);
            return HRESULT_FROM_WIN32(dwError);
        }

        uint32_t timeoutInSeconds = 0;
        RETURN_IF_FAILED(HCHttpCallRequestGetTimeout(m_call, &timeoutInSeconds));

        int timeoutInMilliseconds = static_cast<int>(timeoutInSeconds * 1000);
        if (!WinHttpSetTimeouts(
            m_hSession,
            timeoutInMilliseconds,
            timeoutInMilliseconds,
            timeoutInMilliseconds,
            timeoutInMilliseconds))
        {
            DWORD dwError = GetLastError();
            HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection [ID %llu] [TID %ul] WinHttpSetTimeouts errorcode %d", TO_ULL(HCHttpCallGetId(m_call)), GetCurrentThreadId(), dwError);
            return HRESULT_FROM_WIN32(dwError);
        }

#if HC_PLATFORM_IS_MICROSOFT && (HC_PLATFORM != HC_PLATFORM_UWP) && (HC_PLATFORM != HC_PLATFORM_XDK)
        if (!m_call->sslValidation)
        {
            DWORD dwOption = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
            if (!WinHttpSetOption(
                m_hRequest,
                WINHTTP_OPTION_SECURITY_FLAGS,
                &dwOption,
                sizeof(dwOption)))
            {
                DWORD dwError = GetLastError();
                HC_TRACE_WARNING(HTTPCLIENT, "WinHttpConnection [ID %llu] [TID %ul] WinHttpSetOption errorcode %d", HCHttpCallGetId(m_call), GetCurrentThreadId(), dwError);
            }
        }
#endif

#if HC_PLATFORM != HC_PLATFORM_GDK
        if (m_proxyType == proxy_type::autodiscover_proxy)
        {
            RETURN_IF_FAILED(set_autodiscover_proxy());
        }
#endif

        HCHttpCallRequestBodyReadFunction requestBodyReadFunction{ nullptr };
        void* context{ nullptr };
        RETURN_IF_FAILED(HCHttpCallRequestGetRequestBodyReadFunction(m_call, &requestBodyReadFunction, &m_requestBodySize, &context));

        if (m_requestBodySize > 0)
        {
            // While we won't be transfer-encoding the data, we will write it in portions.
            m_requestBodyType = msg_body_type::content_length_chunked;
            m_requestBodyRemainingToWrite = m_requestBodySize;
        }
        else
        {
            m_requestBodyType = msg_body_type::no_body;
            m_requestBodyRemainingToWrite = 0;
        }

        uint32_t numHeaders = 0;
        RETURN_IF_FAILED(HCHttpCallRequestGetNumHeaders(m_call, &numHeaders));

        if (numHeaders > 0)
        {
            http_internal_wstring flattenedHeaders = flatten_http_headers(m_call->requestHeaders);
            if (!WinHttpAddRequestHeaders(
                m_hRequest,
                flattenedHeaders.c_str(),
                static_cast<DWORD>(flattenedHeaders.length()),
                WINHTTP_ADDREQ_FLAG_ADD))
            {
                DWORD dwError = GetLastError();
                HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection [ID %llu] [TID %ul] WinHttpAddRequestHeaders errorcode %d", TO_ULL(HCHttpCallGetId(m_call)), GetCurrentThreadId(), dwError);
                return HRESULT_FROM_WIN32(dwError);
            }
        }

        if (m_uri.IsSecure())
        {
            if (!WinHttpSetOption(
                m_hRequest,
                WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
                WINHTTP_NO_CLIENT_CERT_CONTEXT,
                0))
            {
                DWORD dwError = GetLastError();
                HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection [ID %llu] [TID %ul] WinHttpSetOption errorcode %d", TO_ULL(HCHttpCallGetId(m_call)), GetCurrentThreadId(), dwError);
                return HRESULT_FROM_WIN32(dwError);
            }
        }
    }
    catch (std::bad_alloc const& e)
    {
        HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection [%d] std::bad_alloc: %s", E_OUTOFMEMORY, e.what());
        return E_OUTOFMEMORY;
    }
    catch (...)
    {
        HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection [%d] unknown exception", E_FAIL);
        return E_FAIL;
    }

    return S_OK;
}