WinHttpSyncHttpClient::WinHttpSyncHttpClient(const ClientConfiguration& config) :
    Base()
{
    AWS_LOGSTREAM_INFO(GetLogTag(), "Creating http client with user agent " << config.userAgent << " with max connections " << config.maxConnections 
        << " request timeout " << config.requestTimeoutMs << ",and connect timeout " << config.connectTimeoutMs);

    DWORD winhttpFlags = WINHTTP_ACCESS_TYPE_NO_PROXY;
    const char* proxyHosts = nullptr;
    Aws::String strProxyHosts;

    m_allowRedirects = config.followRedirects;

    bool isUsingProxy = !config.proxyHost.empty();
    //setup initial proxy config.

    Aws::WString proxyString;

    if (isUsingProxy)
    {
        AWS_LOGSTREAM_INFO(GetLogTag(), "Http Client is using a proxy. Setting up proxy with settings host " << config.proxyHost
             << ", port " << config.proxyPort << ", username " << config.proxyUserName);


        winhttpFlags = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
        Aws::StringStream ss;
        const char* schemeString = Aws::Http::SchemeMapper::ToString(config.scheme);
        ss << StringUtils::ToUpper(schemeString) << "=" << schemeString << "://" << config.proxyHost << ":" << config.proxyPort;
        strProxyHosts.assign(ss.str());
        proxyHosts = strProxyHosts.c_str();

        proxyString = StringUtils::ToWString(proxyHosts);
        AWS_LOGSTREAM_DEBUG(GetLogTag(), "Adding proxy host string to winhttp " << proxyHosts);
    }

    Aws::WString openString = StringUtils::ToWString(config.userAgent.c_str());

    SetOpenHandle(WinHttpOpen(openString.c_str(), winhttpFlags, proxyString.c_str(), nullptr, 0));

    if (!WinHttpSetTimeouts(GetOpenHandle(), config.connectTimeoutMs, config.connectTimeoutMs, -1, config.requestTimeoutMs))
    {
        AWS_LOGSTREAM_WARN(GetLogTag(), "Error setting timeouts " << GetLastError());
    }

    //add proxy auth credentials to everything using this handle.
    if (isUsingProxy)
    {
        if (!config.proxyUserName.empty() && !WinHttpSetOption(GetOpenHandle(), WINHTTP_OPTION_PROXY_USERNAME, (LPVOID)config.proxyUserName.c_str(), (DWORD)config.proxyUserName.length()))
            AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed setting username for proxy with error code: " << GetLastError());
        if (!config.proxyPassword.empty() && !WinHttpSetOption(GetOpenHandle(), WINHTTP_OPTION_PROXY_PASSWORD, (LPVOID)config.proxyPassword.c_str(), (DWORD)config.proxyPassword.length()))
            AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed setting password for proxy with error code: " << GetLastError());
    }

    if (!config.verifySSL)
    {
        AWS_LOG_WARN(GetLogTag(), "Turning ssl unknown ca verification off.");
        DWORD flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID;

        if (!WinHttpSetOption(GetOpenHandle(), WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)))
            AWS_LOG_FATAL(GetLogTag(), "Failed to turn ssl cert ca verification off.");
    }
    else
    {
        //disable insecure tls protocols, otherwise you might as well turn ssl verification off.
        DWORD flags = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;
        if (!WinHttpSetOption(GetOpenHandle(), WINHTTP_OPTION_SECURE_PROTOCOLS, &flags, sizeof(flags)))
        {
            AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed setting secure crypto protocols with error code: " << GetLastError());
        }
    }

    AWS_LOG_DEBUG(GetLogTag(), "API handle %p.", GetOpenHandle());
    SetConnectionPoolManager(Aws::New<WinHttpConnectionPoolMgr>(GetLogTag(),
        GetOpenHandle(), config.maxConnections, config.requestTimeoutMs, config.connectTimeoutMs));
}