ContentHash integration for File/DataLake (#1236)

* Integrate content hash for file/datalake

* Changelog update for content hash in file/datalake

* Resolve minor build error/warning.

* Resolved review comments
This commit is contained in:
Kan Tang 2020-12-22 11:30:31 +08:00 committed by GitHub
parent 9a59445888
commit d9c65ac445
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 287 additions and 185 deletions

View File

@ -58,4 +58,22 @@ namespace Azure { namespace Storage {
Azure::Core::Nullable<std::string> LeaseId;
};
/**
* @brief Specifies HTTP options for conditional requests based on ContentHash.
*/
struct ContentHashAccessConditions
{
/**
* @brief Specify this header to perform the operation only if the resource's ContentHash
* matches the value specified.
*/
Azure::Core::Nullable<ContentHash> IfMatchContentHash;
/**
* @brief Specify this header to perform the operation only if the resource's ContentHash does
* not match the value specified.
*/
Azure::Core::Nullable<ContentHash> IfNoneMatchContentHash;
};
}} // namespace Azure::Storage

View File

@ -21,20 +21,6 @@ namespace Azure { namespace Storage {
std::string CreateUniqueLeaseId();
namespace Details {
struct CaseInsensitiveComparator
{
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return std::lexicographical_compare(
lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char c1, char c2) {
return Core::Strings::ToLower(c1) < Core::Strings::ToLower(c2);
});
}
};
} // namespace Details
using Metadata = std::map<std::string, std::string, Details::CaseInsensitiveComparator>;
/**
* @brief The algorithm used for hash.
*/
@ -64,7 +50,25 @@ namespace Azure { namespace Storage {
/**
* @brief The algorithm used for hash.
*/
HashAlgorithm Algorithm;
HashAlgorithm Algorithm = HashAlgorithm::Md5;
};
namespace Details {
struct CaseInsensitiveComparator
{
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return std::lexicographical_compare(
lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char c1, char c2) {
return Core::Strings::ToLower(c1) < Core::Strings::ToLower(c2);
});
}
};
ContentHash FromBase64String(const std::string& base64String, HashAlgorithm algorithm);
std::string ToBase64String(const ContentHash& hash);
} // namespace Details
using Metadata = std::map<std::string, std::string, Details::CaseInsensitiveComparator>;
}} // namespace Azure::Storage

View File

