azure-core
body_stream.hpp
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // SPDX-License-Identifier: MIT
3 
9 #pragma once
10 
11 #include "azure/core/platform.hpp"
12 
13 #if defined(AZ_PLATFORM_POSIX)
14 #include <unistd.h>
15 #endif
16 
17 #include "azure/core/context.hpp"
18 
19 #include <algorithm>
20 #include <cstdint>
21 #include <cstdio>
22 #include <cstring>
23 #include <functional>
24 #include <memory>
25 #include <vector>
26 
27 namespace Azure { namespace Core { namespace IO {
28 
32  class BodyStream {
33  private:
45  virtual size_t OnRead(uint8_t* buffer, size_t count, Azure::Core::Context const& context) = 0;
46 
47  public:
52  virtual ~BodyStream() = default;
53 
58  virtual int64_t Length() const = 0;
59 
60  /*
61  * @brief Resets the stream back to the beginning (for retries).
62  * @remark Derived classes that send data in an HTTP request MUST override this and implement
63  * it properly.
64  */
65  virtual void Rewind()
66  {
67  AZURE_ASSERT_MSG(
68  false,
69  "The specified BodyStream doesn't support Rewind which is required to guarantee fault "
70  "tolerance when retrying any operation. Consider creating a MemoryBodyStream or "
71  "FileBodyStream, which are rewindable.");
72  }
73 
84  size_t Read(
85  uint8_t* buffer,
86  size_t count,
87  Azure::Core::Context const& context = Azure::Core::Context())
88  {
89  AZURE_ASSERT(buffer || count == 0);
90 
91  context.ThrowIfCancelled();
92  return OnRead(buffer, count, context);
93  }
94 
105  size_t ReadToCount(
106  uint8_t* buffer,
107  size_t count,
108  Azure::Core::Context const& context = Azure::Core::Context());
109 
118  std::vector<uint8_t> ReadToEnd(Azure::Core::Context const& context = Azure::Core::Context());
119  };
120 
124  class MemoryBodyStream final : public BodyStream {
125  private:
126  const uint8_t* m_data;
127  size_t m_length;
128  size_t m_offset = 0;
129 
130  size_t OnRead(uint8_t* buffer, size_t count, Azure::Core::Context const& context) override;
131 
132  public:
133  // Forbid constructor for rval so we don't end up storing dangling ptr
134  MemoryBodyStream(std::vector<uint8_t> const&&) = delete;
135 
141  MemoryBodyStream(std::vector<uint8_t> const& buffer)
142  : MemoryBodyStream(buffer.data(), buffer.size())
143  {
144  }
145 
153  explicit MemoryBodyStream(const uint8_t* data, size_t length) : m_data(data), m_length(length)
154  {
155  AZURE_ASSERT(data || length == 0);
156  }
157 
158  int64_t Length() const override { return this->m_length; }
159 
160  void Rewind() override { m_offset = 0; }
161  };
162 
163  namespace _internal {
168  class RandomAccessFileBodyStream final : public BodyStream {
169  private:
170  // immutable
171 #if defined(AZ_PLATFORM_POSIX)
172  int m_fileDescriptor;
173 #elif defined(AZ_PLATFORM_WINDOWS)
174  void* m_filehandle;
175 #endif
176  int64_t m_baseOffset;
177  int64_t m_length;
178  // mutable
179  int64_t m_offset;
180 
181  size_t OnRead(uint8_t* buffer, size_t count, Azure::Core::Context const& context) override;
182 
183  public:
184 #if defined(AZ_PLATFORM_POSIX)
185 
199  RandomAccessFileBodyStream(int fileDescriptor, int64_t offset, int64_t length)
200  : m_fileDescriptor(fileDescriptor), m_baseOffset(offset), m_length(length), m_offset(0)
201  {
202  AZURE_ASSERT(fileDescriptor >= 0 && offset >= 0 && length >= 0);
203  }
204 
205  RandomAccessFileBodyStream() : m_fileDescriptor(0), m_baseOffset(0), m_length(0), m_offset(0)
206  {
207  }
208 
209 #elif defined(AZ_PLATFORM_WINDOWS)
210 
224  RandomAccessFileBodyStream(void* fileHandle, int64_t offset, int64_t length)
225  : m_filehandle(fileHandle), m_baseOffset(offset), m_length(length), m_offset(0)
226  {
227  AZURE_ASSERT(fileHandle && offset >= 0 && length >= 0);
228  }
229 
230  RandomAccessFileBodyStream() : m_filehandle(NULL), m_baseOffset(0), m_length(0), m_offset(0)
231  {
232  }
233 #endif
234 
235  // Rewind seeks back to 0
236  void Rewind() override { this->m_offset = 0; }
237 
238  int64_t Length() const override { return this->m_length; }
239  };
240 
241  } // namespace _internal
242 
247  class FileBodyStream final : public BodyStream {
248  private:
249  // immutable
250 #if defined(AZ_PLATFORM_WINDOWS)
251  void* m_filehandle;
252 #elif defined(AZ_PLATFORM_POSIX)
253  int m_fileDescriptor;
254 #endif
255  // mutable
256  std::unique_ptr<_internal::RandomAccessFileBodyStream> m_randomAccessFileBodyStream;
257 
258  size_t OnRead(uint8_t* buffer, size_t count, Azure::Core::Context const& context) override;
259 
260  public:
272  FileBodyStream(const std::string& filename);
273 
278  ~FileBodyStream();
279 
280  // Rewind seeks back to 0
281  void Rewind() override;
282 
283  int64_t Length() const override;
284  };
285 
291  private:
292  BodyStream* m_bodyStream;
293  int64_t m_bytesTransferred;
294  std::function<void(int64_t bytesTransferred)> m_callback;
295 
296  private:
297  size_t OnRead(uint8_t* buffer, size_t count, Azure::Core::Context const& context) override;
298 
299  public:
311  BodyStream& bodyStream,
312  std::function<void(int64_t bytesTransferred)> callback);
313 
314  void Rewind() override;
315 
316  int64_t Length() const override;
317  };
318 }}} // namespace Azure::Core::IO
Azure::Core::IO::ProgressBodyStream::Length
int64_t Length() const override
Get the length of the data.
Definition: body_stream.cpp:221
Azure::Core::IO::ProgressBodyStream
A concrete implementation of Azure::Core::IO::BodyStream that wraps another stream and reports progre...
Definition: body_stream.hpp:290
Azure::Core::Context::ThrowIfCancelled
void ThrowIfCancelled() const
Checks if the context is cancelled.
Definition: context.hpp:248
Azure::Core::IO::FileBodyStream::Length
int64_t Length() const override
Get the length of the data.
Definition: body_stream.cpp:193
context.hpp
Context for canceling long running operations.
Azure::Core::IO::BodyStream
Used to read data to/from a service.
Definition: body_stream.hpp:32
Azure::Core::IO::ProgressBodyStream::ProgressBodyStream
ProgressBodyStream(BodyStream &bodyStream, std::function< void(int64_t bytesTransferred)> callback)
Constructs ProgressBodyStream from a BodyStream.
Definition: body_stream.cpp:195
Azure::Core::IO::BodyStream::ReadToEnd
std::vector< uint8_t > ReadToEnd(Azure::Core::Context const &context=Azure::Core::Context())
Read Azure::Core::IO::BodyStream until the stream is read to end, allocating memory for the entirety ...
Definition: body_stream.cpp:62
Azure::Core::IO::MemoryBodyStream
Azure::Core::IO::BodyStream providing data from an initialized memory buffer.
Definition: body_stream.hpp:124
Azure::Core::IO::MemoryBodyStream::Length
int64_t Length() const override
Get the length of the data.
Definition: body_stream.hpp:158
Azure::Core::IO::FileBodyStream::~FileBodyStream
~FileBodyStream()
Closes the file and cleans up any resources.
Definition: body_stream.cpp:169
Azure::Core::IO::MemoryBodyStream::MemoryBodyStream
MemoryBodyStream(const uint8_t *data, size_t length)
Construct using buffer pointer and its size.
Definition: body_stream.hpp:153
Azure::Core::IO::MemoryBodyStream::MemoryBodyStream
MemoryBodyStream(std::vector< uint8_t > const &buffer)
Construct using vector of bytes.
Definition: body_stream.hpp:141
Azure::Core::IO::FileBodyStream
A concrete implementation of Azure::Core::IO::BodyStream used for reading data from a file.
Definition: body_stream.hpp:247
Azure::Core::IO::BodyStream::Read
size_t Read(uint8_t *buffer, size_t count, Azure::Core::Context const &context=Azure::Core::Context())
Read portion of data into a buffer.
Definition: body_stream.hpp:84
Azure
Azure SDK abstractions.
Definition: azure_assert.hpp:55
Azure::Core::IO::BodyStream::~BodyStream
virtual ~BodyStream()=default
Destructs BodyStream.
platform.hpp
Platform-specific macros.
Azure::Core::IO::BodyStream::ReadToCount
size_t ReadToCount(uint8_t *buffer, size_t count, Azure::Core::Context const &context=Azure::Core::Context())
Read Azure::Core::IO::BodyStream into a buffer until the buffer is filled, or until the stream is rea...
Definition: body_stream.cpp:44
Azure::Core::IO::BodyStream::Length
virtual int64_t Length() const =0
Get the length of the data.
Azure::Core::Context
A context is a node within a tree that represents deadlines and key/value pairs.
Definition: context.hpp:45
Azure::Core::IO::FileBodyStream::FileBodyStream
FileBodyStream(const std::string &filename)
Constructs FileBodyStream from a file name.
Definition: body_stream.cpp:93