|
5 | 5 | #include <aws/core/http/standard/StandardHttpRequest.h> |
6 | 6 | #include <aws/core/utils/crypto/CRC32.h> |
7 | 7 | #include <aws/core/utils/stream/AwsChunkedStream.h> |
| 8 | +#include <smithy/client/features/ChunkingInterceptor.h> |
8 | 9 | #include <aws/testing/AwsCppSdkGTestSuite.h> |
9 | 10 |
|
10 | 11 | using namespace Aws; |
11 | 12 | using namespace Aws::Http::Standard; |
12 | 13 | using namespace Aws::Utils::Stream; |
13 | 14 | using namespace Aws::Utils::Crypto; |
14 | 15 |
|
15 | | -class AwsChunkedStreamTest : public Aws::Testing::AwsCppSdkGTestSuite {}; |
16 | | - |
17 | 16 | const char* TEST_LOG_TAG = "AWS_CHUNKED_STREAM_TEST"; |
18 | 17 |
|
| 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 | + |
19 | 64 | 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); |
39 | 69 | 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"; |
40 | 70 | EXPECT_EQ(expectedStreamWithChecksum, encodedStr); |
41 | 71 | } |
42 | 72 |
|
43 | 73 | 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); |
55 | 78 | auto expectedStreamWithChecksum = "5\r\n12345\r\n0\r\nx-amz-checksum-crc32:y/U6HA==\r\n\r\n"; |
56 | 79 | EXPECT_EQ(expectedStreamWithChecksum, encodedStr); |
57 | 80 | } |
58 | 81 |
|
59 | 82 | 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); |
70 | 90 | 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); |
78 | 97 | 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)); |
83 | 102 | EXPECT_EQ(0ul, amountRead); |
84 | 103 | } |
85 | 104 |
|
86 | 105 | 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); |
98 | 157 | EXPECT_EQ("0\r\nx-amz-checksum-crc32:AAAAAA==\r\n\r\n", encodedStr); |
99 | 158 | } |
0 commit comments