AWS SDK for C++

AWS SDK for C++ Version 1.11.607

Loading...
Searching...
No Matches
AwsChunkedStream.h
1
5#pragma once
6#include <aws/core/utils/HashingUtils.h>
7#include <aws/core/utils/Outcome.h>
8#include <aws/core/utils/crypto/Hash.h>
9#include <aws/crt/io/Stream.h>
10
11namespace Aws {
12namespace Utils {
13namespace Stream {
14
15static const size_t AWS_DATA_BUFFER_SIZE = 65536;
16
17template <size_t DataBufferSize = AWS_DATA_BUFFER_SIZE>
18class AwsChunkedStream: public Aws::Crt::Io::StdIOStreamInputStream {
19 public:
20 AwsChunkedStream(Http::HttpRequest *request, const std::shared_ptr<Aws::IOStream> &stream)
21 : StdIOStreamInputStream{stream},
22 m_chunkingStream{Aws::MakeShared<StringStream>("AwsChunkedStream")},
23 m_request(request),
24 m_stream(stream) {
25 assert(m_stream != nullptr);
26 if (m_stream == nullptr) {
27 AWS_LOGSTREAM_ERROR("AwsChunkedStream", "stream is null");
28 }
29 assert(request != nullptr);
30 if (request == nullptr) {
31 AWS_LOGSTREAM_ERROR("AwsChunkedStream", "request is null");
32 }
33 }
34
35 size_t BufferedRead(char *dst, size_t amountToRead) {
36 assert(dst != nullptr);
37
38 // only read and write to chunked stream if the underlying stream
39 // is still in a valid state
40 if (m_stream->good()) {
41 // Try to read in a 64K chunk, if we cant we know the stream is over
42 m_stream->read(m_data.GetUnderlyingData(), DataBufferSize);
43 size_t bytesRead = static_cast<size_t>(m_stream->gcount());
44 writeChunk(bytesRead);
45
46 // if we've read everything from the stream, we want to add the trailer
47 // to the underlying stream
48 if ((m_stream->peek() == EOF || m_stream->eof()) && !m_stream->bad()) {
49 writeTrailerToUnderlyingStream();
50 }
51 }
52
53 // if the underlying stream is empty there is nothing to read
54 if ((m_chunkingStream->peek() == EOF || m_chunkingStream->eof()) && !m_chunkingStream->bad()) {
55 return 0;
56 }
57
58 // Read to destination buffer, return how much was read
59 m_chunkingStream->read(dst, amountToRead);
60 return static_cast<size_t>(m_chunkingStream->gcount());
61 }
62
63protected:
64 bool ReadImpl(Crt::ByteBuf &dstBuffer) noexcept override {
65 size_t amountToRead = dstBuffer.capacity - dstBuffer.len;
66 const auto bytesRead = BufferedRead(reinterpret_cast<char *>(dstBuffer.buffer), amountToRead);
67 dstBuffer.len += bytesRead;;
68 return true;
69 };
70
71 private:
72 void writeTrailerToUnderlyingStream() {
73 Aws::StringStream chunkedTrailerStream;
74 chunkedTrailerStream << "0\r\n";
75 if (m_request->GetRequestHash().second != nullptr) {
76 chunkedTrailerStream << "x-amz-checksum-" << m_request->GetRequestHash().first << ":"
77 << HashingUtils::Base64Encode(m_request->GetRequestHash().second->GetHash().GetResult()) << "\r\n";
78 }
79 chunkedTrailerStream << "\r\n";
80 const auto chunkedTrailer = chunkedTrailerStream.str();
81 if (m_chunkingStream->eof()) {
82 m_chunkingStream->clear();
83 }
84 *m_chunkingStream << chunkedTrailer;
85 }
86
87 void writeChunk(size_t bytesRead) {
88 if (m_request->GetRequestHash().second != nullptr) {
89 m_request->GetRequestHash().second->Update(reinterpret_cast<unsigned char *>(m_data.GetUnderlyingData()), bytesRead);
90 }
91
92 if (bytesRead > 0 && m_chunkingStream != nullptr && !m_chunkingStream->bad()) {
93 if (m_chunkingStream->eof()) {
94 m_chunkingStream->clear();
95 }
96 *m_chunkingStream << Aws::Utils::StringUtils::ToHexString(bytesRead) << "\r\n";
97 m_chunkingStream->write(m_data.GetUnderlyingData(), bytesRead);
98 *m_chunkingStream << "\r\n";
99 }
100 }
101
102 Aws::Utils::Array<char> m_data{DataBufferSize};
103 std::shared_ptr<Aws::IOStream> m_chunkingStream;
104 Http::HttpRequest *m_request{nullptr};
105 std::shared_ptr<Aws::IOStream> m_stream;
106};
107} // namespace Stream
108} // namespace Utils
109} // namespace Aws
const std::pair< Aws::String, std::shared_ptr< Aws::Utils::Crypto::Hash > > & GetRequestHash() const
T * GetUnderlyingData() const
Definition Array.h:232
static Aws::String Base64Encode(const ByteBuffer &byteBuffer)
AwsChunkedStream(Http::HttpRequest *request, const std::shared_ptr< Aws::IOStream > &stream)
bool ReadImpl(Crt::ByteBuf &dstBuffer) noexcept override
size_t BufferedRead(char *dst, size_t amountToRead)
static Aws::String ToHexString(T value)
static const size_t AWS_DATA_BUFFER_SIZE
std::shared_ptr< T > MakeShared(const char *allocationTag, ArgTypes &&... args)
std::basic_stringstream< char, std::char_traits< char >, Aws::Allocator< char > > StringStream