@ -4,6 +4,7 @@
#include "azure/storage/common/storage_common.hpp"
#include "azure/core/uuid.hpp"
#include "azure/storage/common/crypt.hpp"
namespace Azure { namespace Storage {
@ -13,4 +14,16 @@ namespace Azure { namespace Storage {
return uuid.GetUuidString();
}
namespace Details {
ContentHash FromBase64String(const std::string& base64String, HashAlgorithm algorithm)
{
ContentHash hash;
hash.Value = Base64Decode(base64String);
hash.Algorithm = algorithm;
return hash;
}
std::string ToBase64String(const ContentHash& hash) { return Base64Encode(hash.Value); }
} // namespace Details
}} // namespace Azure::Storage

View File

@ -6,6 +6,8 @@
- Move DataLake SAS into `Azure::Storage::Sas` namespace.
- `EncrytionKeySha256` are changed to binary(`std::vector<uint8_t>`).
- Replaced all transactional content MD5/CRC64 with `ContentHash` struct.
- `DataLakeHttpHeaders` is renamed to `PathHttpHeaders`, and now contains `ContentHash` for the resource.
## 12.0.0-beta.5 (2020-11-13)

View File

@ -218,9 +218,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
Azure::Core::Context Context;
/**
* @brief Specify the transactional md5 for the body, to be validated by the service.
* @brief Specify the transactional hash for the body, to be validated by the service.
*/
Azure::Core::Nullable<std::string> ContentMd5;
Azure::Core::Nullable<Storage::ContentHash> TransactionalContentHash;
/**
* @brief Specify the lease access conditions.
@ -263,18 +263,17 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
Azure::Core::Nullable<bool> Close;
/**
* @brief The service stores this value and includes it in the "Content-Md5" response header for
* "Read & Get Properties" operations. If this property is not specified on the request,
* then the property will be cleared for the file. Subsequent calls to "Read & Get
* Properties" will not return this property unless it is explicitly set on that file
* again.
* @brief The service stores this value and is returned for "Read & Get Properties" operations.
* If this property is not specified on the request, then the property will be cleared
* for the file. Subsequent calls to "Read & Get Properties" will not return this
* property unless it is explicitly set on that file again.
*/
Azure::Core::Nullable<std::string> ContentMd5;
Azure::Core::Nullable<Storage::ContentHash> ContentHash;
/**
* @brief Specify the http headers for this path.
*/
Models::DataLakeHttpHeaders HttpHeaders;
Models::PathHttpHeaders HttpHeaders;
/**
* @brief Specify the access condition for the path.
@ -365,7 +364,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
/**
* @brief Specify the http headers for this path.
*/
Models::DataLakeHttpHeaders HttpHeaders;
Models::PathHttpHeaders HttpHeaders;
/**
* @brief User-defined metadata to be stored with the path. Note that the string may only
@ -687,7 +686,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
/**
* @brief The standard HTTP header system properties to set.
*/
Models::DataLakeHttpHeaders HttpHeaders;
Models::PathHttpHeaders HttpHeaders;
/**
* @brief Name-value pairs associated with the blob as metadata.

View File

@ -131,7 +131,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
* @remark This request is sent to blob endpoint.
*/
Azure::Core::Response<Models::SetPathHttpHeadersResult> SetHttpHeaders(
Models::DataLakeHttpHeaders httpHeaders,
Models::PathHttpHeaders httpHeaders,
const SetPathHttpHeadersOptions& options = SetPathHttpHeadersOptions()) const;
/**

View File

@ -84,7 +84,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam
Azure::Core::Nullable<std::string> LeaseDuration;
Azure::Core::Nullable<LeaseStateType> LeaseState;
Azure::Core::Nullable<LeaseStatusType> LeaseStatus;
DataLakeHttpHeaders HttpHeaders;
PathHttpHeaders HttpHeaders;
Azure::Core::Nullable<bool> ServerEncrypted;
Azure::Core::Nullable<std::vector<uint8_t>> EncryptionKeySha256;
Azure::Core::Nullable<bool> AccessTierInferred;
@ -136,16 +136,15 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam
struct ReadFileResult
{
std::unique_ptr<Azure::Core::Http::BodyStream> Body;
DataLakeHttpHeaders HttpHeaders;
PathHttpHeaders HttpHeaders;
Azure::Core::Nullable<int64_t> RangeOffset;
Azure::Core::Nullable<int64_t> RangeLength;
Azure::Core::Nullable<std::string> TransactionalMd5;
Azure::Core::Nullable<Storage::ContentHash> TransactionalContentHash;
std::string ETag;
std::string LastModified;
Azure::Core::Nullable<std::string> LeaseDuration;
LeaseStateType LeaseState = LeaseStateType::Unknown;
LeaseStatusType LeaseStatus = LeaseStatusType::Unknown;
Azure::Core::Nullable<std::string> ContentMd5;
Storage::Metadata Metadata;
std::string CreationTime;
Azure::Core::Nullable<std::string> ExpiryTime;
@ -165,7 +164,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam
std::string ETag;
std::string LastModified;
int64_t ContentLength = 0;
DataLakeHttpHeaders HttpHeaders;
PathHttpHeaders HttpHeaders;
Storage::Metadata Metadata;
Azure::Core::Nullable<bool> ServerEncrypted;
Azure::Core::Nullable<std::vector<uint8_t>> EncryptionKeySha256;

View File

@ -69,7 +69,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
constexpr static const char* HeaderContentType = "x-ms-content-type";
constexpr static const char* HeaderTransactionalContentMd5 = "content-md5";
constexpr static const char* HeaderContentMd5 = "x-ms-content-md5";
constexpr static const char* HeaderContentCrc64 = "x-ms-content-crc64";
constexpr static const char* HeaderTransactionalContentCrc64 = "x-ms-content-crc64";
constexpr static const char* HeaderUmask = "x-ms-umask";
constexpr static const char* HeaderPermissions = "x-ms-permissions";
constexpr static const char* HeaderRenameSource = "x-ms-rename-source";
@ -111,13 +111,14 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
constexpr static const char* HeaderXMsRequestServerEncrypted = "x-ms-request-server-encrypted";
} // namespace Details
namespace Models {
struct DataLakeHttpHeaders
struct PathHttpHeaders
{
std::string CacheControl;
std::string ContentDisposition;
std::string ContentEncoding;
std::string ContentLanguage;
std::string ContentType;
Storage::ContentHash ContentHash;
};
// Mode "set" sets POSIX access control rights on files and directories, "modify" modifies one
// or more POSIX access control rights that pre-exist on files and directories, "remove"
@ -309,10 +310,10 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
{
std::unique_ptr<Azure::Core::Http::BodyStream> BodyStream;
std::string AcceptRanges;
DataLakeHttpHeaders HttpHeaders;
PathHttpHeaders HttpHeaders;
int64_t ContentLength = int64_t();
Azure::Core::Nullable<std::string> ContentRange;
Azure::Core::Nullable<std::string> TransactionalMd5;
Azure::Core::Nullable<Storage::ContentHash> TransactionalContentHash;
std::string ETag;
std::string LastModified;
std::string ResourceType;
@ -320,16 +321,14 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
Azure::Core::Nullable<std::string> LeaseDuration;
Models::LeaseStateType LeaseState = Models::LeaseStateType::Unknown;
Models::LeaseStatusType LeaseStatus = Models::LeaseStatusType::Unknown;
Azure::Core::Nullable<std::string> ContentMd5;
};
struct PathGetPropertiesResult
{
Azure::Core::Nullable<std::string> AcceptRanges;
DataLakeHttpHeaders HttpHeaders;
PathHttpHeaders HttpHeaders;
int64_t ContentLength = int64_t();
Azure::Core::Nullable<std::string> ContentRange;
Azure::Core::Nullable<std::string> ContentMd5;
std::string ETag;
std::string LastModified;
Azure::Core::Nullable<std::string> ResourceType;
@ -372,8 +371,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
struct PathAppendDataResult
{
Azure::Core::Nullable<std::string> ContentMD5;
Azure::Core::Nullable<std::string> ContentCrc64;
Azure::Core::Nullable<Storage::ContentHash> TransactionalContentHash;
bool IsServerEncrypted = bool();
};
@ -2203,8 +2201,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
ContentLength; // Required for "Append Data" and "Flush Data". Must be 0 for "Flush
// Data". Must be the length of the request content in bytes for
// "Append Data".
Azure::Core::Nullable<std::string> ContentMd5; // Specify the transactional md5 for the
// body, to be validated by the service.
Azure::Core::Nullable<Storage::ContentHash>
ContentMd5; // Specify the transactional md5 for the body, to be validated by the
// service.
Azure::Core::Nullable<std::string>
LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease
// is active and matches this ID.
@ -2285,7 +2284,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
}
if (flushDataOptions.ContentMd5.HasValue())
{
request.AddHeader(Details::HeaderContentMd5, flushDataOptions.ContentMd5.GetValue());
request.AddHeader(
Details::HeaderContentMd5,
Storage::Details::ToBase64String(flushDataOptions.ContentMd5.GetValue()));
}
if (flushDataOptions.LeaseIdOptional.HasValue())
{
@ -2365,12 +2366,12 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
ContentLength; // Required for "Append Data" and "Flush Data". Must be 0 for "Flush
// Data". Must be the length of the request content in bytes for
// "Append Data".
Azure::Core::Nullable<std::string>
Azure::Core::Nullable<Storage::ContentHash>
TransactionalContentMd5; // Specify the transactional md5 for the body, to be
// validated by the service.
Azure::Core::Nullable<std::string>
ContentCrc64; // Specify the transactional crc64 for the body, to be validated by the
// service.
Azure::Core::Nullable<Storage::ContentHash>
TransactionalContentCrc64; // Specify the transactional crc64 for the body, to be
// validated by the service.
Azure::Core::Nullable<std::string>
LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease
// is active and matches this ID.
@ -2417,12 +2418,15 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
{
request.AddHeader(
Details::HeaderTransactionalContentMd5,
appendDataOptions.TransactionalContentMd5.GetValue());
Storage::Details::ToBase64String(
appendDataOptions.TransactionalContentMd5.GetValue()));
}
if (appendDataOptions.ContentCrc64.HasValue())
if (appendDataOptions.TransactionalContentCrc64.HasValue())
{
request.AddHeader(
Details::HeaderContentCrc64, appendDataOptions.ContentCrc64.GetValue());
Details::HeaderTransactionalContentCrc64,
Storage::Details::ToBase64String(
appendDataOptions.TransactionalContentCrc64.GetValue()));
}
if (appendDataOptions.LeaseIdOptional.HasValue())
{
@ -2628,7 +2632,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
if (response.GetHeaders().find(Details::HeaderContentMD5)
!= response.GetHeaders().end())
{
result.ContentMd5 = response.GetHeaders().at(Details::HeaderContentMD5);
result.HttpHeaders.ContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderContentMD5), HashAlgorithm::Md5);
}
result.ETag = response.GetHeaders().at(Details::HeaderETag);
result.LastModified = response.GetHeaders().at(Details::HeaderLastModified);
@ -2691,12 +2696,14 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
if (response.GetHeaders().find(Details::HeaderContentMD5)
!= response.GetHeaders().end())
{
result.TransactionalMd5 = response.GetHeaders().at(Details::HeaderContentMD5);
result.TransactionalContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderContentMD5), HashAlgorithm::Md5);
}
if (response.GetHeaders().find(Details::HeaderXMsContentMd5)
!= response.GetHeaders().end())
{
result.ContentMd5 = response.GetHeaders().at(Details::HeaderXMsContentMd5);
result.HttpHeaders.ContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderXMsContentMd5), HashAlgorithm::Md5);
}
result.ETag = response.GetHeaders().at(Details::HeaderETag);
result.LastModified = response.GetHeaders().at(Details::HeaderLastModified);
@ -2774,7 +2781,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
if (response.GetHeaders().find(Details::HeaderContentMD5)
!= response.GetHeaders().end())
{
result.ContentMd5 = response.GetHeaders().at(Details::HeaderContentMD5);
result.HttpHeaders.ContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderContentMD5), HashAlgorithm::Md5);
}
result.ETag = response.GetHeaders().at(Details::HeaderETag);
result.LastModified = response.GetHeaders().at(Details::HeaderLastModified);
@ -2982,12 +2990,14 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
if (response.GetHeaders().find(Details::HeaderContentMD5)
!= response.GetHeaders().end())
{
result.ContentMD5 = response.GetHeaders().at(Details::HeaderContentMD5);
result.TransactionalContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderContentMD5), HashAlgorithm::Md5);
}
if (response.GetHeaders().find(Details::HeaderXMsContentCrc64)
!= response.GetHeaders().end())
{
result.ContentCrc64 = response.GetHeaders().at(Details::HeaderXMsContentCrc64);
result.TransactionalContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderXMsContentCrc64), HashAlgorithm::Crc64);
}
result.IsServerEncrypted
= response.GetHeaders().at(Details::HeaderXMsRequestServerEncrypted) == "true";

View File

@ -42,9 +42,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
return std::make_pair(offset, length);
}
Models::DataLakeHttpHeaders FromBlobHttpHeaders(Blobs::Models::BlobHttpHeaders headers)
Models::PathHttpHeaders FromBlobHttpHeaders(Blobs::Models::BlobHttpHeaders headers)
{
Models::DataLakeHttpHeaders ret;
Models::PathHttpHeaders ret;
ret.CacheControl = std::move(headers.CacheControl);
ret.ContentDisposition = std::move(headers.ContentDisposition);
ret.ContentEncoding = std::move(headers.ContentEncoding);
@ -53,7 +53,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
return ret;
}
Blobs::Models::BlobHttpHeaders FromDataLakeHttpHeaders(Models::DataLakeHttpHeaders headers)
Blobs::Models::BlobHttpHeaders FromPathHttpHeaders(Models::PathHttpHeaders headers)
{
Blobs::Models::BlobHttpHeaders ret;
ret.CacheControl = std::move(headers.CacheControl);
@ -215,7 +215,17 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
Details::DataLakeRestClient::Path::AppendDataOptions protocolLayerOptions;
protocolLayerOptions.Position = offset;
protocolLayerOptions.ContentLength = content->Length();
protocolLayerOptions.TransactionalContentMd5 = options.ContentMd5;
if (options.TransactionalContentHash.HasValue())
{
if (options.TransactionalContentHash.GetValue().Algorithm == HashAlgorithm::Crc64)
{
protocolLayerOptions.TransactionalContentCrc64 = options.TransactionalContentHash;
}
else
{
protocolLayerOptions.TransactionalContentMd5 = options.TransactionalContentHash;
}
}
protocolLayerOptions.LeaseIdOptional = options.AccessConditions.LeaseId;
return Details::DataLakeRestClient::Path::AppendData(
m_dfsUri, *content, *m_pipeline, options.Context, protocolLayerOptions);
@ -230,7 +240,12 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
protocolLayerOptions.RetainUncommittedData = options.RetainUncommittedData;
protocolLayerOptions.Close = options.Close;
protocolLayerOptions.ContentLength = 0;
protocolLayerOptions.ContentMd5 = options.ContentMd5;
if (options.ContentHash.HasValue()
&& options.ContentHash.GetValue().Algorithm != HashAlgorithm::Md5)
{
abort();
}
protocolLayerOptions.ContentMd5 = options.ContentHash;
protocolLayerOptions.LeaseIdOptional = options.AccessConditions.LeaseId;
protocolLayerOptions.CacheControl = options.HttpHeaders.CacheControl;
protocolLayerOptions.ContentType = options.HttpHeaders.ContentType;
@ -322,10 +337,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
}
ret.RangeOffset = RangeOffset;
ret.RangeLength = RangeLength;
if (result->TransactionalContentHash.HasValue())
{
ret.TransactionalMd5 = Base64Encode(result->TransactionalContentHash.GetValue().Value);
}
ret.TransactionalContentHash = std::move(result->TransactionalContentHash);
ret.ETag = std::move(result->ETag);
ret.LastModified = std::move(result->LastModified);
ret.LeaseDuration = std::move(result->LeaseDuration);
@ -350,7 +362,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
Blobs::UploadBlockBlobFromOptions blobOptions;
blobOptions.Context = options.Context;
blobOptions.ChunkSize = options.ChunkSize;
blobOptions.HttpHeaders = FromDataLakeHttpHeaders(options.HttpHeaders);
blobOptions.HttpHeaders = FromPathHttpHeaders(options.HttpHeaders);
blobOptions.Metadata = options.Metadata;
blobOptions.Concurrency = options.Concurrency;
return m_blockBlobClient.UploadFrom(fileName, blobOptions);
@ -364,7 +376,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
Blobs::UploadBlockBlobFromOptions blobOptions;
blobOptions.Context = options.Context;
blobOptions.ChunkSize = options.ChunkSize;
blobOptions.HttpHeaders = FromDataLakeHttpHeaders(options.HttpHeaders);
blobOptions.HttpHeaders = FromPathHttpHeaders(options.HttpHeaders);
blobOptions.Metadata = options.Metadata;
blobOptions.Concurrency = options.Concurrency;
return m_blockBlobClient.UploadFrom(buffer, bufferSize, blobOptions);

View File

@ -212,7 +212,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
}
Azure::Core::Response<Models::SetPathHttpHeadersResult> PathClient::SetHttpHeaders(
Models::DataLakeHttpHeaders httpHeaders,
Models::PathHttpHeaders httpHeaders,
const SetPathHttpHeadersOptions& options) const
{
Blobs::SetBlobHttpHeadersOptions blobOptions;

View File

@ -16,7 +16,7 @@
namespace Azure { namespace Storage { namespace Files { namespace DataLake { namespace Models {
bool operator==(const DataLakeHttpHeaders& lhs, const DataLakeHttpHeaders& rhs)
bool operator==(const PathHttpHeaders& lhs, const PathHttpHeaders& rhs)
{
return lhs.ContentType == rhs.ContentType && lhs.ContentEncoding == rhs.ContentEncoding
&& lhs.ContentLanguage == rhs.ContentLanguage && lhs.CacheControl == rhs.CacheControl

View File

@ -78,11 +78,11 @@ namespace Azure { namespace Storage { namespace Test {
return result;
}
Files::DataLake::Models::DataLakeHttpHeaders
Files::DataLake::Models::PathHttpHeaders
DataLakeFileSystemClientTest::GetInterestingHttpHeaders()
{
static Files::DataLake::Models::DataLakeHttpHeaders result = []() {
Files::DataLake::Models::DataLakeHttpHeaders ret;
static Files::DataLake::Models::PathHttpHeaders result = []() {
Files::DataLake::Models::PathHttpHeaders ret;
ret.CacheControl = std::string("no-cache");
ret.ContentDisposition = std::string("attachment");
ret.ContentEncoding = std::string("deflate");

View File

@ -15,7 +15,7 @@ namespace Azure { namespace Storage { namespace Test {
bool recursive,
const std::string& directory = std::string());
static Files::DataLake::Models::DataLakeHttpHeaders GetInterestingHttpHeaders();
static Files::DataLake::Models::PathHttpHeaders GetInterestingHttpHeaders();
static std::shared_ptr<Files::DataLake::FileSystemClient> m_fileSystemClient;
static std::string m_fileSystemName;

View File

@ -401,7 +401,7 @@ namespace Azure { namespace Storage { namespace Test {
// response headers override
{
Files::DataLake::Models::DataLakeHttpHeaders headers;
Files::DataLake::Models::PathHttpHeaders headers;
headers.ContentType = "application/x-binary";
headers.ContentLanguage = "en-US";
headers.ContentDisposition = "attachment";

View File

@ -12,6 +12,8 @@
- ShareClient::BreakLease
- ShareClient::RenewLease
- Move File SAS into `Azure::Storage::Sas` namespace.
- Replaced all transactional content MD5/CRC64 with `ContentHash` struct.
- `FileShareHttpHeaders` is renamed to `ShareFileHttpHeaders`, and member `std::string ContentMd5` is changed to `Storage::ContentHash ContentHash`.
## 12.0.0-beta.5 (2020-11-13)

View File

@ -40,7 +40,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
constexpr static const char* HeaderVersion = "x-ms-version";
constexpr static const char* HeaderRequestId = "x-ms-client-request-id";
constexpr static const char* HeaderContentLength = "content-length";
constexpr static const char* HeaderContentMd5 = "content-md5";
constexpr static const char* HeaderContentHash = "content-md5";
constexpr static const char* HeaderCopyActionAbortConstant = "x-ms-copy-action";
constexpr static const char* HeaderCopySource = "x-ms-copy-source";
constexpr static const char* HeaderFilePermissionCopyMode = "x-ms-file-permission-copy-mode";
@ -72,9 +72,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
constexpr static const char* HeaderRange = "x-ms-range";
constexpr static const char* HeaderRecursive = "x-ms-recursive";
constexpr static const char* HeaderQuota = "x-ms-share-quota";
constexpr static const char* HeaderSourceContentCrc64 = "x-ms-source-content-crc64";
constexpr static const char* HeaderSourceIfMatchCrc64 = "x-ms-source-if-match-crc64";
constexpr static const char* HeaderSourceIfNoneMatchCrc64 = "x-ms-source-if-none-match-crc64";
constexpr static const char* HeaderSourceContentHash = "x-ms-source-content-crc64";
constexpr static const char* HeaderSourceIfMatchHash = "x-ms-source-if-match-crc64";
constexpr static const char* HeaderSourceIfNoneMatchHash = "x-ms-source-if-none-match-crc64";
constexpr static const char* HeaderSourceRange = "x-ms-source-range";
constexpr static const char* HeaderErrorCode = "x-ms-error-code";
constexpr static const char* HeaderETag = "etag";
@ -105,7 +105,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
= "x-ms-number-of-handles-failed";
constexpr static const char* HeaderXMsContentLength = "x-ms-content-length";
constexpr static const char* HeaderContentRange = "content-range";
constexpr static const char* HeaderTransactionalContentMd5 = "content-md5";
constexpr static const char* HeaderTransactionalContentHash = "content-md5";
constexpr static const char* HeaderContentEncoding = "content-encoding";
constexpr static const char* HeaderCacheControl = "cache-control";
constexpr static const char* HeaderContentDisposition = "content-disposition";
@ -120,17 +120,16 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
constexpr static const char* HeaderXMsRange = "x-ms-range";
constexpr static const char* HeaderFileRangeWrite = "x-ms-write";
constexpr static const char* HeaderFileRangeWriteTypeDefault = "update";
constexpr static const char* HeaderXMsContentCrc64 = "x-ms-content-crc64";
} // namespace Details
namespace Models {
struct FileShareHttpHeaders
struct ShareFileHttpHeaders
{
std::string CacheControl;
std::string ContentDisposition;
std::string ContentEncoding;
std::string ContentLanguage;
std::string ContentType;
std::string ContentMd5;
Storage::ContentHash ContentHash;
};
// Specifies the option to copy file security descriptor from source file or to set it using the
// value which is defined by the header value of x-ms-file-permission or
@ -650,14 +649,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
int32_t MaxResults = int32_t();
Models::FilesAndDirectoriesListSegment Segment;
std::string ContinuationToken;
FileShareHttpHeaders HttpHeaders;
ShareFileHttpHeaders HttpHeaders;
};
struct DirectoryListHandlesResult
{
std::vector<Models::HandleItem> HandleList;
std::string ContinuationToken;
FileShareHttpHeaders HttpHeaders;
ShareFileHttpHeaders HttpHeaders;
};
struct DirectoryForceCloseHandlesResult
@ -687,10 +686,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
std::string LastModified;
Storage::Metadata Metadata;
int64_t ContentLength = int64_t();
FileShareHttpHeaders HttpHeaders;
ShareFileHttpHeaders HttpHeaders;
Azure::Core::Nullable<std::string> ContentRange;
std::string ETag;
Azure::Core::Nullable<std::string> TransactionalContentMd5;
Azure::Core::Nullable<Storage::ContentHash> TransactionalContentHash;
std::string AcceptRanges;
Azure::Core::Nullable<std::string> CopyCompletionTime;
Azure::Core::Nullable<std::string> CopyStatusDescription;
@ -717,7 +716,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Storage::Metadata Metadata;
std::string FileType;
int64_t ContentLength = int64_t();
FileShareHttpHeaders HttpHeaders;
ShareFileHttpHeaders HttpHeaders;
std::string ETag;
Azure::Core::Nullable<std::string> CopyCompletionTime;
Azure::Core::Nullable<std::string> CopyStatusDescription;
@ -793,7 +792,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
{
std::string ETag;
std::string LastModified;
std::string TransactionalContentMd5;
Storage::ContentHash TransactionalContentHash;
bool IsServerEncrypted = bool();
};
@ -801,7 +800,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
{
std::string ETag;
std::string LastModified;
std::string XMsContentCrc64;
Storage::ContentHash TransactionalContentHash;
bool IsServerEncrypted = bool();
};
@ -830,7 +829,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
{
std::vector<Models::HandleItem> HandleList;
std::string ContinuationToken;
FileShareHttpHeaders HttpHeaders;
ShareFileHttpHeaders HttpHeaders;
};
struct FileForceCloseHandlesResult
@ -1371,9 +1370,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
{
writer.Write(
Storage::Details::XmlNode{Storage::Details::XmlNodeType::StartTag, "Days"});
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::Text,
nullptr,
std::to_string(object.Days.GetValue()).data()});
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::Text,
nullptr,
std::to_string(object.Days.GetValue()).data()});
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::EndTag});
}
}
@ -1394,14 +1394,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
{
writer.Write(
Storage::Details::XmlNode{Storage::Details::XmlNodeType::StartTag, "IncludeAPIs"});
writer.Write(
Storage::Details::XmlNode{Storage::Details::XmlNodeType::Text,
nullptr,
object.IncludeApis.GetValue() ? "true" : "false"});
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::Text,
nullptr,
object.IncludeApis.GetValue() ? "true" : "false"});
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::EndTag});
}
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::StartTag,
"RetentionPolicy"});
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::StartTag, "RetentionPolicy"});
ShareRetentionPolicyToXml(writer, object.RetentionPolicy);
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::EndTag});
}
@ -1432,11 +1432,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::Text, nullptr, object.ExposedHeaders.data()});
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::EndTag});
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::StartTag,
"MaxAgeInSeconds"});
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::Text,
nullptr,
std::to_string(object.MaxAgeInSeconds).data()});
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::StartTag, "MaxAgeInSeconds"});
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::Text,
nullptr,
std::to_string(object.MaxAgeInSeconds).data()});
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::EndTag});
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::EndTag});
}
@ -1468,8 +1469,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Storage::Details::XmlWriter& writer,
const Models::ShareProtocolSettings& object)
{
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::StartTag,
"ProtocolSettings"});
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::StartTag, "ProtocolSettings"});
SmbSettingsToXml(writer, object.Settings);
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::EndTag});
}
@ -1478,8 +1479,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Storage::Details::XmlWriter& writer,
const Models::StorageServiceProperties& object)
{
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::StartTag,
"StorageServiceProperties"});
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::StartTag, "StorageServiceProperties"});
writer.Write(
Storage::Details::XmlNode{Storage::Details::XmlNodeType::StartTag, "HourMetrics"});
MetricsToXml(writer, object.HourMetrics);
@ -4147,8 +4148,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Storage::Details::XmlWriter& writer,
const Models::SignedIdentifier& object)
{
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::StartTag,
"SignedIdentifier"});
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::StartTag, "SignedIdentifier"});
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::StartTag, "Id"});
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::Text, nullptr, object.Id.data()});
@ -4161,8 +4162,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Storage::Details::XmlWriter& writer,
const std::vector<Models::SignedIdentifier>& object)
{
writer.Write(Storage::Details::XmlNode{Storage::Details::XmlNodeType::StartTag,
"SignedIdentifiers"});
writer.Write(Storage::Details::XmlNode{
Storage::Details::XmlNodeType::StartTag, "SignedIdentifiers"});
for (const auto& item : object)
{
SignedIdentifierToXml(writer, item);
@ -5566,7 +5567,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Azure::Core::Nullable<std::string>
FileCacheControl; // Sets the file's cache control. The File service stores this value
// but does not use or modify it.
Azure::Core::Nullable<std::string> FileContentMd5; // Sets the file's MD5 hash.
Azure::Core::Nullable<Storage::ContentHash>
ContentMd5; // An MD5 hash of the content. This hash is used to verify the integrity
// of the data during transport. When the Content-MD5 header is specified,
// the File service compares the hash of the content that has arrived with
// the header value that was sent. If the two hashes do not match, the
// operation will fail with error code 400 (Bad Request).
Azure::Core::Nullable<std::string>
FileContentDisposition; // Sets the file's Content-Disposition header.
Storage::Metadata Metadata; // A name-value pair to associate with a file storage object.
@ -5631,9 +5637,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
request.AddHeader(
Details::HeaderFileCacheControl, createOptions.FileCacheControl.GetValue());
}
if (createOptions.FileContentMd5.HasValue())
if (createOptions.ContentMd5.HasValue())
{
request.AddHeader(Details::HeaderContentMd5, createOptions.FileContentMd5.GetValue());
request.AddHeader(
Details::HeaderContentHash,
Storage::Details::ToBase64String(createOptions.ContentMd5.GetValue()));
}
if (createOptions.FileContentDisposition.HasValue())
{
@ -5828,7 +5836,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Azure::Core::Nullable<std::string>
FileCacheControl; // Sets the file's cache control. The File service stores this value
// but does not use or modify it.
Azure::Core::Nullable<std::string> FileContentMd5; // Sets the file's MD5 hash.
Azure::Core::Nullable<Storage::ContentHash>
ContentMd5; // An MD5 hash of the content. This hash is used to verify the integrity
// of the data during transport. When the Content-MD5 header is specified,
// the File service compares the hash of the content that has arrived with
// the header value that was sent. If the two hashes do not match, the
// operation will fail with error code 400 (Bad Request).
Azure::Core::Nullable<std::string>
FileContentDisposition; // Sets the file's Content-Disposition header.
Azure::Core::Nullable<std::string>
@ -5898,10 +5911,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
request.AddHeader(
Details::HeaderFileCacheControl, setHttpHeadersOptions.FileCacheControl.GetValue());
}
if (setHttpHeadersOptions.FileContentMd5.HasValue())
if (setHttpHeadersOptions.ContentMd5.HasValue())
{
request.AddHeader(
Details::HeaderContentMd5, setHttpHeadersOptions.FileContentMd5.GetValue());
Details::HeaderContentHash,
Storage::Details::ToBase64String(setHttpHeadersOptions.ContentMd5.GetValue()));
}
if (setHttpHeadersOptions.FileContentDisposition.HasValue())
{
@ -6213,7 +6227,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
= int64_t(); // Specifies the number of bytes being transmitted in the request body.
// When the x-ms-write header is set to clear, the value of this header
// must be set to zero.
Azure::Core::Nullable<std::string>
Azure::Core::Nullable<Storage::ContentHash>
ContentMd5; // An MD5 hash of the content. This hash is used to verify the integrity
// of the data during transport. When the Content-MD5 header is specified,
// the File service compares the hash of the content that has arrived with
@ -6251,7 +6265,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Details::HeaderContentLength, std::to_string(uploadRangeOptions.ContentLength));
if (uploadRangeOptions.ContentMd5.HasValue())
{
request.AddHeader(Details::HeaderContentMd5, uploadRangeOptions.ContentMd5.GetValue());
request.AddHeader(
Details::HeaderContentHash,
Storage::Details::ToBase64String(uploadRangeOptions.ContentMd5.GetValue()));
}
request.AddHeader(Details::HeaderVersion, uploadRangeOptions.ApiVersionParameter);
if (uploadRangeOptions.LeaseIdOptional.HasValue())
@ -6289,13 +6305,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
= int64_t(); // Specifies the number of bytes being transmitted in the request body.
// When the x-ms-write header is set to clear, the value of this header
// must be set to zero.
Azure::Core::Nullable<std::string>
Azure::Core::Nullable<Storage::ContentHash>
SourceContentCrc64; // Specify the crc64 calculated for the range of bytes that must
// be read from the copy source.
Azure::Core::Nullable<std::string>
Azure::Core::Nullable<Storage::ContentHash>
SourceIfMatchCrc64; // Specify the crc64 value to operate only on range with a
// matching crc64 checksum.
Azure::Core::Nullable<std::string>
Azure::Core::Nullable<Storage::ContentHash>
SourceIfNoneMatchCrc64; // Specify the crc64 value to operate only on range without a
// matching crc64 checksum.
std::string ApiVersionParameter
@ -6338,20 +6354,23 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
if (uploadRangeFromUrlOptions.SourceContentCrc64.HasValue())
{
request.AddHeader(
Details::HeaderSourceContentCrc64,
uploadRangeFromUrlOptions.SourceContentCrc64.GetValue());
Details::HeaderSourceContentHash,
Storage::Details::ToBase64String(
uploadRangeFromUrlOptions.SourceContentCrc64.GetValue()));
}
if (uploadRangeFromUrlOptions.SourceIfMatchCrc64.HasValue())
{
request.AddHeader(
Details::HeaderSourceIfMatchCrc64,
uploadRangeFromUrlOptions.SourceIfMatchCrc64.GetValue());
Details::HeaderSourceIfMatchHash,
Storage::Details::ToBase64String(
uploadRangeFromUrlOptions.SourceIfMatchCrc64.GetValue()));
}
if (uploadRangeFromUrlOptions.SourceIfNoneMatchCrc64.HasValue())
{
request.AddHeader(
Details::HeaderSourceIfNoneMatchCrc64,
uploadRangeFromUrlOptions.SourceIfNoneMatchCrc64.GetValue());
Details::HeaderSourceIfNoneMatchHash,
Storage::Details::ToBase64String(
uploadRangeFromUrlOptions.SourceIfNoneMatchCrc64.GetValue()));
}
request.AddHeader(Details::HeaderVersion, uploadRangeFromUrlOptions.ApiVersionParameter);
if (uploadRangeFromUrlOptions.LeaseIdOptional.HasValue())
@ -6794,11 +6813,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
result.ContentRange = response.GetHeaders().at(Details::HeaderContentRange);
}
result.ETag = response.GetHeaders().at(Details::HeaderETag);
if (response.GetHeaders().find(Details::HeaderTransactionalContentMd5)
if (response.GetHeaders().find(Details::HeaderTransactionalContentHash)
!= response.GetHeaders().end())
{
result.TransactionalContentMd5
= response.GetHeaders().at(Details::HeaderTransactionalContentMd5);
result.TransactionalContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderTransactionalContentHash),
HashAlgorithm::Md5);
}
if (response.GetHeaders().find(Details::HeaderContentEncoding)
!= response.GetHeaders().end())
@ -6857,10 +6877,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
result.CopyStatus
= CopyStatusTypeFromString(response.GetHeaders().at(Details::HeaderCopyStatus));
}
if (response.GetHeaders().find(Details::HeaderContentMd5)
if (response.GetHeaders().find(Details::HeaderContentHash)
!= response.GetHeaders().end())
{
result.HttpHeaders.ContentMd5 = response.GetHeaders().at(Details::HeaderContentMd5);
result.HttpHeaders.ContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderContentHash), HashAlgorithm::Md5);
}
if (response.GetHeaders().find(Details::HeaderIsServerEncrypted)
!= response.GetHeaders().end())
@ -6919,11 +6940,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
result.ContentRange = response.GetHeaders().at(Details::HeaderContentRange);
}
result.ETag = response.GetHeaders().at(Details::HeaderETag);
if (response.GetHeaders().find(Details::HeaderTransactionalContentMd5)
if (response.GetHeaders().find(Details::HeaderTransactionalContentHash)
!= response.GetHeaders().end())
{
result.TransactionalContentMd5
= response.GetHeaders().at(Details::HeaderTransactionalContentMd5);
result.TransactionalContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderTransactionalContentHash),
HashAlgorithm::Md5);
}
if (response.GetHeaders().find(Details::HeaderContentEncoding)
!= response.GetHeaders().end())
@ -6982,10 +7004,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
result.CopyStatus
= CopyStatusTypeFromString(response.GetHeaders().at(Details::HeaderCopyStatus));
}
if (response.GetHeaders().find(Details::HeaderContentMd5)
if (response.GetHeaders().find(Details::HeaderContentHash)
!= response.GetHeaders().end())
{
result.HttpHeaders.ContentMd5 = response.GetHeaders().at(Details::HeaderContentMd5);
result.HttpHeaders.ContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderContentHash), HashAlgorithm::Md5);
}
if (response.GetHeaders().find(Details::HeaderIsServerEncrypted)
!= response.GetHeaders().end())
@ -7055,11 +7078,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
result.HttpHeaders.ContentType = response.GetHeaders().at(Details::HeaderContentType);
}
result.ETag = response.GetHeaders().at(Details::HeaderETag);
if (response.GetHeaders().find(Details::HeaderTransactionalContentMd5)
if (response.GetHeaders().find(Details::HeaderTransactionalContentHash)
!= response.GetHeaders().end())
{
result.HttpHeaders.ContentMd5
= response.GetHeaders().at(Details::HeaderTransactionalContentMd5);
result.HttpHeaders.ContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderTransactionalContentHash),
HashAlgorithm::Md5);
}
if (response.GetHeaders().find(Details::HeaderContentEncoding)
!= response.GetHeaders().end())
@ -7330,11 +7354,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Models::FileUploadRangeResult result;
result.ETag = response.GetHeaders().at(Details::HeaderETag);
result.LastModified = response.GetHeaders().at(Details::HeaderLastModified);
if (response.GetHeaders().find(Details::HeaderTransactionalContentMd5)
if (response.GetHeaders().find(Details::HeaderTransactionalContentHash)
!= response.GetHeaders().end())
{
result.TransactionalContentMd5
= response.GetHeaders().at(Details::HeaderTransactionalContentMd5);
result.TransactionalContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderTransactionalContentHash),
HashAlgorithm::Md5);
}
if (response.GetHeaders().find(Details::HeaderRequestIsServerEncrypted)
!= response.GetHeaders().end())
@ -7364,7 +7389,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Models::FileUploadRangeFromUrlResult result;
result.ETag = response.GetHeaders().at(Details::HeaderETag);
result.LastModified = response.GetHeaders().at(Details::HeaderLastModified);
result.XMsContentCrc64 = response.GetHeaders().at(Details::HeaderXMsContentCrc64);
result.TransactionalContentHash = Storage::Details::FromBase64String(
response.GetHeaders().at(Details::HeaderTransactionalContentHash),
HashAlgorithm::Crc64);
result.IsServerEncrypted
= response.GetHeaders().at(Details::HeaderRequestIsServerEncrypted) == "true";
return Azure::Core::Response<Models::FileUploadRangeFromUrlResult>(

View File

@ -207,7 +207,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
* the file returned from the server.
*/
Azure::Core::Response<Models::SetFilePropertiesResult> SetProperties(
Models::FileShareHttpHeaders httpHeaders,
Models::ShareFileHttpHeaders httpHeaders,
Models::FileShareSmbProperties smbProperties,
const SetFilePropertiesOptions& options = SetFilePropertiesOptions()) const;

View File

@ -440,7 +440,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
/**
* @brief Specifies the HttpHeaders of the file.
*/
Models::FileShareHttpHeaders HttpHeaders;
Models::ShareFileHttpHeaders HttpHeaders;
/**
* @brief A name-value pair to associate with a file storage object.
@ -616,11 +616,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
/**
* @brief An MD5 hash of the content. This hash is used to verify the integrity of the data
* during transport. When the ContentMD5 parameter is specified, the File service compares the
* hash of the content that has arrived with the header value that was sent. If the two hashes
* do not match, the operation will fail with error code 400 (Bad Request).
* during transport. When the TransactionalContentHash parameter is specified, the File service
* compares the hash of the content that has arrived with the header value that was sent. If the
* two hashes do not match, the operation will fail with error code 400 (Bad Request).
*/
Azure::Core::Nullable<std::string> TransactionalMd5;
Azure::Core::Nullable<ContentHash> TransactionalContentHash;
/**
* @brief The operation will only succeed if the access condition is met.
@ -662,20 +662,15 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
* @brief Specify the crc64 calculated for the range of bytes that must be read from the copy
* source.
*/
Azure::Core::Nullable<std::string> SourceContentCrc64;
Azure::Core::Nullable<ContentHash> SourceContentHash;
/**
* @brief Specify the crc64 value to operate only on range with a matching crc64 checksum.
* @brief Specify the access condition for the source. Only ContentHash with Crc64 is supported.
*/
Azure::Core::Nullable<std::string> SourceIfMatchCrc64;
ContentHashAccessConditions SourceAccessCondition;
/**
* @brief Specify the crc64 value to operate only on range without a matching crc64 checksum.
*/
Azure::Core::Nullable<std::string> SourceIfNoneMatchCrc64;
/**
* @brief The operation will only succeed if the access condition is met.
* @brief The operation will only succeed if the lease access condition is met.
*/
LeaseAccessConditions AccessConditions;
};
@ -853,7 +848,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
/**
* @brief The standard HTTP header system properties to set.
*/
Models::FileShareHttpHeaders HttpHeaders;
Models::ShareFileHttpHeaders HttpHeaders;
/**
* @brief Name-value pairs associated with the file as metadata.

View File

@ -116,7 +116,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { names
std::string ETag;
std::string LastModified;
int64_t ContentLength = 0;
FileShareHttpHeaders HttpHeaders;
ShareFileHttpHeaders HttpHeaders;
Storage::Metadata Metadata;
Azure::Core::Nullable<bool> IsServerEncrypted;
};

View File

@ -171,9 +171,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
{
protocolLayerOptions.FileContentDisposition = options.HttpHeaders.ContentDisposition;
}
if (!options.HttpHeaders.ContentMd5.empty())
if (!options.HttpHeaders.ContentHash.Value.empty())
{
protocolLayerOptions.FileContentMd5 = options.HttpHeaders.ContentMd5;
if (options.HttpHeaders.ContentHash.Algorithm != HashAlgorithm::Md5)
{
abort();
}
protocolLayerOptions.ContentMd5 = options.HttpHeaders.ContentHash;
}
protocolLayerOptions.LeaseIdOptional = options.AccessConditions.LeaseId;
return Details::ShareRestClient::File::Create(
@ -327,7 +331,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
}
Azure::Core::Response<Models::SetFilePropertiesResult> ShareFileClient::SetProperties(
Models::FileShareHttpHeaders httpHeaders,
Models::ShareFileHttpHeaders httpHeaders,
Models::FileShareSmbProperties smbProperties,
const SetFilePropertiesOptions& options) const
{
@ -410,7 +414,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
protocolLayerOptions.ContentLength = content->Length();
protocolLayerOptions.XMsRange = std::string("bytes=") + std::to_string(offset)
+ std::string("-") + std::to_string(offset + content->Length() - 1);
protocolLayerOptions.ContentMd5 = options.TransactionalMd5;
if (options.TransactionalContentHash.HasValue()
&& options.TransactionalContentHash.GetValue().Algorithm != HashAlgorithm::Md5)
{
abort();
}
protocolLayerOptions.ContentMd5 = options.TransactionalContentHash;
protocolLayerOptions.LeaseIdOptional = options.AccessConditions.LeaseId;
return Details::ShareRestClient::File::UploadRange(
m_shareFileUri, *content, *m_pipeline, options.Context, protocolLayerOptions);
@ -853,9 +862,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
{
protocolLayerOptions.FileContentDisposition = options.HttpHeaders.ContentDisposition;
}
if (!options.HttpHeaders.ContentMd5.empty())
if (!options.HttpHeaders.ContentHash.Value.empty())
{
protocolLayerOptions.FileContentMd5 = options.HttpHeaders.ContentMd5;
if (options.HttpHeaders.ContentHash.Algorithm != HashAlgorithm::Md5)
{
abort();
}
protocolLayerOptions.ContentMd5 = options.HttpHeaders.ContentHash;
}
protocolLayerOptions.Metadata = options.Metadata;
auto createResult = Details::ShareRestClient::File::Create(
@ -946,9 +959,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
{
protocolLayerOptions.FileContentDisposition = options.HttpHeaders.ContentDisposition;
}
if (!options.HttpHeaders.ContentMd5.empty())
if (!options.HttpHeaders.ContentHash.Value.empty())
{
protocolLayerOptions.FileContentMd5 = options.HttpHeaders.ContentMd5;
if (options.HttpHeaders.ContentHash.Algorithm != HashAlgorithm::Md5)
{
abort();
}
protocolLayerOptions.ContentMd5 = options.HttpHeaders.ContentHash;
}
protocolLayerOptions.Metadata = options.Metadata;
auto createResult = Details::ShareRestClient::File::Create(

View File

@ -39,10 +39,10 @@ namespace Azure { namespace Storage { namespace Test {
m_shareClient->Delete(deleteOptions);
}
Files::Shares::Models::FileShareHttpHeaders FileShareClientTest::GetInterestingHttpHeaders()
Files::Shares::Models::ShareFileHttpHeaders FileShareClientTest::GetInterestingHttpHeaders()
{
static Files::Shares::Models::FileShareHttpHeaders result = []() {
Files::Shares::Models::FileShareHttpHeaders ret;
static Files::Shares::Models::ShareFileHttpHeaders result = []() {
Files::Shares::Models::ShareFileHttpHeaders ret;
ret.CacheControl = std::string("no-cache");
ret.ContentDisposition = std::string("attachment");
ret.ContentEncoding = std::string("deflate");

View File

@ -11,7 +11,7 @@ namespace Azure { namespace Storage { namespace Test {
static void SetUpTestSuite();
static void TearDownTestSuite();
static Files::Shares::Models::FileShareHttpHeaders GetInterestingHttpHeaders();
static Files::Shares::Models::ShareFileHttpHeaders GetInterestingHttpHeaders();
static std::shared_ptr<Files::Shares::ShareClient> m_shareClient;
static std::string m_shareName;

View File

@ -26,11 +26,11 @@ namespace Azure { namespace Storage { namespace Test {
void FileShareDirectoryClientTest::TearDownTestSuite() { m_shareClient->Delete(); }
Files::Shares::Models::FileShareHttpHeaders
Files::Shares::Models::ShareFileHttpHeaders
FileShareDirectoryClientTest::GetInterestingHttpHeaders()
{
static Files::Shares::Models::FileShareHttpHeaders result = []() {
Files::Shares::Models::FileShareHttpHeaders ret;
static Files::Shares::Models::ShareFileHttpHeaders result = []() {
Files::Shares::Models::ShareFileHttpHeaders ret;
ret.CacheControl = std::string("no-cache");
ret.ContentDisposition = std::string("attachment");
ret.ContentEncoding = std::string("deflate");

View File

@ -19,7 +19,7 @@ namespace Azure { namespace Storage { namespace Test {
const std::string& directoryPath = std::string(),
const std::string& prefix = std::string());
static Files::Shares::Models::FileShareHttpHeaders GetInterestingHttpHeaders();
static Files::Shares::Models::ShareFileHttpHeaders GetInterestingHttpHeaders();
static std::shared_ptr<Files::Shares::ShareDirectoryClient> m_fileShareDirectoryClient;
static std::string m_directoryName;

View File

@ -560,14 +560,18 @@ namespace Azure { namespace Storage { namespace Test {
{
// MD5 works.
memBodyStream.Rewind();
auto md5String = Base64Encode(Md5::Hash(rangeContent.data(), rangeContent.size()));
auto invalidMd5String = Base64Encode(Md5::Hash(std::string("This is garbage.")));
auto md5 = Md5::Hash(rangeContent.data(), rangeContent.size());
auto invalidMd5 = Md5::Hash(std::string("This is garbage."));
auto fileClient = m_shareClient->GetShareFileClient(LowercaseRandomString(10));
Files::Shares::UploadFileRangeOptions uploadOptions;
fileClient.Create(static_cast<int64_t>(numOfChunks) * rangeSize);
uploadOptions.TransactionalMd5 = md5String;
ContentHash hash;
hash.Value = md5;
hash.Algorithm = HashAlgorithm::Md5;
uploadOptions.TransactionalContentHash = hash;
EXPECT_NO_THROW(fileClient.UploadRange(0, &memBodyStream, uploadOptions));
uploadOptions.TransactionalMd5 = invalidMd5String;
hash.Value = invalidMd5;
uploadOptions.TransactionalContentHash = hash;
memBodyStream.Rewind();
EXPECT_THROW(fileClient.UploadRange(0, &memBodyStream, uploadOptions), StorageException);
}

View File

@ -186,7 +186,7 @@ namespace Azure { namespace Storage { namespace Test {
// response headers override
{
Files::Shares::Models::FileShareHttpHeaders headers;
Files::Shares::Models::ShareFileHttpHeaders headers;
headers.ContentType = "application/x-binary";
headers.ContentLanguage = "en-US";
headers.ContentDisposition = "attachment";