diff --git a/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h b/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h index 203022fa2253..b6072387f984 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h +++ b/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h @@ -362,6 +362,16 @@ namespace Aws */ bool disableExpectHeader = false; + /** + * Only works for Curl http client. + * Sets the timeout in milliseconds that Curl will wait for a 100-Continue response from the server + * before sending the request body. This corresponds to CURLOPT_EXPECT_100_TIMEOUT_MS. + * Useful when operating behind proxies that introduce network delays, where the default 1000ms + * may be too short and cause IncompleteBody errors. + * Default 1000ms (Curl's built-in default). + */ + long expect100ContinueTimeoutMs = 1000; + /** * If set to true clock skew will be adjusted after each http attempt, default to true. */ diff --git a/src/aws-cpp-sdk-core/include/aws/core/http/curl/CurlHandleContainer.h b/src/aws-cpp-sdk-core/include/aws/core/http/curl/CurlHandleContainer.h index 3ce921b57db1..328b9947430b 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/http/curl/CurlHandleContainer.h +++ b/src/aws-cpp-sdk-core/include/aws/core/http/curl/CurlHandleContainer.h @@ -31,7 +31,7 @@ class CurlHandleContainer */ CurlHandleContainer(unsigned maxSize = 50, long httpRequestTimeout = 0, long connectTimeout = 1000, bool tcpKeepAlive = true, unsigned long tcpKeepAliveIntervalMs = 30000, long lowSpeedTime = 3000, unsigned long lowSpeedLimit = 1, - Version version = Version::HTTP_VERSION_2TLS); + Version version = Version::HTTP_VERSION_2TLS, long expect100ContinueTimeoutMs = 1000); ~CurlHandleContainer(); /** @@ -71,6 +71,7 @@ class CurlHandleContainer unsigned m_poolSize; std::mutex m_containerLock; Version m_version; + long m_expect100ContinueTimeoutMs; }; } // namespace Http diff --git a/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp b/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp index cc805c69eb99..f793bb5d49df 100644 --- a/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp +++ b/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp @@ -247,6 +247,7 @@ void setLegacyClientConfigurationParameters(ClientConfiguration& clientConfig) clientConfig.httpClientChunkedMode = HttpClientChunkedMode::CLIENT_IMPLEMENTATION; clientConfig.followRedirects = FollowRedirectsPolicy::DEFAULT; clientConfig.disableExpectHeader = false; + clientConfig.expect100ContinueTimeoutMs = 1000; clientConfig.enableClockSkewAdjustment = true; clientConfig.enableHostPrefixInjection = true; clientConfig.enableHttpClientTrace = false; diff --git a/src/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp b/src/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp index edc410a4ee67..bb70f86248c2 100644 --- a/src/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp +++ b/src/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp @@ -16,10 +16,10 @@ static const char* CURL_HANDLE_CONTAINER_TAG = "CurlHandleContainer"; CurlHandleContainer::CurlHandleContainer(unsigned maxSize, long httpRequestTimeout, long connectTimeout, bool enableTcpKeepAlive, unsigned long tcpKeepAliveIntervalMs, long lowSpeedTime, unsigned long lowSpeedLimit, - Version version) : + Version version, long expect100ContinueTimeoutMs) : m_maxPoolSize(maxSize), m_httpRequestTimeout(httpRequestTimeout), m_connectTimeout(connectTimeout), m_enableTcpKeepAlive(enableTcpKeepAlive), m_tcpKeepAliveIntervalMs(tcpKeepAliveIntervalMs), m_lowSpeedTime(lowSpeedTime), m_lowSpeedLimit(lowSpeedLimit), m_poolSize(0), - m_version(version) + m_version(version), m_expect100ContinueTimeoutMs(expect100ContinueTimeoutMs) { AWS_LOGSTREAM_INFO(CURL_HANDLE_CONTAINER_TAG, "Initializing CurlHandleContainer with size " << maxSize); } @@ -174,6 +174,7 @@ void CurlHandleContainer::SetDefaultOptionsOnHandle(CURL* handle) curl_easy_setopt(handle, CURLOPT_TCP_KEEPIDLE, m_tcpKeepAliveIntervalMs / 1000); curl_easy_setopt(handle, CURLOPT_HTTP_VERSION, ConvertHttpVersion(m_version)); curl_easy_setopt(handle, CURLOPT_MAXCONNECTS, m_maxPoolSize); + curl_easy_setopt(handle, CURLOPT_EXPECT_100_TIMEOUT_MS, m_expect100ContinueTimeoutMs); } long CurlHandleContainer::ConvertHttpVersion(Version version) { diff --git a/src/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp b/src/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp index 58fc56875de7..a2df8714f137 100644 --- a/src/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp +++ b/src/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp @@ -602,7 +602,8 @@ const bool FORCE_ENABLE_CURL_LOGGING = false; CurlHttpClient::CurlHttpClient(const ClientConfiguration& clientConfig) : Base(), m_curlHandleContainer(clientConfig.maxConnections, clientConfig.httpRequestTimeoutMs, clientConfig.connectTimeoutMs, clientConfig.enableTcpKeepAlive, - clientConfig.tcpKeepAliveIntervalMs, clientConfig.requestTimeoutMs, clientConfig.lowSpeedLimit, clientConfig.version), + clientConfig.tcpKeepAliveIntervalMs, clientConfig.requestTimeoutMs, clientConfig.lowSpeedLimit, clientConfig.version, + clientConfig.expect100ContinueTimeoutMs), m_isAllowSystemProxy(clientConfig.allowSystemProxy), m_isUsingProxy(!clientConfig.proxyHost.empty()), m_proxyUserName(clientConfig.proxyUserName), m_proxyPassword(clientConfig.proxyPassword), m_proxyScheme(SchemeMapper::ToString(clientConfig.proxyScheme)), m_proxyHost(clientConfig.proxyHost), m_proxySSLCertPath(clientConfig.proxySSLCertPath), m_proxySSLCertType(clientConfig.proxySSLCertType),