diff --git a/sdk/storage/azure-storage-common/inc/azure/storage/common/access_conditions.hpp b/sdk/storage/azure-storage-common/inc/azure/storage/common/access_conditions.hpp index 99793aae6..c774faa41 100644 --- a/sdk/storage/azure-storage-common/inc/azure/storage/common/access_conditions.hpp +++ b/sdk/storage/azure-storage-common/inc/azure/storage/common/access_conditions.hpp @@ -58,4 +58,22 @@ namespace Azure { namespace Storage { Azure::Core::Nullable 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 IfMatchContentHash; + + /** + * @brief Specify this header to perform the operation only if the resource's ContentHash does + * not match the value specified. + */ + Azure::Core::Nullable IfNoneMatchContentHash; + }; + }} // namespace Azure::Storage diff --git a/sdk/storage/azure-storage-common/inc/azure/storage/common/storage_common.hpp b/sdk/storage/azure-storage-common/inc/azure/storage/common/storage_common.hpp index 1ccd3baf4..1ff8459ae 100644 --- a/sdk/storage/azure-storage-common/inc/azure/storage/common/storage_common.hpp +++ b/sdk/storage/azure-storage-common/inc/azure/storage/common/storage_common.hpp @@ -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; - /** * @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; + }} // namespace Azure::Storage diff --git a/sdk/storage/azure-storage-common/src/storage_common.cpp b/sdk/storage/azure-storage-common/src/storage_common.cpp index ffaa0cca4..b32ab6190 100644 --- a/sdk/storage/azure-storage-common/src/storage_common.cpp +++ b/sdk/storage/azure-storage-common/src/storage_common.cpp @@ -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 diff --git a/sdk/storage/azure-storage-files-datalake/CHANGELOG.md b/sdk/storage/azure-storage-files-datalake/CHANGELOG.md index c078f7fad..93d01c23f 100644 --- a/sdk/storage/azure-storage-files-datalake/CHANGELOG.md +++ b/sdk/storage/azure-storage-files-datalake/CHANGELOG.md @@ -6,6 +6,8 @@ - Move DataLake SAS into `Azure::Storage::Sas` namespace. - `EncrytionKeySha256` are changed to binary(`std::vector`). +- 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) diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp index b7594081c..28e56838b 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp @@ -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 ContentMd5; + Azure::Core::Nullable TransactionalContentHash; /** * @brief Specify the lease access conditions. @@ -263,18 +263,17 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { Azure::Core::Nullable 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 ContentMd5; + Azure::Core::Nullable 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. diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_path_client.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_path_client.hpp index d5117c99e..eed429363 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_path_client.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_path_client.hpp @@ -131,7 +131,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { * @remark This request is sent to blob endpoint. */ Azure::Core::Response SetHttpHeaders( - Models::DataLakeHttpHeaders httpHeaders, + Models::PathHttpHeaders httpHeaders, const SetPathHttpHeadersOptions& options = SetPathHttpHeadersOptions()) const; /** diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp index 35522c332..f3589458d 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp @@ -84,7 +84,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam Azure::Core::Nullable LeaseDuration; Azure::Core::Nullable LeaseState; Azure::Core::Nullable LeaseStatus; - DataLakeHttpHeaders HttpHeaders; + PathHttpHeaders HttpHeaders; Azure::Core::Nullable ServerEncrypted; Azure::Core::Nullable> EncryptionKeySha256; Azure::Core::Nullable AccessTierInferred; @@ -136,16 +136,15 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam struct ReadFileResult { std::unique_ptr Body; - DataLakeHttpHeaders HttpHeaders; + PathHttpHeaders HttpHeaders; Azure::Core::Nullable RangeOffset; Azure::Core::Nullable RangeLength; - Azure::Core::Nullable TransactionalMd5; + Azure::Core::Nullable TransactionalContentHash; std::string ETag; std::string LastModified; Azure::Core::Nullable LeaseDuration; LeaseStateType LeaseState = LeaseStateType::Unknown; LeaseStatusType LeaseStatus = LeaseStatusType::Unknown; - Azure::Core::Nullable ContentMd5; Storage::Metadata Metadata; std::string CreationTime; Azure::Core::Nullable 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 ServerEncrypted; Azure::Core::Nullable> EncryptionKeySha256; diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp index ffb7dfe21..ce4823825 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp @@ -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 BodyStream; std::string AcceptRanges; - DataLakeHttpHeaders HttpHeaders; + PathHttpHeaders HttpHeaders; int64_t ContentLength = int64_t(); Azure::Core::Nullable ContentRange; - Azure::Core::Nullable TransactionalMd5; + Azure::Core::Nullable 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 LeaseDuration; Models::LeaseStateType LeaseState = Models::LeaseStateType::Unknown; Models::LeaseStatusType LeaseStatus = Models::LeaseStatusType::Unknown; - Azure::Core::Nullable ContentMd5; }; struct PathGetPropertiesResult { Azure::Core::Nullable AcceptRanges; - DataLakeHttpHeaders HttpHeaders; + PathHttpHeaders HttpHeaders; int64_t ContentLength = int64_t(); Azure::Core::Nullable ContentRange; - Azure::Core::Nullable ContentMd5; std::string ETag; std::string LastModified; Azure::Core::Nullable ResourceType; @@ -372,8 +371,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { struct PathAppendDataResult { - Azure::Core::Nullable ContentMD5; - Azure::Core::Nullable ContentCrc64; + Azure::Core::Nullable 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 ContentMd5; // Specify the transactional md5 for the - // body, to be validated by the service. + Azure::Core::Nullable + ContentMd5; // Specify the transactional md5 for the body, to be validated by the + // service. Azure::Core::Nullable 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 + Azure::Core::Nullable TransactionalContentMd5; // Specify the transactional md5 for the body, to be // validated by the service. - Azure::Core::Nullable - ContentCrc64; // Specify the transactional crc64 for the body, to be validated by the - // service. + Azure::Core::Nullable + TransactionalContentCrc64; // Specify the transactional crc64 for the body, to be + // validated by the service. Azure::Core::Nullable 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"; diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp index 8ab33a80a..87998e07f 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp @@ -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); diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_path_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_path_client.cpp index 9460cdeb4..4bd418a87 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_path_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_path_client.cpp @@ -212,7 +212,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { } Azure::Core::Response PathClient::SetHttpHeaders( - Models::DataLakeHttpHeaders httpHeaders, + Models::PathHttpHeaders httpHeaders, const SetPathHttpHeadersOptions& options) const { Blobs::SetBlobHttpHeadersOptions blobOptions; diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp b/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp index bae86fcfd..e10018f92 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp @@ -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 diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp b/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp index 0fc3f4377..9b8ba8d66 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp @@ -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"); diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.hpp b/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.hpp index 78311940d..6db14dfee 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.hpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.hpp @@ -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 m_fileSystemClient; static std::string m_fileSystemName; diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_sas_test.cpp b/sdk/storage/azure-storage-files-datalake/test/datalake_sas_test.cpp index a47734759..c0b67af6d 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_sas_test.cpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_sas_test.cpp @@ -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"; diff --git a/sdk/storage/azure-storage-files-shares/CHANGELOG.md b/sdk/storage/azure-storage-files-shares/CHANGELOG.md index 0c7aafa1d..6add78cff 100644 --- a/sdk/storage/azure-storage-files-shares/CHANGELOG.md +++ b/sdk/storage/azure-storage-files-shares/CHANGELOG.md @@ -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) diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/protocol/share_rest_client.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/protocol/share_rest_client.hpp index 5f065bdde..5ccdc29d1 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/protocol/share_rest_client.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/protocol/share_rest_client.hpp @@ -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 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 ContentRange; std::string ETag; - Azure::Core::Nullable TransactionalContentMd5; + Azure::Core::Nullable TransactionalContentHash; std::string AcceptRanges; Azure::Core::Nullable CopyCompletionTime; Azure::Core::Nullable 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 CopyCompletionTime; Azure::Core::Nullable 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 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& 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 FileCacheControl; // Sets the file's cache control. The File service stores this value // but does not use or modify it. - Azure::Core::Nullable FileContentMd5; // Sets the file's MD5 hash. + Azure::Core::Nullable + 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 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 FileCacheControl; // Sets the file's cache control. The File service stores this value // but does not use or modify it. - Azure::Core::Nullable FileContentMd5; // Sets the file's MD5 hash. + Azure::Core::Nullable + 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 FileContentDisposition; // Sets the file's Content-Disposition header. Azure::Core::Nullable @@ -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 + Azure::Core::Nullable 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 + Azure::Core::Nullable SourceContentCrc64; // Specify the crc64 calculated for the range of bytes that must // be read from the copy source. - Azure::Core::Nullable + Azure::Core::Nullable SourceIfMatchCrc64; // Specify the crc64 value to operate only on range with a // matching crc64 checksum. - Azure::Core::Nullable + Azure::Core::Nullable 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( diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_file_client.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_file_client.hpp index fff833820..a9ef51107 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_file_client.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_file_client.hpp @@ -207,7 +207,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * the file returned from the server. */ Azure::Core::Response SetProperties( - Models::FileShareHttpHeaders httpHeaders, + Models::ShareFileHttpHeaders httpHeaders, Models::FileShareSmbProperties smbProperties, const SetFilePropertiesOptions& options = SetFilePropertiesOptions()) const; diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp index c921bd3ec..43a445348 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp @@ -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 TransactionalMd5; + Azure::Core::Nullable 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 SourceContentCrc64; + Azure::Core::Nullable 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 SourceIfMatchCrc64; + ContentHashAccessConditions SourceAccessCondition; /** - * @brief Specify the crc64 value to operate only on range without a matching crc64 checksum. - */ - Azure::Core::Nullable 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. diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_responses.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_responses.hpp index 6ce121a6b..ce09672db 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_responses.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_responses.hpp @@ -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 IsServerEncrypted; }; diff --git a/sdk/storage/azure-storage-files-shares/src/share_file_client.cpp b/sdk/storage/azure-storage-files-shares/src/share_file_client.cpp index ad1cfc339..159e856b6 100644 --- a/sdk/storage/azure-storage-files-shares/src/share_file_client.cpp +++ b/sdk/storage/azure-storage-files-shares/src/share_file_client.cpp @@ -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 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( diff --git a/sdk/storage/azure-storage-files-shares/test/share_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/share_client_test.cpp index bc0e57dea..2180bcc20 100644 --- a/sdk/storage/azure-storage-files-shares/test/share_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/share_client_test.cpp @@ -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"); diff --git a/sdk/storage/azure-storage-files-shares/test/share_client_test.hpp b/sdk/storage/azure-storage-files-shares/test/share_client_test.hpp index cdd8ae8a4..6f28020d8 100644 --- a/sdk/storage/azure-storage-files-shares/test/share_client_test.hpp +++ b/sdk/storage/azure-storage-files-shares/test/share_client_test.hpp @@ -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 m_shareClient; static std::string m_shareName; diff --git a/sdk/storage/azure-storage-files-shares/test/share_directory_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/share_directory_client_test.cpp index 5d3efeba1..f64ca0483 100644 --- a/sdk/storage/azure-storage-files-shares/test/share_directory_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/share_directory_client_test.cpp @@ -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"); diff --git a/sdk/storage/azure-storage-files-shares/test/share_directory_client_test.hpp b/sdk/storage/azure-storage-files-shares/test/share_directory_client_test.hpp index 22a46ded3..21f5e2b1c 100644 --- a/sdk/storage/azure-storage-files-shares/test/share_directory_client_test.hpp +++ b/sdk/storage/azure-storage-files-shares/test/share_directory_client_test.hpp @@ -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 m_fileShareDirectoryClient; static std::string m_directoryName; diff --git a/sdk/storage/azure-storage-files-shares/test/share_file_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/share_file_client_test.cpp index 48b560b00..4f9251876 100644 --- a/sdk/storage/azure-storage-files-shares/test/share_file_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/share_file_client_test.cpp @@ -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(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); } diff --git a/sdk/storage/azure-storage-files-shares/test/share_sas_test.cpp b/sdk/storage/azure-storage-files-shares/test/share_sas_test.cpp index ab766097b..5b5f90ed9 100644 --- a/sdk/storage/azure-storage-files-shares/test/share_sas_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/share_sas_test.cpp @@ -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";