std::shared_ptr<HttpResponse> WinSyncHttpClient::MakeRequest(HttpRequest& request, Aws::Utils::RateLimits::RateLimiterInterface* readLimiter, Aws::Utils::RateLimits::RateLimiterInterface* writeLimiter) const { //we URL encode right before going over the wire to avoid double encoding problems with the signer. URI& uriRef = request.GetUri(); uriRef.SetPath(URI::URLEncodePath(uriRef.GetPath())); AWS_LOGSTREAM_TRACE(GetLogTag(), "Making " << HttpMethodMapper::GetNameForHttpMethod(request.GetMethod()) << " request to uri " << uriRef.GetURIString(true)); bool success = IsRequestProcessingEnabled(); void* connection = nullptr; void* hHttpRequest = nullptr; if(success) { if (writeLimiter != nullptr) { writeLimiter->ApplyAndPayForCost(request.GetSize()); } connection = m_connectionPoolMgr->AquireConnectionForHost(uriRef.GetAuthority(), uriRef.GetPort()); AWS_LOGSTREAM_DEBUG(GetLogTag(), "Acquired connection " << connection); hHttpRequest = AllocateWindowsHttpRequest(request, connection); AddHeadersToRequest(request, hHttpRequest); success = DoSendRequest(hHttpRequest); } if(success) { success = StreamPayloadToRequest(request, hHttpRequest); } std::shared_ptr<HttpResponse> response(nullptr); if(success) { response = BuildSuccessResponse(request, hHttpRequest, readLimiter); } else if (!IsRequestProcessingEnabled()) { AWS_LOG_INFO(GetLogTag(), "Request cancelled by client controller"); } else { LogRequestInternalFailure(); } if (hHttpRequest) { AWS_LOGSTREAM_DEBUG(GetLogTag(), "Closing http request handle " << hHttpRequest); GetConnectionPoolManager()->DoCloseHandle(hHttpRequest); } AWS_LOGSTREAM_DEBUG(GetLogTag(), "Releasing connection handle " << connection); GetConnectionPoolManager()->ReleaseConnectionForHost(request.GetUri().GetAuthority(), request.GetUri().GetPort(), connection); return response; }
std::shared_ptr<HttpResponse> CurlHttpClient::MakeRequest(HttpRequest& request, Aws::Utils::RateLimits::RateLimiterInterface* readLimiter, Aws::Utils::RateLimits::RateLimiterInterface* writeLimiter) const { //handle uri encoding at last second. Otherwise, the signer and the http layer will mismatch. URI uri = request.GetUri(); uri.SetPath(URI::URLEncodePath(uri.GetPath())); Aws::String url = uri.GetURIString(); AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, "Making request to " << url); struct curl_slist* headers = NULL; if (writeLimiter != nullptr) { writeLimiter->ApplyAndPayForCost(request.GetSize()); } Aws::StringStream headerStream; HeaderValueCollection requestHeaders = request.GetHeaders(); AWS_LOG_TRACE(CURL_HTTP_CLIENT_TAG, "Including headers:"); for (auto& requestHeader : requestHeaders) { headerStream.str(""); headerStream << requestHeader.first << ": " << requestHeader.second; Aws::String headerString = headerStream.str(); AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, headerString); headers = curl_slist_append(headers, headerString.c_str()); } headers = curl_slist_append(headers, "transfer-encoding:"); if (!request.HasHeader(Http::CONTENT_LENGTH_HEADER)) { headers = curl_slist_append(headers, "content-length:"); } if (!request.HasHeader(Http::CONTENT_TYPE_HEADER)) { headers = curl_slist_append(headers, "content-type:"); } std::shared_ptr<HttpResponse> response(nullptr); CURL* connectionHandle = m_curlHandleContainer.AcquireCurlHandle(); if (connectionHandle) { AWS_LOGSTREAM_DEBUG(CURL_HTTP_CLIENT_TAG, "Obtained connection handle " << connectionHandle); if (headers) { curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, headers); } response = Aws::MakeShared<StandardHttpResponse>(CURL_HTTP_CLIENT_TAG, request); CurlWriteCallbackContext writeContext(this, &request, response.get(), readLimiter); CurlReadCallbackContext readContext(this, &request); SetOptCodeForHttpMethod(connectionHandle, request); curl_easy_setopt(connectionHandle, CURLOPT_URL, url.c_str()); curl_easy_setopt(connectionHandle, CURLOPT_WRITEFUNCTION, &CurlHttpClient::WriteData); curl_easy_setopt(connectionHandle, CURLOPT_WRITEDATA, &writeContext); curl_easy_setopt(connectionHandle, CURLOPT_HEADERFUNCTION, &CurlHttpClient::WriteHeader); curl_easy_setopt(connectionHandle, CURLOPT_HEADERDATA, response.get()); //we only want to override the default path if someone has explicitly told us to. if(!m_caPath.empty()) { curl_easy_setopt(connectionHandle, CURLOPT_CAPATH, m_caPath.c_str()); } // only set by android test builds because the emulator is missing a cert needed for aws services #ifdef TEST_CERT_PATH curl_easy_setopt(connectionHandle, CURLOPT_CAPATH, TEST_CERT_PATH); #endif // TEST_CERT_PATH if (m_verifySSL) { curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 2L); #if LIBCURL_VERSION_MAJOR >= 7 #if LIBCURL_VERSION_MINOR >= 34 curl_easy_setopt(connectionHandle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); #endif //LIBCURL_VERSION_MINOR #endif //LIBCURL_VERSION_MAJOR } else { curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 0L); } if (m_allowRedirects) { curl_easy_setopt(connectionHandle, CURLOPT_FOLLOWLOCATION, 1L); } else { curl_easy_setopt(connectionHandle, CURLOPT_FOLLOWLOCATION, 0L); } //curl_easy_setopt(connectionHandle, CURLOPT_VERBOSE, 1); //curl_easy_setopt(connectionHandle, CURLOPT_DEBUGFUNCTION, CurlDebugCallback); if (m_isUsingProxy) { curl_easy_setopt(connectionHandle, CURLOPT_PROXY, m_proxyHost.c_str()); curl_easy_setopt(connectionHandle, CURLOPT_PROXYPORT, (long) m_proxyPort); curl_easy_setopt(connectionHandle, CURLOPT_PROXYUSERNAME, m_proxyUserName.c_str()); curl_easy_setopt(connectionHandle, CURLOPT_PROXYPASSWORD, m_proxyPassword.c_str()); } if (request.GetContentBody()) { curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, &CurlHttpClient::ReadBody); curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &readContext); } CURLcode curlResponseCode = curl_easy_perform(connectionHandle); if (curlResponseCode != CURLE_OK) { response = nullptr; AWS_LOGSTREAM_ERROR(CURL_HTTP_CLIENT_TAG, "Curl returned error code " << curlResponseCode); } else { long responseCode; curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &responseCode); response->SetResponseCode(static_cast<HttpResponseCode>(responseCode)); AWS_LOGSTREAM_DEBUG(CURL_HTTP_CLIENT_TAG, "Returned http response code " << responseCode); char* contentType = nullptr; curl_easy_getinfo(connectionHandle, CURLINFO_CONTENT_TYPE, &contentType); if (contentType) { response->SetContentType(contentType); AWS_LOGSTREAM_DEBUG(CURL_HTTP_CLIENT_TAG, "Returned content type " << contentType); } AWS_LOGSTREAM_DEBUG(CURL_HTTP_CLIENT_TAG, "Releasing curl handle " << connectionHandle); } m_curlHandleContainer.ReleaseCurlHandle(connectionHandle); //go ahead and flush the response body stream if(response) { response->GetResponseBody().flush(); } } if (headers) { curl_slist_free_all(headers); } return response; }