Skip to content

Commit 76637a7

Browse files
committed
fix reviews on awschunking and default behavior
1 parent 74517bf commit 76637a7

File tree

6 files changed

+198
-90
lines changed

6 files changed

+198
-90
lines changed

src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClientBase.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ namespace client
100100
m_serviceUserAgentName(std::move(serviceUserAgentName)),
101101
m_httpClient(std::move(httpClient)),
102102
m_errorMarshaller(std::move(errorMarshaller)),
103-
m_interceptors{Aws::MakeShared<ChecksumInterceptor>("AwsSmithyClientBase", *m_clientConfig)}
103+
m_interceptors{
104+
Aws::MakeShared<ChecksumInterceptor>("AwsSmithyClientBase", *m_clientConfig),
105+
Aws::MakeShared<features::ChunkingInterceptor>("AwsSmithyClientBase", *m_clientConfig)
106+
}
104107
{
105-
if (m_clientConfig->httpClientChunkedMode == Aws::Client::HttpClientChunkedMode::DEFAULT) {
106-
m_interceptors.emplace_back(Aws::MakeShared<features::ChunkingInterceptor>("AwsSmithyClientBase", *m_clientConfig));
107-
}
108108
baseInit();
109109
}
110110

src/aws-cpp-sdk-core/include/smithy/client/features/ChunkingInterceptor.h

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77

88
#include <aws/core/Core_EXPORTS.h>
99
#include <aws/core/client/ClientConfiguration.h>
10-
#include <aws/core/utils/stream/AwsChunkedStream.h>
10+
#include <aws/core/utils/HashingUtils.h>
11+
#include <aws/core/utils/StringUtils.h>
12+
#include <aws/core/utils/Array.h>
1113
#include <smithy/interceptor/Interceptor.h>
1214
#include <smithy/client/common/AwsSmithyClientUtils.h>
1315

