Documentation for Storage Blob Service, Nullable, signed int, and others (#213)

* use Nullable

* use C++ style cast

* Add documentation

* use signed int instead of unsigned

* disable storage ut

* add timeout in protocol layer

* enable stroage ut

* undelete test case

* Support copy status in properties

* Remove default value for SequenceNumber in CreatePageBlobOptions
This commit is contained in:
JinmingHu 2020-06-30 03:03:42 -07:00 committed by GitHub
parent 2877c959e1
commit 74ce80659b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2763 additions and 1910 deletions

View File

@ -12,40 +12,127 @@
namespace Azure { namespace Storage { namespace Blobs {
/**
* @brief The AppendBlobClient allows you to manipulate Azure Storage append blobs.
*
* An append blob is comprised of blocks and is optimized for append operations. When you modify
* an append blob, blocks are added to the end of the blob only, via the AppendBlock operation.
* Updating or deleting of existing blocks is not supported. Unlike a block blob, an append blob
* does not expose its block IDs.
*/
class AppendBlobClient : public BlobClient {
public:
// connection string
/**
* @brief Initialize a new instance of AppendBlobClient.
*
* @param connectionString A connection string includes the authentication information required
* for your application to access data in an Azure Storage account at runtime.
* @param containerName The name of the container containing this blob.
* @param blobName The name of this blob.
* @param options Optional client options that define the transport pipeline policies for
* authentication, retries, etc., that are applied to every request.
* @return A new AppendBlobClient instance.
*/
static AppendBlobClient CreateFromConnectionString(
const std::string& connectionString,
const std::string& containerName,
const std::string& blobName,
const AppendBlobClientOptions& options = AppendBlobClientOptions());
// shared key auth
/**
* @brief Initialize a new instance of AppendBlobClient.
*
* @param blobUri A uri
* referencing the blob that includes the name of the account, the name of the container, and
* the name of the blob.
* @param credential The shared key credential used to sign
* requests.
* @param options Optional client options that define the transport pipeline
* policies for authentication, retries, etc., that are applied to every request.
*/
explicit AppendBlobClient(
const std::string& blobUri,
std::shared_ptr<SharedKeyCredential> credential,
const AppendBlobClientOptions& options = AppendBlobClientOptions());
// token auth
/**
* @brief Initialize a new instance of AppendBlobClient.
*
* @param blobUri A uri
* referencing the blob that includes the name of the account, the name of the container, and
* the name of the blob.
* @param credential The token credential used to sign requests.
* @param options Optional client options that define the transport pipeline policies for
* authentication, retries, etc., that are applied to every request.
*/
explicit AppendBlobClient(
const std::string& blobUri,
std::shared_ptr<TokenCredential> credential,
const AppendBlobClientOptions& options = AppendBlobClientOptions());
// anonymous/SAS/customized pipeline auth
/**
* @brief Initialize a new instance of AppendBlobClient.
*
* @param blobUri A uri
* referencing the blob that includes the name of the account, the name of the container, and
* the name of the blob, and possibly also a SAS token.
* @param options Optional client
* options that define the transport pipeline policies for authentication, retries, etc., that
* are applied to every request.
*/
explicit AppendBlobClient(
const std::string& blobUri,
const AppendBlobClientOptions& options = AppendBlobClientOptions());
/**
* @brief Initializes a new instance of the AppendBlobClient class with an identical uri
* source but the specified snapshot timestamp.
*
* @param snapshot The snapshot
* identifier.
* @return A new AppendBlobClient instance.
* @remarks Pass empty string to remove the snapshot returning the base blob.
*/
AppendBlobClient WithSnapshot(const std::string& snapshot) const;
/**
* @brief Creates a new 0-length append blob. The content of any existing blob is
* overwritten with the newly initialized append blob.
*
* @param options Optional
* parameters to execute this function.
* @return A BlobContentInfo describing the newly
* created append blob.
*/
BlobContentInfo Create(const CreateAppendBlobOptions& options = CreateAppendBlobOptions());
/**
* @brief Commits a new block of data, represented by the content BodyStream to the end
* of the existing append blob.
*
* @param content A BodyStream containing the
* content of the block to append.
* @param options Optional parameters to execute this
* function.
* @return A BlobAppendInfo describing the state of the updated append blob.
*/
BlobAppendInfo AppendBlock(
std::unique_ptr<Azure::Core::Http::BodyStream> content,
const AppendBlockOptions& options = AppendBlockOptions());
/**
* @brief Commits a new block of data, represented by the content BodyStream to the end
* of the existing append blob.
*
* @param sourceUri Specifies the uri of the source
* blob. The value may be a uri of up to 2 KB in length that specifies a blob. The source blob
* must either be public or must be authenticated via a shared access signature. If the source
* blob is public, no authentication is required to perform the operation.
* @param options
* Optional parameters to execute this function.
* @return A BlobAppendInfo describing the
* state of the updated append blob.
*/
BlobAppendInfo AppendBlockFromUri(
const std::string& sourceUri,
const AppendBlockFromUriOptions& options = AppendBlockFromUriOptions()) const;

View File

@ -18,72 +18,237 @@ namespace Azure { namespace Storage { namespace Blobs {
class AppendBlobClient;
class PageBlobClient;
/**
* @brief The BlobClient allows you to manipulate Azure Storage blobs.
*/
class BlobClient {
public:
// connection string
/**
* @brief Initialize a new instance of BlobClient.
*
* @param connectionString A connection string includes the authentication information required
* for your application to access data in an Azure Storage account at runtime.
* @param containerName The name of the container containing this blob.
* @param blobName The name of this blob.
* @param options Optional client options that define the transport pipeline policies for
* authentication, retries, etc., that are applied to every request.
* @return A new BlobClient instance.
*/
static BlobClient CreateFromConnectionString(
const std::string& connectionString,
const std::string& containerName,
const std::string& blobName,
const BlobClientOptions& options = BlobClientOptions());
// shared key auth
/**
* @brief Initialize a new instance of BlobClient.
*
* @param blobUri A uri
* referencing the blob that includes the name of the account, the name of the container, and
* the name of the blob.
* @param credential The shared key credential used to sign
* requests.
* @param options Optional client options that define the transport pipeline
* policies for authentication, retries, etc., that are applied to every request.
*/
explicit BlobClient(
const std::string& blobUri,
std::shared_ptr<SharedKeyCredential> credential,
const BlobClientOptions& options = BlobClientOptions());
// token auth
/**
* @brief Initialize a new instance of BlobClient.
*
* @param blobUri A uri
* referencing the blob that includes the name of the account, the name of the container, and
* the name of the blob.
* @param credential The token credential used to sign requests.
* @param options Optional client options that define the transport pipeline policies for
* authentication, retries, etc., that are applied to every request.
*/
explicit BlobClient(
const std::string& blobUri,
std::shared_ptr<TokenCredential> credential,
const BlobClientOptions& options = BlobClientOptions());
// anonymous/SAS/customized pipeline auth
/**
* @brief Initialize a new instance of BlobClient.
*
* @param blobUri A uri
* referencing the blob that includes the name of the account, the name of the container, and
* the name of the blob, and possibly also a SAS token.
* @param options Optional client
* options that define the transport pipeline policies for authentication, retries, etc., that
* are applied to every request.
*/
explicit BlobClient(
const std::string& blobUri,
const BlobClientOptions& options = BlobClientOptions());
/**
* @brief Creates a new BlockBlobClient object with the same uri as this BlobClient. The
* new BlockBlobClient uses the same request policy pipeline as this BlobClient.
*
*
* @return A new BlockBlobClient instance.
*/
BlockBlobClient GetBlockBlobClient() const;
/**
* @brief Creates a new AppendBlobClient object with the same uri as this BlobClient.
* The new AppendBlobClient uses the same request policy pipeline as this BlobClient.
*
* @return A new AppendBlobClient instance.
*/
AppendBlobClient GetAppendBlobClient() const;
/**
* @brief Creates a new PageBlobClient object with the same uri as this BlobClient.
* The new PageBlobClient uses the same request policy pipeline as this BlobClient.
*
* @return A new PageBlobClient instance.
*/
PageBlobClient GetPageBlobClient() const;
/**
* @brief Gets the blob's primary uri endpoint.
*
* @return The blob's
* primary uri endpoint.
*/
std::string GetUri() const { return m_blobUrl.ToString(); }
/**
* @brief Initializes a new instance of the BlobClient class with an identical uri
* source but the specified snapshot timestamp.
*
* @param snapshot The snapshot
* identifier.
* @return A new BlobClient instance.
* @remarks Pass empty string to remove the snapshot returning the base blob.
*/
BlobClient WithSnapshot(const std::string& snapshot) const;
/**
* @brief Returns all user-defined metadata, standard HTTP properties, and system
* properties for the blob. It does not return the content of the blob.
*
* @param
* options Optional parameters to execute this function.
* @return A BlobProperties
* describing the blob's properties.
*/
BlobProperties GetProperties(
const GetBlobPropertiesOptions& options = GetBlobPropertiesOptions()) const;
/**
* @brief Sets system properties on the blob.
*
* @param options Optional
* parameters to execute this function.
* @return A BlobInfo describing the updated blob.
*/
BlobInfo SetHttpHeaders(
const SetBlobHttpHeadersOptions& options = SetBlobHttpHeadersOptions()) const;
/**
* @brief Sets user-defined metadata for the specified blob as one or more name-value
* pairs.
*
* @param metadata Custom metadata to set for this blob.
* @param
* options Optional parameters to execute this function.
* @return A BlobInfo describing
* the updated blob.
*/
BlobInfo SetMetadata(
std::map<std::string, std::string> metadata,
const SetBlobMetadataOptions& options = SetBlobMetadataOptions()) const;
/**
* @brief Sets the tier on a blob. The operation is allowed on a page blob in a premium
* storage account and on a block blob in a blob storage or general purpose v2 account.
*
* @param Tier Indicates the tier to be set on the blob.
* @param options Optional
* parameters to execute this function.
* @return A BasicResponse on successfully setting
* the tier.
*/
BasicResponse SetAccessTier(
AccessTier Tier,
const SetAccessTierOptions& options = SetAccessTierOptions()) const;
/**
* @brief Copies data at from the source to this blob.
*
* @param sourceUri
* Specifies the uri of the source blob. The value may a uri of up to 2 KB in length that
* specifies a blob. A source blob in the same storage account can be authenticated via Shared
* Key. However, if the source is a blob in another account, the source blob must either be
* public or must be authenticated via a shared access signature. If the source blob is public,
* no authentication is required to perform the copy operation.
* @param options Optional parameters to execute this function.
* @return A BlobCopyInfo describing the state of the copy operation.
*/
BlobCopyInfo StartCopyFromUri(
const std::string& sourceUri,
const StartCopyFromUriOptions& options = StartCopyFromUriOptions()) const;
/**
* @brief Aborts a pending StartCopyFromUri operation, and leaves this blob with zero
* length and full metadata.
*
* @param copyId ID of the copy operation to abort.
* @param options Optional parameters to execute this function.
* @return A BasicResponse
* on successfully aborting.
*/
BasicResponse AbortCopyFromUri(
const std::string& copyId,
const AbortCopyFromUriOptions& options = AbortCopyFromUriOptions()) const;
FlattenedDownloadProperties Download(
const DownloadBlobOptions& options = DownloadBlobOptions()) const;
/**
* @brief Downloads a blob from the service, including its metadata and properties.
* *
* @param options Optional parameters to execute this function.
* @return A
* BlobDownloadInfo describing the downloaded blob.
* BlobDownloadInfo.BodyStream contains the blob's data.
*/
BlobDownloadInfo Download(const DownloadBlobOptions& options = DownloadBlobOptions()) const;
/**
* @brief Creates a read-only snapshot of a blob.
*
* @param options Optional
* parameters to execute this function.
* @return A BlobSnapshotInfo describing the new
* blob snapshot.
*/
BlobSnapshotInfo CreateSnapshot(
const CreateSnapshotOptions& options = CreateSnapshotOptions()) const;
/**
* @brief Marks the specified blob or snapshot for deletion. The blob is later deleted
* during garbage collection. Note that in order to delete a blob, you must delete all of its
* snapshots. You can delete both at the same time using DeleteBlobOptions.DeleteSnapshots.
*
* @param options Optional parameters to execute this function.
* @return A
* BasicResponse on successfully deleting.
*/
BasicResponse Delete(const DeleteBlobOptions& options = DeleteBlobOptions()) const;
/**
* @brief Restores the contents and metadata of a soft deleted blob and any associated
* soft deleted snapshots.
*
* @param options Optional parameters to execute this
* function.
* @return A BasicResponse on successfully deleting.
*/
BasicResponse Undelete(const UndeleteBlobOptions& options = UndeleteBlobOptions()) const;
protected:

View File

@ -15,55 +15,176 @@
namespace Azure { namespace Storage { namespace Blobs {
/**
* The BlobContainerClient allows you to manipulate Azure Storage containers and their
* blobs.
*/
class BlobContainerClient {
public:
// connection string
/**
* @brief Initialize a new instance of BlobContainerClient.
*
* @param connectionString A connection string includes the authentication information required
* for your application to access data in an Azure Storage account at runtime.
* @param containerName The name of the container containing this blob.
* @param options Optional client options that define the transport pipeline policies for
* authentication, retries, etc., that are applied to every request.
* @return A new BlobContainerClient instance.
*/
static BlobContainerClient CreateFromConnectionString(
const std::string& connectionString,
const std::string& containerName,
const BlobContainerClientOptions& options = BlobContainerClientOptions());
// shared key auth
/**
* @brief Initialize a new instance of BlobContainerClient.
*
* @param containerUri A uri
* referencing the blob container that includes the name of the account and the name of the
* container.
* @param credential The shared key credential used to sign
* requests.
* @param options Optional client options that define the transport pipeline
* policies for authentication, retries, etc., that are applied to every request.
*/
explicit BlobContainerClient(
const std::string& containerUri,
std::shared_ptr<SharedKeyCredential> credential,
const BlobContainerClientOptions& options = BlobContainerClientOptions());
// token auth
/**
* @brief Initialize a new instance of BlobContainerClient.
*
* @param containerUri A uri
* referencing the blob container that includes the name of the account and the name of the
* container.
* @param credential The token credential used to sign requests.
* @param options Optional client options that define the transport pipeline policies for
* authentication, retries, etc., that are applied to every request.
*/
explicit BlobContainerClient(
const std::string& containerUri,
std::shared_ptr<TokenCredential> credential,
const BlobContainerClientOptions& options = BlobContainerClientOptions());
// anonymous/SAS/customized pipeline auth
/**
* @brief Initialize a new instance of BlobContainerClient.
*
* @param containerUri A uri
* referencing the blob that includes the name of the account and the name of the container, and
* possibly also a SAS token.
* @param options Optional client
* options that define the transport pipeline policies for authentication, retries, etc., that
* are applied to every request.
*/
explicit BlobContainerClient(
const std::string& containerUri,
const BlobContainerClientOptions& options = BlobContainerClientOptions());
/**
* @brief Create a new BlobClient object by appending blobName to the end of uri. The
* new BlobClient uses the same request policy pipeline as this BlobContainerClient.
*
* @param blobName The name of the blob.
* @return A new BlobClient instance.
*/
BlobClient GetBlobClient(const std::string& blobName) const;
/**
* @brief Create a new BlockBlobClient object by appending blobName to the end of uri.
* The new BlockBlobClient uses the same request policy pipeline as this BlobContainerClient.
*
* @param blobName The name of the blob.
* @return A new BlockBlobClient instance.
*/
BlockBlobClient GetBlockBlobClient(const std::string& blobName) const;
/**
* @brief Create a new AppendBlobClient object by appending blobName to the end of uri.
* The new AppendBlobClient uses the same request policy pipeline as this BlobContainerClient.
*
* @param blobName The name of the blob.
* @return A new AppendBlobClient instance.
*/
AppendBlobClient GetAppendBlobClient(const std::string& blobName) const;
/**
* @brief Create a new PageBlobClient object by appending blobName to the end of uri.
* The new PageBlobClient uses the same request policy pipeline as this BlobContainerClient.
*
* @param blobName The name of the blob.
* @return A new PageBlobClient instance.
*/
PageBlobClient GetPageBlobClient(const std::string& blobName) const;
/**
* @brief Gets the container's primary uri endpoint.
*
* @return The
* container's primary uri endpoint.
*/
std::string GetUri() const { return m_containerUrl.ToString(); }
/**
* @brief Creates a new container under the specified account. If the container with the
* same name already exists, the operation fails.
*
* @param options Optional
* parameters to execute this function.
* @return A BlobContainerInfo describing the newly
* created blob container.
*/
BlobContainerInfo Create(
const CreateBlobContainerOptions& options = CreateBlobContainerOptions()) const;
/**
* @brief Marks the specified container for deletion. The container and any blobs
* contained within it are later deleted during garbage collection.
*
* @param
* options Optional parameters to execute this function.
* @return A BasicResponse if
* successful.
*/
BasicResponse Delete(
const DeleteBlobContainerOptions& options = DeleteBlobContainerOptions()) const;
/**
* @brief Returns all user-defined metadata and system properties for the specified
* container. The data returned does not include the container's list of blobs.
*
* @param options Optional parameters to execute this function.
* @return A
* BlobContainerProperties describing the container and its properties.
*/
BlobContainerProperties GetProperties(
const GetBlobContainerPropertiesOptions& options
= GetBlobContainerPropertiesOptions()) const;
/**
* @brief Sets one or more user-defined name-value pairs for the specified container.
*
* @param metadata Custom metadata to set for this container.
* @param options
* Optional parameters to execute this function.
* @return A BlobContainerInfo if
* successful.
*/
BlobContainerInfo SetMetadata(
std::map<std::string, std::string> metadata,
SetBlobContainerMetadataOptions options = SetBlobContainerMetadataOptions()) const;
/**
* @brief Returns a single segment of blobs in this container, starting from the
* specified Marker, Use an empty Marker to start enumeration from the beginning and the
* NextMarker if it's not empty to make subsequent calls to ListBlobs to continue enumerating
* the blobs segment by segment. Blobs are ordered lexicographically by name. A Delimiter can be
* used to traverse a virtual hierarchy of blobs as though it were a file system.
*
* @param options Optional parameters to execute this function.
* @return A
* BlobsFlatSegment describing a segment of the blobs in the container.
*/
BlobsFlatSegment ListBlobs(const ListBlobsOptions& options = ListBlobsOptions()) const;
private:

View File

@ -19,16 +19,15 @@ namespace Azure { namespace Storage { namespace Blobs {
struct ListBlobContainersOptions
{
Azure::Core::Context Context;
std::string Prefix;
std::string Marker;
int MaxResults = 0;
Azure::Core::Nullable<std::string> Prefix;
Azure::Core::Nullable<std::string> Marker;
Azure::Core::Nullable<int32_t> MaxResults;
std::vector<ListBlobContainersIncludeOption> Include;
};
struct GetUserDelegationKeyOptions
{
Azure::Core::Context Context;
std::string StartsOn;
};
struct BlobContainerClientOptions
@ -39,15 +38,15 @@ namespace Azure { namespace Storage { namespace Blobs {
struct CreateBlobContainerOptions
{
Azure::Core::Context Context;
PublicAccessType AccessType = PublicAccessType::Private;
Azure::Core::Nullable<PublicAccessType> AccessType;
std::map<std::string, std::string> Metadata;
};
struct DeleteBlobContainerOptions
{
Azure::Core::Context Context;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
};
struct GetBlobContainerPropertiesOptions
@ -58,16 +57,16 @@ namespace Azure { namespace Storage { namespace Blobs {
struct SetBlobContainerMetadataOptions
{
Azure::Core::Context Context;
std::string IfModifiedSince;
Azure::Core::Nullable<std::string> IfModifiedSince;
};
struct ListBlobsOptions
{
Azure::Core::Context Context;
std::string Prefix;
std::string Delimiter;
std::string Marker;
int MaxResults = 0;
Azure::Core::Nullable<std::string> Prefix;
Azure::Core::Nullable<std::string> Delimiter;
Azure::Core::Nullable<std::string> Marker;
Azure::Core::Nullable<int32_t> MaxResults;
std::vector<ListBlobsIncludeItem> Include;
};
@ -91,10 +90,10 @@ namespace Azure { namespace Storage { namespace Blobs {
struct GetBlobPropertiesOptions
{
Azure::Core::Context Context;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct SetBlobHttpHeadersOptions
@ -106,81 +105,81 @@ namespace Azure { namespace Storage { namespace Blobs {
std::string ContentMD5;
std::string CacheControl;
std::string ContentDisposition;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct SetBlobMetadataOptions
{
Azure::Core::Context Context;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct SetAccessTierOptions
{
Azure::Core::Context Context;
Blobs::RehydratePriority RehydratePriority = Blobs::RehydratePriority::Unknown;
Azure::Core::Nullable<Blobs::RehydratePriority> RehydratePriority;
};
struct StartCopyFromUriOptions
{
Azure::Core::Context Context;
std::map<std::string, std::string> Metadata;
std::string LeaseId;
std::string SourceLeaseId;
AccessTier Tier = AccessTier::Unknown;
Blobs::RehydratePriority RehydratePriority = Blobs::RehydratePriority::Unknown;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
std::string SourceIfModifiedSince;
std::string SourceIfUnmodifiedSince;
std::string SourceIfMatch;
std::string SourceIfNoneMatch;
Azure::Core::Nullable<std::string> LeaseId;
Azure::Core::Nullable<std::string> SourceLeaseId;
Azure::Core::Nullable<AccessTier> Tier = AccessTier::Unknown;
Azure::Core::Nullable<Blobs::RehydratePriority> RehydratePriority;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
Azure::Core::Nullable<std::string> SourceIfModifiedSince;
Azure::Core::Nullable<std::string> SourceIfUnmodifiedSince;
Azure::Core::Nullable<std::string> SourceIfMatch;
Azure::Core::Nullable<std::string> SourceIfNoneMatch;
};
struct AbortCopyFromUriOptions
{
Azure::Core::Context Context;
std::string LeaseId;
Azure::Core::Nullable<std::string> LeaseId;
};
struct DownloadBlobOptions
{
Azure::Core::Context Context;
uint64_t Offset = std::numeric_limits<uint64_t>::max(); // max means the whole blob
uint64_t Length = 0; // 0 means till the end
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<int64_t> Offset;
Azure::Core::Nullable<int64_t> Length;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct CreateSnapshotOptions
{
Azure::Core::Context Context;
std::map<std::string, std::string> Metadata;
std::string LeaseId;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> LeaseId;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct DeleteBlobOptions
{
Azure::Core::Context Context;
DeleteSnapshotsOption DeleteSnapshots = DeleteSnapshotsOption::None;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<DeleteSnapshotsOption> DeleteSnapshots;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct UndeleteBlobOptions
@ -191,36 +190,36 @@ namespace Azure { namespace Storage { namespace Blobs {
struct UploadBlobOptions
{
Azure::Core::Context Context;
std::string ContentMD5;
std::string ContentCRC64;
Azure::Core::Nullable<std::string> ContentMD5;
Azure::Core::Nullable<std::string> ContentCRC64;
BlobHttpHeaders Properties;
std::map<std::string, std::string> Metadata;
AccessTier Tier = AccessTier::Unknown;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<AccessTier> Tier;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct StageBlockOptions
{
Azure::Core::Context Context;
std::string ContentMD5;
std::string ContentCRC64;
Azure::Core::Nullable<std::string> ContentMD5;
Azure::Core::Nullable<std::string> ContentCRC64;
};
struct StageBlockFromUriOptions
{
Azure::Core::Context Context;
uint64_t SourceOffset = std::numeric_limits<uint64_t>::max();
uint64_t SourceLength = 0;
std::string ContentMD5;
std::string ContentCRC64;
std::string LeaseId;
std::string SourceIfModifiedSince;
std::string SourceIfUnmodifiedSince;
std::string SourceIfMatch;
std::string SourceIfNoneMatch;
Azure::Core::Nullable<int64_t> SourceOffset;
Azure::Core::Nullable<int64_t> SourceLength;
Azure::Core::Nullable<std::string> ContentMD5;
Azure::Core::Nullable<std::string> ContentCRC64;
Azure::Core::Nullable<std::string> LeaseId;
Azure::Core::Nullable<std::string> SourceIfModifiedSince;
Azure::Core::Nullable<std::string> SourceIfUnmodifiedSince;
Azure::Core::Nullable<std::string> SourceIfMatch;
Azure::Core::Nullable<std::string> SourceIfNoneMatch;
};
struct CommitBlockListOptions
@ -228,21 +227,21 @@ namespace Azure { namespace Storage { namespace Blobs {
Azure::Core::Context Context;
BlobHttpHeaders Properties;
std::map<std::string, std::string> Metadata;
AccessTier Tier = AccessTier::Unknown;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<AccessTier> Tier;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct GetBlockListOptions
{
Azure::Core::Context Context;
BlockListTypeOption ListType = BlockListTypeOption::All;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<BlockListTypeOption> ListType;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct CreateAppendBlobOptions
@ -250,119 +249,119 @@ namespace Azure { namespace Storage { namespace Blobs {
Azure::Core::Context Context;
BlobHttpHeaders Properties;
std::map<std::string, std::string> Metadata;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct AppendBlockOptions
{
Azure::Core::Context Context;
std::string ContentMD5;
std::string ContentCRC64;
std::string LeaseId;
uint64_t MaxSize = std::numeric_limits<uint64_t>::max();
uint64_t AppendPosition = std::numeric_limits<uint64_t>::max();
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> ContentMD5;
Azure::Core::Nullable<std::string> ContentCRC64;
Azure::Core::Nullable<std::string> LeaseId;
Azure::Core::Nullable<int64_t> MaxSize;
Azure::Core::Nullable<int64_t> AppendPosition;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct AppendBlockFromUriOptions
{
Azure::Core::Context Context;
uint64_t SourceOffset = std::numeric_limits<uint64_t>::max();
uint64_t SourceLength = 0;
std::string ContentMD5;
std::string ContentCRC64;
std::string LeaseId;
uint64_t MaxSize = std::numeric_limits<uint64_t>::max();
uint64_t AppendPosition = std::numeric_limits<uint64_t>::max();
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<int64_t> SourceOffset;
Azure::Core::Nullable<int64_t> SourceLength;
Azure::Core::Nullable<std::string> ContentMD5;
Azure::Core::Nullable<std::string> ContentCRC64;
Azure::Core::Nullable<std::string> LeaseId;
Azure::Core::Nullable<int64_t> MaxSize;
Azure::Core::Nullable<int64_t> AppendPosition;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct CreatePageBlobOptions
{
Azure::Core::Context Context;
uint64_t SequenceNumber = 0;
Azure::Core::Nullable<int64_t> SequenceNumber;
BlobHttpHeaders Properties;
std::map<std::string, std::string> Metadata;
AccessTier Tier = AccessTier::Unknown;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<AccessTier> Tier;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct UploadPagesOptions
{
Azure::Core::Context Context;
std::string ContentMD5;
std::string ContentCRC64;
std::string LeaseId;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> ContentMD5;
Azure::Core::Nullable<std::string> ContentCRC64;
Azure::Core::Nullable<std::string> LeaseId;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct UploadPagesFromUriOptions
{
Azure::Core::Context Context;
std::string ContentMD5;
std::string ContentCRC64;
std::string LeaseId;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> ContentMD5;
Azure::Core::Nullable<std::string> ContentCRC64;
Azure::Core::Nullable<std::string> LeaseId;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct ClearPagesOptions
{
Azure::Core::Context Context;
std::string LeaseId;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> LeaseId;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct ResizePageBlobOptions
{
Azure::Core::Context Context;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct GetPageRangesOptions
{
Azure::Core::Context Context;
std::string PreviousSnapshot;
std::string PreviousSnapshotUrl;
uint64_t Offset = 0;
uint64_t Length = 0;
std::string LeaseId;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> PreviousSnapshot;
Azure::Core::Nullable<std::string> PreviousSnapshotUrl;
Azure::Core::Nullable<int64_t> Offset;
Azure::Core::Nullable<int64_t> Length;
Azure::Core::Nullable<std::string> LeaseId;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
struct IncrementalCopyPageBlobOptions
{
Azure::Core::Context Context;
std::string IfModifiedSince;
std::string IfUnmodifiedSince;
std::string IfMatch;
std::string IfNoneMatch;
Azure::Core::Nullable<std::string> IfModifiedSince;
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
Azure::Core::Nullable<std::string> IfMatch;
Azure::Core::Nullable<std::string> IfNoneMatch;
};
}}} // namespace Azure::Storage::Blobs

View File

@ -4,9 +4,9 @@
#pragma once
#include "blob_options.hpp"
#include "blobs/blob_container_client.hpp"
#include "common/storage_credential.hpp"
#include "common/storage_url_builder.hpp"
#include "blobs/blob_container_client.hpp"
#include "internal/protocol/blob_rest_client.hpp"
#include <memory>
@ -14,38 +14,111 @@
namespace Azure { namespace Storage { namespace Blobs {
/**
* The BlobServiceClient allows you to manipulate Azure Storage service resources and blob
* containers. The storage account provides the top-level namespace for the Blob service.
*/
class BlobServiceClient {
public:
// connection string
/**
* @brief Initialize a new instance of BlobServiceClient.
*
* @param connectionString A connection string includes the authentication information required
* for your application to access data in an Azure Storage account at runtime.
* @param options Optional client options that define the transport pipeline policies for
* authentication, retries, etc., that are applied to every request.
* @return A new BlobServiceClient instance.
*/
static BlobServiceClient CreateFromConnectionString(
const std::string& connectionString,
const BlobServiceClientOptions& options = BlobServiceClientOptions());
// shared key auth
/**
* @brief Initialize a new instance of BlobServiceClient.
*
* @param serviceUri A uri
* referencing the blob that includes the name of the account.
* @param credential The shared key credential used to sign
* requests.
* @param options Optional client options that define the transport pipeline
* policies for authentication, retries, etc., that are applied to every request.
*/
explicit BlobServiceClient(
const std::string& serviceUri,
std::shared_ptr<SharedKeyCredential> credential,
const BlobServiceClientOptions& options = BlobServiceClientOptions());
// token auth
/**
* @brief Initialize a new instance of BlobServiceClient.
*
* @param serviceUri A uri
* referencing the blob that includes the name of the account.
* @param credential The token credential used to sign requests.
* @param options Optional client options that define the transport pipeline policies for
* authentication, retries, etc., that are applied to every request.
*/
explicit BlobServiceClient(
const std::string& serviceUri,
std::shared_ptr<TokenCredential> credential,
const BlobServiceClientOptions& options = BlobServiceClientOptions());
// anonymous/SAS/customized pipeline auth
/**
* @brief Initialize a new instance of BlobServiceClient.
*
* @param serviceUri A uri
* referencing the blob that includes the name of the account, and possibly also a SAS token.
* @param options Optional client
* options that define the transport pipeline policies for authentication, retries, etc., that
* are applied to every request.
*/
explicit BlobServiceClient(
const std::string& serviceUri,
const BlobServiceClientOptions& options = BlobServiceClientOptions());
/**
* @brief Creates a new BlobContainerClient object with the same uri as this BlobServiceClient.
* The new BlobContainerClient uses the same request policy pipeline as this BlobServiceClient.
*
*
* @return A new BlobContainerClient instance.
*/
BlobContainerClient GetBlobContainerClient(const std::string& containerName) const;
/**
* @brief Gets the blob service's primary uri endpoint.
*
* @return the blob
* service's primary uri endpoint.
*/
std::string GetUri() const { return m_serviceUrl.ToString(); }
/**
* @brief Returns a single segment of blob containers in the storage account, starting
* from the specified Marker. Use an empty Marker to start enumeration from the beginning and
* the NextMarker if it's not empty to make subsequent calls to ListBlobContainersSegment to
* continue enumerating the containers segment by segment. Containers are ordered
* lexicographically by name.
*
* @param options Optional parameters to execute this function.
* @return A
* ListContainersSegment describing segment of the blob containers in the storage account.
*/
ListContainersSegment ListBlobContainersSegment(
const ListBlobContainersOptions& options = ListBlobContainersOptions()) const;
/**
* @brief Retrieves a key that can be used to delegate Active Directory authorization to
* shared access signatures.
*
* @param startsOn Start time for the key's validity. The time should be specified in UTC.
* @param expiresOn Expiration of the key's validity.
* The time should be specified in UTC.
* @param options Optional parameters to execute
* this function.
* @return A deserialized UserDelegationKey instance.
*/
UserDelegationKey GetUserDelegationKey(
const std::string& startsOn,
const std::string& expiresOn,
const GetUserDelegationKeyOptions& options = GetUserDelegationKeyOptions()) const;

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,8 @@ namespace Azure { namespace Storage { namespace Blobs {
struct PageRange
{
uint64_t Offset;
uint64_t Length;
int64_t Offset;
int64_t Length;
};
struct PageRangesInfo
@ -23,69 +23,202 @@ namespace Azure { namespace Storage { namespace Blobs {
std::string RequestId;
std::string Date;
std::string Version;
std::string ClientRequestId;
Azure::Core::Nullable<std::string> ClientRequestId;
std::string ETag;
std::string LastModified;
uint64_t BlobContentLength = 0;
int64_t BlobContentLength = 0;
std::vector<PageRange> PageRanges;
std::vector<PageRange> ClearRanges;
};
/**
* The PageBlobClient allows you to manipulate Azure Storage page blobs.
*
* Page blobs are a collection of 512-byte pages optimized for random read and write operations.
* To create a page blob, you initialize the page blob and specify the maximum size the page blob
* will grow. To add or update the contents of a page blob, you write a page or pages by
* specifying an offset and a range that align to 512-byte page boundaries. Writes to page blobs
* happen in-place and are immediately committed to the blob.
*/
class PageBlobClient : public BlobClient {
public:
// connection string
/**
* @brief Initialize a new instance of PageBlobClient.
*
* @param connectionString A connection string includes the authentication information required
* for your application to access data in an Azure Storage account at runtime.
* @param containerName The name of the container containing this blob.
* @param blobName The name of this blob.
* @param options Optional client options that define the transport pipeline policies for
* authentication, retries, etc., that are applied to every request.
* @return A new PageBlobClient instance.
*/
static PageBlobClient CreateFromConnectionString(
const std::string& connectionString,
const std::string& containerName,
const std::string& blobName,
const PageBlobClientOptions& options = PageBlobClientOptions());
// shared key auth
/**
* @brief Initialize a new instance of PageBlobClient.
*
* @param blobUri A uri
* referencing the blob that includes the name of the account, the name of the container, and
* the name of the blob.
* @param credential The shared key credential used to sign
* requests.
* @param options Optional client options that define the transport pipeline
* policies for authentication, retries, etc., that are applied to every request.
*/
explicit PageBlobClient(
const std::string& blobUri,
std::shared_ptr<SharedKeyCredential> credential,
const PageBlobClientOptions& options = PageBlobClientOptions());
// token auth
/**
* @brief Initialize a new instance of PageBlobClient.
*
* @param blobUri A uri
* referencing the blob that includes the name of the account, the name of the container, and
* the name of the blob.
* @param credential The token credential used to sign requests.
* @param options Optional client options that define the transport pipeline policies for
* authentication, retries, etc., that are applied to every request.
*/
explicit PageBlobClient(
const std::string& blobUri,
std::shared_ptr<TokenCredential> credential,
const PageBlobClientOptions& options = PageBlobClientOptions());
// anonymous/SAS/customized pipeline auth
/**
* @brief Initialize a new instance of PageBlobClient.
*
* @param blobUri A uri
* referencing the blob that includes the name of the account, the name of the container, and
* the name of the blob, and possibly also a SAS token.
* @param options Optional client
* options that define the transport pipeline policies for authentication, retries, etc., that
* are applied to every request.
*/
explicit PageBlobClient(
const std::string& blobUri,
const PageBlobClientOptions& options = PageBlobClientOptions());
/**
* @brief Initializes a new instance of the PageBlobClient class with an identical uri
* source but the specified snapshot timestamp.
*
* @param snapshot The snapshot
* identifier.
* @return A new PageBlobClient instance.
* @remarks Pass empty string to remove the snapshot returning the base blob.
*/
PageBlobClient WithSnapshot(const std::string& snapshot) const;
/**
* @brief Creates a new page blob of the specified size. The content of any existing
* blob is overwritten with the newly initialized page blob.
*
* @param
* blobContentLength Specifies the maximum size for the page blob. The size must be aligned to a
* 512-byte boundary.
* @param options Optional parameters to execute this function.
* @return A BlobContentInfo describing the newly created page blob.
*/
BlobContentInfo Create(
uint64_t blobContentLength,
int64_t blobContentLength,
const CreatePageBlobOptions& options = CreatePageBlobOptions());
/**
* @brief Writes content to a range of pages in a page blob, starting at offset.
*
* @param content A BodyStream containing the content of the pages to upload.
* @param offset Specifies the starting offset for the content to be written as a page. Given
* that pages must be aligned with 512-byte boundaries, the start offset must be a modulus of
* 512.
* @param options Optional parameters to execute this function.
* @return A
* PageInfo describing the state of the updated pages.
*/
PageInfo UploadPages(
std::unique_ptr<Azure::Core::Http::BodyStream> content,
uint64_t offset,
int64_t offset,
const UploadPagesOptions& options = UploadPagesOptions());
/**
* @brief Writes a range of pages to a page blob where the contents are read from a
* uri.
*
* @param sourceUri Specifies the uri of the source blob. The value may be a
* uri of up to 2 KB in length that specifies a blob. The source blob must either be public or
* must be authenticated via a shared access signature. If the source blob is public, no
* authentication is required to perform the operation.
* @param sourceOffset Only upload a
* part of the blob in the sourceUri from the specified offset.
* @param sourceLength Only
* upload specified length of the blob in the sourceUri.
* @param destinationOffset
* Specifies the starting offset for the content to be written. Given that pages must be aligned
* with 512-byte boundaries, the start offset must be a modulus of 512.
* @param options
* Optional parameters to execute this function.
* @return A PageInfo describing the state
* of the updated pages.
*/
PageInfo UploadPagesFromUri(
std::string sourceUri,
uint64_t sourceOffset,
uint64_t sourceLength,
uint64_t destinationoffset,
int64_t sourceOffset,
int64_t sourceLength,
int64_t destinationoffset,
const UploadPagesFromUriOptions& options = UploadPagesFromUriOptions());
/**
* @brief Clears one or more pages from the page blob, as specificed by offset and length.
*
* @param offset Specifies the starting offset for the content to be cleared. Given that pages
* must be aligned with 512-byte boundaries, the start offset must be a modulus of 512.
* @param length Specifies the length of the content to be cleared.
* @param options Optional parameters to execute this function.
* @return A PageInfo describing the state of the updated pages.
*/
PageInfo ClearPages(
uint64_t offset,
uint64_t length,
int64_t offset,
int64_t length,
const ClearPagesOptions& options = ClearPagesOptions());
/**
* @brief Resizes the page blob to the specified size (which must be a multiple of 512). If the
* specified value is less than the current size of the blob, then all pages above the specified
* value are cleared.
*
* @param blobContentLength Specifies the maximum size for the page blob. The size must be
* aligned to a 512-byte boundary.
* @param options Optional parameters to execute this function.
* @return A PageBlobInfo describing the resized page blob.
*/
PageBlobInfo Resize(
uint64_t blobContentLength,
int64_t blobContentLength,
const ResizePageBlobOptions& options = ResizePageBlobOptions());
/**
* @brief Returns the list of valid page ranges for a page blob or snapshot of a page blob.
*
* @param options Optional parameters to execute this function.
* @return A PageRangesInfo describing the valid page ranges for this blob.
*/
PageRangesInfo GetPageRanges(const GetPageRangesOptions& options = GetPageRangesOptions());
/**
* @brief Starts copying a snapshot of the sourceUri page blob to this page blob. The snapshot
* is copied such that only the differential changes between the previously copied snapshot
* are transferred to the destination. The copied snapshots are complete copies of the original
* snapshot and can be read or copied from as usual.
*
* @param sourceUri Specifies the to the source page blob as a uri up to 2 KB in length. The
* source blob must either be public or must be authenticated via a shared access signature.
* @param options Optional parameters to execute this function.
* @return A BlobCopyInfo describing the state of the copy operation.
*/
BlobCopyInfo StartCopyIncremental(
const std::string& sourceUri,
const IncrementalCopyPageBlobOptions& options = IncrementalCopyPageBlobOptions());

View File

@ -38,15 +38,17 @@ void BlobsGettingStarted()
auto blobDownloadContent = blobClient.Download();
blobContent.resize(static_cast<std::size_t>(blobDownloadContent.BodyStream->Length()));
// read body stream until it returns 0 (all content read)
auto readTotal = uint64_t();
do
std::size_t offset = 0;
while (true)
{
auto offset = uint64_t();
readTotal = blobDownloadContent.BodyStream->Read(
reinterpret_cast<uint8_t*>(&blobContent[(size_t)offset]), blobContent.length());
offset += readTotal;
} while (readTotal != 0);
auto bytesRead = blobDownloadContent.BodyStream->Read(
reinterpret_cast<uint8_t*>(&blobContent[offset]), blobContent.length() - offset);
offset += static_cast<std::size_t>(bytesRead);
if (bytesRead == 0 || offset == blobContent.length())
{
break;
}
}
std::cout << blobContent << std::endl;

View File

@ -95,8 +95,19 @@ namespace Azure { namespace Storage { namespace Blobs {
{
BlobRestClient::AppendBlob::AppendBlockFromUriOptions protocolLayerOptions;
protocolLayerOptions.SourceUri = sourceUri;
protocolLayerOptions.SourceRange
= std::make_pair(options.SourceOffset, options.SourceOffset + options.SourceLength - 1);
if (options.SourceOffset.HasValue() && options.SourceLength.HasValue())
{
protocolLayerOptions.SourceRange = std::make_pair(
options.SourceOffset.GetValue(),
options.SourceOffset.GetValue() + options.SourceLength.GetValue() - 1);
}
else if (options.SourceOffset.HasValue())
{
protocolLayerOptions.SourceRange = std::make_pair(
options.SourceOffset.GetValue(),
std::numeric_limits<
std::remove_reference_t<decltype(options.SourceOffset.GetValue())>>::max());
}
protocolLayerOptions.ContentMD5 = options.ContentMD5;
protocolLayerOptions.ContentCRC64 = options.ContentCRC64;
protocolLayerOptions.LeaseId = options.LeaseId;

View File

@ -105,26 +105,19 @@ namespace Azure { namespace Storage { namespace Blobs {
return newClient;
}
FlattenedDownloadProperties BlobClient::Download(const DownloadBlobOptions& options) const
BlobDownloadInfo BlobClient::Download(const DownloadBlobOptions& options) const
{
BlobRestClient::Blob::DownloadOptions protocolLayerOptions;
if (options.Offset != std::numeric_limits<decltype(options.Offset)>::max())
if (options.Offset.HasValue() && options.Length.HasValue())
{
if (options.Length == 0)
{
protocolLayerOptions.Range
= std::make_pair(options.Offset, std::numeric_limits<decltype(options.Offset)>::max());
}
else
{
protocolLayerOptions.Range
= std::make_pair(options.Offset, options.Offset + options.Length - 1);
}
protocolLayerOptions.Range = std::make_pair(
options.Offset.GetValue(), options.Offset.GetValue() + options.Length.GetValue() - 1);
}
else
else if (options.Offset.HasValue())
{
protocolLayerOptions.Range
= std::make_pair(std::numeric_limits<uint64_t>::max(), uint64_t(0));
protocolLayerOptions.Range = std::make_pair(
options.Offset.GetValue(),
std::numeric_limits<std::remove_reference_t<decltype(options.Offset.GetValue())>>::max());
}
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;

View File

@ -112,11 +112,12 @@ namespace Azure { namespace Storage { namespace Blobs {
}
UserDelegationKey BlobServiceClient::GetUserDelegationKey(
const std::string& startsOn,
const std::string& expiresOn,
const GetUserDelegationKeyOptions& options) const
{
BlobRestClient::Service::GetUserDelegationKeyOptions protocolLayerOptions;
protocolLayerOptions.StartsOn = options.StartsOn;
protocolLayerOptions.StartsOn = startsOn;
protocolLayerOptions.ExpiresOn = expiresOn;
return BlobRestClient::Service::GetUserDelegationKey(
options.Context, *m_pipeline, m_serviceUrl.ToString(), protocolLayerOptions);

View File

@ -98,23 +98,18 @@ namespace Azure { namespace Storage { namespace Blobs {
BlobRestClient::BlockBlob::StageBlockFromUriOptions protocolLayerOptions;
protocolLayerOptions.BlockId = blockId;
protocolLayerOptions.SourceUri = sourceUri;
if (options.SourceOffset != std::numeric_limits<decltype(options.SourceOffset)>::max())
if (options.SourceOffset.HasValue() && options.SourceLength.HasValue())
{
if (options.SourceLength == 0)
{
protocolLayerOptions.SourceRange = std::make_pair(
options.SourceOffset, std::numeric_limits<decltype(options.SourceOffset)>::max());
}
else
{
protocolLayerOptions.SourceRange
= std::make_pair(options.SourceOffset, options.SourceOffset + options.SourceLength - 1);
}
protocolLayerOptions.SourceRange = std::make_pair(
options.SourceOffset.GetValue(),
options.SourceOffset.GetValue() + options.SourceLength.GetValue() - 1);
}
else
else if (options.SourceOffset.HasValue())
{
protocolLayerOptions.SourceRange
= std::make_pair(std::numeric_limits<uint64_t>::max(), uint64_t(0));
protocolLayerOptions.SourceRange = std::make_pair(
options.SourceOffset.GetValue(),
std::numeric_limits<
std::remove_reference_t<decltype(options.SourceOffset.GetValue())>>::max());
}
protocolLayerOptions.ContentMD5 = options.ContentMD5;
protocolLayerOptions.ContentCRC64 = options.ContentCRC64;

View File

@ -56,7 +56,7 @@ namespace Azure { namespace Storage { namespace Blobs {
}
BlobContentInfo PageBlobClient::Create(
uint64_t blobContentLength,
int64_t blobContentLength,
const CreatePageBlobOptions& options)
{
BlobRestClient::PageBlob::CreateOptions protocolLayerOptions;
@ -75,7 +75,7 @@ namespace Azure { namespace Storage { namespace Blobs {
PageInfo PageBlobClient::UploadPages(
std::unique_ptr<Azure::Core::Http::BodyStream> content,
uint64_t offset,
int64_t offset,
const UploadPagesOptions& options)
{
BlobRestClient::PageBlob::UploadPagesOptions protocolLayerOptions;
@ -95,9 +95,9 @@ namespace Azure { namespace Storage { namespace Blobs {
PageInfo PageBlobClient::UploadPagesFromUri(
std::string sourceUri,
uint64_t sourceOffset,
uint64_t sourceLength,
uint64_t destinationoffset,
int64_t sourceOffset,
int64_t sourceLength,
int64_t destinationoffset,
const UploadPagesFromUriOptions& options)
{
BlobRestClient::PageBlob::UploadPagesFromUriOptions protocolLayerOptions;
@ -118,8 +118,8 @@ namespace Azure { namespace Storage { namespace Blobs {
}
PageInfo PageBlobClient::ClearPages(
uint64_t offset,
uint64_t length,
int64_t offset,
int64_t length,
const ClearPagesOptions& options)
{
BlobRestClient::PageBlob::ClearPagesOptions protocolLayerOptions;
@ -134,7 +134,7 @@ namespace Azure { namespace Storage { namespace Blobs {
}
PageBlobInfo PageBlobClient::Resize(
uint64_t blobContentLength,
int64_t blobContentLength,
const ResizePageBlobOptions& options)
{
BlobRestClient::PageBlob::ResizeOptions protocolLayerOptions;
@ -152,8 +152,11 @@ namespace Azure { namespace Storage { namespace Blobs {
BlobRestClient::PageBlob::GetPageRangesOptions protocolLayerOptions;
protocolLayerOptions.PreviousSnapshot = options.PreviousSnapshot;
protocolLayerOptions.PreviousSnapshotUrl = options.PreviousSnapshotUrl;
protocolLayerOptions.Range
= std::make_pair(options.Offset, options.Offset + options.Length - 1);
if (options.Offset.HasValue() && options.Length.HasValue())
{
protocolLayerOptions.Range = std::make_pair(
options.Offset.GetValue(), options.Offset.GetValue() + options.Length.GetValue() - 1);
}
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.IfMatch = options.IfMatch;

View File

@ -9,7 +9,7 @@
namespace Azure { namespace Storage {
StorageError StorageError::CreateFromResponse(
/* const */ std::unique_ptr<Azure::Core::Http::Response> response)
std::unique_ptr<Azure::Core::Http::Response> response)
{
auto bodyStream = response->GetBodyStream();
auto bodyBuffer = std::make_unique<std::vector<uint8_t>>();

View File

@ -16,7 +16,7 @@ add_executable (
append_blob_client_test.cpp
page_blob_client_test.hpp
page_blob_client_test.cpp
main.cpp
main.cpp
)
target_link_libraries(azure-storage-test PRIVATE azure-storage)

View File

@ -43,14 +43,15 @@ namespace Azure { namespace Storage { namespace Test {
appendBlobClient.Create(m_blobUploadOptions);
auto properties = appendBlobClient.GetProperties();
EXPECT_EQ(properties.CommittedBlockCount, 0);
EXPECT_TRUE(properties.CommittedBlockCount.HasValue());
EXPECT_EQ(properties.CommittedBlockCount.GetValue(), 0);
EXPECT_EQ(properties.ContentLength, 0);
appendBlobClient.AppendBlock(
Azure::Storage::CreateMemoryStream(m_blobContent.data(), m_blobContent.size()));
properties = appendBlobClient.GetProperties();
EXPECT_EQ(properties.CommittedBlockCount, 1);
EXPECT_EQ(properties.ContentLength, m_blobContent.size());
EXPECT_EQ(properties.CommittedBlockCount.GetValue(), 1);
EXPECT_EQ(properties.ContentLength, static_cast<int64_t>(m_blobContent.size()));
Azure::Storage::Blobs::AppendBlockOptions options;
options.AppendPosition = 1_MB;

View File

@ -109,7 +109,7 @@ namespace Azure { namespace Storage { namespace Test {
;
EXPECT_FALSE(res.Version.empty());
EXPECT_FALSE(res.ServiceEndpoint.empty());
EXPECT_EQ(res.MaxResults, options.MaxResults);
EXPECT_EQ(res.MaxResults.GetValue(), options.MaxResults.GetValue());
EXPECT_EQ(res.Container, m_containerName);
options.Marker = res.NextMarker;
@ -123,7 +123,7 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_NE(blob.Tier, Azure::Storage::Blobs::AccessTier::Unknown);
listBlobs.insert(blob.Name);
}
} while (!options.Marker.empty());
} while (!options.Marker.GetValue().empty());
EXPECT_TRUE(
std::includes(listBlobs.begin(), listBlobs.end(), p1p2Blobs.begin(), p1p2Blobs.end()));
@ -137,7 +137,7 @@ namespace Azure { namespace Storage { namespace Test {
{
listBlobs.insert(blob.Name);
}
} while (!options.Marker.empty());
} while (!options.Marker.GetValue().empty());
EXPECT_TRUE(std::includes(listBlobs.begin(), listBlobs.end(), p1Blobs.begin(), p1Blobs.end()));
}
@ -162,8 +162,8 @@ namespace Azure { namespace Storage { namespace Test {
while (true)
{
auto res = m_blobContainerClient->ListBlobs(options);
EXPECT_EQ(res.Delimiter, options.Delimiter);
EXPECT_EQ(res.Prefix, options.Prefix);
EXPECT_EQ(res.Delimiter, options.Delimiter.GetValue());
EXPECT_EQ(res.Prefix, options.Prefix.GetValue());
for (const auto& blob : res.BlobItems)
{
listBlobs.insert(blob.Name);
@ -175,7 +175,10 @@ namespace Azure { namespace Storage { namespace Test {
else if (!res.BlobItems.empty())
{
options.Prefix = res.BlobItems[0].Name + delimiter;
options.Marker.clear();
if (options.Marker.HasValue())
{
options.Marker.Reset();
}
}
else
{

View File

@ -53,14 +53,14 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_FALSE(res.Date.empty());
EXPECT_FALSE(res.Version.empty());
EXPECT_FALSE(res.ServiceEndpoint.empty());
EXPECT_EQ(res.MaxResults, options.MaxResults);
EXPECT_EQ(res.MaxResults.GetValue(), options.MaxResults.GetValue());
options.Marker = res.NextMarker;
for (const auto& container : res.BlobContainerItems)
{
listContainers.insert(container.Name);
}
} while (!options.Marker.empty());
} while (!options.Marker.GetValue().empty());
EXPECT_TRUE(std::includes(
listContainers.begin(),
listContainers.end(),
@ -76,7 +76,7 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_FALSE(res.Date.empty());
EXPECT_FALSE(res.Version.empty());
EXPECT_FALSE(res.ServiceEndpoint.empty());
EXPECT_EQ(res.MaxResults, options.MaxResults);
EXPECT_EQ(res.MaxResults.GetValue(), options.MaxResults.GetValue());
options.Marker = res.NextMarker;
for (const auto& container : res.BlobContainerItems)
@ -86,7 +86,7 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_FALSE(container.LastModified.empty());
listContainers.insert(container.Name);
}
} while (!options.Marker.empty());
} while (!options.Marker.GetValue().empty());
EXPECT_TRUE(std::includes(
listContainers.begin(), listContainers.end(), p1Containers.begin(), p1Containers.end()));

View File

@ -34,7 +34,7 @@ namespace Azure { namespace Storage { namespace Test {
StandardStorageConnectionString(), m_containerName, m_blobName);
m_blockBlobClient
= std::make_shared<Azure::Storage::Blobs::BlockBlobClient>(std::move(blockBlobClient));
m_blobContent.resize((size_t)8_MB);
m_blobContent.resize(static_cast<std::size_t>(8_MB));
RandomBuffer(reinterpret_cast<char*>(&m_blobContent[0]), m_blobContent.size());
m_blobUploadOptions.Metadata = {{"key1", "V1"}, {"KEY2", "Value2"}};
m_blobUploadOptions.Properties.ContentType = "application/x-binary";
@ -62,6 +62,9 @@ namespace Azure { namespace Storage { namespace Test {
blockBlobClient.Delete();
EXPECT_THROW(blockBlobClient.Delete(), std::runtime_error);
blockBlobClient.Undelete();
blockBlobClient.Delete();
EXPECT_THROW(blockBlobClient.Delete(), std::runtime_error);
}
TEST_F(BlockBlobClientTest, UploadDownload)
@ -83,16 +86,17 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_EQ(
ReadBodyStream(res.BodyStream),
std::vector<uint8_t>(
m_blobContent.begin() + (size_t)options.Offset,
m_blobContent.begin() + (size_t)(options.Offset + options.Length)));
EXPECT_FALSE(res.ContentRange.empty());
m_blobContent.begin() + static_cast<std::size_t>(options.Offset.GetValue()),
m_blobContent.begin()
+ static_cast<std::size_t>(options.Offset.GetValue() + options.Length.GetValue())));
EXPECT_FALSE(res.ContentRange.GetValue().empty());
}
TEST_F(BlockBlobClientTest, CopyFromUri)
{
auto blobClient = m_blobContainerClient->GetBlobClient(RandomString());
auto res = blobClient.StartCopyFromUri(m_blockBlobClient->GetUri());
;
EXPECT_FALSE(res.RequestId.empty());
EXPECT_FALSE(res.Date.empty());
EXPECT_FALSE(res.Version.empty());
@ -102,6 +106,17 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_TRUE(
res.CopyStatus == Azure::Storage::Blobs::CopyStatus::Pending
|| res.CopyStatus == Azure::Storage::Blobs::CopyStatus::Success);
auto properties = blobClient.GetProperties();
EXPECT_EQ(properties.CopyId.GetValue(), res.CopyId);
EXPECT_FALSE(properties.CopySource.GetValue().empty());
EXPECT_TRUE(
properties.CopyStatus.GetValue() == Azure::Storage::Blobs::CopyStatus::Pending
|| properties.CopyStatus.GetValue() == Azure::Storage::Blobs::CopyStatus::Success);
EXPECT_FALSE(properties.CopyProgress.GetValue().empty());
if (properties.CopyStatus.GetValue() == Azure::Storage::Blobs::CopyStatus::Success)
{
EXPECT_FALSE(properties.CopyCompletionTime.GetValue().empty());
}
}
TEST_F(BlockBlobClientTest, SnapShot)
@ -156,15 +171,15 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_FALSE(res.LastModified.empty());
EXPECT_FALSE(res.CreationTime.empty());
EXPECT_EQ(res.Metadata, m_blobUploadOptions.Metadata);
EXPECT_EQ(res.ContentLength, m_blobContent.size());
EXPECT_EQ(res.ContentLength, static_cast<int64_t>(m_blobContent.size()));
EXPECT_EQ(res.ContentType, options.ContentType);
EXPECT_EQ(res.ContentEncoding, options.ContentEncoding);
EXPECT_EQ(res.ContentLanguage, options.ContentLanguage);
EXPECT_EQ(res.ContentMD5, options.ContentMD5);
EXPECT_EQ(res.CacheControl, options.CacheControl);
EXPECT_EQ(res.ContentDisposition, options.ContentDisposition);
EXPECT_EQ(res.Tier, Azure::Storage::Blobs::AccessTier::Cool);
EXPECT_FALSE(res.AccessTierChangeTime.empty());
EXPECT_EQ(res.Tier.GetValue(), Azure::Storage::Blobs::AccessTier::Cool);
EXPECT_FALSE(res.AccessTierChangeTime.GetValue().empty());
}
TEST_F(BlockBlobClientTest, StageBlock)
@ -189,10 +204,10 @@ namespace Azure { namespace Storage { namespace Test {
EXPECT_FALSE(res.Version.empty());
EXPECT_FALSE(res.ETag.empty());
EXPECT_FALSE(res.LastModified.empty());
EXPECT_EQ(res.ContentLength, block1Content.size());
EXPECT_EQ(res.ContentLength, static_cast<int64_t>(block1Content.size()));
ASSERT_FALSE(res.CommittedBlocks.empty());
EXPECT_EQ(res.CommittedBlocks[0].Name, blockId1);
EXPECT_EQ(res.CommittedBlocks[0].Size, block1Content.size());
EXPECT_EQ(res.CommittedBlocks[0].Size, static_cast<int64_t>(block1Content.size()));
EXPECT_TRUE(res.UncommittedBlocks.empty());
// TODO: StageBlockFromUri must be authorized with SAS, but we don't have SAS for now.

View File

@ -19,7 +19,7 @@ namespace Azure { namespace Storage { namespace Test {
StandardStorageConnectionString(), m_containerName, m_blobName);
m_pageBlobClient
= std::make_shared<Azure::Storage::Blobs::PageBlobClient>(std::move(pageBlobClient));
m_blobContent.resize((size_t)1_KB);
m_blobContent.resize(static_cast<std::size_t>(1_KB));
RandomBuffer(reinterpret_cast<char*>(&m_blobContent[0]), m_blobContent.size());
m_blobUploadOptions.Metadata = {{"key1", "V1"}, {"KEY2", "Value2"}};
m_blobUploadOptions.Properties.ContentType = "application/x-binary";
@ -53,16 +53,16 @@ namespace Azure { namespace Storage { namespace Test {
pageBlobClient.Create(0, m_blobUploadOptions);
EXPECT_EQ(pageBlobClient.GetProperties().ContentLength, 0);
pageBlobClient.Resize((size_t)2_KB);
EXPECT_EQ(pageBlobClient.GetProperties().ContentLength, 2_KB);
pageBlobClient.Resize((size_t)1_KB);
EXPECT_EQ(pageBlobClient.GetProperties().ContentLength, 1_KB);
pageBlobClient.Resize(static_cast<int64_t>(2_KB));
EXPECT_EQ(static_cast<uint64_t>(pageBlobClient.GetProperties().ContentLength), 2_KB);
pageBlobClient.Resize(static_cast<int64_t>(1_KB));
EXPECT_EQ(static_cast<uint64_t>(pageBlobClient.GetProperties().ContentLength), 1_KB);
}
TEST_F(PageBlobClientTest, UploadClear)
{
std::vector<uint8_t> blobContent;
blobContent.resize((size_t)4_KB);
blobContent.resize(static_cast<std::size_t>(4_KB));
RandomBuffer(reinterpret_cast<char*>(&blobContent[0]), blobContent.size());
auto pageBlobClient = Azure::Storage::Blobs::PageBlobClient::CreateFromConnectionString(
@ -71,12 +71,14 @@ namespace Azure { namespace Storage { namespace Test {
pageBlobClient.UploadPages(
Azure::Storage::CreateMemoryStream(blobContent.data(), blobContent.size()), 2_KB);
// |_|_|x|x| |x|x|_|_|
blobContent.insert(blobContent.begin(), (size_t)2_KB, '\x00');
blobContent.resize((size_t)8_KB, '\x00');
blobContent.insert(blobContent.begin(), static_cast<std::size_t>(2_KB), '\x00');
blobContent.resize(static_cast<std::size_t>(8_KB), '\x00');
pageBlobClient.ClearPages(2_KB, 1_KB);
// |_|_|_|x| |x|x|_|_|
std::fill(
blobContent.begin() + (size_t)2_KB, blobContent.begin() + (size_t)(2_KB + 1_KB), '\x00');
blobContent.begin() + static_cast<std::size_t>(2_KB),
blobContent.begin() + static_cast<std::size_t>(2_KB + 1_KB),
'\x00');
auto downloadContent = pageBlobClient.Download();
EXPECT_EQ(ReadBodyStream(downloadContent.BodyStream), blobContent);
@ -84,8 +86,8 @@ namespace Azure { namespace Storage { namespace Test {
auto pageRanges = pageBlobClient.GetPageRanges();
EXPECT_TRUE(pageRanges.ClearRanges.empty());
ASSERT_FALSE(pageRanges.PageRanges.empty());
EXPECT_EQ(pageRanges.PageRanges[0].Offset, 3_KB);
EXPECT_EQ(pageRanges.PageRanges[0].Length, 3_KB);
EXPECT_EQ(static_cast<uint64_t>(pageRanges.PageRanges[0].Offset), 3_KB);
EXPECT_EQ(static_cast<uint64_t>(pageRanges.PageRanges[0].Length), 3_KB);
Azure::Storage::Blobs::GetPageRangesOptions options;
options.Offset = 4_KB;
@ -93,12 +95,12 @@ namespace Azure { namespace Storage { namespace Test {
pageRanges = pageBlobClient.GetPageRanges(options);
EXPECT_TRUE(pageRanges.ClearRanges.empty());
ASSERT_FALSE(pageRanges.PageRanges.empty());
EXPECT_EQ(pageRanges.PageRanges[0].Offset, 4_KB);
EXPECT_EQ(pageRanges.PageRanges[0].Length, 1_KB);
EXPECT_EQ(static_cast<uint64_t>(pageRanges.PageRanges[0].Offset), 4_KB);
EXPECT_EQ(static_cast<uint64_t>(pageRanges.PageRanges[0].Length), 1_KB);
auto snapshot = pageBlobClient.CreateSnapshot().Snapshot;
// |_|_|_|x| |x|x|_|_| This is what's in snapshot
blobContent.resize((size_t)1_KB);
blobContent.resize(static_cast<std::size_t>(1_KB));
pageBlobClient.UploadPages(
Azure::Storage::CreateMemoryStream(blobContent.data(), blobContent.size()), 0);
pageBlobClient.ClearPages(3_KB, 1_KB);
@ -110,9 +112,9 @@ namespace Azure { namespace Storage { namespace Test {
ASSERT_FALSE(pageRanges.ClearRanges.empty());
ASSERT_FALSE(pageRanges.PageRanges.empty());
EXPECT_EQ(pageRanges.PageRanges[0].Offset, 0);
EXPECT_EQ(pageRanges.PageRanges[0].Length, 1_KB);
EXPECT_EQ(pageRanges.ClearRanges[0].Offset, 3_KB);
EXPECT_EQ(pageRanges.ClearRanges[0].Length, 1_KB);
EXPECT_EQ(static_cast<uint64_t>(pageRanges.PageRanges[0].Length), 1_KB);
EXPECT_EQ(static_cast<uint64_t>(pageRanges.ClearRanges[0].Offset), 3_KB);
EXPECT_EQ(static_cast<uint64_t>(pageRanges.ClearRanges[0].Length), 1_KB);
}
TEST_F(PageBlobClientTest, UploadFromUri)

View File

@ -134,25 +134,39 @@ namespace Azure { namespace Storage { namespace Test {
std::vector<uint8_t> ReadBodyStream(std::unique_ptr<Azure::Core::Http::BodyStream>& stream)
{
auto s = stream->Length();
std::vector<uint8_t> body((size_t)s, '\x00');
// Read 15k at at time. warning C6262: exceeds /analyze:stacksize '16384'.
std::vector<uint8_t> body;
if (stream->Length() == static_cast<decltype(stream->Length())>(-1))
{
constexpr uint64_t fixedSize = 1024 * 15;
uint8_t tempBuffer[fixedSize];
auto readBytes = uint64_t();
auto offset = uint64_t();
do
std::size_t bufferSize = static_cast<std::size_t>(16_KB);
auto readBuffer = std::make_unique<uint8_t[]>(bufferSize);
while (true)
{
readBytes = stream->Read(tempBuffer, fixedSize);
for (uint64_t index = 0; index != readBytes; index++)
auto bytesRead = stream->Read(readBuffer.get(), bufferSize);
if (bytesRead == 0)
{
body[(size_t)(offset + index)] = tempBuffer[index];
break;
}
offset += readBytes;
} while (readBytes != 0);
body.insert(body.end(), readBuffer.get(), readBuffer.get() + bytesRead);
}
}
else
{
body.resize(static_cast<std::size_t>(stream->Length()));
std::size_t offset = 0;
while (true)
{
auto bytesRead = stream->Read(&body[offset], body.size() - offset);
offset += static_cast<std::size_t>(bytesRead);
if (bytesRead == 0 || offset == body.size())
{
break;
}
}
if (offset != body.size())
{
throw std::runtime_error("failed to read all content from body stream");
}
}
return body;
}