bool WinSyncHttpClient::BuildSuccessResponse()

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;
}