std::unique_ptr curl_easy::create()

in src/Windows/curl_easy.cpp [127:238]


std::unique_ptr<curl_easy> curl_easy::create(
    const std::string& url,
    const std::string* const p_body,
    unsigned long dwFlags)
{
    struct make_unique_enabler : public curl_easy
    {
    };
    std::unique_ptr<curl_easy> curl = std::make_unique<make_unique_enabler>();

    curl->sessionHandle.reset(WinHttpOpen(
        nullptr,
        WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS,
        0));
    if (!curl->sessionHandle)
    {
        throw_on_error(GetLastError(), "curl_easy::create/WinHttpOpen");
    }

    URL_COMPONENTSW urlComponents = {0};

    // Allocate some buffers to hold the various pieces of the URL.
    auto urlLen(url.size() + 1);
    auto schemeBuffer(std::make_unique<wchar_t[]>(urlLen));
    auto hostBuffer(std::make_unique<wchar_t[]>(urlLen));
    auto urlBuffer(std::make_unique<wchar_t[]>(urlLen));
    auto extraBuffer(std::make_unique<wchar_t[]>(urlLen));

    // Set required component lengths to non-zero
    // so that they are cracked.
    urlComponents.dwStructSize = sizeof(URL_COMPONENTS);
    urlComponents.dwSchemeLength = (DWORD)-1;
    urlComponents.lpszScheme = schemeBuffer.get();
    urlComponents.dwHostNameLength = (DWORD)-1;
    urlComponents.lpszHostName = hostBuffer.get();
    urlComponents.dwUrlPathLength = (DWORD)-1;
    urlComponents.lpszUrlPath = urlBuffer.get();
    urlComponents.dwExtraInfoLength = (DWORD)-1;
    urlComponents.lpszExtraInfo = extraBuffer.get();

    if (!WinHttpCrackUrl(
            UnicodeStringFromUtf8String(url).c_str(),
            0,
            ICU_REJECT_USERPWD,
            &urlComponents))
    {
        throw_on_error(GetLastError(), "curl_easy::create/WinHttpCrackUrl");
    }

    curl->connectionHandle.reset(WinHttpConnect(
        curl->sessionHandle.get(),
        urlComponents.lpszHostName,
        urlComponents.nPort,
        0));
    if (!curl->connectionHandle)
    {
        throw_on_error(GetLastError(), "curl_easy::create/WinHttpConnect");
    }

    std::wstring urlToRetrieve(urlComponents.lpszUrlPath);
    urlToRetrieve += urlComponents.lpszExtraInfo;

    curl->request.reset(WinHttpOpenRequest(
        curl->connectionHandle.get(),
        L"GET",
        urlToRetrieve.c_str(),
        nullptr,
        WINHTTP_NO_REFERER,
        WINHTTP_DEFAULT_ACCEPT_TYPES,
        dwFlags));

    if (!curl->request)
    {
        throw_on_error(GetLastError(), "curl_easy::create/WinHttpOpenRequest");
    }

    // Enable following redirects on this request.
    DWORD redirectPolicy = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS;
    if (!WinHttpSetOption(
            curl->request.get(),
            WINHTTP_OPTION_REDIRECT_POLICY,
            &redirectPolicy,
            sizeof(redirectPolicy)))
    {
        throw_on_error(
            GetLastError(),
            "curl_easy::create/WinHttpSetOption(RedirectPolicy)");
    }

    // Specify TLS 1.2
    DWORD protocolOptions =
        WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 | WINHTTP_FLAG_SECURE_PROTOCOL_SSL3;
    if (!WinHttpSetOption(
            curl->sessionHandle.get(),
            WINHTTP_OPTION_SECURE_PROTOCOLS,
            &protocolOptions,
            sizeof(protocolOptions)))
    {
        throw_on_error(
            GetLastError(),
            "curl_easy::create/WinHttpSetOption(SecureProtocols)");
    }

    if (p_body != nullptr)
    {
        curl->request_body_data = *p_body;
    }

    return std::move(curl);
}