@@ -17,14 +19,17 @@ namespace features {
1719

1820
namespace {
1921

20-
// String constants
2122
static const char* const CHECKSUM_HEADER_PREFIX = "x-amz-checksum-";
2223
static const char* const ALLOCATION_TAG = "ChunkingInterceptor";
24+
static const size_t DATA_BUFFER_SIZE = 65536;
25+
26+
} // anonymous namespace
2327

2428
class AwsChunkedStreamBuf : public std::streambuf {
2529
public:
26-
AwsChunkedStreamBuf(Aws::Http::HttpRequest* request, const std::shared_ptr<Aws::IOStream>& originalBody)
27-
: m_chunkStream(request, originalBody) {
30+
AwsChunkedStreamBuf(Aws::Http::HttpRequest* request, const std::shared_ptr<Aws::IOStream>& originalBody, size_t bufferSize = DATA_BUFFER_SIZE)
31+
: m_request(request), m_stream(originalBody), m_data(bufferSize), m_bufferSize(bufferSize),
32+
m_chunkingStream(Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG)) {
2833
setg(nullptr, nullptr, nullptr);
2934
}
3035

@@ -33,8 +38,23 @@ class AwsChunkedStreamBuf : public std::streambuf {
3338
if (gptr() < egptr()) {
3439
return traits_type::to_int_type(*gptr());
3540
}
41+
42+
if (m_stream->good()) {
43+
m_stream->read(m_data.GetUnderlyingData(), m_bufferSize);
44+
size_t bytesRead = static_cast<size_t>(m_stream->gcount());
45+
writeChunk(bytesRead);
46+
47+
if ((m_stream->peek() == EOF || m_stream->eof()) && !m_stream->bad()) {
48+
writeTrailerToUnderlyingStream();
49+
}
50+
}
3651

37-
size_t bytesRead = m_chunkStream.BufferedRead(m_buffer, sizeof(m_buffer));
52+
if ((m_chunkingStream->peek() == EOF || m_chunkingStream->eof()) && !m_chunkingStream->bad()) {
53+
return traits_type::eof();
54+
}
55+
56+
m_chunkingStream->read(m_buffer, sizeof(m_buffer));
57+
size_t bytesRead = static_cast<size_t>(m_chunkingStream->gcount());
3858
if (bytesRead == 0) {
3959
return traits_type::eof();
4060
}
@@ -43,24 +63,51 @@ class AwsChunkedStreamBuf : public std::streambuf {
4363
return traits_type::to_int_type(*gptr());
4464
}
4565

46-
std::streamsize showmanyc() override {
47-
return egptr() - gptr();
66+
private:
67+
void writeTrailerToUnderlyingStream() {
68+
Aws::StringStream chunkedTrailerStream;
69+
chunkedTrailerStream << "0\r\n";
70+
if (m_request->GetRequestHash().second != nullptr) {
71+
chunkedTrailerStream << "x-amz-checksum-" << m_request->GetRequestHash().first << ":"
72+
<< Aws::Utils::HashingUtils::Base64Encode(m_request->GetRequestHash().second->GetHash().GetResult()) << "\r\n";
73+
}
74+
chunkedTrailerStream << "\r\n";
75+
const auto chunkedTrailer = chunkedTrailerStream.str();
76+
if (m_chunkingStream->eof()) {
77+
m_chunkingStream->clear();
78+
}
79+
*m_chunkingStream << chunkedTrailer;
80+
}
81+
82+
void writeChunk(size_t bytesRead) {
83+
if (m_request->GetRequestHash().second != nullptr) {
84+
m_request->GetRequestHash().second->Update(reinterpret_cast<unsigned char*>(m_data.GetUnderlyingData()), bytesRead);
85+
}
86+
87+
if (bytesRead > 0 && m_chunkingStream != nullptr && !m_chunkingStream->bad()) {
88+
if (m_chunkingStream->eof()) {
89+
m_chunkingStream->clear();
90+
}
91+
*m_chunkingStream << Aws::Utils::StringUtils::ToHexString(bytesRead) << "\r\n";
92+
m_chunkingStream->write(m_data.GetUnderlyingData(), bytesRead);
93+
*m_chunkingStream << "\r\n";
94+
}
4895
}
4996

50-
private:
51-
Aws::Utils::Stream::AwsChunkedStream<> m_chunkStream;
97+
Aws::Http::HttpRequest* m_request;
98+
std::shared_ptr<Aws::IOStream> m_stream;
99+
Aws::Utils::Array<char> m_data;
100+
size_t m_bufferSize;
101+
std::shared_ptr<Aws::IOStream> m_chunkingStream;
52102
char m_buffer[8192];
53103
};
54104

55-
} // anonymous namespace
56-
57105
/**
58106
* Interceptor that handles chunked encoding for streaming requests with checksums.
59107
* Wraps request body with chunked stream and sets appropriate headers.
60108
*/
61109
class ChunkingInterceptor : public smithy::interceptor::Interceptor {
62110
public:
63-
ChunkingInterceptor() : m_httpClientChunkedMode(Aws::Client::HttpClientChunkedMode::DEFAULT) {}
64111
explicit ChunkingInterceptor(const Aws::Client::ClientConfiguration& config)
65112
: m_httpClientChunkedMode(config.httpClientChunkedMode) {}
66113
~ChunkingInterceptor() override = default;

src/aws-cpp-sdk-core/source/client/AWSClient.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ AWSClient::AWSClient(const Aws::Client::ClientConfiguration& configuration,
140140
m_enableClockSkewAdjustment(configuration.enableClockSkewAdjustment),
141141
m_requestCompressionConfig(configuration.requestCompressionConfig),
142142
m_userAgentInterceptor{Aws::MakeShared<smithy::client::UserAgentInterceptor>(AWS_CLIENT_LOG_TAG, configuration, m_retryStrategy->GetStrategyName(), m_serviceName)},
143-
m_interceptors{Aws::MakeShared<smithy::client::ChecksumInterceptor>(AWS_CLIENT_LOG_TAG), Aws::MakeShared<smithy::client::features::ChunkingInterceptor>(AWS_CLIENT_LOG_TAG), m_userAgentInterceptor}
143+
m_interceptors{Aws::MakeShared<smithy::client::ChecksumInterceptor>(AWS_CLIENT_LOG_TAG), Aws::MakeShared<smithy::client::features::ChunkingInterceptor>(AWS_CLIENT_LOG_TAG, configuration), m_userAgentInterceptor}
144144
{
145145
}
146146

src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,9 @@ void setLegacyClientConfigurationParameters(ClientConfiguration& clientConfig)
220220
clientConfig.writeRateLimiter = nullptr;
221221
clientConfig.readRateLimiter = nullptr;
222222
clientConfig.httpLibOverride = Aws::Http::TransferLibType::DEFAULT_CLIENT;
223-
224-
// Set chunking mode based on HTTP client type
225-
// AWS built-in clients should use SDK's ChunkingInterceptor (DEFAULT mode)
226-
// Custom clients should handle chunking themselves (CLIENT_IMPLEMENTATION mode)
227-
if (clientConfig.httpLibOverride == Aws::Http::TransferLibType::DEFAULT_CLIENT) {
228-
clientConfig.httpClientChunkedMode = HttpClientChunkedMode::CLIENT_IMPLEMENTATION;
229-
} else {
230-
clientConfig.httpClientChunkedMode = HttpClientChunkedMode::DEFAULT;
231-
}
223+
224+
// Users can explicitly set CLIENT_IMPLEMENTATION if their custom client handles chunking
225+
clientConfig.httpClientChunkedMode = HttpClientChunkedMode::DEFAULT;
232226

233227
clientConfig.followRedirects = FollowRedirectsPolicy::DEFAULT;
234228
clientConfig.disableExpectHeader = false;

src/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,14 @@ static size_t SeekBody(void* userdata, curl_off_t offset, int origin)
370370
return CURL_SEEKFUNC_FAIL;
371371
}
372372

373+
// Fail seek for aws-chunk encoded body as the length and offset is unknown
374+
if (context->m_request &&
375+
context->m_request->HasHeader(Aws::Http::CONTENT_ENCODING_HEADER) &&
376+
context->m_request->GetHeaderValue(Aws::Http::CONTENT_ENCODING_HEADER).find(Aws::Http::AWS_CHUNKED_VALUE) != Aws::String::npos)
377+
{
378+
return CURL_SEEKFUNC_FAIL;
379+
}
380+
373381

374382
HttpRequest* request = context->m_request;
375383
const std::shared_ptr<Aws::IOStream>& ioStream = request->GetContentBody();

tests/aws-cpp-sdk-core-tests/utils/stream/AwsChunkedStreamTest.cpp

Lines changed: 123 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,95 +5,154 @@
55
#include <aws/core/http/standard/StandardHttpRequest.h>
66
#include <aws/core/utils/crypto/CRC32.h>
77
#include <aws/core/utils/stream/AwsChunkedStream.h>
8+
#include <smithy/client/features/ChunkingInterceptor.h>
89
#include <aws/testing/AwsCppSdkGTestSuite.h>
910

1011
using namespace Aws;
1112
using namespace Aws::Http::Standard;
1213
using namespace Aws::Utils::Stream;
1314
using namespace Aws::Utils::Crypto;
1415

15-
class AwsChunkedStreamTest : public Aws::Testing::AwsCppSdkGTestSuite {};
16-
1716
const char* TEST_LOG_TAG = "AWS_CHUNKED_STREAM_TEST";
1817

18+
class AwsChunkedStreamTest : public Aws::Testing::AwsCppSdkGTestSuite {
19+
protected:
20+
StandardHttpRequest CreateRequestWithChecksum(const std::string& url, const std::string& /* data */) {
21+
StandardHttpRequest request{url, Http::HttpMethod::HTTP_GET};
22+
auto requestHash = Aws::MakeShared<CRC32>(TEST_LOG_TAG);
23+
request.SetRequestHash("crc32", requestHash);
24+
return request;
25+
}
26+
27+
std::shared_ptr<Aws::IOStream> CreateChunkedStreamBuf(StandardHttpRequest& request, const std::string& data, size_t bufferSize = 65536) {
28+
auto inputStream = Aws::MakeShared<StringStream>(TEST_LOG_TAG, data);
29+
auto chunkedBuf = Aws::MakeUnique<smithy::client::features::AwsChunkedStreamBuf>(
30+
TEST_LOG_TAG, &request, inputStream, bufferSize);
31+
return std::shared_ptr<Aws::IOStream>(new Aws::IOStream(chunkedBuf.release()));
32+
}
33+
34+
std::string ReadEntireStream(std::shared_ptr<Aws::IOStream> stream) {
35+
Aws::StringStream output;
36+
char buffer[100];
37+
while (stream->read(buffer, sizeof(buffer))) {
38+
output.write(buffer, stream->gcount());
39+
}
40+
if (stream->gcount() > 0) {
41+
output.write(buffer, stream->gcount());
42+
}
43+
return output.str();
44+
}
45+
46+
template<size_t BufferSize>
47+
std::string ReadEntireStream(std::shared_ptr<AwsChunkedStream<BufferSize>> stream) {
48+
Aws::StringStream output;
49+
Aws::Utils::Array<char> buffer{100};
50+
size_t bytesRead;
51+
while ((bytesRead = stream->BufferedRead(buffer.GetUnderlyingData(), 100)) > 0) {
52+
std::copy(buffer.GetUnderlyingData(), buffer.GetUnderlyingData() + bytesRead, std::ostream_iterator<char>(output));
53+
}
54+
return output.str();
55+
}
56+
57+
template<size_t BufferSize>
58+
std::shared_ptr<AwsChunkedStream<BufferSize>> CreateAwsChunkedStream(StandardHttpRequest& request, const std::string& data) {
59+
auto inputStream = Aws::MakeShared<StringStream>(TEST_LOG_TAG, data);
60+
return Aws::MakeShared<AwsChunkedStream<BufferSize>>(TEST_LOG_TAG, &request, inputStream);
61+
}
62+
};
63+
1964
TEST_F(AwsChunkedStreamTest, ChunkedStreamShouldWork) {
20-
StandardHttpRequest request{"www.elda.com/will", Http::HttpMethod::HTTP_GET};
21-
auto requestHash = Aws::MakeShared<CRC32>(TEST_LOG_TAG);
22-
request.SetRequestHash("crc32", requestHash);
23-
std::shared_ptr<IOStream> inputStream = Aws::MakeShared<StringStream>(TEST_LOG_TAG, "1234567890123456789012345");
24-
AwsChunkedStream<10> chunkedStream{&request, inputStream};
25-
Aws::Utils::Array<char> outputBuffer{100};
26-
Aws::StringStream output;
27-
size_t readIterations{4};
28-
size_t bufferOffset{0};
29-
while (readIterations > 0) {
30-
bufferOffset = chunkedStream.BufferedRead(outputBuffer.GetUnderlyingData(), 10);
31-
std::copy(outputBuffer.GetUnderlyingData(), outputBuffer.GetUnderlyingData() + bufferOffset, std::ostream_iterator<char>(output));
32-
readIterations--;
33-
}
34-
// Read trailing checksum that is greater than 10 chars
35-
bufferOffset = chunkedStream.BufferedRead(outputBuffer.GetUnderlyingData(), 40);
36-
EXPECT_EQ(36ul, bufferOffset);
37-
std::copy(outputBuffer.GetUnderlyingData(), outputBuffer.GetUnderlyingData() + bufferOffset, std::ostream_iterator<char>(output));
38-
const auto encodedStr = output.str();
65+
auto request = CreateRequestWithChecksum("www.elda.com/will", "1234567890123456789012345");
66+
auto chunkedStream = CreateAwsChunkedStream<10>(request, "1234567890123456789012345");
67+
68+
const auto encodedStr = ReadEntireStream(chunkedStream);
3969
auto expectedStreamWithChecksum = "A\r\n1234567890\r\nA\r\n1234567890\r\n5\r\n12345\r\n0\r\nx-amz-checksum-crc32:78DeVw==\r\n\r\n";
4070
EXPECT_EQ(expectedStreamWithChecksum, encodedStr);
4171
}
4272

4373
TEST_F(AwsChunkedStreamTest, ShouldNotRequireTwoReadsOnSmallChunk) {
44-
StandardHttpRequest request{"www.clemar.com/strohl", Http::HttpMethod::HTTP_GET};
45-
auto requestHash = Aws::MakeShared<CRC32>(TEST_LOG_TAG);
46-
request.SetRequestHash("crc32", requestHash);
47-
std::shared_ptr<IOStream> inputStream = Aws::MakeShared<StringStream>(TEST_LOG_TAG, "12345");
48-
AwsChunkedStream<100> chunkedStream{&request, inputStream};
49-
Aws::Utils::Array<char> outputBuffer{100};
50-
Aws::StringStream output;
51-
const auto bufferOffset = chunkedStream.BufferedRead(outputBuffer.GetUnderlyingData(), 100);
52-
std::copy(outputBuffer.GetUnderlyingData(), outputBuffer.GetUnderlyingData() + bufferOffset, std::ostream_iterator<char>(output));
53-
EXPECT_EQ(46ul, bufferOffset);
54-
const auto encodedStr = output.str();
74+
auto request = CreateRequestWithChecksum("www.clemar.com/strohl", "12345");
75+
auto chunkedStream = CreateAwsChunkedStream<100>(request, "12345");
76+
77+
const auto encodedStr = ReadEntireStream(chunkedStream);
5578
auto expectedStreamWithChecksum = "5\r\n12345\r\n0\r\nx-amz-checksum-crc32:y/U6HA==\r\n\r\n";
5679
EXPECT_EQ(expectedStreamWithChecksum, encodedStr);
5780
}
5881

5982
TEST_F(AwsChunkedStreamTest, ShouldWorkOnSmallBuffer) {
60-
StandardHttpRequest request{"www.eugief.com/hesimay", Http::HttpMethod::HTTP_GET};
61-
auto requestHash = Aws::MakeShared<CRC32>(TEST_LOG_TAG);
62-
request.SetRequestHash("crc32", requestHash);
63-
std::shared_ptr<IOStream> inputStream = Aws::MakeShared<StringStream>(TEST_LOG_TAG, "1234567890");
64-
AwsChunkedStream<5> chunkedStream{&request, inputStream};
65-
Aws::Utils::Array<char> outputBuffer{100};
66-
// Read first 5 bytes, we get back ten bytes chunk encoded since it is "5\r\n12345\r\n"
67-
Aws::StringStream firstRead;
68-
auto amountRead = chunkedStream.BufferedRead(outputBuffer.GetUnderlyingData(), 100);
69-
std::copy(outputBuffer.GetUnderlyingData(), outputBuffer.GetUnderlyingData() + amountRead, std::ostream_iterator<char>(firstRead));
83+
auto request = CreateRequestWithChecksum("www.eugief.com/hesimay", "1234567890");
84+
auto chunkedStream = CreateAwsChunkedStream<5>(request, "1234567890");
85+
86+
// Read first chunk
87+
char buffer[10];
88+
auto amountRead = chunkedStream->BufferedRead(buffer, sizeof(buffer));
89+
std::string firstRead(buffer, amountRead);
7090
EXPECT_EQ(10ul, amountRead);
71-
auto encodedStr = firstRead.str();
72-
EXPECT_EQ("5\r\n12345\r\n", encodedStr);
73-
// Read second 5 bytes, we get back 46 bytes because we exhaust the underlying buffer
74-
// abd write the trailer "5\r\n67890\r\n0\r\nx-amz-checksum-crc32:Jh2u5Q==\r\n\r\n"
75-
Aws::StringStream secondRead;
76-
amountRead = chunkedStream.BufferedRead(outputBuffer.GetUnderlyingData(), 100);
77-
std::copy(outputBuffer.GetUnderlyingData(), outputBuffer.GetUnderlyingData() + amountRead, std::ostream_iterator<char>(secondRead));
91+
EXPECT_EQ("5\r\n12345\r\n", firstRead);
92+
93+
// Read remaining data
94+
char buffer2[50];
95+
amountRead = chunkedStream->BufferedRead(buffer2, sizeof(buffer2));
96+
std::string secondRead(buffer2, amountRead);
7897
EXPECT_EQ(46ul, amountRead);
79-
encodedStr = secondRead.str();
80-
EXPECT_EQ("5\r\n67890\r\n0\r\nx-amz-checksum-crc32:Jh2u5Q==\r\n\r\n", encodedStr);
81-
// Any subsequent reads will return 0 because all streams are exhausted
82-
amountRead = chunkedStream.BufferedRead(outputBuffer.GetUnderlyingData(), 100);
98+
EXPECT_EQ("5\r\n67890\r\n0\r\nx-amz-checksum-crc32:Jh2u5Q==\r\n\r\n", secondRead);
99+
100+
// Any subsequent reads should return 0
101+
amountRead = chunkedStream->BufferedRead(buffer, sizeof(buffer));
83102
EXPECT_EQ(0ul, amountRead);
84103
}
85104

86105
TEST_F(AwsChunkedStreamTest, ShouldWorkOnEmptyStream) {
87-
StandardHttpRequest request{"www.nidia.com/juna", Http::HttpMethod::HTTP_GET};
88-
auto requestHash = Aws::MakeShared<CRC32>(TEST_LOG_TAG);
89-
request.SetRequestHash("crc32", requestHash);
90-
std::shared_ptr<IOStream> inputStream = Aws::MakeShared<StringStream>(TEST_LOG_TAG, "");
91-
AwsChunkedStream<5> chunkedStream{&request, inputStream};
92-
Aws::Utils::Array<char> outputBuffer{100};
93-
Aws::StringStream firstRead;
94-
auto amountRead = chunkedStream.BufferedRead(outputBuffer.GetUnderlyingData(), 100);
95-
std::copy(outputBuffer.GetUnderlyingData(), outputBuffer.GetUnderlyingData() + amountRead, std::ostream_iterator<char>(firstRead));
96-
EXPECT_EQ(36ul, amountRead);
97-
auto encodedStr = firstRead.str();
106+
auto request = CreateRequestWithChecksum("www.nidia.com/juna", "");
107+
auto chunkedStream = CreateAwsChunkedStream<5>(request, "");
108+
109+
const auto encodedStr = ReadEntireStream(chunkedStream);
110+
EXPECT_EQ("0\r\nx-amz-checksum-crc32:AAAAAA==\r\n\r\n", encodedStr);
111+
}
112+
113+
TEST_F(AwsChunkedStreamTest, ChunkingInterceptorStreamBufShouldWork) {
114+
auto request = CreateRequestWithChecksum("www.elda.com/will", "1234567890123456789012345");
115+
auto chunkedBody = CreateChunkedStreamBuf(request, "1234567890123456789012345", 10);
116+
117+
const auto encodedStr = ReadEntireStream(chunkedBody);
118+
auto expectedStreamWithChecksum = "A\r\n1234567890\r\nA\r\n1234567890\r\n5\r\n12345\r\n0\r\nx-amz-checksum-crc32:78DeVw==\r\n\r\n";
119+
EXPECT_EQ(expectedStreamWithChecksum, encodedStr);
120+
}
121+
122+
TEST_F(AwsChunkedStreamTest, ChunkingInterceptorShouldNotRequireTwoReadsOnSmallChunk) {
123+
auto request = CreateRequestWithChecksum("www.clemar.com/strohl", "12345");
124+
auto chunkedBody = CreateChunkedStreamBuf(request, "12345", 100);
125+
126+
const auto encodedStr = ReadEntireStream(chunkedBody);
127+
auto expectedStreamWithChecksum = "5\r\n12345\r\n0\r\nx-amz-checksum-crc32:y/U6HA==\r\n\r\n";
128+
EXPECT_EQ(expectedStreamWithChecksum, encodedStr);
129+
}
130+
131+
TEST_F(AwsChunkedStreamTest, ChunkingInterceptorShouldWorkOnSmallBuffer) {
132+
auto request = CreateRequestWithChecksum("www.eugief.com/hesimay", "1234567890");
133+
auto chunkedBody = CreateChunkedStreamBuf(request, "1234567890", 5);
134+
135+
// Read first chunk
136+
char buffer[10];
137+
chunkedBody->read(buffer, sizeof(buffer));
138+
std::string firstRead(buffer, chunkedBody->gcount());
139+
EXPECT_EQ("5\r\n12345\r\n", firstRead);
140+
141+
// Read remaining data
142+
char buffer2[50];
143+
chunkedBody->read(buffer2, sizeof(buffer2));
144+
std::string secondRead(buffer2, chunkedBody->gcount());
145+
EXPECT_EQ("5\r\n67890\r\n0\r\nx-amz-checksum-crc32:Jh2u5Q==\r\n\r\n", secondRead);
146+
147+
// Any subsequent reads should return 0
148+
chunkedBody->read(buffer, sizeof(buffer));
149+
EXPECT_EQ(0, chunkedBody->gcount());
150+
}
151+
152+
TEST_F(AwsChunkedStreamTest, ChunkingInterceptorShouldWorkOnEmptyStream) {
153+
auto request = CreateRequestWithChecksum("www.nidia.com/juna", "");
154+
auto chunkedBody = CreateChunkedStreamBuf(request, "", 5);
155+
156+
const auto encodedStr = ReadEntireStream(chunkedBody);
98157
EXPECT_EQ("0\r\nx-amz-checksum-crc32:AAAAAA==\r\n\r\n", encodedStr);
99158
}

0 commit comments

Comments
 (0)