diff --git a/sdk/core/azure-core/src/http/curl/curl.cpp b/sdk/core/azure-core/src/http/curl/curl.cpp index 372dcf41f..3c9a01d03 100644 --- a/sdk/core/azure-core/src/http/curl/curl.cpp +++ b/sdk/core/azure-core/src/http/curl/curl.cpp @@ -399,7 +399,7 @@ CURLcode CurlSession::Perform(Context const& context) } Log::Write(Logger::Level::Verbose, LogMsgPrefix + "Upload payload"); - if (this->m_bodyStartInBuffer > 0) + if (this->m_bodyStartInBuffer < this->m_innerBufferSize) { // If internal buffer has more data after the 100-continue means Server return an error. // We don't need to upload body, just parse the response from Server and return @@ -556,7 +556,7 @@ CURLcode CurlSession::SendRawHttp(Context const& context) { // something like GET /path HTTP1.0 \r\nheaders\r\n auto rawRequest = GetHTTPMessagePreBody(this->m_request); - int64_t rawRequestLen = rawRequest.size(); + auto rawRequestLen = rawRequest.size(); CURLcode sendResult = m_connection->SendBuffer( reinterpret_cast(rawRequest.data()), @@ -581,20 +581,20 @@ void CurlSession::ParseChunkSize(Context const& context) // Move to after chunk size for (bool keepPolling = true; keepPolling;) { - for (int64_t index = this->m_bodyStartInBuffer, i = 0; index < this->m_innerBufferSize; - index++, i++) + for (size_t index = this->m_bodyStartInBuffer, iteration = 0; index < this->m_innerBufferSize; + index++, iteration++) { strChunkSize.append(reinterpret_cast(&this->m_readBuffer[index]), 1); - if (i > 1 && this->m_readBuffer[index] == '\n') + if (iteration > 1 && this->m_readBuffer[index] == '\n') { // get chunk size. Chunk size comes in Hex value try { - this->m_chunkSize = static_cast(std::stoull(strChunkSize, nullptr, 16)); + // Required cast for MSVC x86 + this->m_chunkSize = static_cast(std::stoull(strChunkSize, nullptr, 16)); } - catch (const std::invalid_argument& ex) + catch (std::invalid_argument const&) { - (void)ex; // Server can return something like `\n\r\n` for a chunk of zero length data. This is // allowed by RFC. `stoull` will throw invalid_argument if there is not at least one hex // digit to be parsed. For those cases, we consider the response as zero-length. @@ -656,23 +656,22 @@ void CurlSession::ReadStatusLineAndHeadersFromRawResponse( bool reuseInternalBuffer) { auto parser = ResponseBufferParser(); - auto bufferSize = int64_t(); + auto bufferSize = size_t(); // Keep reading until all headers were read while (!parser.IsParseCompleted()) { - int64_t bytesParsed = 0; + size_t bytesParsed = 0; if (reuseInternalBuffer) { // parse from internal buffer. This means previous read from server got more than one // response. This happens when Server returns a 100-continue plus an error code bufferSize = this->m_innerBufferSize - this->m_bodyStartInBuffer; - bytesParsed = parser.Parse( - this->m_readBuffer + this->m_bodyStartInBuffer, static_cast(bufferSize)); + bytesParsed = parser.Parse(this->m_readBuffer + this->m_bodyStartInBuffer, bufferSize); // if parsing from internal buffer is not enough, do next read from wire reuseInternalBuffer = false; // reset body start - this->m_bodyStartInBuffer = -1; + this->m_bodyStartInBuffer = _detail::DefaultLibcurlReaderSize; } else { @@ -687,7 +686,7 @@ void CurlSession::ReadStatusLineAndHeadersFromRawResponse( "Connection was closed by the server while trying to read a response"); } // returns the number of bytes parsed up to the body Start - bytesParsed = parser.Parse(this->m_readBuffer, static_cast(bufferSize)); + bytesParsed = parser.Parse(this->m_readBuffer, bufferSize); } if (bytesParsed < bufferSize) @@ -697,7 +696,7 @@ void CurlSession::ReadStatusLineAndHeadersFromRawResponse( } this->m_response = parser.ExtractResponse(); - this->m_innerBufferSize = static_cast(bufferSize); + this->m_innerBufferSize = bufferSize; this->m_lastStatusCode = this->m_response->GetStatusCode(); // For Head request, set the length of body response to 0. @@ -709,7 +708,7 @@ void CurlSession::ReadStatusLineAndHeadersFromRawResponse( || this->m_lastStatusCode == HttpStatusCode::NoContent) { this->m_contentLength = 0; - this->m_bodyStartInBuffer = -1; + this->m_bodyStartInBuffer = _detail::DefaultLibcurlReaderSize; return; } @@ -724,6 +723,7 @@ void CurlSession::ReadStatusLineAndHeadersFromRawResponse( return; } + // No content-length from headers, check transfer-encoding this->m_contentLength = -1; auto isTransferEncodingHeaderInResponse = headers.find("transfer-encoding"); if (isTransferEncodingHeaderInResponse != headers.end()) @@ -738,10 +738,17 @@ void CurlSession::ReadStatusLineAndHeadersFromRawResponse( this->m_isChunkedResponseType = true; // Need to move body start after chunk size - if (this->m_bodyStartInBuffer == -1) + if (this->m_bodyStartInBuffer >= this->m_innerBufferSize) { // if nothing on inner buffer, pull from wire this->m_innerBufferSize = m_connection->ReadFromSocket( this->m_readBuffer, _detail::DefaultLibcurlReaderSize, context); + if (this->m_innerBufferSize == 0) + { + // closed connection, prevent application from keep trying to pull more bytes from the + // wire + throw TransportException( + "Connection was closed by the server while trying to read a response"); + } this->m_bodyStartInBuffer = 0; } @@ -758,13 +765,25 @@ void CurlSession::ReadStatusLineAndHeadersFromRawResponse( */ } +/** + * @brief Reads data from network and validates the data is equal to \p expected. + * + * @param expected The data that should came from the wire. + * @param context A context to control the request lifetime. + */ void CurlSession::ReadExpected(uint8_t expected, Context const& context) { - if (this->m_bodyStartInBuffer == -1 || this->m_bodyStartInBuffer == this->m_innerBufferSize) + if (this->m_bodyStartInBuffer >= this->m_innerBufferSize) { // end of buffer, pull data from wire this->m_innerBufferSize = m_connection->ReadFromSocket( this->m_readBuffer, _detail::DefaultLibcurlReaderSize, context); + if (this->m_innerBufferSize == 0) + { + // closed connection, prevent application from keep trying to pull more bytes from the wire + throw TransportException( + "Connection was closed by the server while trying to read a response"); + } this->m_bodyStartInBuffer = 0; } auto data = this->m_readBuffer[this->m_bodyStartInBuffer]; @@ -812,47 +831,40 @@ size_t CurlSession::OnRead(uint8_t* buffer, size_t count, Context const& context } auto totalRead = size_t(); - int64_t readRequestLength = this->m_isChunkedResponseType - ? (std::min)(this->m_chunkSize - this->m_sessionTotalRead, static_cast(count)) - : static_cast(count); + size_t readRequestLength = this->m_isChunkedResponseType + ? (std::min)(this->m_chunkSize - this->m_sessionTotalRead, count) + : count; // For responses with content-length, avoid trying to read beyond Content-length or // libcurl could return a second response as BadRequest. // https://github.com/Azure/azure-sdk-for-cpp/issues/306 if (this->m_contentLength > 0) { - auto remainingBodyContent = this->m_contentLength - this->m_sessionTotalRead; + size_t remainingBodyContent + = static_cast(this->m_contentLength) - this->m_sessionTotalRead; readRequestLength = (std::min)(readRequestLength, remainingBodyContent); } // Take data from inner buffer if any - if (this->m_bodyStartInBuffer >= 0) + if (this->m_bodyStartInBuffer < this->m_innerBufferSize) { // still have data to take from innerbuffer - // TODO: Change the fields to be size_t for a less error-prone implementation - // The casts here are safe to do because we know the buffers and the offset are within the - // range. Azure::Core::IO::MemoryBodyStream innerBufferMemoryStream( this->m_readBuffer + this->m_bodyStartInBuffer, - static_cast(this->m_innerBufferSize - this->m_bodyStartInBuffer)); + this->m_innerBufferSize - this->m_bodyStartInBuffer); // From code inspection, it is guaranteed that the readRequestLength will fit within size_t // since count is bounded by size_t. - totalRead - = innerBufferMemoryStream.Read(buffer, static_cast(readRequestLength), context); + totalRead = innerBufferMemoryStream.Read(buffer, readRequestLength, context); this->m_bodyStartInBuffer += totalRead; this->m_sessionTotalRead += totalRead; - if (this->m_bodyStartInBuffer == this->m_innerBufferSize) - { - this->m_bodyStartInBuffer = -1; // read everything from inner buffer already - } return totalRead; } // Head request have contentLength = 0, so we won't read more, just return 0 // Also if we have already read all contentLength - if (this->m_sessionTotalRead == this->m_contentLength || this->IsEOF()) + if (this->m_sessionTotalRead == static_cast(this->m_contentLength) || this->IsEOF()) { return 0; } @@ -949,9 +961,9 @@ size_t CurlConnection::ReadFromSocket(uint8_t* buffer, size_t bufferSize, Contex std::unique_ptr CurlSession::ExtractResponse() { return std::move(this->m_response); } -int64_t CurlSession::ResponseBufferParser::Parse( +size_t CurlSession::ResponseBufferParser::Parse( uint8_t const* const buffer, - int64_t const bufferSize) + size_t const bufferSize) { if (this->m_parseCompleted) { @@ -959,7 +971,7 @@ int64_t CurlSession::ResponseBufferParser::Parse( } // Read all buffer until \r\n is found - int64_t start = 0, index = 0; + size_t start = 0, index = 0; for (; index < bufferSize; index++) { if (buffer[index] == '\r') @@ -1069,9 +1081,9 @@ int64_t CurlSession::ResponseBufferParser::Parse( } // Finds delimiter '\r' as the end of the -int64_t CurlSession::ResponseBufferParser::BuildStatusCode( +size_t CurlSession::ResponseBufferParser::BuildStatusCode( uint8_t const* const buffer, - int64_t const bufferSize) + size_t const bufferSize) { if (this->state != ResponseParserState::StatusLine) { @@ -1120,9 +1132,9 @@ int64_t CurlSession::ResponseBufferParser::BuildStatusCode( } // Finds delimiter '\r' as the end of the -int64_t CurlSession::ResponseBufferParser::BuildHeader( +size_t CurlSession::ResponseBufferParser::BuildHeader( uint8_t const* const buffer, - int64_t const bufferSize) + size_t const bufferSize) { if (this->state != ResponseParserState::Headers) { diff --git a/sdk/core/azure-core/src/http/curl/curl_connection_pool_private.hpp b/sdk/core/azure-core/src/http/curl/curl_connection_pool_private.hpp index c5e8576fd..a4334be27 100644 --- a/sdk/core/azure-core/src/http/curl/curl_connection_pool_private.hpp +++ b/sdk/core/azure-core/src/http/curl/curl_connection_pool_private.hpp @@ -119,7 +119,7 @@ namespace Azure { namespace Core { namespace Http { namespace _detail { // Makes possible to know the number of current connections in the connection pool for an // index - int64_t ConnectionsOnPool(std::string const& host) { return ConnectionPoolIndex[host].size(); }; + size_t ConnectionsOnPool(std::string const& host) { return ConnectionPoolIndex[host].size(); }; std::thread m_cleanThread; }; diff --git a/sdk/core/azure-core/src/http/curl/curl_connection_private.hpp b/sdk/core/azure-core/src/http/curl/curl_connection_private.hpp index b3ff2d672..8e60a3ffd 100644 --- a/sdk/core/azure-core/src/http/curl/curl_connection_private.hpp +++ b/sdk/core/azure-core/src/http/curl/curl_connection_private.hpp @@ -20,8 +20,8 @@ namespace Azure { namespace Core { namespace Http { namespace _detail { // libcurl CURL_MAX_WRITE_SIZE is 64k. Using same value for default uploading chunk size. // This can be customizable in the HttpRequest - constexpr static int64_t DefaultUploadChunkSize = 1024 * 64; - constexpr static auto DefaultLibcurlReaderSize = 1024; + constexpr static size_t DefaultUploadChunkSize = 1024 * 64; + constexpr static size_t DefaultLibcurlReaderSize = 1024; // Run time error template constexpr static const char* DefaultFailedToGetNewConnectionTemplate = "Fail to get a new connection for: "; @@ -35,7 +35,7 @@ namespace Azure { namespace Core { namespace Http { constexpr static int32_t DefaultConnectionExpiredMilliseconds = 1000 * 60; // Define the maximun allowed connections per host-index in the pool. If this number is reached // for the host-index, next connections trying to be added to the pool will be ignored. - constexpr static size_t MaxConnectionsPerIndex = 1024; + constexpr static int32_t MaxConnectionsPerIndex = 1024; } // namespace _detail /** diff --git a/sdk/core/azure-core/src/http/curl/curl_session_private.hpp b/sdk/core/azure-core/src/http/curl/curl_session_private.hpp index a7145ba52..3e39a2c73 100644 --- a/sdk/core/azure-core/src/http/curl/curl_session_private.hpp +++ b/sdk/core/azure-core/src/http/curl/curl_session_private.hpp @@ -146,7 +146,7 @@ namespace Azure { namespace Core { namespace Http { * @param bufferSize Indicates the size of the buffer. * @return Returns the index of the last parsed position from buffer. */ - int64_t BuildStatusCode(uint8_t const* const buffer, int64_t const bufferSize); + size_t BuildStatusCode(uint8_t const* const buffer, size_t const bufferSize); /** * @brief This method is invoked by the Parsing process if the internal state is set to @@ -159,7 +159,7 @@ namespace Azure { namespace Core { namespace Http { * value is smaller than the body size, means there is part of the body response in the * buffer. */ - int64_t BuildHeader(uint8_t const* const buffer, int64_t const bufferSize); + size_t BuildHeader(uint8_t const* const buffer, size_t const bufferSize); public: /** @@ -182,8 +182,9 @@ namespace Azure { namespace Core { namespace Http { * Returning a value smaller than the buffer size will likely indicate that the HTTP * RawResponse is completed and that the rest of the buffer contains part of the response * body. + * */ - int64_t Parse(uint8_t const* const buffer, int64_t const bufferSize); + size_t Parse(uint8_t const* const buffer, size_t const bufferSize); /** * @brief Indicates when the parser has completed parsing and building the HTTP RawResponse. @@ -238,8 +239,10 @@ namespace Azure { namespace Core { namespace Http { * inner buffer. When a libcurl stream tries to read part of the body, this field will help to * decide how much data to take from the inner buffer before pulling more data from network. * + * @note The initial value is set to the size of the inner buffer as a sentinel that indicate + * that the buffer has not data or all data has already taken from it. */ - int64_t m_bodyStartInBuffer = -1; + size_t m_bodyStartInBuffer = _detail::DefaultLibcurlReaderSize; /** * @brief Control field to handle the number of bytes containing relevant data within the @@ -247,7 +250,7 @@ namespace Azure { namespace Core { namespace Http { * from wire into it, it can be holding less then N bytes. * */ - int64_t m_innerBufferSize = _detail::DefaultLibcurlReaderSize; + size_t m_innerBufferSize = _detail::DefaultLibcurlReaderSize; bool m_isChunkedResponseType = false; @@ -264,12 +267,12 @@ namespace Azure { namespace Core { namespace Http { /** * @brief For chunked responses, this field knows the size of the current chuck size server - * will de sending + * will be sending. * */ - int64_t m_chunkSize = 0; + size_t m_chunkSize = 0; - int64_t m_sessionTotalRead = 0; + size_t m_sessionTotalRead = 0; /** * @brief Internal buffer from a session used to read bytes from a socket. This buffer is only @@ -333,7 +336,9 @@ namespace Azure { namespace Core { namespace Http { */ bool IsEOF() { - auto eof = m_isChunkedResponseType ? m_chunkSize == 0 : m_contentLength == m_sessionTotalRead; + auto eof = m_isChunkedResponseType + ? m_chunkSize == 0 + : static_cast(m_contentLength) == m_sessionTotalRead; // `IsEOF` is called before trying to move a connection back to the connection pool. // If the session state is `PERFORM` it means the request could not complete an upload diff --git a/sdk/core/azure-core/test/fault-injector/fault_injector_test.cpp b/sdk/core/azure-core/test/fault-injector/fault_injector_test.cpp index d89d4a0e7..d9e2e0daa 100644 --- a/sdk/core/azure-core/test/fault-injector/fault_injector_test.cpp +++ b/sdk/core/azure-core/test/fault-injector/fault_injector_test.cpp @@ -81,25 +81,31 @@ int main() Azure::Core::Http::WinHttpTransportOptions winHttpOptions; auto implementationClient = std::make_shared(winHttpOptions); #endif + try + { + FaultInjectionClientOptions options; + options.m_url = Azure::Core::Url("https://localhost:7778"); + options.m_transport = implementationClient; + FaultInjectionClient client(options); - FaultInjectionClientOptions options; - options.m_url = Azure::Core::Url("https://localhost:7778"); - options.m_transport = implementationClient; - FaultInjectionClient client(options); + std::cout << "Sending request..." << std::endl; - std::cout << "Sending request..." << std::endl; - - Azure::Core::Context context; - auto request = Azure::Core::Http::Request( - Azure::Core::Http::HttpMethod::Get, Azure::Core::Url("https://www.example.org")); - auto response = client.Send(request, context); - // Make sure to pull all bytes from network. - auto body = response->ExtractBodyStream()->ReadToEnd(); - - std::cout << "Status Code: " - << static_cast::type>( - response->GetStatusCode()) - << std::endl; + Azure::Core::Context context; + auto request = Azure::Core::Http::Request( + Azure::Core::Http::HttpMethod::Get, Azure::Core::Url("https://www.example.org")); + auto response = client.Send(request, context); + // Make sure to pull all bytes from network. + auto body = response->ExtractBodyStream()->ReadToEnd(); + std::cout + << "Status Code: " + << static_cast::type>( + response->GetStatusCode()) + << std::endl; + } + catch (std::exception const&) + { + std::cout << "Check fault injector server is running."; + } return 0; } diff --git a/sdk/core/azure-core/test/ut/curl_session_test_test.cpp b/sdk/core/azure-core/test/ut/curl_session_test_test.cpp index ae3dfc0e8..ef8f87668 100644 --- a/sdk/core/azure-core/test/ut/curl_session_test_test.cpp +++ b/sdk/core/azure-core/test/ut/curl_session_test_test.cpp @@ -21,6 +21,7 @@ namespace Azure { namespace Core { namespace Test { { std::string response( "HTTP/1.1 200 Ok\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n{\r\n\"somejson\":45\r}"); + int32_t const payloadSize = static_cast(response.size()); // Can't mock the curMock directly from a unique ptr, heap allocate it first and then make a // unique ptr for it @@ -28,8 +29,8 @@ namespace Azure { namespace Core { namespace Test { EXPECT_CALL(*curlMock, SendBuffer(_, _, _)).WillOnce(Return(CURLE_OK)); EXPECT_CALL(*curlMock, ReadFromSocket(_, _, _)) .WillOnce(DoAll( - SetArrayArgument<0>(response.data(), response.data() + response.size()), - Return(response.size()))); + SetArrayArgument<0>(response.data(), response.data() + payloadSize), + Return(payloadSize))); // Create the unique ptr to take care about memory free at the end std::unique_ptr uniqueCurlMock(curlMock); @@ -51,6 +52,7 @@ namespace Azure { namespace Core { namespace Test { // chunked response with no content and no size std::string response("HTTP/1.1 200 Ok\r\ntransfer-encoding: chunked\r\n\r\n\n\r\n"); std::string connectionKey("connection-key"); + int32_t const payloadSize = static_cast(response.size()); // Can't mock the curMock directly from a unique ptr, heap allocate it first and then make a // unique ptr for it @@ -58,8 +60,8 @@ namespace Azure { namespace Core { namespace Test { EXPECT_CALL(*curlMock, SendBuffer(_, _, _)).WillOnce(Return(CURLE_OK)); EXPECT_CALL(*curlMock, ReadFromSocket(_, _, _)) .WillOnce(DoAll( - SetArrayArgument<0>(response.data(), response.data() + response.size()), - Return(response.size()))); + SetArrayArgument<0>(response.data(), response.data() + payloadSize), + Return(payloadSize))); EXPECT_CALL(*curlMock, GetConnectionKey()).WillRepeatedly(ReturnRef(connectionKey)); EXPECT_CALL(*curlMock, UpdateLastUsageTime()); EXPECT_CALL(*curlMock, DestructObj()); @@ -89,6 +91,8 @@ namespace Azure { namespace Core { namespace Test { std::string response("HTTP/1.1 200 Ok\r\ntransfer-encoding: chunked\r\n\r\n9\r\n"); std::string response2("123456789\r\n0\r\n\rx"); std::string connectionKey("connection-key"); + int32_t const payloadSize = static_cast(response.size()); + int32_t const payloadSize2 = static_cast(response2.size()); // Can't mock the curMock directly from a unique ptr, heap allocate it first and then make a // unique ptr for it @@ -96,11 +100,11 @@ namespace Azure { namespace Core { namespace Test { EXPECT_CALL(*curlMock, SendBuffer(_, _, _)).WillOnce(Return(CURLE_OK)); EXPECT_CALL(*curlMock, ReadFromSocket(_, _, _)) .WillOnce(DoAll( - SetArrayArgument<0>(response.data(), response.data() + response.size()), - Return(response.size()))) + SetArrayArgument<0>(response.data(), response.data() + payloadSize), + Return(payloadSize))) .WillOnce(DoAll( - SetArrayArgument<0>(response2.data(), response2.data() + response2.size()), - Return(response2.size()))); + SetArrayArgument<0>(response2.data(), response2.data() + payloadSize2), + Return(payloadSize2))); EXPECT_CALL(*curlMock, GetConnectionKey()).WillRepeatedly(ReturnRef(connectionKey)); EXPECT_CALL(*curlMock, UpdateLastUsageTime()); EXPECT_CALL(*curlMock, DestructObj()); @@ -144,6 +148,15 @@ namespace Azure { namespace Core { namespace Test { std::string response6("123"); std::string response7("\r\n0\r\n"); std::string response8("\r\n"); + int32_t const payloadSize0 = static_cast(response0.size()); + int32_t const payloadSize1 = static_cast(response1.size()); + int32_t const payloadSize2 = static_cast(response2.size()); + int32_t const payloadSize3 = static_cast(response3.size()); + int32_t const payloadSize4 = static_cast(response4.size()); + int32_t const payloadSize5 = static_cast(response5.size()); + int32_t const payloadSize6 = static_cast(response6.size()); + int32_t const payloadSize7 = static_cast(response7.size()); + int32_t const payloadSize8 = static_cast(response8.size()); std::string connectionKey("connection-key"); @@ -153,32 +166,32 @@ namespace Azure { namespace Core { namespace Test { EXPECT_CALL(*curlMock, SendBuffer(_, _, _)).WillOnce(Return(CURLE_OK)); EXPECT_CALL(*curlMock, ReadFromSocket(_, _, _)) .WillOnce(DoAll( - SetArrayArgument<0>(response0.data(), response0.data() + response0.size()), - Return(response0.size()))) + SetArrayArgument<0>(response0.data(), response0.data() + payloadSize0), + Return(payloadSize0))) .WillOnce(DoAll( - SetArrayArgument<0>(response1.data(), response1.data() + response1.size()), - Return(response1.size()))) + SetArrayArgument<0>(response1.data(), response1.data() + payloadSize1), + Return(payloadSize1))) .WillOnce(DoAll( - SetArrayArgument<0>(response2.data(), response2.data() + response2.size()), - Return(response2.size()))) + SetArrayArgument<0>(response2.data(), response2.data() + payloadSize2), + Return(payloadSize2))) .WillOnce(DoAll( - SetArrayArgument<0>(response3.data(), response3.data() + response3.size()), - Return(response3.size()))) + SetArrayArgument<0>(response3.data(), response3.data() + payloadSize3), + Return(payloadSize3))) .WillOnce(DoAll( - SetArrayArgument<0>(response4.data(), response4.data() + response4.size()), - Return(response4.size()))) + SetArrayArgument<0>(response4.data(), response4.data() + payloadSize4), + Return(payloadSize4))) .WillOnce(DoAll( - SetArrayArgument<0>(response5.data(), response5.data() + response5.size()), - Return(response5.size()))) + SetArrayArgument<0>(response5.data(), response5.data() + payloadSize5), + Return(payloadSize5))) .WillOnce(DoAll( - SetArrayArgument<0>(response6.data(), response6.data() + response6.size()), - Return(response6.size()))) + SetArrayArgument<0>(response6.data(), response6.data() + payloadSize6), + Return(payloadSize6))) .WillOnce(DoAll( - SetArrayArgument<0>(response7.data(), response7.data() + response7.size()), - Return(response7.size()))) + SetArrayArgument<0>(response7.data(), response7.data() + payloadSize7), + Return(payloadSize7))) .WillOnce(DoAll( - SetArrayArgument<0>(response8.data(), response8.data() + response8.size()), - Return(response8.size()))); + SetArrayArgument<0>(response8.data(), response8.data() + payloadSize8), + Return(payloadSize8))); EXPECT_CALL(*curlMock, GetConnectionKey()).WillRepeatedly(ReturnRef(connectionKey)); EXPECT_CALL(*curlMock, UpdateLastUsageTime()); EXPECT_CALL(*curlMock, DestructObj());