diff --git a/.cspell.json b/.cspell.json index 46ecb400fb1..495da466755 100644 --- a/.cspell.json +++ b/.cspell.json @@ -39,7 +39,7 @@ // MSVC "msvc", "MSFT", "LPDWORD", "DATAW", "mkgmtime", "vscprintf", "wtoi", "msxml", "runtimeobject", "winhttp", "Wininet", "HINTERNET", "ADDREQ", "LPCSTR", "MAKELANGID", "SUBLANG", "WSADATA", "Initate", "ioctlsocket", - "dupenv", "USERPROFILE", "subblock", "LANGANDCODEPAGE", + "dupenv", "USERPROFILE", "subblock", "LANGANDCODEPAGE", "keepalivetime", "keepaliveinterval", // Crypto "decryptor", "encryptor", "NTSTATUS", "PBYTE", "PUCHAR", "noconf", "HAMC", "PBCRYPT", "BCRYPT", "libcrypto", "AWSLC", "CBCCTS", "tweaklen", "taglen", "blockcipher", "AESGCM", "compated", "outdata", "Decrypto", "GCMAAD", diff --git a/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinHttpSyncHttpClient.h b/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinHttpSyncHttpClient.h index 1dcfa4313c8..f5c517d84f3 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinHttpSyncHttpClient.h +++ b/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinHttpSyncHttpClient.h @@ -54,6 +54,8 @@ namespace Aws bool DoReadData(void* hHttpRequest, char* body, uint64_t size, uint64_t& read) const override; void* GetClientModule() const override; + const char* GetActualHttpVersionUsed(void* hHttpRequest) const override; + bool m_usingProxy = false; bool m_verifySSL = true; Aws::Http::Version m_version = Aws::Http::Version::HTTP_VERSION_2TLS; diff --git a/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinINetSyncHttpClient.h b/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinINetSyncHttpClient.h index 6a49767e21f..f9c3425cc26 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinINetSyncHttpClient.h +++ b/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinINetSyncHttpClient.h @@ -52,6 +52,8 @@ namespace Aws bool DoReadData(void* hHttpRequest, char* body, uint64_t size, uint64_t& read) const override; void* GetClientModule() const override; + const char* GetActualHttpVersionUsed(void* hHttpRequest) const override; + WinINetSyncHttpClient &operator =(const WinINetSyncHttpClient &rhs); bool m_usingProxy; diff --git a/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinSyncHttpClient.h b/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinSyncHttpClient.h index e3a29a169d9..f1b0adddf57 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinSyncHttpClient.h +++ b/src/aws-cpp-sdk-core/include/aws/core/http/windows/WinSyncHttpClient.h @@ -82,6 +82,8 @@ namespace Aws */ bool m_allowRedirects; + bool m_enableHttpClientTrace = false; + private: virtual void* OpenRequest(const std::shared_ptr& request, void* connection, const Aws::StringStream& ss) const = 0; virtual void DoAddHeaders(void* hHttpRequest, Aws::String& headerStr) const = 0; @@ -93,6 +95,8 @@ namespace Aws virtual bool DoReadData(void* hHttpRequest, char* body, uint64_t size, uint64_t& read) const = 0; virtual void* GetClientModule() const = 0; + virtual const char* GetActualHttpVersionUsed(void* hHttpRequest) const = 0; + bool StreamPayloadToRequest(const std::shared_ptr& request, void* hHttpRequest, Aws::Utils::RateLimits::RateLimiterInterface* writeLimiter) const; void LogRequestInternalFailure() const; bool BuildSuccessResponse(const std::shared_ptr& request, std::shared_ptr& response, void* hHttpRequest, Aws::Utils::RateLimits::RateLimiterInterface* readLimiter) const; diff --git a/src/aws-cpp-sdk-core/source/http/windows/WinHttpSyncHttpClient.cpp b/src/aws-cpp-sdk-core/source/http/windows/WinHttpSyncHttpClient.cpp index 7e47dbfebd1..3fbd4822fc4 100644 --- a/src/aws-cpp-sdk-core/source/http/windows/WinHttpSyncHttpClient.cpp +++ b/src/aws-cpp-sdk-core/source/http/windows/WinHttpSyncHttpClient.cpp @@ -19,6 +19,7 @@ #include #include +#include // for tcp_keepalive #include #include #include @@ -85,6 +86,104 @@ DWORD ConvertHttpVersionToWinHttpVersion(const Aws::Http::Version version) #endif } +void AzWinHttpLogLastError(const char* FuncName) +{ +#define AZ_WINHTTP_ERROR(win_http_error) \ + {win_http_error, #win_http_error} +#define AZ_WINHTTP_ERROR_FALLBACK(win_http_error, value) \ + {value, #win_http_error} + + static const std::pair WIN_HTTP_ERRORS[] = { + AZ_WINHTTP_ERROR(ERROR_WINHTTP_OUT_OF_HANDLES), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_TIMEOUT), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_INTERNAL_ERROR), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_INVALID_URL), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_UNRECOGNIZED_SCHEME), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_NAME_NOT_RESOLVED), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_INVALID_OPTION), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_OPTION_NOT_SETTABLE), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SHUTDOWN), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_LOGIN_FAILURE), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_OPERATION_CANCELLED), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_INCORRECT_HANDLE_TYPE), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_INCORRECT_HANDLE_STATE), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CANNOT_CONNECT), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CONNECTION_ERROR), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_RESEND_REQUEST), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CANNOT_CALL_AFTER_OPEN), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_HEADER_NOT_FOUND), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_INVALID_SERVER_RESPONSE), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_INVALID_HEADER), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_INVALID_QUERY_REQUEST), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_HEADER_ALREADY_EXISTS), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_REDIRECT_FAILED), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_UNHANDLED_SCRIPT_TYPE), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SCRIPT_EXECUTION_ERROR), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_NOT_INITIALIZED), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SECURE_FAILURE), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SECURE_CERT_DATE_INVALID), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SECURE_CERT_CN_INVALID), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SECURE_INVALID_CA), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SECURE_CERT_REV_FAILED), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SECURE_CHANNEL_ERROR), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SECURE_INVALID_CERT), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SECURE_CERT_REVOKED), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_AUTODETECTION_FAILED), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_HEADER_COUNT_EXCEEDED), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_HEADER_SIZE_OVERFLOW), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CLIENT_CERT_NO_ACCESS_PRIVATE_KEY), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED_PROXY), + AZ_WINHTTP_ERROR(ERROR_WINHTTP_SECURE_FAILURE_PROXY), + AZ_WINHTTP_ERROR_FALLBACK(ERROR_WINHTTP_RESERVED_189, (WINHTTP_ERROR_BASE + 189)), + AZ_WINHTTP_ERROR_FALLBACK(ERROR_WINHTTP_HTTP_PROTOCOL_MISMATCH, (WINHTTP_ERROR_BASE + 190)), + AZ_WINHTTP_ERROR_FALLBACK(ERROR_WINHTTP_GLOBAL_CALLBACK_FAILED, (WINHTTP_ERROR_BASE + 191)), + AZ_WINHTTP_ERROR_FALLBACK(ERROR_WINHTTP_FEATURE_DISABLED, (WINHTTP_ERROR_BASE + 192)), + AZ_WINHTTP_ERROR(ERROR_INVALID_PARAMETER), + AZ_WINHTTP_ERROR(ERROR_NOT_ENOUGH_MEMORY) + }; +#undef AZ_WINHTTP_ERROR +#undef AZ_WINHTTP_ERROR_FALLBACK + + static const size_t WIN_HTTP_ERRORS_SZ = sizeof(WIN_HTTP_ERRORS) / sizeof(WIN_HTTP_ERRORS[0]); + + const auto lastError = GetLastError(); + size_t errorIdx = 0; + for(; errorIdx < WIN_HTTP_ERRORS_SZ; ++errorIdx) + { + if(WIN_HTTP_ERRORS[errorIdx].first == lastError) + { + AWS_LOGSTREAM_ERROR("WinHttp", "Failed to " << FuncName << " with an error code: " << WIN_HTTP_ERRORS[errorIdx].second); + break; + } + } + if (errorIdx == WIN_HTTP_ERRORS_SZ) + { + AWS_LOGSTREAM_ERROR("WinHttp", "Failed to " << FuncName << " with an unknown error code: " << lastError); + } +} + +template +bool AzCallWinHttp(const char* FuncName, WinHttpFunc func, Args &&... args) +{ + bool success = func(std::forward(args)...); + if (!success) + { + AzWinHttpLogLastError(FuncName); + } + return success; +} + static void WinHttpSetHttpVersion(void* handle, const Aws::Http::Version version) { DWORD winHttpVersion = ConvertHttpVersionToWinHttpVersion(version); @@ -92,7 +191,7 @@ static void WinHttpSetHttpVersion(void* handle, const Aws::Http::Version version { return; } - if (!WinHttpSetOption(handle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, &winHttpVersion, sizeof(winHttpVersion))) + if (!AzCallWinHttp("WinHttpSetOption", WinHttpSetOption, handle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, &winHttpVersion, sizeof(winHttpVersion))) { AWS_LOGSTREAM_ERROR("WinHttpHttp2", "Failed to set WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL to " << winHttpVersion << " on WinHttp handle: " << handle); } @@ -282,7 +381,7 @@ static void CALLBACK WinHttpSyncLogCallback(HINTERNET hInternet, } else { - AWS_LOGSTREAM_TRACE("WinHttp", data->statusString); + AWS_LOGSTREAM_TRACE("WinHttp", data->statusString); } found = true; }//found handler @@ -299,6 +398,8 @@ WinHttpSyncHttpClient::WinHttpSyncHttpClient(const ClientConfiguration& config) m_verifySSL(config.verifySSL), m_version(config.version) { + m_enableHttpClientTrace = config.enableHttpClientTrace; + 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); @@ -349,8 +450,12 @@ WinHttpSyncHttpClient::WinHttpSyncHttpClient(const ClientConfiguration& config) Aws::WString openString = StringUtils::ToWString(config.userAgent.c_str()); // WinhttpOpen will create a session handle HINTERNET hHttpSession = WinHttpOpen(openString.c_str(), winhttpFlags, proxyString.c_str(), nullptr, 0); + if (!hHttpSession) + { + AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed to open WinHttp session, last error: " << GetLastError()); + } - if (config.enableHttpClientTrace) + if (m_enableHttpClientTrace) { AWS_LOGSTREAM_DEBUG(GetLogTag(), "Enabling WinHttp traces"); WinHttpSetStatusCallback(hHttpSession, WinHttpSyncLogCallback, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, (DWORD_PTR)NULL); @@ -358,10 +463,8 @@ WinHttpSyncHttpClient::WinHttpSyncHttpClient(const ClientConfiguration& config) SetOpenHandle(hHttpSession); - if (!WinHttpSetTimeouts(GetOpenHandle(), config.connectTimeoutMs, config.connectTimeoutMs, -1, config.requestTimeoutMs)) - { - AWS_LOGSTREAM_WARN(GetLogTag(), "Error setting timeouts " << GetLastError()); - } + AzCallWinHttp("WinHttpSetTimeouts", WinHttpSetTimeouts, + GetOpenHandle(), config.connectTimeoutMs, config.connectTimeoutMs, -1, config.requestTimeoutMs); WinHttpSetHttpVersion(GetOpenHandle(), m_version); if (m_verifySSL) { @@ -384,12 +487,29 @@ WinHttpSyncHttpClient::WinHttpSyncHttpClient(const ClientConfiguration& config) WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2; #endif - if (!WinHttpSetOption(GetOpenHandle(), WINHTTP_OPTION_SECURE_PROTOCOLS, &flags, sizeof(flags))) + if (!AzCallWinHttp("WinHttpSetOption", WinHttpSetOption, GetOpenHandle(), WINHTTP_OPTION_SECURE_PROTOCOLS, &flags, sizeof(flags))) { AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed setting secure crypto protocols with error code: " << GetLastError()); } } + if (config.enableTcpKeepAlive) + { + tcp_keepalive keepAlive = {}; + keepAlive.onoff = 1; + // Default 3000 and 30000 ms according to our ClientConfig doc + keepAlive.keepalivetime = config.requestTimeoutMs ? config.requestTimeoutMs : 3000; + keepAlive.keepaliveinterval = config.tcpKeepAliveIntervalMs ? config.tcpKeepAliveIntervalMs : 30000; + +#if !defined(WINHTTP_OPTION_TCP_KEEPALIVE) +#define WINHTTP_OPTION_TCP_KEEPALIVE 152 +#endif + if (!AzCallWinHttp("WinHttpSetOption", WinHttpSetOption, hHttpSession, WINHTTP_OPTION_TCP_KEEPALIVE, &keepAlive, sizeof(keepAlive))) + { + AWS_LOGSTREAM_WARN(GetLogTag(), "Failed setting TCP keep-alive config on WinHttpSession"); + } + } + AWS_LOGSTREAM_DEBUG(GetLogTag(), "API handle " << GetOpenHandle()); SetConnectionPoolManager(Aws::New(GetLogTag(), GetOpenHandle(), config.maxConnections, config.requestTimeoutMs, config.connectTimeoutMs, config.enableTcpKeepAlive, config.tcpKeepAliveIntervalMs)); @@ -427,28 +547,30 @@ void* WinHttpSyncHttpClient::OpenRequest(const std::shared_ptr& req //add proxy auth credentials to everything using this handle. if (m_usingProxy) { - if (!m_proxyUserName.empty() && !WinHttpSetOption(hHttpRequest, WINHTTP_OPTION_PROXY_USERNAME, (LPVOID)m_proxyUserName.c_str(), (DWORD)m_proxyUserName.length())) + if (!m_proxyUserName.empty() && !AzCallWinHttp("WinHttpSetOption", WinHttpSetOption, hHttpRequest, WINHTTP_OPTION_PROXY_USERNAME, (LPVOID)m_proxyUserName.c_str(), (DWORD)m_proxyUserName.length())) + { AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed setting username for proxy with error code: " << GetLastError()); - if (!m_proxyPassword.empty() && !WinHttpSetOption(hHttpRequest, WINHTTP_OPTION_PROXY_PASSWORD, (LPVOID)m_proxyPassword.c_str(), (DWORD)m_proxyPassword.length())) + } + if (!m_proxyPassword.empty() && !AzCallWinHttp("WinHttpSetOption", WinHttpSetOption, hHttpRequest, WINHTTP_OPTION_PROXY_PASSWORD, (LPVOID)m_proxyPassword.c_str(), (DWORD)m_proxyPassword.length())) + { AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed setting password for proxy with error code: " << GetLastError()); + } } if (!m_verifySSL) // Turning ssl unknown ca verification off { DWORD flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID; - if (!WinHttpSetOption(hHttpRequest, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags))) + if (!AzCallWinHttp("WinHttpSetOption", WinHttpSetOption, hHttpRequest, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags))) + { AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed to turn ssl cert ca verification off."); + } } - // WinHTTP doesn't have the option to turn off keep-alive, so we will only set the value if keep-alive is turned on. - // see https://docs.microsoft.com/en-us/windows/desktop/winhttp/option-flags for more information on default values. - if (GetConnectionPoolManager()->GetEnableTcpKeepAlive()) + if (!GetConnectionPoolManager()->GetEnableTcpKeepAlive()) { - DWORD keepAliveIntervalMs = GetConnectionPoolManager()->GetTcpKeepAliveInterval(); - if (!WinHttpSetOption(hHttpRequest, WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL, &keepAliveIntervalMs, sizeof(keepAliveIntervalMs))) - { - AWS_LOGSTREAM_WARN(GetLogTag(), "Failed setting TCP keep-alive interval with error code: " << GetLastError()); - } + DWORD keepAliveDisable = WINHTTP_DISABLE_KEEP_ALIVE; + AzCallWinHttp("WinHttpSetOption:WINHTTP_DISABLE_KEEP_ALIVE", WinHttpSetOption, + hHttpRequest, WINHTTP_OPTION_DISABLE_FEATURE, &keepAliveDisable, sizeof(keepAliveDisable)); } //DISABLE_FEATURE settings need to be made after OpenRequest but before SendRequest @@ -456,8 +578,10 @@ void* WinHttpSyncHttpClient::OpenRequest(const std::shared_ptr& req { requestFlags = WINHTTP_DISABLE_REDIRECTS; - if (!WinHttpSetOption(hHttpRequest, WINHTTP_OPTION_DISABLE_FEATURE, &requestFlags, sizeof(requestFlags))) + if (!AzCallWinHttp("WinHttpSetOption", WinHttpSetOption, hHttpRequest, WINHTTP_OPTION_DISABLE_FEATURE, &requestFlags, sizeof(requestFlags))) + { AWS_LOGSTREAM_FATAL(GetLogTag(), "Failed to turn off redirects!"); + } } WinHttpSetHttpVersion(hHttpRequest, m_version); @@ -469,8 +593,11 @@ void WinHttpSyncHttpClient::DoAddHeaders(void* hHttpRequest, Aws::String& header Aws::WString wHeaderString = StringUtils::ToWString(headerStr.c_str()); - if (!WinHttpAddRequestHeaders(hHttpRequest, wHeaderString.c_str(), (DWORD)wHeaderString.length(), WINHTTP_ADDREQ_FLAG_REPLACE | WINHTTP_ADDREQ_FLAG_ADD)) + if (!AzCallWinHttp("WinHttpAddRequestHeaders", WinHttpAddRequestHeaders, + hHttpRequest, wHeaderString.c_str(), (DWORD)wHeaderString.length(), WINHTTP_ADDREQ_FLAG_REPLACE | WINHTTP_ADDREQ_FLAG_ADD)) + { AWS_LOGSTREAM_ERROR(GetLogTag(), "Failed to add HTTP request headers: " << headerStr << ", with error code: " << GetLastError()); + } } uint64_t WinHttpSyncHttpClient::DoWriteData(void* hHttpRequest, char* streamBuffer, uint64_t bytesRead, bool isChunked) const @@ -483,17 +610,17 @@ uint64_t WinHttpSyncHttpClient::DoWriteData(void* hHttpRequest, char* streamBuff { Aws::String chunkSizeHexString = StringUtils::ToHexString(bytesRead) + CRLF; - if (!WinHttpWriteData(hHttpRequest, chunkSizeHexString.c_str(), (DWORD)chunkSizeHexString.size(), &bytesWritten)) + if (!AzCallWinHttp("WinHttpWriteData", WinHttpWriteData, hHttpRequest, chunkSizeHexString.c_str(), (DWORD)chunkSizeHexString.size(), &bytesWritten)) { return totalBytesWritten; } totalBytesWritten += bytesWritten; - if (!WinHttpWriteData(hHttpRequest, streamBuffer, (DWORD)bytesRead, &bytesWritten)) + if (!AzCallWinHttp("WinHttpWriteData", WinHttpWriteData, hHttpRequest, streamBuffer, (DWORD)bytesRead, &bytesWritten)) { return totalBytesWritten; } totalBytesWritten += bytesWritten; - if (!WinHttpWriteData(hHttpRequest, CRLF, (DWORD)(sizeof(CRLF) - 1), &bytesWritten)) + if (!AzCallWinHttp("WinHttpWriteData", WinHttpWriteData, hHttpRequest, CRLF, (DWORD)(sizeof(CRLF) - 1), &bytesWritten)) { return totalBytesWritten; } @@ -501,7 +628,7 @@ uint64_t WinHttpSyncHttpClient::DoWriteData(void* hHttpRequest, char* streamBuff } else { - if (!WinHttpWriteData(hHttpRequest, streamBuffer, (DWORD)bytesRead, &bytesWritten)) + if (!AzCallWinHttp("WinHttpWriteData", WinHttpWriteData, hHttpRequest, streamBuffer, (DWORD)bytesRead, &bytesWritten)) { return totalBytesWritten; } @@ -515,7 +642,7 @@ uint64_t WinHttpSyncHttpClient::FinalizeWriteData(void* hHttpRequest) const { DWORD bytesWritten = 0; const char trailingCRLF[] = "0\r\n\r\n"; - if (!WinHttpWriteData(hHttpRequest, trailingCRLF, (DWORD)(sizeof(trailingCRLF) - 1), &bytesWritten)) + if (!AzCallWinHttp("WinHttpWriteData", WinHttpWriteData, hHttpRequest, trailingCRLF, (DWORD)(sizeof(trailingCRLF) - 1), &bytesWritten)) { return 0; } @@ -575,7 +702,12 @@ bool WinHttpSyncHttpClient::DoQueryHeaders(void* hHttpRequest, std::shared_ptr& AWS_LOGSTREAM_DEBUG(GetLogTag(), "with headers:"); for (auto& header : request->GetHeaders()) { - ss << header.first << ": " << header.second << "\r\n"; + if (!header.first.empty() && !header.second.empty()) + { + ss << header.first << ": " << header.second << "\r\n"; + } + else + { + // WinHttp does not accept empty header key or value + AWS_LOGSTREAM_DEBUG(GetLogTag(), "Empty header is ignored: " << header.first << ": " << header.second); + } } Aws::String headerString = ss.str(); @@ -352,6 +360,7 @@ std::shared_ptr WinSyncHttpClient::MakeRequest(const std::shared_p } else if(!success) { + AWS_LOGSTREAM_INFO(GetLogTag(), "Actual HTTP Version used " << GetActualHttpVersionUsed(hHttpRequest)); LogRequestInternalFailure(); }