Skip to content

Commit 4c65270

Browse files
committed
direct copy of awschunkestream
1 parent 86518de commit 4c65270

File tree

1 file changed

+121
-142
lines changed

1 file changed

+121
-142
lines changed

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

Lines changed: 121 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -26,111 +26,90 @@ static const char* CHECKSUM_HEADER_PREFIX = "x-amz-checksum-";
2626
template <size_t DataBufferSize = AWS_DATA_BUFFER_SIZE>
2727
class AwsChunkedStreamBuf : public std::streambuf {
2828
public:
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

4943
protected:
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+
8669
private:
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

124106
class AwsChunkedIOStream : public Aws::IOStream {
125107
public:
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

132111
private:
133-
AwsChunkedStreamBuf<> m_buf;
112+
AwsChunkedStreamBuf<> m_buf;
134113
};
135114

136115
/**
@@ -139,73 +118,73 @@ class AwsChunkedIOStream : public Aws::IOStream {
139118
*/
140119
class ChunkingInterceptor : public smithy::interceptor::Interceptor {
141120
public:
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

192171
private:
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

Comments
 (0)