in src/aws-cpp-sdk-core/source/http/windows/WinSyncHttpClient.cpp [233:375]
bool WinSyncHttpClient::BuildSuccessResponse(const std::shared_ptr<HttpRequest>& request, std::shared_ptr<HttpResponse>& response, void* hHttpRequest, Aws::Utils::RateLimits::RateLimiterInterface* readLimiter) const
{
Aws::StringStream ss;
uint64_t read = 0;
DoQueryHeaders(hHttpRequest, response, ss, read);
if(readLimiter != nullptr && read > 0)
{
readLimiter->ApplyAndPayForCost(read);
}
Aws::Vector<Aws::String> rawHeaders = StringUtils::SplitOnLine(ss.str());
for (auto& header : rawHeaders)
{
Aws::Vector<Aws::String> keyValuePair = StringUtils::Split(header, ':', 2);
if (keyValuePair.size() == 2)
{
response->AddHeader(StringUtils::Trim(keyValuePair[0].c_str()), StringUtils::Trim(keyValuePair[1].c_str()));
}
}
if (request->GetMethod() != HttpMethod::HTTP_HEAD)
{
if(!ContinueRequest(*request) || !IsRequestProcessingEnabled())
{
response->SetClientErrorType(CoreErrors::USER_CANCELLED);
response->SetClientErrorMessage("Request processing disabled or continuation cancelled by user's continuation handler.");
response->SetResponseCode(Aws::Http::HttpResponseCode::NO_RESPONSE);
return false;
}
if (response->GetResponseBody().fail()) {
const auto& ref = response->GetResponseBody();
AWS_LOGSTREAM_ERROR(GetLogTag(), "Response output stream is in a bad state (eof: " << ref.eof() << ", bad: " << ref.bad() << ")");
response->SetClientErrorType(CoreErrors::NETWORK_CONNECTION);
response->SetClientErrorMessage("Response output stream is in a bad state.");
return false;
}
bool connectionOpen = true;
auto writerFunc =
[this, hHttpRequest, &request, readLimiter, &response, &connectionOpen](char* dst, uint64_t dstSz, uint64_t& read) -> bool
{
bool success = true;
uint64_t available = 0;
connectionOpen = DoQueryDataAvailable(hHttpRequest, available);
if (connectionOpen && available)
{
dstSz = (std::min)(dstSz, available);
success = DoReadData(hHttpRequest, dst, dstSz, read);
if (success && read > 0)
{
for (const auto& hashIterator : request->GetResponseValidationHashes())
{
std::stringstream headerStr;
headerStr<<"x-amz-checksum-"<<hashIterator.first;
if(response->HasHeader(headerStr.str().c_str()))
{
hashIterator.second->Update(reinterpret_cast<unsigned char*>(dst), static_cast<size_t>(read));
break;
}
}
auto& headersHandler = request->GetHeadersReceivedEventHandler();
if (headersHandler)
{
headersHandler(request.get(), response.get());
}
if (readLimiter != nullptr)
{
readLimiter->ApplyAndPayForCost(read);
}
auto& receivedHandler = request->GetDataReceivedEventHandler();
if (receivedHandler)
{
receivedHandler(request.get(), response.get(), (long long)read);
}
}
if (!ContinueRequest(*request) || !IsRequestProcessingEnabled())
{
return false;
}
}
return connectionOpen && success && ContinueRequest(*request) && IsRequestProcessingEnabled();
};
uint64_t numBytesResponseReceived = Aws::Utils::Stream::StreamBufProtectedWriter::WriteToBuffer(response->GetResponseBody(), writerFunc);
if(!ContinueRequest(*request) || !IsRequestProcessingEnabled())
{
response->SetClientErrorType(CoreErrors::USER_CANCELLED);
response->SetClientErrorMessage("Request processing disabled or continuation cancelled by user's continuation handler.");
response->SetResponseCode(Aws::Http::HttpResponseCode::NO_RESPONSE);
return false;
}
if (response->GetResponseBody().fail()) {
Aws::OStringStream errorMsgStr;
errorMsgStr << "Failed to write received response (eof: "
<< response->GetResponseBody().eof() << ", bad: " << response->GetResponseBody().bad() << ")";
Aws::String errorMsg = errorMsgStr.str();
AWS_LOGSTREAM_ERROR(GetLogTag(), errorMsg);
response->SetClientErrorType(CoreErrors::NETWORK_CONNECTION);
response->SetClientErrorMessage(errorMsg);
return false;
}
if (request->IsEventStreamRequest() && !response->HasHeader(Aws::Http::X_AMZN_ERROR_TYPE))
{
response->GetResponseBody().flush();
if (response->GetResponseBody().fail()) {
const auto& ref = response->GetResponseBody();
AWS_LOGSTREAM_ERROR(GetLogTag(), "Failed to flush event response (eof: " << ref.eof() << ", bad: " << ref.bad() << ")");
response->SetClientErrorType(CoreErrors::NETWORK_CONNECTION);
response->SetClientErrorMessage("Failed to flush event stream event response");
return false;
}
}
if (response->HasHeader(Aws::Http::CONTENT_LENGTH_HEADER))
{
const Aws::String& contentLength = response->GetHeader(Aws::Http::CONTENT_LENGTH_HEADER);
AWS_LOGSTREAM_TRACE(GetLogTag(), "Response content-length header: " << contentLength);
AWS_LOGSTREAM_TRACE(GetLogTag(), "Response body length: " << numBytesResponseReceived);
if ((uint64_t) StringUtils::ConvertToInt64(contentLength.c_str()) != numBytesResponseReceived)
{
response->SetClientErrorType(CoreErrors::NETWORK_CONNECTION);
response->SetClientErrorMessage("Response body length doesn't match the content-length header.");
AWS_LOGSTREAM_ERROR(GetLogTag(), "Response body length doesn't match the content-length header.");
return false;
}
}
}
//go ahead and flush the response body.
response->GetResponseBody().flush();
return true;
}