@@ -26,111 +26,90 @@ static const char* CHECKSUM_HEADER_PREFIX = "x-amz-checksum-";
2626template <size_t DataBufferSize = AWS_DATA_BUFFER_SIZE>
2727class AwsChunkedStreamBuf : public std ::streambuf {
2828public:
29- AwsChunkedStreamBuf (Aws::Http::HttpRequest* request,
30- const std::shared_ptr<Aws::IOStream>& stream,
31- size_t bufferSize = DataBufferSize)
32- : m_chunkingStream(Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG)),
33- m_request (request),
34- m_stream(stream),
35- m_data(bufferSize)
36- {
37- assert (m_stream != nullptr );
38- if (m_stream == nullptr ) {
39- AWS_LOGSTREAM_ERROR (" AwsChunkedStream" , " stream is null" );
40- }
41- assert (m_request != nullptr );
42- if (m_request == nullptr ) {
43- AWS_LOGSTREAM_ERROR (" AwsChunkedStream" , " request is null" );
44- }
45-
46- setg (nullptr , nullptr , nullptr );
29+ AwsChunkedStreamBuf (Http::HttpRequest *request, const std::shared_ptr<Aws::IOStream> &stream):
30+ m_chunkingStream{Aws::MakeShared<StringStream>(" AwsChunkedStream" )},
31+ m_request (request),
32+ m_stream (stream) {
33+ assert (m_stream != nullptr );
34+ if (m_stream == nullptr ) {
35+ AWS_LOGSTREAM_ERROR (" AwsChunkedStream" , " stream is null" );
36+ }
37+ assert (request != nullptr );
38+ if (request == nullptr ) {
39+ AWS_LOGSTREAM_ERROR (" AwsChunkedStream" , " request is null" );
4740 }
41+ }
4842
4943protected:
50- int_type underflow () override {
51- if (gptr () && gptr () < egptr ()) {
52- return traits_type::to_int_type (*gptr ());
53- }
54-
55- // only read and write to chunked stream if the underlying stream
56- // is still in a valid state
57- if (m_stream->good ()) {
58- // Try to read in a 64K chunk, if we cant we know the stream is over
59- m_stream->read (m_data.GetUnderlyingData (), m_data.GetLength ());
60- size_t bytesRead = static_cast <size_t >(m_stream->gcount ());
61- writeChunk (bytesRead);
62-
63- // if we've read everything from the stream, we want to add the trailer
64- // to the underlying stream
65- if ((m_stream->peek () == EOF || m_stream->eof ()) && !m_stream->bad ()) {
66- writeTrailerToUnderlyingStream ();
67- }
68- }
69-
70- // if the underlying stream is empty there is nothing to read
71- if ((m_chunkingStream->peek () == EOF || m_chunkingStream->eof ()) && !m_chunkingStream->bad ()) {
72- return traits_type::eof ();
73- }
74-
75- // Read from chunking stream to internal buffer
76- m_chunkingStream->read (m_buffer.GetUnderlyingData (), m_buffer.GetLength ());
77- size_t bytesRead = static_cast <size_t >(m_chunkingStream->gcount ());
78- if (bytesRead == 0 ) {
79- return traits_type::eof ();
80- }
44+ int_type underflow () override {
45+ // only read and write to chunked stream if the underlying stream
46+ // is still in a valid state
47+ if (m_stream->good ()) {
48+ // Try to read in a 64K chunk, if we cant we know the stream is over
49+ m_stream->read (m_data.GetUnderlyingData (), DataBufferSize);
50+ size_t bytesRead = static_cast <size_t >(m_stream->gcount ());
51+ writeChunk (bytesRead);
52+
53+ // if we've read everything from the stream, we want to add the trailer
54+ // to the underlying stream
55+ if ((m_stream->peek () == EOF || m_stream->eof ()) && !m_stream->bad ()) {
56+ writeTrailerToUnderlyingStream ();
57+ }
58+ }
8159
82- setg (m_buffer.GetUnderlyingData (), m_buffer.GetUnderlyingData (), m_buffer.GetUnderlyingData () + bytesRead);
83- return traits_type::to_int_type (*gptr ());
60+ // if the underlying stream is empty there is nothing to read
61+ if ((m_chunkingStream->peek () == EOF || m_chunkingStream->eof ()) && !m_chunkingStream->bad ()) {
62+ return 0 ;
8463 }
8564
65+ setg (m_data.GetUnderlyingData (), m_data.GetUnderlyingData (), m_data.GetUnderlyingData () + m_chunkingStream->rdbuf ()->in_avail ());
66+ return m_data.GetUnderlyingData ()[0 ];
67+ }
68+
8669private:
87- void writeTrailerToUnderlyingStream () {
88- Aws::StringStream chunkedTrailerStream;
89- chunkedTrailerStream << " 0\r\n " ;
90- if (m_request->GetRequestHash ().second != nullptr ) {
91- chunkedTrailerStream << " x-amz-checksum-" << m_request->GetRequestHash ().first << " :"
92- << Aws::Utils::HashingUtils::Base64Encode (m_request->GetRequestHash ().second ->GetHash ().GetResult ()) << " \r\n " ;
93- }
94- chunkedTrailerStream << " \r\n " ;
95- const auto chunkedTrailer = chunkedTrailerStream.str ();
96- if (m_chunkingStream->eof ()) {
97- m_chunkingStream->clear ();
98- }
99- *m_chunkingStream << chunkedTrailer;
70+ void writeTrailerToUnderlyingStream () {
71+ Aws::StringStream chunkedTrailerStream;
72+ chunkedTrailerStream << " 0\r\n " ;
73+ if (m_request->GetRequestHash ().second != nullptr ) {
74+ chunkedTrailerStream << " x-amz-checksum-" << m_request->GetRequestHash ().first << " :"
75+ << HashingUtils::Base64Encode (m_request->GetRequestHash ().second ->GetHash ().GetResult ()) << " \r\n " ;
76+ }
77+ chunkedTrailerStream << " \r\n " ;
78+ const auto chunkedTrailer = chunkedTrailerStream.str ();
79+ if (m_chunkingStream->eof ()) {
80+ m_chunkingStream->clear ();
10081 }
82+ *m_chunkingStream << chunkedTrailer;
83+ }
10184
102- void writeChunk (size_t bytesRead) {
103- if (m_request->GetRequestHash ().second != nullptr ) {
104- m_request->GetRequestHash ().second ->Update (reinterpret_cast <unsigned char *>(m_data.GetUnderlyingData ()), bytesRead);
105- }
85+ void writeChunk (size_t bytesRead) {
86+ if (m_request->GetRequestHash ().second != nullptr ) {
87+ m_request->GetRequestHash ().second ->Update (reinterpret_cast <unsigned char *>(m_data.GetUnderlyingData ()), bytesRead);
88+ }
10689
107- if (bytesRead > 0 && m_chunkingStream && !m_chunkingStream->bad ()) {
108- if (m_chunkingStream->eof ()) {
109- m_chunkingStream->clear ();
110- }
111- *m_chunkingStream << Aws::Utils::StringUtils::ToHexString (bytesRead) << " \r\n " ;
112- m_chunkingStream->write (m_data.GetUnderlyingData (), bytesRead);
113- *m_chunkingStream << " \r\n " ;
114- }
90+ if (bytesRead > 0 && m_chunkingStream != nullptr && !m_chunkingStream->bad ()) {
91+ if (m_chunkingStream->eof ()) {
92+ m_chunkingStream->clear ();
93+ }
94+ *m_chunkingStream << Aws::Utils::StringUtils::ToHexString (bytesRead) << " \r\n " ;
95+ m_chunkingStream->write (m_data.GetUnderlyingData (), bytesRead);
96+ *m_chunkingStream << " \r\n " ;
11597 }
98+ }
11699
117- std::shared_ptr<Aws::IOStream> m_chunkingStream;
118- Aws::Http::HttpRequest* m_request{nullptr };
119- std::shared_ptr<Aws::IOStream> m_stream;
120- Aws::Utils::Array<char > m_data;
121- Aws::Utils::Array<char > m_buffer{DataBufferSize};
100+ Aws::Utils::Array<char > m_data{DataBufferSize};
101+ std::shared_ptr<Aws::IOStream> m_chunkingStream;
102+ Http::HttpRequest *m_request{nullptr };
103+ std::shared_ptr<Aws::IOStream> m_stream;
122104};
123105
124106class AwsChunkedIOStream : public Aws ::IOStream {
125107public:
126- AwsChunkedIOStream (Aws::Http::HttpRequest* request,
127- const std::shared_ptr<Aws::IOStream>& originalBody,
128- size_t bufferSize = AWS_DATA_BUFFER_SIZE)
129- : Aws::IOStream(&m_buf),
130- m_buf (request, originalBody, bufferSize) {}
108+ AwsChunkedIOStream (Aws::Http::HttpRequest* request, const std::shared_ptr<Aws::IOStream>& originalBody)
109+ : Aws::IOStream(&m_buf), m_buf(request, originalBody) {}
131110
132111private:
133- AwsChunkedStreamBuf<> m_buf;
112+ AwsChunkedStreamBuf<> m_buf;
134113};
135114
136115/* *
@@ -139,73 +118,73 @@ class AwsChunkedIOStream : public Aws::IOStream {
139118 */
140119class ChunkingInterceptor : public smithy ::interceptor::Interceptor {
141120public:
142- explicit ChunkingInterceptor (const Aws::Client::ClientConfiguration& config)
143- : m_httpClientChunkedMode(config.httpClientChunkedMode) {}
144- ~ChunkingInterceptor () override = default ;
121+ explicit ChunkingInterceptor (const Aws::Client::ClientConfiguration& config)
122+ : m_httpClientChunkedMode(config.httpClientChunkedMode) {}
123+ ~ChunkingInterceptor () override = default ;
145124
146- ModifyRequestOutcome ModifyBeforeSigning (smithy::interceptor::InterceptorContext& context) override {
147- auto request = context.GetTransmitRequest ();
125+ ModifyRequestOutcome ModifyBeforeSigning (smithy::interceptor::InterceptorContext& context) override {
126+ auto request = context.GetTransmitRequest ();
148127
149- if (!ShouldApplyChunking (request)) {
150- return request;
151- }
128+ if (!ShouldApplyChunking (request)) {
129+ return request;
130+ }
152131
153- auto originalBody = request->GetContentBody ();
154- if (!originalBody) {
155- return request;
156- }
132+ auto originalBody = request->GetContentBody ();
133+ if (!originalBody) {
134+ return request;
135+ }
157136
158- // Set up chunked encoding headers for checksum calculation
159- const auto & hashPair = request->GetRequestHash ();
160- if (hashPair.second != nullptr ) {
161- Aws::String checksumHeaderValue = Aws::String (CHECKSUM_HEADER_PREFIX) + hashPair.first ;
162- request->DeleteHeader (checksumHeaderValue.c_str ());
163- request->SetHeaderValue (Aws::Http::AWS_TRAILER_HEADER, checksumHeaderValue);
164- request->SetTransferEncoding (Aws::Http::CHUNKED_VALUE);
165-
166- if (!request->HasContentEncoding ()) {
167- request->SetContentEncoding (Aws::Http::AWS_CHUNKED_VALUE);
168- } else {
169- Aws::String currentEncoding = request->GetContentEncoding ();
170- if (currentEncoding.find (Aws::Http::AWS_CHUNKED_VALUE) == Aws::String::npos) {
171- request->SetContentEncoding (Aws::String{Aws::Http::AWS_CHUNKED_VALUE} + " ," + currentEncoding);
172- }
173- }
174-
175- if (request->HasHeader (Aws::Http::CONTENT_LENGTH_HEADER)) {
176- request->SetHeaderValue (Aws::Http::DECODED_CONTENT_LENGTH_HEADER, request->GetHeaderValue (Aws::Http::CONTENT_LENGTH_HEADER));
177- request->DeleteHeader (Aws::Http::CONTENT_LENGTH_HEADER);
178- }
137+ // Set up chunked encoding headers for checksum calculation
138+ const auto & hashPair = request->GetRequestHash ();
139+ if (hashPair.second != nullptr ) {
140+ Aws::String checksumHeaderValue = Aws::String (CHECKSUM_HEADER_PREFIX) + hashPair.first ;
141+ request->DeleteHeader (checksumHeaderValue.c_str ());
142+ request->SetHeaderValue (Aws::Http::AWS_TRAILER_HEADER, checksumHeaderValue);
143+ request->SetTransferEncoding (Aws::Http::CHUNKED_VALUE);
144+
145+ if (!request->HasContentEncoding ()) {
146+ request->SetContentEncoding (Aws::Http::AWS_CHUNKED_VALUE);
147+ } else {
148+ Aws::String currentEncoding = request->GetContentEncoding ();
149+ if (currentEncoding.find (Aws::Http::AWS_CHUNKED_VALUE) == Aws::String::npos) {
150+ request->SetContentEncoding (Aws::String{Aws::Http::AWS_CHUNKED_VALUE} + " ," + currentEncoding);
179151 }
152+ }
180153
181- auto chunkedBody = Aws::MakeShared<AwsChunkedIOStream>(
182- ALLOCATION_TAG, request.get (), originalBody);
183-
184- request->AddContentBody (chunkedBody);
185- return request;
154+ if (request->HasHeader (Aws::Http::CONTENT_LENGTH_HEADER)) {
155+ request->SetHeaderValue (Aws::Http::DECODED_CONTENT_LENGTH_HEADER, request->GetHeaderValue (Aws::Http::CONTENT_LENGTH_HEADER));
156+ request->DeleteHeader (Aws::Http::CONTENT_LENGTH_HEADER);
157+ }
186158 }
187159
188- ModifyResponseOutcome ModifyBeforeDeserialization (smithy::interceptor::InterceptorContext& context) override {
189- return context.GetTransmitResponse ();
190- }
160+ auto chunkedBody = Aws::MakeShared<AwsChunkedStreamBuf<>>(
161+ ALLOCATION_TAG, request.get (), originalBody);
162+
163+ request->AddContentBody (chunkedBody);
164+ return request;
165+ }
166+
167+ ModifyResponseOutcome ModifyBeforeDeserialization (smithy::interceptor::InterceptorContext& context) override {
168+ return context.GetTransmitResponse ();
169+ }
191170
192171private:
193- bool ShouldApplyChunking (const std::shared_ptr<Aws::Http::HttpRequest>& request) const {
194- // Use configuration setting to determine chunking behavior
195- if (m_httpClientChunkedMode != Aws::Client::HttpClientChunkedMode::DEFAULT) {
196- return false ;
197- }
198-
199- if (!request || !request->GetContentBody ()) {
200- return false ;
201- }
202-
203- // Check if request has checksum requirements
204- const auto & hashPair = request->GetRequestHash ();
205- return hashPair.second != nullptr ;
172+ bool ShouldApplyChunking (const std::shared_ptr<Aws::Http::HttpRequest>& request) const {
173+ // Use configuration setting to determine chunking behavior
174+ if (m_httpClientChunkedMode != Aws::Client::HttpClientChunkedMode::DEFAULT) {
175+ return false ;
176+ }
177+
178+ if (!request || !request->GetContentBody ()) {
179+ return false ;
206180 }
207181
208- Aws::Client::HttpClientChunkedMode m_httpClientChunkedMode;
182+ // Check if request has checksum requirements
183+ const auto & hashPair = request->GetRequestHash ();
184+ return hashPair.second != nullptr ;
185+ }
186+
187+ Aws::Client::HttpClientChunkedMode m_httpClientChunkedMode;
209188};
210189
211190} // namespace features
0 commit comments