Integrate Core::DateTime into storage (#1246)
* blob package can build * test can build * changelog * datatime for datalake sas * fix test error * user delegation key doesn't support time fractional part * add comments * Added DateTime for DataLake and many other refinements. * Resolved review comments. * Added changelog Co-authored-by: Tank Tang <kat@microsoft.com>
This commit is contained in:
parent
9abe10b228
commit
b8e5c95d21
@ -58,6 +58,7 @@
|
||||
- `ListBlobContainersSegment` is renamed to `ListBlobContainersSinglePage`.
|
||||
- `FindBlobsByTags` is renamed to `FindBlobsByTagsSinglePage`.
|
||||
- `MaxResults` in list APIs are renamed to `PageSizeHint`.
|
||||
- All date time related strings are now changed to `Azure::Core::DateTime` type.
|
||||
|
||||
## 12.0.0-beta.5 (2020-11-13)
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ namespace Azure { namespace Storage { namespace Blobs { namespace Models {
|
||||
struct DownloadBlobToResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
Azure::Core::DateTime LastModified;
|
||||
int64_t ContentLength = 0;
|
||||
BlobHttpHeaders HttpHeaders;
|
||||
Storage::Metadata Metadata;
|
||||
@ -36,7 +36,7 @@ namespace Azure { namespace Storage { namespace Blobs { namespace Models {
|
||||
struct GetPageBlobPageRangesResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
Azure::Core::DateTime LastModified;
|
||||
int64_t BlobContentLength = 0;
|
||||
std::vector<PageRange> PageRanges;
|
||||
std::vector<PageRange> ClearRanges;
|
||||
|
||||
@ -182,15 +182,16 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
|
||||
/**
|
||||
* @brief Optionally specify the time at which the shared access signature becomes
|
||||
* valid.
|
||||
* valid. This timestamp will be truncated to second.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> StartsOn;
|
||||
Azure::Core::Nullable<Azure::Core::DateTime> StartsOn;
|
||||
|
||||
/**
|
||||
* @brief The time at which the shared access signature becomes invalid. This field must
|
||||
* be omitted if it has been specified in an associated stored access policy.
|
||||
* be omitted if it has been specified in an associated stored access policy. This timestamp
|
||||
* will be truncated to second.
|
||||
*/
|
||||
std::string ExpiresOn;
|
||||
Azure::Core::DateTime ExpiresOn;
|
||||
|
||||
/**
|
||||
* @brief Specifies an IP address or a range of IP addresses from which to accept
|
||||
|
||||
@ -104,16 +104,16 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
* @brief Retrieves a key that can be used to delegate Active Directory authorization to
|
||||
* shared access signatures.
|
||||
*
|
||||
* @param startsOn Start time for the key's validity, in ISO date format. The time should be
|
||||
* specified in UTC.
|
||||
* @param expiresOn Expiration of the key's validity, in ISO date format. The time should be
|
||||
* specified in UTC.
|
||||
* @param startsOn Start time for the key's validity. The time should be specified in UTC, and
|
||||
* will be truncated to second.
|
||||
* @param expiresOn Expiration of the key's validity. The time should be specified in UTC, and
|
||||
* will be truncated to second.
|
||||
* @param options Optional parameters to execute this function.
|
||||
* @return A deserialized GetUserDelegationKeyResult instance.
|
||||
*/
|
||||
Azure::Core::Response<Models::GetUserDelegationKeyResult> GetUserDelegationKey(
|
||||
const std::string& startsOn,
|
||||
const std::string& expiresOn,
|
||||
const Azure::Core::DateTime& startsOn,
|
||||
const Azure::Core::DateTime& expiresOn,
|
||||
const GetUserDelegationKeyOptions& options = GetUserDelegationKeyOptions()) const;
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -128,12 +128,18 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
snapshotVersion = BlobVersionId;
|
||||
}
|
||||
|
||||
std::string stringToSign = Permissions + "\n" + (StartsOn.HasValue() ? StartsOn.GetValue() : "")
|
||||
+ "\n" + ExpiresOn + "\n" + canonicalName + "\n" + Identifier + "\n"
|
||||
+ (IPRange.HasValue() ? IPRange.GetValue() : "") + "\n" + protocol + "\n"
|
||||
+ Storage::Details::DefaultSasVersion + "\n" + resource + "\n" + snapshotVersion + "\n"
|
||||
+ CacheControl + "\n" + ContentDisposition + "\n" + ContentEncoding + "\n" + ContentLanguage
|
||||
+ "\n" + ContentType;
|
||||
std::string startsOnStr = StartsOn.HasValue()
|
||||
? StartsOn.GetValue().GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate)
|
||||
: "";
|
||||
std::string expiresOnStr = Identifier.empty()
|
||||
? ExpiresOn.GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate)
|
||||
: "";
|
||||
|
||||
std::string stringToSign = Permissions + "\n" + startsOnStr + "\n" + expiresOnStr + "\n"
|
||||
+ canonicalName + "\n" + Identifier + "\n" + (IPRange.HasValue() ? IPRange.GetValue() : "")
|
||||
+ "\n" + protocol + "\n" + Storage::Details::DefaultSasVersion + "\n" + resource + "\n"
|
||||
+ snapshotVersion + "\n" + CacheControl + "\n" + ContentDisposition + "\n" + ContentEncoding
|
||||
+ "\n" + ContentLanguage + "\n" + ContentType;
|
||||
|
||||
std::string signature = Base64Encode(Storage::Details::HmacSha256(
|
||||
std::vector<uint8_t>(stringToSign.begin(), stringToSign.end()),
|
||||
@ -143,14 +149,13 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
builder.AppendQueryParameter(
|
||||
"sv", Storage::Details::UrlEncodeQueryParameter(Storage::Details::DefaultSasVersion));
|
||||
builder.AppendQueryParameter("spr", Storage::Details::UrlEncodeQueryParameter(protocol));
|
||||
if (StartsOn.HasValue())
|
||||
if (!startsOnStr.empty())
|
||||
{
|
||||
builder.AppendQueryParameter(
|
||||
"st", Storage::Details::UrlEncodeQueryParameter(StartsOn.GetValue()));
|
||||
builder.AppendQueryParameter("st", Storage::Details::UrlEncodeQueryParameter(startsOnStr));
|
||||
}
|
||||
if (!ExpiresOn.empty())
|
||||
if (!expiresOnStr.empty())
|
||||
{
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(ExpiresOn));
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(expiresOnStr));
|
||||
}
|
||||
if (IPRange.HasValue())
|
||||
{
|
||||
@ -217,12 +222,21 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
snapshotVersion = BlobVersionId;
|
||||
}
|
||||
|
||||
std::string stringToSign = Permissions + "\n" + (StartsOn.HasValue() ? StartsOn.GetValue() : "")
|
||||
+ "\n" + ExpiresOn + "\n" + canonicalName + "\n" + userDelegationKey.SignedObjectId + "\n"
|
||||
+ userDelegationKey.SignedTenantId + "\n" + userDelegationKey.SignedStartsOn + "\n"
|
||||
+ userDelegationKey.SignedExpiresOn + "\n" + userDelegationKey.SignedService + "\n"
|
||||
+ userDelegationKey.SignedVersion + "\n\n\n\n"
|
||||
+ (IPRange.HasValue() ? IPRange.GetValue() : "") + "\n" + protocol + "\n"
|
||||
std::string startsOnStr = StartsOn.HasValue()
|
||||
? StartsOn.GetValue().GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate)
|
||||
: "";
|
||||
std::string expiresOnStr
|
||||
= ExpiresOn.GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate);
|
||||
std::string signedStartsOnStr = userDelegationKey.SignedStartsOn.GetRfc3339String(
|
||||
Azure::Core::DateTime::TimeFractionFormat::Truncate);
|
||||
std::string signedExpiresOnStr = userDelegationKey.SignedExpiresOn.GetRfc3339String(
|
||||
Azure::Core::DateTime::TimeFractionFormat::Truncate);
|
||||
|
||||
std::string stringToSign = Permissions + "\n" + startsOnStr + "\n" + expiresOnStr + "\n"
|
||||
+ canonicalName + "\n" + userDelegationKey.SignedObjectId + "\n"
|
||||
+ userDelegationKey.SignedTenantId + "\n" + signedStartsOnStr + "\n" + signedExpiresOnStr
|
||||
+ "\n" + userDelegationKey.SignedService + "\n" + userDelegationKey.SignedVersion
|
||||
+ "\n\n\n\n" + (IPRange.HasValue() ? IPRange.GetValue() : "") + "\n" + protocol + "\n"
|
||||
+ Storage::Details::DefaultSasVersion + "\n" + resource + "\n" + snapshotVersion + "\n"
|
||||
+ CacheControl + "\n" + ContentDisposition + "\n" + ContentEncoding + "\n" + ContentLanguage
|
||||
+ "\n" + ContentType;
|
||||
@ -235,12 +249,11 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
builder.AppendQueryParameter(
|
||||
"sv", Storage::Details::UrlEncodeQueryParameter(Storage::Details::DefaultSasVersion));
|
||||
builder.AppendQueryParameter("sr", Storage::Details::UrlEncodeQueryParameter(resource));
|
||||
if (StartsOn.HasValue())
|
||||
if (!startsOnStr.empty())
|
||||
{
|
||||
builder.AppendQueryParameter(
|
||||
"st", Storage::Details::UrlEncodeQueryParameter(StartsOn.GetValue()));
|
||||
builder.AppendQueryParameter("st", Storage::Details::UrlEncodeQueryParameter(startsOnStr));
|
||||
}
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(ExpiresOn));
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(expiresOnStr));
|
||||
builder.AppendQueryParameter("sp", Storage::Details::UrlEncodeQueryParameter(Permissions));
|
||||
if (IPRange.HasValue())
|
||||
{
|
||||
@ -253,9 +266,9 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
builder.AppendQueryParameter(
|
||||
"sktid", Storage::Details::UrlEncodeQueryParameter(userDelegationKey.SignedTenantId));
|
||||
builder.AppendQueryParameter(
|
||||
"skt", Storage::Details::UrlEncodeQueryParameter(userDelegationKey.SignedStartsOn));
|
||||
"skt", Storage::Details::UrlEncodeQueryParameter(signedStartsOnStr));
|
||||
builder.AppendQueryParameter(
|
||||
"ske", Storage::Details::UrlEncodeQueryParameter(userDelegationKey.SignedExpiresOn));
|
||||
"ske", Storage::Details::UrlEncodeQueryParameter(signedExpiresOnStr));
|
||||
builder.AppendQueryParameter(
|
||||
"sks", Storage::Details::UrlEncodeQueryParameter(userDelegationKey.SignedService));
|
||||
builder.AppendQueryParameter(
|
||||
|
||||
@ -134,8 +134,8 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
}
|
||||
|
||||
Azure::Core::Response<Models::GetUserDelegationKeyResult> BlobServiceClient::GetUserDelegationKey(
|
||||
const std::string& startsOn,
|
||||
const std::string& expiresOn,
|
||||
const Azure::Core::DateTime& startsOn,
|
||||
const Azure::Core::DateTime& expiresOn,
|
||||
const GetUserDelegationKeyOptions& options) const
|
||||
{
|
||||
Details::BlobRestClient::Service::GetUserDelegationKeyOptions protocolLayerOptions;
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
auto blobContentInfo = appendBlobClient.Create(m_blobUploadOptions);
|
||||
EXPECT_FALSE(blobContentInfo->ETag.empty());
|
||||
EXPECT_FALSE(blobContentInfo->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(blobContentInfo->LastModified));
|
||||
EXPECT_TRUE(blobContentInfo->VersionId.HasValue());
|
||||
EXPECT_FALSE(blobContentInfo->VersionId.GetValue().empty());
|
||||
EXPECT_FALSE(blobContentInfo->EncryptionScope.HasValue());
|
||||
@ -111,9 +111,9 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
UnmodifiedSince,
|
||||
};
|
||||
|
||||
auto lastModifiedTime = FromRfc1123(appendBlobClient.GetProperties()->LastModified);
|
||||
auto timeBeforeStr = ToRfc1123(lastModifiedTime - std::chrono::seconds(1));
|
||||
auto timeAfterStr = ToRfc1123(lastModifiedTime + std::chrono::seconds(1));
|
||||
auto lastModifiedTime = appendBlobClient.GetProperties()->LastModified;
|
||||
auto timeBeforeStr = lastModifiedTime - std::chrono::seconds(1);
|
||||
auto timeAfterStr = lastModifiedTime + std::chrono::seconds(1);
|
||||
for (auto condition : {Condition::ModifiedSince, Condition::UnmodifiedSince})
|
||||
{
|
||||
for (auto sinceTime : {TimePoint::TimeBefore, TimePoint::TimeAfter})
|
||||
@ -204,9 +204,9 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
= sourceBlobClient.AcquireLease(CreateUniqueLeaseId(), InfiniteLeaseDuration);
|
||||
std::string leaseId = leaseResponse->LeaseId;
|
||||
std::string eTag = leaseResponse->ETag;
|
||||
auto lastModifiedTime = FromRfc1123(leaseResponse->LastModified);
|
||||
auto timeBeforeStr = ToRfc1123(lastModifiedTime - std::chrono::seconds(1));
|
||||
auto timeAfterStr = ToRfc1123(lastModifiedTime + std::chrono::seconds(1));
|
||||
auto lastModifiedTime = leaseResponse->LastModified;
|
||||
auto timeBeforeStr = lastModifiedTime - std::chrono::seconds(1);
|
||||
auto timeAfterStr = lastModifiedTime + std::chrono::seconds(1);
|
||||
|
||||
auto destBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString(
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
@ -285,7 +285,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
sealOptions.AccessConditions.IfAppendPositionEqual = m_blobContent.size();
|
||||
auto sealResult = blobClient.Seal(sealOptions);
|
||||
EXPECT_FALSE(sealResult->ETag.empty());
|
||||
EXPECT_FALSE(sealResult->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(sealResult->LastModified));
|
||||
EXPECT_TRUE(sealResult->IsSealed);
|
||||
|
||||
downloadResult = blobClient.Download();
|
||||
|
||||
@ -25,10 +25,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
{
|
||||
Sas::AccountSasBuilder accountSasBuilder;
|
||||
accountSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp;
|
||||
accountSasBuilder.StartsOn
|
||||
= ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
accountSasBuilder.ExpiresOn
|
||||
= ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(60));
|
||||
accountSasBuilder.StartsOn = Azure::Core::DateTime::Now() - std::chrono::minutes(5);
|
||||
accountSasBuilder.ExpiresOn = Azure::Core::DateTime::Now() + std::chrono::minutes(60);
|
||||
accountSasBuilder.Services = Sas::AccountSasServices::Blobs;
|
||||
accountSasBuilder.ResourceTypes
|
||||
= Sas::AccountSasResource::Object | Sas::AccountSasResource::BlobContainer;
|
||||
|
||||
@ -42,7 +42,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
{
|
||||
Sas::BlobSasBuilder sasBuilder;
|
||||
sasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp;
|
||||
sasBuilder.ExpiresOn = ToIso8601(std::chrono::system_clock::now() + std::chrono::hours(72));
|
||||
sasBuilder.ExpiresOn = Azure::Core::DateTime::Now() + std::chrono::hours(72);
|
||||
sasBuilder.BlobContainerName = m_containerName;
|
||||
sasBuilder.Resource = Sas::BlobSasResource::BlobContainer;
|
||||
sasBuilder.SetPermissions(Sas::BlobContainerSasPermissions::All);
|
||||
@ -64,7 +64,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderDate).empty());
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderXMsVersion).empty());
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_THROW(container_client.Create(), StorageException);
|
||||
|
||||
auto res2 = container_client.Delete();
|
||||
@ -105,7 +105,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderDate).empty());
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderXMsVersion).empty());
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
|
||||
auto res2 = m_blobContainerClient->GetProperties();
|
||||
EXPECT_FALSE(res2.GetRawResponse().GetHeaders().at(Details::HttpHeaderRequestId).empty());
|
||||
@ -113,7 +113,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(res2.GetRawResponse().GetHeaders().at(Details::HttpHeaderXMsVersion).empty());
|
||||
auto properties = *res2;
|
||||
EXPECT_FALSE(properties.ETag.empty());
|
||||
EXPECT_FALSE(properties.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(properties.LastModified));
|
||||
EXPECT_EQ(properties.Metadata, metadata);
|
||||
|
||||
metadata.clear();
|
||||
@ -174,8 +174,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
for (const auto& blob : res->Items)
|
||||
{
|
||||
EXPECT_FALSE(blob.Name.empty());
|
||||
EXPECT_FALSE(blob.CreationTime.empty());
|
||||
EXPECT_FALSE(blob.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(blob.CreatedOn));
|
||||
EXPECT_TRUE(IsValidTime(blob.LastModified));
|
||||
EXPECT_FALSE(blob.ETag.empty());
|
||||
EXPECT_NE(blob.BlobType, Azure::Storage::Blobs::Models::BlobType::Unknown);
|
||||
if (blob.BlobType == Blobs::Models::BlobType::BlockBlob)
|
||||
@ -376,19 +376,19 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
options.AccessType = Blobs::Models::PublicAccessType::Blob;
|
||||
Blobs::Models::BlobSignedIdentifier identifier;
|
||||
identifier.Id = RandomString(64);
|
||||
identifier.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(1), 7);
|
||||
identifier.ExpiresOn = ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(1), 7);
|
||||
identifier.StartsOn = Azure::Core::DateTime::Now() - std::chrono::minutes(1);
|
||||
identifier.ExpiresOn = Azure::Core::DateTime::Now() + std::chrono::minutes(1);
|
||||
identifier.Permissions = "r";
|
||||
options.SignedIdentifiers.emplace_back(identifier);
|
||||
identifier.Id = RandomString(64);
|
||||
identifier.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(2), 7);
|
||||
identifier.ExpiresOn = ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(2), 7);
|
||||
identifier.StartsOn = Azure::Core::DateTime::Now() - std::chrono::minutes(2);
|
||||
identifier.ExpiresOn = Azure::Core::DateTime::Now() + std::chrono::minutes(2);
|
||||
identifier.Permissions = "racwdxlt";
|
||||
options.SignedIdentifiers.emplace_back(identifier);
|
||||
|
||||
auto ret = container_client.SetAccessPolicy(options);
|
||||
EXPECT_FALSE(ret->ETag.empty());
|
||||
EXPECT_FALSE(ret->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(ret->LastModified));
|
||||
|
||||
auto ret2 = container_client.GetAccessPolicy();
|
||||
EXPECT_EQ(ret2->ETag, ret->ETag);
|
||||
@ -405,11 +405,11 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
int32_t leaseDuration = 20;
|
||||
auto aLease = *m_blobContainerClient->AcquireLease(leaseId1, leaseDuration);
|
||||
EXPECT_FALSE(aLease.ETag.empty());
|
||||
EXPECT_FALSE(aLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(aLease.LastModified));
|
||||
EXPECT_EQ(aLease.LeaseId, leaseId1);
|
||||
aLease = *m_blobContainerClient->AcquireLease(leaseId1, leaseDuration);
|
||||
EXPECT_FALSE(aLease.ETag.empty());
|
||||
EXPECT_FALSE(aLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(aLease.LastModified));
|
||||
EXPECT_EQ(aLease.LeaseId, leaseId1);
|
||||
|
||||
auto properties = *m_blobContainerClient->GetProperties();
|
||||
@ -419,32 +419,32 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
auto rLease = *m_blobContainerClient->RenewLease(leaseId1);
|
||||
EXPECT_FALSE(rLease.ETag.empty());
|
||||
EXPECT_FALSE(rLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(rLease.LastModified));
|
||||
EXPECT_EQ(rLease.LeaseId, leaseId1);
|
||||
|
||||
std::string leaseId2 = CreateUniqueLeaseId();
|
||||
EXPECT_NE(leaseId1, leaseId2);
|
||||
auto cLease = *m_blobContainerClient->ChangeLease(leaseId1, leaseId2);
|
||||
EXPECT_FALSE(cLease.ETag.empty());
|
||||
EXPECT_FALSE(cLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(cLease.LastModified));
|
||||
EXPECT_EQ(cLease.LeaseId, leaseId2);
|
||||
|
||||
auto containerInfo = *m_blobContainerClient->ReleaseLease(leaseId2);
|
||||
EXPECT_FALSE(containerInfo.ETag.empty());
|
||||
EXPECT_FALSE(containerInfo.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(containerInfo.LastModified));
|
||||
|
||||
aLease = *m_blobContainerClient->AcquireLease(CreateUniqueLeaseId(), InfiniteLeaseDuration);
|
||||
properties = *m_blobContainerClient->GetProperties();
|
||||
EXPECT_FALSE(properties.LeaseDuration.GetValue().empty());
|
||||
auto brokenLease = *m_blobContainerClient->BreakLease();
|
||||
EXPECT_FALSE(brokenLease.ETag.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(brokenLease.LastModified));
|
||||
EXPECT_EQ(brokenLease.LeaseTime, 0);
|
||||
|
||||
aLease = *m_blobContainerClient->AcquireLease(CreateUniqueLeaseId(), leaseDuration);
|
||||
brokenLease = *m_blobContainerClient->BreakLease();
|
||||
EXPECT_FALSE(brokenLease.ETag.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(brokenLease.LastModified));
|
||||
EXPECT_NE(brokenLease.LeaseTime, 0);
|
||||
|
||||
Blobs::BreakBlobContainerLeaseOptions options;
|
||||
@ -645,21 +645,21 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
{
|
||||
for (auto sinceTime : {TimePoint::TimeBefore, TimePoint::TimeAfter})
|
||||
{
|
||||
auto lastModifiedTime = FromRfc1123(containerClient.GetProperties()->LastModified);
|
||||
auto timeBeforeStr = ToRfc1123(lastModifiedTime - std::chrono::seconds(1));
|
||||
auto timeAfterStr = ToRfc1123(lastModifiedTime + std::chrono::seconds(1));
|
||||
auto lastModifiedTime = containerClient.GetProperties()->LastModified;
|
||||
auto timeBefore = lastModifiedTime - std::chrono::seconds(1);
|
||||
auto timeAfter = lastModifiedTime + std::chrono::seconds(1);
|
||||
|
||||
Blobs::SetBlobContainerAccessPolicyOptions options;
|
||||
options.AccessType = Blobs::Models::PublicAccessType::Private;
|
||||
if (condition == Condition::ModifiedSince)
|
||||
{
|
||||
options.AccessConditions.IfModifiedSince
|
||||
= sinceTime == TimePoint::TimeBefore ? timeBeforeStr : timeAfterStr;
|
||||
= sinceTime == TimePoint::TimeBefore ? timeBefore : timeAfter;
|
||||
}
|
||||
else if (condition == Condition::UnmodifiedSince)
|
||||
{
|
||||
options.AccessConditions.IfUnmodifiedSince
|
||||
= sinceTime == TimePoint::TimeBefore ? timeBeforeStr : timeAfterStr;
|
||||
= sinceTime == TimePoint::TimeBefore ? timeBefore : timeAfter;
|
||||
}
|
||||
bool shouldThrow
|
||||
= (condition == Condition::ModifiedSince && sinceTime == TimePoint::TimeAfter)
|
||||
@ -723,8 +723,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_TRUE(deletedContainerItem.IsDeleted);
|
||||
EXPECT_TRUE(deletedContainerItem.VersionId.HasValue());
|
||||
EXPECT_FALSE(deletedContainerItem.VersionId.GetValue().empty());
|
||||
EXPECT_TRUE(deletedContainerItem.DeletedTime.HasValue());
|
||||
EXPECT_FALSE(deletedContainerItem.DeletedTime.GetValue().empty());
|
||||
EXPECT_TRUE(deletedContainerItem.DeletedOn.HasValue());
|
||||
EXPECT_TRUE(IsValidTime(deletedContainerItem.DeletedOn.GetValue()));
|
||||
EXPECT_TRUE(deletedContainerItem.RemainingRetentionDays.HasValue());
|
||||
EXPECT_GE(deletedContainerItem.RemainingRetentionDays.GetValue(), 0);
|
||||
|
||||
|
||||
@ -10,21 +10,22 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
TEST_F(BlobContainerClientTest, BlobSasTest)
|
||||
{
|
||||
auto sasStartsOn = Azure::Core::DateTime::Now() - std::chrono::minutes(5);
|
||||
auto sasExpiredOn = Azure::Core::DateTime::Now() - std::chrono::minutes(1);
|
||||
auto sasExpiresOn = Azure::Core::DateTime::Now() + std::chrono::minutes(60);
|
||||
|
||||
Sas::AccountSasBuilder accountSasBuilder;
|
||||
accountSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp;
|
||||
accountSasBuilder.StartsOn
|
||||
= ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
accountSasBuilder.ExpiresOn
|
||||
= ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(60));
|
||||
accountSasBuilder.StartsOn = sasStartsOn;
|
||||
accountSasBuilder.ExpiresOn = sasExpiresOn;
|
||||
accountSasBuilder.Services = Sas::AccountSasServices::Blobs;
|
||||
accountSasBuilder.ResourceTypes = Sas::AccountSasResource::All;
|
||||
|
||||
std::string blobName = RandomString();
|
||||
Sas::BlobSasBuilder blobSasBuilder;
|
||||
blobSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp;
|
||||
blobSasBuilder.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
blobSasBuilder.ExpiresOn
|
||||
= ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(60));
|
||||
blobSasBuilder.StartsOn = sasStartsOn;
|
||||
blobSasBuilder.ExpiresOn = sasExpiresOn;
|
||||
blobSasBuilder.BlobContainerName = m_containerName;
|
||||
blobSasBuilder.BlobName = blobName;
|
||||
blobSasBuilder.Resource = Sas::BlobSasResource::Blob;
|
||||
@ -49,9 +50,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
serviceUrl,
|
||||
std::make_shared<Azure::Identity::ClientSecretCredential>(
|
||||
AadTenantId(), AadClientId(), AadClientSecret()));
|
||||
auto userDelegationKey = *blobServiceClient1.GetUserDelegationKey(
|
||||
ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5)),
|
||||
ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(60)));
|
||||
auto userDelegationKey = *blobServiceClient1.GetUserDelegationKey(sasStartsOn, sasExpiresOn);
|
||||
|
||||
auto verify_blob_read = [&](const std::string& sas) {
|
||||
EXPECT_NO_THROW(blobClient0.Create());
|
||||
@ -218,8 +217,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
// Expires
|
||||
{
|
||||
Sas::AccountSasBuilder builder2 = accountSasBuilder;
|
||||
builder2.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
builder2.ExpiresOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(1));
|
||||
builder2.StartsOn = sasStartsOn;
|
||||
builder2.ExpiresOn = sasExpiredOn;
|
||||
auto sasToken = builder2.GenerateSasToken(*keyCredential);
|
||||
EXPECT_THROW(verify_blob_create(sasToken), StorageException);
|
||||
}
|
||||
@ -330,8 +329,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
// Expires
|
||||
{
|
||||
Sas::BlobSasBuilder builder2 = blobSasBuilder;
|
||||
builder2.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
builder2.ExpiresOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(1));
|
||||
builder2.StartsOn = sasStartsOn;
|
||||
builder2.ExpiresOn = sasExpiredOn;
|
||||
auto sasToken = builder2.GenerateSasToken(*keyCredential);
|
||||
EXPECT_THROW(verify_blob_create(sasToken), StorageException);
|
||||
|
||||
@ -372,15 +371,15 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
options.AccessType = Blobs::Models::PublicAccessType::Blob;
|
||||
Blobs::Models::BlobSignedIdentifier identifier;
|
||||
identifier.Id = RandomString(64);
|
||||
identifier.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
identifier.ExpiresOn = ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(60));
|
||||
identifier.StartsOn = sasStartsOn;
|
||||
identifier.ExpiresOn = sasExpiresOn;
|
||||
identifier.Permissions = "r";
|
||||
options.SignedIdentifiers.emplace_back(identifier);
|
||||
m_blobContainerClient->SetAccessPolicy(options);
|
||||
|
||||
Sas::BlobSasBuilder builder2 = blobSasBuilder;
|
||||
builder2.StartsOn.Reset();
|
||||
builder2.ExpiresOn.clear();
|
||||
builder2.ExpiresOn = Azure::Core::DateTime();
|
||||
builder2.SetPermissions(static_cast<Sas::BlobContainerSasPermissions>(0));
|
||||
builder2.Identifier = identifier.Id;
|
||||
|
||||
|
||||
@ -144,10 +144,10 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
{
|
||||
EXPECT_FALSE(container.Name.empty());
|
||||
EXPECT_FALSE(container.ETag.empty());
|
||||
EXPECT_FALSE(container.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(container.LastModified));
|
||||
EXPECT_FALSE(container.IsDeleted);
|
||||
EXPECT_FALSE(container.VersionId.HasValue());
|
||||
EXPECT_FALSE(container.DeletedTime.HasValue());
|
||||
EXPECT_FALSE(container.DeletedOn.HasValue());
|
||||
EXPECT_FALSE(container.RemainingRetentionDays.HasValue());
|
||||
EXPECT_EQ(container.DefaultEncryptionScope, AccountEncryptionKey);
|
||||
EXPECT_FALSE(container.PreventEncryptionScopeOverride);
|
||||
@ -339,9 +339,9 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto serviceStatistics = *secondaryServiceClient.GetStatistics();
|
||||
EXPECT_NE(
|
||||
serviceStatistics.GeoReplication.Status, Blobs::Models::BlobGeoReplicationStatus::Unknown);
|
||||
if (serviceStatistics.GeoReplication.LastSyncTime.HasValue())
|
||||
if (serviceStatistics.GeoReplication.LastSyncedOn.HasValue())
|
||||
{
|
||||
EXPECT_FALSE(serviceStatistics.GeoReplication.LastSyncTime.GetValue().empty());
|
||||
EXPECT_TRUE(IsValidTime(serviceStatistics.GeoReplication.LastSyncedOn.GetValue()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
= Azure::Core::Http::MemoryBodyStream(m_blobContent.data(), m_blobContent.size());
|
||||
auto blobContentInfo = blockBlobClient.Upload(&blobContent, m_blobUploadOptions);
|
||||
EXPECT_FALSE(blobContentInfo->ETag.empty());
|
||||
EXPECT_FALSE(blobContentInfo->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(blobContentInfo->LastModified));
|
||||
EXPECT_TRUE(blobContentInfo->VersionId.HasValue());
|
||||
EXPECT_FALSE(blobContentInfo->VersionId.GetValue().empty());
|
||||
EXPECT_FALSE(blobContentInfo->EncryptionScope.HasValue());
|
||||
@ -84,8 +84,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderDate).empty());
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderXMsVersion).empty());
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_FALSE(res->CreationTime.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_TRUE(IsValidTime(res->CreatedOn));
|
||||
EXPECT_EQ(res->HttpHeaders, m_blobUploadOptions.HttpHeaders);
|
||||
EXPECT_EQ(res->Metadata, m_blobUploadOptions.Metadata);
|
||||
EXPECT_EQ(res->BlobType, Azure::Storage::Blobs::Models::BlobType::BlockBlob);
|
||||
@ -106,16 +106,16 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
{
|
||||
{
|
||||
auto res = m_blockBlobClient->Download();
|
||||
ASSERT_TRUE(res->LastAccessTime.HasValue());
|
||||
EXPECT_FALSE(res->LastAccessTime.GetValue().empty());
|
||||
ASSERT_TRUE(res->LastAccessedOn.HasValue());
|
||||
EXPECT_TRUE(IsValidTime(res->LastAccessedOn.GetValue()));
|
||||
}
|
||||
{
|
||||
auto res = m_blockBlobClient->GetProperties();
|
||||
ASSERT_TRUE(res->LastAccessTime.HasValue());
|
||||
EXPECT_FALSE(res->LastAccessTime.GetValue().empty());
|
||||
ASSERT_TRUE(res->LastAccessedOn.HasValue());
|
||||
EXPECT_TRUE(IsValidTime(res->LastAccessedOn.GetValue()));
|
||||
}
|
||||
{
|
||||
std::string lastAccessTime;
|
||||
Azure::Core::DateTime lastAccessedOn;
|
||||
|
||||
Azure::Storage::Blobs::ListBlobsSinglePageOptions options;
|
||||
options.Prefix = m_blobName;
|
||||
@ -127,13 +127,13 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
{
|
||||
if (blob.Name == m_blobName)
|
||||
{
|
||||
lastAccessTime = blob.LastAccessTime.GetValue();
|
||||
lastAccessedOn = blob.LastAccessedOn.GetValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (!options.ContinuationToken.GetValue().empty());
|
||||
|
||||
EXPECT_FALSE(lastAccessTime.empty());
|
||||
EXPECT_TRUE(IsValidTime(lastAccessedOn));
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderDate).empty());
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderXMsVersion).empty());
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(res->HttpHeaders, m_blobUploadOptions.HttpHeaders);
|
||||
EXPECT_EQ(res->Metadata, m_blobUploadOptions.Metadata);
|
||||
EXPECT_EQ(res->BlobType, Azure::Storage::Blobs::Models::BlobType::BlockBlob);
|
||||
@ -175,7 +175,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderDate).empty());
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderXMsVersion).empty());
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_FALSE(res->CopyId.empty());
|
||||
EXPECT_TRUE(res->VersionId.HasValue());
|
||||
EXPECT_FALSE(res->VersionId.GetValue().empty());
|
||||
@ -191,7 +191,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(properties.CopyProgress.GetValue().empty());
|
||||
if (properties.CopyStatus.GetValue() == Azure::Storage::Blobs::Models::CopyStatus::Success)
|
||||
{
|
||||
EXPECT_FALSE(properties.CopyCompletionTime.GetValue().empty());
|
||||
EXPECT_TRUE(IsValidTime(properties.CopyCompletedOn.GetValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,7 +202,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderDate).empty());
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderXMsVersion).empty());
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_FALSE(res->Snapshot.empty());
|
||||
EXPECT_TRUE(res->VersionId.HasValue());
|
||||
EXPECT_FALSE(res->VersionId.GetValue().empty());
|
||||
@ -256,14 +256,14 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderDate).empty());
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderXMsVersion).empty());
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_FALSE(res->CreationTime.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_TRUE(IsValidTime(res->CreatedOn));
|
||||
EXPECT_EQ(res->Metadata, m_blobUploadOptions.Metadata);
|
||||
EXPECT_EQ(res->ContentLength, static_cast<int64_t>(m_blobContent.size()));
|
||||
EXPECT_EQ(res->HttpHeaders, m_blobUploadOptions.HttpHeaders);
|
||||
EXPECT_EQ(res->HttpHeaders.ContentHash.Algorithm, Storage::HashAlgorithm::Md5);
|
||||
EXPECT_EQ(res->Tier.GetValue(), Azure::Storage::Blobs::Models::AccessTier::Cool);
|
||||
EXPECT_FALSE(res->AccessTierChangeTime.GetValue().empty());
|
||||
EXPECT_TRUE(IsValidTime(res->AccessTierChangedOn.GetValue()));
|
||||
}
|
||||
|
||||
TEST_F(BlockBlobClientTest, StageBlock)
|
||||
@ -283,7 +283,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
options.Metadata = m_blobUploadOptions.Metadata;
|
||||
auto blobContentInfo = blockBlobClient.CommitBlockList({blockId1}, options);
|
||||
EXPECT_FALSE(blobContentInfo->ETag.empty());
|
||||
EXPECT_FALSE(blobContentInfo->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(blobContentInfo->LastModified));
|
||||
EXPECT_TRUE(blobContentInfo->VersionId.HasValue());
|
||||
EXPECT_FALSE(blobContentInfo->VersionId.GetValue().empty());
|
||||
auto res = blockBlobClient.GetBlockList();
|
||||
@ -291,7 +291,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderDate).empty());
|
||||
EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderXMsVersion).empty());
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(res->ContentLength, static_cast<int64_t>(block1Content.size()));
|
||||
ASSERT_FALSE(res->CommittedBlocks.empty());
|
||||
EXPECT_EQ(res->CommittedBlocks[0].Name, blockId1);
|
||||
@ -568,14 +568,14 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto res = blockBlobClient.DownloadTo(emptyContent.data(), 0);
|
||||
EXPECT_EQ(res->ContentLength, 0);
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(res->HttpHeaders, m_blobUploadOptions.HttpHeaders);
|
||||
EXPECT_EQ(res->Metadata, m_blobUploadOptions.Metadata);
|
||||
EXPECT_EQ(res->BlobType, Azure::Storage::Blobs::Models::BlobType::BlockBlob);
|
||||
res = blockBlobClient.DownloadTo(tempFilename);
|
||||
EXPECT_EQ(res->ContentLength, 0);
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(res->HttpHeaders, m_blobUploadOptions.HttpHeaders);
|
||||
EXPECT_EQ(res->Metadata, m_blobUploadOptions.Metadata);
|
||||
EXPECT_EQ(res->BlobType, Azure::Storage::Blobs::Models::BlobType::BlockBlob);
|
||||
@ -585,14 +585,14 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
res = blockBlobClient.DownloadTo(emptyContent.data(), static_cast<std::size_t>(8_MB));
|
||||
EXPECT_EQ(res->ContentLength, 0);
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(res->HttpHeaders, m_blobUploadOptions.HttpHeaders);
|
||||
EXPECT_EQ(res->Metadata, m_blobUploadOptions.Metadata);
|
||||
EXPECT_EQ(res->BlobType, Azure::Storage::Blobs::Models::BlobType::BlockBlob);
|
||||
res = blockBlobClient.DownloadTo(tempFilename);
|
||||
EXPECT_EQ(res->ContentLength, 0);
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(res->HttpHeaders, m_blobUploadOptions.HttpHeaders);
|
||||
EXPECT_EQ(res->Metadata, m_blobUploadOptions.Metadata);
|
||||
EXPECT_EQ(res->BlobType, Azure::Storage::Blobs::Models::BlobType::BlockBlob);
|
||||
@ -610,14 +610,14 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
emptyContent.data(), static_cast<std::size_t>(8_MB), options);
|
||||
EXPECT_EQ(res->ContentLength, 0);
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(res->HttpHeaders, m_blobUploadOptions.HttpHeaders);
|
||||
EXPECT_EQ(res->Metadata, m_blobUploadOptions.Metadata);
|
||||
EXPECT_EQ(res->BlobType, Azure::Storage::Blobs::Models::BlobType::BlockBlob);
|
||||
res = blockBlobClient.DownloadTo(tempFilename, options);
|
||||
EXPECT_EQ(res->ContentLength, 0);
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(res->HttpHeaders, m_blobUploadOptions.HttpHeaders);
|
||||
EXPECT_EQ(res->Metadata, m_blobUploadOptions.Metadata);
|
||||
EXPECT_EQ(res->BlobType, Azure::Storage::Blobs::Models::BlobType::BlockBlob);
|
||||
@ -670,7 +670,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto res = blockBlobClient.UploadFrom(
|
||||
blobContent.data(), static_cast<std::size_t>(blobSize), options);
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
auto properties = *blockBlobClient.GetProperties();
|
||||
properties.HttpHeaders.ContentHash.Value.clear();
|
||||
EXPECT_EQ(properties.ContentLength, blobSize);
|
||||
@ -705,7 +705,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
}
|
||||
auto res = blockBlobClient.UploadFrom(tempFilename, options);
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
auto properties = *blockBlobClient.GetProperties();
|
||||
properties.HttpHeaders.ContentHash.Value.clear();
|
||||
EXPECT_EQ(properties.ContentLength, blobSize);
|
||||
|
||||
@ -50,7 +50,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
StandardStorageConnectionString(), m_containerName, RandomString());
|
||||
auto blobContentInfo = pageBlobClient.Create(0, m_blobUploadOptions);
|
||||
EXPECT_FALSE(blobContentInfo->ETag.empty());
|
||||
EXPECT_FALSE(blobContentInfo->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(blobContentInfo->LastModified));
|
||||
EXPECT_TRUE(blobContentInfo->VersionId.HasValue());
|
||||
EXPECT_FALSE(blobContentInfo->VersionId.GetValue().empty());
|
||||
EXPECT_FALSE(blobContentInfo->EncryptionScope.HasValue());
|
||||
@ -147,7 +147,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
sourceUri.AppendQueryParameters(GetSas());
|
||||
auto copyInfo = pageBlobClient.StartCopyIncremental(sourceUri.GetAbsoluteUrl());
|
||||
EXPECT_FALSE(copyInfo->ETag.empty());
|
||||
EXPECT_FALSE(copyInfo->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(copyInfo->LastModified));
|
||||
EXPECT_FALSE(copyInfo->CopyId.empty());
|
||||
EXPECT_NE(copyInfo->CopyStatus, Blobs::Models::CopyStatus::Unknown);
|
||||
EXPECT_TRUE(copyInfo->VersionId.HasValue());
|
||||
@ -160,11 +160,11 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
int32_t leaseDuration = 20;
|
||||
auto aLease = *m_pageBlobClient->AcquireLease(leaseId1, leaseDuration);
|
||||
EXPECT_FALSE(aLease.ETag.empty());
|
||||
EXPECT_FALSE(aLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(aLease.LastModified));
|
||||
EXPECT_EQ(aLease.LeaseId, leaseId1);
|
||||
aLease = *m_pageBlobClient->AcquireLease(leaseId1, leaseDuration);
|
||||
EXPECT_FALSE(aLease.ETag.empty());
|
||||
EXPECT_FALSE(aLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(aLease.LastModified));
|
||||
EXPECT_EQ(aLease.LeaseId, leaseId1);
|
||||
|
||||
auto properties = *m_pageBlobClient->GetProperties();
|
||||
@ -174,32 +174,32 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
auto rLease = *m_pageBlobClient->RenewLease(leaseId1);
|
||||
EXPECT_FALSE(rLease.ETag.empty());
|
||||
EXPECT_FALSE(rLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(rLease.LastModified));
|
||||
EXPECT_EQ(rLease.LeaseId, leaseId1);
|
||||
|
||||
std::string leaseId2 = CreateUniqueLeaseId();
|
||||
EXPECT_NE(leaseId1, leaseId2);
|
||||
auto cLease = *m_pageBlobClient->ChangeLease(leaseId1, leaseId2);
|
||||
EXPECT_FALSE(cLease.ETag.empty());
|
||||
EXPECT_FALSE(cLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(cLease.LastModified));
|
||||
EXPECT_EQ(cLease.LeaseId, leaseId2);
|
||||
|
||||
auto blobInfo = *m_pageBlobClient->ReleaseLease(leaseId2);
|
||||
EXPECT_FALSE(blobInfo.ETag.empty());
|
||||
EXPECT_FALSE(blobInfo.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(blobInfo.LastModified));
|
||||
|
||||
aLease = *m_pageBlobClient->AcquireLease(CreateUniqueLeaseId(), InfiniteLeaseDuration);
|
||||
properties = *m_pageBlobClient->GetProperties();
|
||||
EXPECT_FALSE(properties.LeaseDuration.GetValue().empty());
|
||||
auto brokenLease = *m_pageBlobClient->BreakLease();
|
||||
EXPECT_FALSE(brokenLease.ETag.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(brokenLease.LastModified));
|
||||
EXPECT_EQ(brokenLease.LeaseTime, 0);
|
||||
|
||||
aLease = *m_pageBlobClient->AcquireLease(CreateUniqueLeaseId(), leaseDuration);
|
||||
brokenLease = *m_pageBlobClient->BreakLease();
|
||||
EXPECT_FALSE(brokenLease.ETag.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(brokenLease.LastModified));
|
||||
EXPECT_NE(brokenLease.LeaseTime, 0);
|
||||
|
||||
Blobs::BreakBlobLeaseOptions options;
|
||||
|
||||
@ -87,7 +87,9 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
response->AddHeader("x-ms-request-id", Core::Uuid::CreateUuid().GetUuidString());
|
||||
response->AddHeader("x-ms-version", Blobs::Details::ApiVersion);
|
||||
response->AddHeader("x-ms-error-code", "BlobNotFound");
|
||||
response->AddHeader("date", ToRfc1123(std::chrono::system_clock::now()));
|
||||
response->AddHeader(
|
||||
"date",
|
||||
Azure::Core::DateTime::Now().GetString(Azure::Core::DateTime::DateFormat::Rfc1123));
|
||||
return response;
|
||||
};
|
||||
auto ConstructPreconditionFailedResponse = []() {
|
||||
@ -109,36 +111,40 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
response->AddHeader("x-ms-request-id", Core::Uuid::CreateUuid().GetUuidString());
|
||||
response->AddHeader("x-ms-version", Blobs::Details::ApiVersion);
|
||||
response->AddHeader("x-ms-error-code", "ConditionNotMet");
|
||||
response->AddHeader("date", ToRfc1123(std::chrono::system_clock::now()));
|
||||
response->AddHeader(
|
||||
"date",
|
||||
Azure::Core::DateTime::Now().GetString(Azure::Core::DateTime::DateFormat::Rfc1123));
|
||||
return response;
|
||||
};
|
||||
auto ConstructPrimaryResponse
|
||||
= [requestOffset, requestLength, this, ConstructNotFoundResponse]() {
|
||||
if (!m_primaryContent)
|
||||
{
|
||||
return ConstructNotFoundResponse();
|
||||
}
|
||||
auto response = std::make_unique<Core::Http::RawResponse>(
|
||||
Core::Http::RawResponse(1, 1, Core::Http::HttpStatusCode::Ok, "OK"));
|
||||
int64_t bodyLength = std::min(
|
||||
static_cast<int64_t>(m_primaryContent->length()) - requestOffset, requestLength);
|
||||
auto bodyStream = std::make_unique<Core::Http::MemoryBodyStream>(
|
||||
reinterpret_cast<const uint8_t*>(m_primaryContent->data() + requestOffset),
|
||||
bodyLength);
|
||||
response->SetBodyStream(std::move(bodyStream));
|
||||
response->AddHeader("content-length", std::to_string(bodyLength));
|
||||
response->AddHeader("etag", m_primaryETag);
|
||||
response->AddHeader("last-modified", "Thu 27 Aug 2001 07:00:00 GMT");
|
||||
response->AddHeader("x-ms-request-id", Core::Uuid::CreateUuid().GetUuidString());
|
||||
response->AddHeader("x-ms-version", Blobs::Details::ApiVersion);
|
||||
response->AddHeader("x-ms-creation-time", "Thu 27 Aug 2002 07:00:00 GMT");
|
||||
response->AddHeader("x-ms-lease-status", "unlocked");
|
||||
response->AddHeader("x-ms-lease-state", "available");
|
||||
response->AddHeader("x-ms-blob-type", "BlockBlob");
|
||||
response->AddHeader("x-ms-server-encrypted", "true");
|
||||
response->AddHeader("date", ToRfc1123(std::chrono::system_clock::now()));
|
||||
return response;
|
||||
};
|
||||
auto ConstructPrimaryResponse =
|
||||
[requestOffset, requestLength, this, ConstructNotFoundResponse]() {
|
||||
if (!m_primaryContent)
|
||||
{
|
||||
return ConstructNotFoundResponse();
|
||||
}
|
||||
auto response = std::make_unique<Core::Http::RawResponse>(
|
||||
Core::Http::RawResponse(1, 1, Core::Http::HttpStatusCode::Ok, "OK"));
|
||||
int64_t bodyLength = std::min(
|
||||
static_cast<int64_t>(m_primaryContent->length()) - requestOffset, requestLength);
|
||||
auto bodyStream = std::make_unique<Core::Http::MemoryBodyStream>(
|
||||
reinterpret_cast<const uint8_t*>(m_primaryContent->data() + requestOffset),
|
||||
bodyLength);
|
||||
response->SetBodyStream(std::move(bodyStream));
|
||||
response->AddHeader("content-length", std::to_string(bodyLength));
|
||||
response->AddHeader("etag", m_primaryETag);
|
||||
response->AddHeader("last-modified", "Thu, 23 Aug 2001 07:00:00 GMT");
|
||||
response->AddHeader("x-ms-request-id", Core::Uuid::CreateUuid().GetUuidString());
|
||||
response->AddHeader("x-ms-version", Blobs::Details::ApiVersion);
|
||||
response->AddHeader("x-ms-creation-time", "Thu, 22 Aug 2002 07:00:00 GMT");
|
||||
response->AddHeader("x-ms-lease-status", "unlocked");
|
||||
response->AddHeader("x-ms-lease-state", "available");
|
||||
response->AddHeader("x-ms-blob-type", "BlockBlob");
|
||||
response->AddHeader("x-ms-server-encrypted", "true");
|
||||
response->AddHeader(
|
||||
"date",
|
||||
Azure::Core::DateTime::Now().GetString(Azure::Core::DateTime::DateFormat::Rfc1123));
|
||||
return response;
|
||||
};
|
||||
auto ConstructSecondaryResponse =
|
||||
[requestOffset, requestLength, this, ConstructNotFoundResponse]() {
|
||||
if (!m_secondaryContent)
|
||||
@ -155,15 +161,17 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
response->SetBodyStream(std::move(bodyStream));
|
||||
response->AddHeader("content-length", std::to_string(bodyLength));
|
||||
response->AddHeader("etag", m_secondaryETag);
|
||||
response->AddHeader("last-modified", "Thu 27 Aug 2001 07:00:00 GMT");
|
||||
response->AddHeader("last-modified", "Thu, 23 Aug 2001 07:00:00 GMT");
|
||||
response->AddHeader("x-ms-request-id", Core::Uuid::CreateUuid().GetUuidString());
|
||||
response->AddHeader("x-ms-version", Blobs::Details::ApiVersion);
|
||||
response->AddHeader("x-ms-creation-time", "Thu 27 Aug 2002 07:00:00 GMT");
|
||||
response->AddHeader("x-ms-creation-time", "Thu, 22 Aug 2002 07:00:00 GMT");
|
||||
response->AddHeader("x-ms-lease-status", "unlocked");
|
||||
response->AddHeader("x-ms-lease-state", "available");
|
||||
response->AddHeader("x-ms-blob-type", "BlockBlob");
|
||||
response->AddHeader("x-ms-server-encrypted", "true");
|
||||
response->AddHeader("date", ToRfc1123(std::chrono::system_clock::now()));
|
||||
response->AddHeader(
|
||||
"date",
|
||||
Azure::Core::DateTime::Now().GetString(Azure::Core::DateTime::DateFormat::Rfc1123));
|
||||
return response;
|
||||
};
|
||||
|
||||
|
||||
@ -2,12 +2,18 @@
|
||||
|
||||
## 12.0.0-beta.6 (Unreleased)
|
||||
|
||||
### New Features
|
||||
|
||||
- Add new type `ContentHash`.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- Rename `SharedKeyCredential` to `StorageSharedKeyCredential`.
|
||||
- Rename `StorageSharedKeyCredential::UpdateAccountKey` to `StorageSharedKeyCredential::Update`.
|
||||
- Move `StorageRetryPolicy`, `StoragePerRetryPolicy` and `SharedKeyPolicy` to `Details` namespace.
|
||||
- Remove `StorageRetryOptions`, use `Azure::Core::Http::RetryOptions` instead.
|
||||
- Move Account SAS into `Azure::Storage::Sas` namespace.
|
||||
- Add new type `ContentHash`.
|
||||
- All date time related strings are now changed to `Azure::Core::DateTime` type.
|
||||
|
||||
## 12.0.0-beta.5 (2020-11-13)
|
||||
|
||||
|
||||
@ -18,15 +18,15 @@ namespace Azure { namespace Storage {
|
||||
{
|
||||
/**
|
||||
* @brief Specify this header to perform the operation only if the resource has been
|
||||
* modified since the specified time.
|
||||
* modified since the specified time. This timestamp will be truncated to second.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> IfModifiedSince;
|
||||
Azure::Core::Nullable<Azure::Core::DateTime> IfModifiedSince;
|
||||
|
||||
/**
|
||||
* @brief Specify this header to perform the operation only if the resource has not been
|
||||
* modified since the specified date/time.
|
||||
* modified since the specified date/time. This timestamp will be truncated to second.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> IfUnmodifiedSince;
|
||||
Azure::Core::Nullable<Azure::Core::DateTime> IfUnmodifiedSince;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include <azure/core/datetime.hpp>
|
||||
#include <azure/core/nullable.hpp>
|
||||
|
||||
#include "azure/storage/common/constants.hpp"
|
||||
@ -216,13 +217,13 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
* @brief Optionally specify the time at which the shared access signature becomes
|
||||
* valid.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> StartsOn;
|
||||
Azure::Core::Nullable<Azure::Core::DateTime> StartsOn;
|
||||
|
||||
/**
|
||||
* @brief The time at which the shared access signature becomes invalid. This field must
|
||||
* be omitted if it has been specified in an associated stored access policy.
|
||||
*/
|
||||
std::string ExpiresOn;
|
||||
Azure::Core::DateTime ExpiresOn;
|
||||
|
||||
/**
|
||||
* @brief Specifies an IP address or a range of IP addresses from which to accept
|
||||
|
||||
@ -91,9 +91,15 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
resourceTypes += "o";
|
||||
}
|
||||
|
||||
std::string startsOnStr = StartsOn.HasValue()
|
||||
? StartsOn.GetValue().GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate)
|
||||
: "";
|
||||
std::string expiresOnStr
|
||||
= ExpiresOn.GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate);
|
||||
|
||||
std::string stringToSign = credential.AccountName + "\n" + Permissions + "\n" + services + "\n"
|
||||
+ resourceTypes + "\n" + (StartsOn.HasValue() ? StartsOn.GetValue() : "") + "\n" + ExpiresOn
|
||||
+ "\n" + (IPRange.HasValue() ? IPRange.GetValue() : "") + "\n" + protocol + "\n"
|
||||
+ resourceTypes + "\n" + startsOnStr + "\n" + expiresOnStr + "\n"
|
||||
+ (IPRange.HasValue() ? IPRange.GetValue() : "") + "\n" + protocol + "\n"
|
||||
+ Storage::Details::DefaultSasVersion + "\n";
|
||||
|
||||
std::string signature = Base64Encode(Storage::Details::HmacSha256(
|
||||
@ -106,12 +112,11 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
builder.AppendQueryParameter("ss", Storage::Details::UrlEncodeQueryParameter(services));
|
||||
builder.AppendQueryParameter("srt", Storage::Details::UrlEncodeQueryParameter(resourceTypes));
|
||||
builder.AppendQueryParameter("sp", Storage::Details::UrlEncodeQueryParameter(Permissions));
|
||||
if (StartsOn.HasValue())
|
||||
if (!startsOnStr.empty())
|
||||
{
|
||||
builder.AppendQueryParameter(
|
||||
"st", Storage::Details::UrlEncodeQueryParameter(StartsOn.GetValue()));
|
||||
builder.AppendQueryParameter("st", startsOnStr);
|
||||
}
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(ExpiresOn));
|
||||
builder.AppendQueryParameter("se", expiresOnStr);
|
||||
if (IPRange.HasValue())
|
||||
{
|
||||
builder.AppendQueryParameter(
|
||||
|
||||
@ -235,66 +235,6 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ToIso8601(
|
||||
const std::chrono::system_clock::time_point& timePoint,
|
||||
int numDecimalDigits)
|
||||
{
|
||||
std::time_t epoch_seconds = std::chrono::system_clock::to_time_t(timePoint);
|
||||
struct tm ct;
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
gmtime_s(&ct, &epoch_seconds);
|
||||
#elif defined(AZ_PLATFORM_POSIX)
|
||||
gmtime_r(&epoch_seconds, &ct);
|
||||
#endif
|
||||
std::string time_str;
|
||||
time_str.resize(64);
|
||||
std::strftime(&time_str[0], time_str.length(), "%Y-%m-%dT%H:%M:%S", &ct);
|
||||
time_str = time_str.data();
|
||||
if (numDecimalDigits != 0)
|
||||
{
|
||||
time_str += ".";
|
||||
auto time_point_second = std::chrono::time_point_cast<std::chrono::seconds>(timePoint);
|
||||
auto decimal_part = timePoint - time_point_second;
|
||||
uint64_t num_nanoseconds
|
||||
= std::chrono::duration_cast<std::chrono::nanoseconds>(decimal_part).count();
|
||||
std::string decimal_part_str = std::to_string(num_nanoseconds);
|
||||
decimal_part_str = std::string(9 - decimal_part_str.length(), '0') + decimal_part_str;
|
||||
decimal_part_str.resize(numDecimalDigits);
|
||||
time_str += decimal_part_str;
|
||||
}
|
||||
time_str += "Z";
|
||||
return time_str;
|
||||
}
|
||||
|
||||
std::string ToRfc1123(const std::chrono::system_clock::time_point& timePoint)
|
||||
{
|
||||
std::time_t epoch_seconds = std::chrono::system_clock::to_time_t(timePoint);
|
||||
struct tm ct;
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
gmtime_s(&ct, &epoch_seconds);
|
||||
#elif defined(AZ_PLATFORM_POSIX)
|
||||
gmtime_r(&epoch_seconds, &ct);
|
||||
#endif
|
||||
std::stringstream ss;
|
||||
ss.imbue(std::locale("C"));
|
||||
ss << std::put_time(&ct, "%a, %d %b %Y %H:%M:%S GMT");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point FromRfc1123(const std::string& timeStr)
|
||||
{
|
||||
std::tm t;
|
||||
std::stringstream ss(timeStr);
|
||||
ss.imbue(std::locale("C"));
|
||||
ss >> std::get_time(&t, "%a, %d %b %Y %H:%M:%S GMT");
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
time_t tt = _mkgmtime(&t);
|
||||
#elif defined(AZ_PLATFORM_POSIX)
|
||||
time_t tt = timegm(&t);
|
||||
#endif
|
||||
return std::chrono::system_clock::from_time_t(tt);
|
||||
}
|
||||
|
||||
std::string InferSecondaryUrl(const std::string primaryUrl)
|
||||
{
|
||||
Azure::Core::Http::Url secondaryUri(primaryUrl);
|
||||
@ -306,4 +246,12 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
return secondaryUri.GetAbsoluteUrl();
|
||||
}
|
||||
|
||||
bool IsValidTime(const Azure::Core::DateTime& datetime)
|
||||
{
|
||||
// We assume datetime within a week is valid.
|
||||
const auto minTime = Azure::Core::DateTime::Now() - std::chrono::hours(24 * 7);
|
||||
const auto maxTime = Azure::Core::DateTime::Now() + std::chrono::hours(24 * 7);
|
||||
return datetime > minTime && datetime < maxTime;
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include <azure/core/datetime.hpp>
|
||||
#include <azure/core/http/body_stream.hpp>
|
||||
#include <azure/storage/common/constants.hpp>
|
||||
#include <azure/storage/common/storage_common.hpp>
|
||||
@ -78,13 +79,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
void DeleteFile(const std::string& filename);
|
||||
|
||||
std::string ToIso8601(
|
||||
const std::chrono::system_clock::time_point& timePoint,
|
||||
int numDecimalDigits = 0);
|
||||
std::string ToRfc1123(const std::chrono::system_clock::time_point& timePoint);
|
||||
|
||||
std::chrono::system_clock::time_point FromRfc1123(const std::string& timeStr);
|
||||
|
||||
std::string InferSecondaryUrl(const std::string primaryUri);
|
||||
|
||||
bool IsValidTime(const Azure::Core::DateTime& datetime);
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
|
||||
@ -8,6 +8,12 @@
|
||||
- `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.
|
||||
- All date time related strings are now changed to `Azure::Core::DateTime` type.
|
||||
- `CreationTime` is renamed to `CreatedOn`.
|
||||
- `AccessTierChangeTime` is renamed to `AccessTierChangedOn`.
|
||||
- `CopyCompletionTime` is renamed to `CopyCompletedOn`.
|
||||
- `ExpiryTime` is renamed to `ExpiresOn`.
|
||||
- `LastAccessTime` is renamed to `LastAccessedOn`.
|
||||
|
||||
## 12.0.0-beta.5 (2020-11-13)
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam
|
||||
struct GetFileSystemPropertiesResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
Core::DateTime LastModified;
|
||||
Storage::Metadata Metadata;
|
||||
};
|
||||
|
||||
@ -82,8 +82,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam
|
||||
struct GetPathPropertiesResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
std::string CreationTime;
|
||||
Core::DateTime LastModified;
|
||||
Core::DateTime CreatedOn;
|
||||
int64_t ContentLength;
|
||||
Storage::Metadata Metadata;
|
||||
Azure::Core::Nullable<std::string> LeaseDuration;
|
||||
@ -93,39 +93,39 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam
|
||||
Azure::Core::Nullable<bool> ServerEncrypted;
|
||||
Azure::Core::Nullable<std::vector<uint8_t>> EncryptionKeySha256;
|
||||
Azure::Core::Nullable<bool> AccessTierInferred;
|
||||
Azure::Core::Nullable<std::string> AccessTierChangeTime;
|
||||
Azure::Core::Nullable<Core::DateTime> AccessTierChangedOn;
|
||||
Azure::Core::Nullable<std::string> CopyId;
|
||||
Azure::Core::Nullable<std::string> CopySource;
|
||||
Azure::Core::Nullable<Blobs::Models::CopyStatus> CopyStatus;
|
||||
Azure::Core::Nullable<std::string> CopyProgress;
|
||||
Azure::Core::Nullable<std::string> CopyCompletionTime;
|
||||
Azure::Core::Nullable<std::string> ExpiryTime;
|
||||
Azure::Core::Nullable<std::string> LastAccessTime;
|
||||
Azure::Core::Nullable<Core::DateTime> CopyCompletedOn;
|
||||
Azure::Core::Nullable<Core::DateTime> ExpiresOn;
|
||||
Azure::Core::Nullable<Core::DateTime> LastAccessedOn;
|
||||
};
|
||||
|
||||
struct GetPathAccessControlResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
Core::DateTime LastModified;
|
||||
std::vector<Acl> Acls;
|
||||
};
|
||||
|
||||
struct SetPathHttpHeadersResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
Core::DateTime LastModified;
|
||||
};
|
||||
|
||||
struct SetPathMetadataResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
Core::DateTime LastModified;
|
||||
};
|
||||
|
||||
struct CreatePathResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
Core::DateTime LastModified;
|
||||
Azure::Core::Nullable<int64_t> ContentLength;
|
||||
};
|
||||
|
||||
@ -146,14 +146,14 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam
|
||||
Azure::Core::Nullable<int64_t> RangeLength;
|
||||
Azure::Core::Nullable<Storage::ContentHash> TransactionalContentHash;
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
Core::DateTime LastModified;
|
||||
Azure::Core::Nullable<std::string> LeaseDuration;
|
||||
LeaseStateType LeaseState = LeaseStateType::Unknown;
|
||||
LeaseStatusType LeaseStatus = LeaseStatusType::Unknown;
|
||||
Storage::Metadata Metadata;
|
||||
std::string CreationTime;
|
||||
Azure::Core::Nullable<std::string> ExpiryTime;
|
||||
Azure::Core::Nullable<std::string> LastAccessTime;
|
||||
Core::DateTime CreatedOn;
|
||||
Azure::Core::Nullable<Core::DateTime> ExpiresOn;
|
||||
Azure::Core::Nullable<Core::DateTime> LastAccessedOn;
|
||||
};
|
||||
|
||||
struct RenameFileResult
|
||||
@ -167,7 +167,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam
|
||||
struct DownloadFileToResult
|
||||
{
|
||||
std::string ETag;
|
||||
std::string LastModified;
|
||||
Core::DateTime LastModified;
|
||||
int64_t ContentLength = 0;
|
||||
PathHttpHeaders HttpHeaders;
|
||||
Storage::Metadata Metadata;
|
||||
|
||||
@ -186,15 +186,16 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
|
||||
/**
|
||||
* @brief Optionally specify the time at which the shared access signature becomes
|
||||
* valid.
|
||||
* valid. This timestamp will be truncated to second.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> StartsOn;
|
||||
Azure::Core::Nullable<Azure::Core::DateTime> StartsOn;
|
||||
|
||||
/**
|
||||
* @brief The time at which the shared access signature becomes invalid. This field must
|
||||
* be omitted if it has been specified in an associated stored access policy.
|
||||
* be omitted if it has been specified in an associated stored access policy. This timestamp
|
||||
* will be truncated to second.
|
||||
*/
|
||||
std::string ExpiresOn;
|
||||
Azure::Core::DateTime ExpiresOn;
|
||||
|
||||
/**
|
||||
* @brief Specifies an IP address or a range of IP addresses from which to accept
|
||||
|
||||
@ -100,10 +100,10 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
* @brief Retrieves a key that can be used to delegate Active Directory authorization to
|
||||
* shared access signatures.
|
||||
*
|
||||
* @param startsOn Start time for the key's validity, in ISO date format. The time should be
|
||||
* specified in UTC.
|
||||
* @param expiresOn Expiration of the key's validity, in ISO date format. The time should be
|
||||
* specified in UTC.
|
||||
* @param startsOn Start time for the key's validity. The time should be specified in UTC, and
|
||||
* will be truncated to second.
|
||||
* @param expiresOn Expiration of the key's validity. The time should be specified in UTC, and
|
||||
* will be truncated to second.
|
||||
* @param options Optional parameters to execute
|
||||
* this function.
|
||||
* @return Azure::Core::Response<Models::GetUserDelegationKeyResult> containing the user
|
||||
@ -111,8 +111,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
* @remark This request is sent to blob endpoint.
|
||||
*/
|
||||
Azure::Core::Response<Models::GetUserDelegationKeyResult> GetUserDelegationKey(
|
||||
const std::string& startsOn,
|
||||
const std::string& expiresOn,
|
||||
const Azure::Core::DateTime& startsOn,
|
||||
const Azure::Core::DateTime& expiresOn,
|
||||
const GetUserDelegationKeyOptions& options = GetUserDelegationKeyOptions()) const
|
||||
{
|
||||
return m_blobServiceClient.GetUserDelegationKey(startsOn, expiresOn, options);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -52,6 +52,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
ret.ContentEncoding = std::move(headers.ContentEncoding);
|
||||
ret.ContentLanguage = std::move(headers.ContentLanguage);
|
||||
ret.ContentType = std::move(headers.ContentType);
|
||||
ret.ContentHash = std::move(headers.ContentHash);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -350,9 +351,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
? FromBlobLeaseStatus(result->LeaseStatus.GetValue())
|
||||
: ret.LeaseStatus;
|
||||
ret.Metadata = std::move(result->Metadata);
|
||||
ret.CreationTime = std::move(result->CreationTime);
|
||||
ret.ExpiryTime = std::move(result->ExpiryTime);
|
||||
ret.LastAccessTime = std::move(result->LastAccessTime);
|
||||
ret.CreatedOn = std::move(result->CreatedOn);
|
||||
ret.ExpiresOn = std::move(result->ExpiriesOn);
|
||||
ret.LastAccessedOn = std::move(result->LastAccessedOn);
|
||||
return Azure::Core::Response<Models::ReadFileResult>(
|
||||
std::move(ret), result.ExtractRawResponse());
|
||||
}
|
||||
|
||||
@ -248,6 +248,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
const ListPathsOptions& options) const
|
||||
{
|
||||
Details::DataLakeRestClient::FileSystem::ListPathsOptions protocolLayerOptions;
|
||||
protocolLayerOptions.Resource = Models::FileSystemResourceType::Filesystem;
|
||||
protocolLayerOptions.Upn = options.UserPrincipalName;
|
||||
protocolLayerOptions.ContinuationToken = options.ContinuationToken;
|
||||
protocolLayerOptions.MaxResults = options.MaxResults;
|
||||
|
||||
@ -292,7 +292,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
Models::GetPathPropertiesResult ret;
|
||||
ret.ETag = std::move(result->ETag);
|
||||
ret.LastModified = std::move(result->LastModified);
|
||||
ret.CreationTime = std::move(result->CreationTime);
|
||||
ret.CreatedOn = std::move(result->CreatedOn);
|
||||
ret.Metadata = std::move(result->Metadata);
|
||||
ret.LeaseDuration = std::move(result->LeaseDuration);
|
||||
ret.LeaseState = result->LeaseState.HasValue()
|
||||
@ -309,14 +309,14 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
|
||||
ret.ServerEncrypted = result->IsServerEncrypted;
|
||||
ret.EncryptionKeySha256 = std::move(result->EncryptionKeySha256);
|
||||
ret.AccessTierInferred = std::move(result->IsAccessTierInferred);
|
||||
ret.AccessTierChangeTime = std::move(result->AccessTierChangeTime);
|
||||
ret.AccessTierChangedOn = std::move(result->AccessTierChangedOn);
|
||||
ret.CopyId = std::move(result->CopyId);
|
||||
ret.CopySource = std::move(result->CopySource);
|
||||
ret.CopyStatus = std::move(result->CopyStatus);
|
||||
ret.CopyProgress = std::move(result->CopyProgress);
|
||||
ret.CopyCompletionTime = std::move(result->CopyCompletionTime);
|
||||
ret.ExpiryTime = std::move(result->ExpiryTime);
|
||||
ret.LastAccessTime = std::move(result->LastAccessTime);
|
||||
ret.CopyCompletedOn = std::move(result->CopyCompletedOn);
|
||||
ret.ExpiresOn = std::move(result->ExpiriesOn);
|
||||
ret.LastAccessedOn = std::move(result->LastAccessedOn);
|
||||
ret.ContentLength = result->ContentLength;
|
||||
return Azure::Core::Response<Models::GetPathPropertiesResult>(
|
||||
std::move(ret), result.ExtractRawResponse());
|
||||
|
||||
@ -123,11 +123,18 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
std::string protocol = Details::SasProtocolToString(Protocol);
|
||||
std::string resource = DataLakeSasResourceToString(Resource);
|
||||
|
||||
std::string stringToSign = Permissions + "\n" + (StartsOn.HasValue() ? StartsOn.GetValue() : "")
|
||||
+ "\n" + ExpiresOn + "\n" + canonicalName + "\n" + Identifier + "\n"
|
||||
+ (IPRange.HasValue() ? IPRange.GetValue() : "") + "\n" + protocol + "\n"
|
||||
+ Storage::Details::DefaultSasVersion + "\n" + resource + "\n" + "\n" + CacheControl + "\n"
|
||||
+ ContentDisposition + "\n" + ContentEncoding + "\n" + ContentLanguage + "\n" + ContentType;
|
||||
std::string startsOnStr = StartsOn.HasValue()
|
||||
? StartsOn.GetValue().GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate)
|
||||
: "";
|
||||
std::string expiresOnStr = Identifier.empty()
|
||||
? ExpiresOn.GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate)
|
||||
: "";
|
||||
|
||||
std::string stringToSign = Permissions + "\n" + startsOnStr + "\n" + expiresOnStr + "\n"
|
||||
+ canonicalName + "\n" + Identifier + "\n" + (IPRange.HasValue() ? IPRange.GetValue() : "")
|
||||
+ "\n" + protocol + "\n" + Storage::Details::DefaultSasVersion + "\n" + resource + "\n"
|
||||
+ "\n" + CacheControl + "\n" + ContentDisposition + "\n" + ContentEncoding + "\n"
|
||||
+ ContentLanguage + "\n" + ContentType;
|
||||
|
||||
std::string signature = Base64Encode(Storage::Details::HmacSha256(
|
||||
std::vector<uint8_t>(stringToSign.begin(), stringToSign.end()),
|
||||
@ -137,14 +144,13 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
builder.AppendQueryParameter(
|
||||
"sv", Storage::Details::UrlEncodeQueryParameter(Storage::Details::DefaultSasVersion));
|
||||
builder.AppendQueryParameter("spr", Storage::Details::UrlEncodeQueryParameter(protocol));
|
||||
if (StartsOn.HasValue())
|
||||
if (!startsOnStr.empty())
|
||||
{
|
||||
builder.AppendQueryParameter(
|
||||
"st", Storage::Details::UrlEncodeQueryParameter(StartsOn.GetValue()));
|
||||
builder.AppendQueryParameter("st", Storage::Details::UrlEncodeQueryParameter(startsOnStr));
|
||||
}
|
||||
if (!ExpiresOn.empty())
|
||||
if (!expiresOnStr.empty())
|
||||
{
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(ExpiresOn));
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(expiresOnStr));
|
||||
}
|
||||
if (IPRange.HasValue())
|
||||
{
|
||||
@ -200,15 +206,24 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
std::string protocol = Details::SasProtocolToString(Protocol);
|
||||
std::string resource = DataLakeSasResourceToString(Resource);
|
||||
|
||||
std::string stringToSign = Permissions + "\n" + (StartsOn.HasValue() ? StartsOn.GetValue() : "")
|
||||
+ "\n" + ExpiresOn + "\n" + canonicalName + "\n" + userDelegationKey.SignedObjectId + "\n"
|
||||
+ userDelegationKey.SignedTenantId + "\n" + userDelegationKey.SignedStartsOn + "\n"
|
||||
+ userDelegationKey.SignedExpiresOn + "\n" + userDelegationKey.SignedService + "\n"
|
||||
+ userDelegationKey.SignedVersion + "\n" + PreauthorizedAgentObjectId + "\n" + AgentObjectId
|
||||
+ "\n" + CorrelationId + "\n" + (IPRange.HasValue() ? IPRange.GetValue() : "") + "\n"
|
||||
+ protocol + "\n" + Storage::Details::DefaultSasVersion + "\n" + resource + "\n" + "\n"
|
||||
+ CacheControl + "\n" + ContentDisposition + "\n" + ContentEncoding + "\n" + ContentLanguage
|
||||
+ "\n" + ContentType;
|
||||
std::string startsOnStr = StartsOn.HasValue()
|
||||
? StartsOn.GetValue().GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate)
|
||||
: "";
|
||||
std::string expiresOnStr
|
||||
= ExpiresOn.GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate);
|
||||
std::string signedStartsOnStr = userDelegationKey.SignedStartsOn.GetRfc3339String(
|
||||
Azure::Core::DateTime::TimeFractionFormat::Truncate);
|
||||
std::string signedExpiresOnStr = userDelegationKey.SignedExpiresOn.GetRfc3339String(
|
||||
Azure::Core::DateTime::TimeFractionFormat::Truncate);
|
||||
|
||||
std::string stringToSign = Permissions + "\n" + startsOnStr + "\n" + expiresOnStr + "\n"
|
||||
+ canonicalName + "\n" + userDelegationKey.SignedObjectId + "\n"
|
||||
+ userDelegationKey.SignedTenantId + "\n" + signedStartsOnStr + "\n" + signedExpiresOnStr
|
||||
+ "\n" + userDelegationKey.SignedService + "\n" + userDelegationKey.SignedVersion + "\n"
|
||||
+ PreauthorizedAgentObjectId + "\n" + AgentObjectId + "\n" + CorrelationId + "\n"
|
||||
+ (IPRange.HasValue() ? IPRange.GetValue() : "") + "\n" + protocol + "\n"
|
||||
+ Storage::Details::DefaultSasVersion + "\n" + resource + "\n" + "\n" + CacheControl + "\n"
|
||||
+ ContentDisposition + "\n" + ContentEncoding + "\n" + ContentLanguage + "\n" + ContentType;
|
||||
|
||||
std::string signature = Base64Encode(Storage::Details::HmacSha256(
|
||||
std::vector<uint8_t>(stringToSign.begin(), stringToSign.end()),
|
||||
@ -218,12 +233,11 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
builder.AppendQueryParameter(
|
||||
"sv", Storage::Details::UrlEncodeQueryParameter(Storage::Details::DefaultSasVersion));
|
||||
builder.AppendQueryParameter("sr", Storage::Details::UrlEncodeQueryParameter(resource));
|
||||
if (StartsOn.HasValue())
|
||||
if (!startsOnStr.empty())
|
||||
{
|
||||
builder.AppendQueryParameter(
|
||||
"st", Storage::Details::UrlEncodeQueryParameter(StartsOn.GetValue()));
|
||||
builder.AppendQueryParameter("st", Storage::Details::UrlEncodeQueryParameter(startsOnStr));
|
||||
}
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(ExpiresOn));
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(expiresOnStr));
|
||||
builder.AppendQueryParameter("sp", Permissions);
|
||||
if (IPRange.HasValue())
|
||||
{
|
||||
@ -236,9 +250,9 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
builder.AppendQueryParameter(
|
||||
"sktid", Storage::Details::UrlEncodeQueryParameter(userDelegationKey.SignedTenantId));
|
||||
builder.AppendQueryParameter(
|
||||
"skt", Storage::Details::UrlEncodeQueryParameter(userDelegationKey.SignedStartsOn));
|
||||
"skt", Storage::Details::UrlEncodeQueryParameter(signedStartsOnStr));
|
||||
builder.AppendQueryParameter(
|
||||
"ske", Storage::Details::UrlEncodeQueryParameter(userDelegationKey.SignedExpiresOn));
|
||||
"ske", Storage::Details::UrlEncodeQueryParameter(signedExpiresOnStr));
|
||||
builder.AppendQueryParameter(
|
||||
"sks", Storage::Details::UrlEncodeQueryParameter(userDelegationKey.SignedService));
|
||||
builder.AppendQueryParameter(
|
||||
|
||||
@ -59,6 +59,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto response = client.GetProperties();
|
||||
Files::DataLake::DeleteDirectoryOptions options1;
|
||||
options1.AccessConditions.IfModifiedSince = response->LastModified;
|
||||
EXPECT_TRUE(IsValidTime(response->LastModified));
|
||||
EXPECT_THROW(client.Delete(false, options1), StorageException);
|
||||
Files::DataLake::DeleteDirectoryOptions options2;
|
||||
options2.AccessConditions.IfUnmodifiedSince = response->LastModified;
|
||||
@ -145,6 +146,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto response = client.GetProperties();
|
||||
Files::DataLake::RenameDirectoryOptions options1;
|
||||
options1.SourceAccessConditions.IfModifiedSince = response->LastModified;
|
||||
EXPECT_TRUE(IsValidTime(response->LastModified));
|
||||
EXPECT_THROW(client.Rename(LowercaseRandomString(), options1), StorageException);
|
||||
Files::DataLake::RenameDirectoryOptions options2;
|
||||
options2.SourceAccessConditions.IfUnmodifiedSince = response->LastModified;
|
||||
@ -266,6 +268,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto properties1 = m_directoryClient->GetProperties();
|
||||
auto properties2 = m_directoryClient->GetProperties();
|
||||
EXPECT_EQ(properties1->ETag, properties2->ETag);
|
||||
EXPECT_TRUE(IsValidTime(properties1->LastModified));
|
||||
EXPECT_EQ(properties1->LastModified, properties2->LastModified);
|
||||
|
||||
// This operation changes ETag/LastModified.
|
||||
|
||||
@ -75,6 +75,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto response = client.GetProperties();
|
||||
Files::DataLake::FileDeleteOptions options1;
|
||||
options1.AccessConditions.IfModifiedSince = response->LastModified;
|
||||
EXPECT_TRUE(IsValidTime(response->LastModified));
|
||||
EXPECT_THROW(client.Delete(options1), StorageException);
|
||||
Files::DataLake::FileDeleteOptions options2;
|
||||
options2.AccessConditions.IfUnmodifiedSince = response->LastModified;
|
||||
@ -263,6 +264,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto properties1 = m_fileClient->GetProperties();
|
||||
auto properties2 = m_fileClient->GetProperties();
|
||||
EXPECT_EQ(properties1->ETag, properties2->ETag);
|
||||
EXPECT_TRUE(IsValidTime(properties1->LastModified));
|
||||
EXPECT_EQ(properties1->LastModified, properties2->LastModified);
|
||||
|
||||
// This operation changes ETag/LastModified.
|
||||
@ -309,6 +311,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto properties2 = m_fileClient->GetProperties();
|
||||
// Append does not change etag because not committed yet.
|
||||
EXPECT_EQ(properties1->ETag, properties2->ETag);
|
||||
EXPECT_TRUE(IsValidTime(properties1->LastModified));
|
||||
EXPECT_EQ(properties1->LastModified, properties2->LastModified);
|
||||
|
||||
// Flush
|
||||
@ -339,6 +342,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto properties2 = newFileClient->GetProperties();
|
||||
// Append does not change etag because not committed yet.
|
||||
EXPECT_EQ(properties1->ETag, properties2->ETag);
|
||||
EXPECT_TRUE(IsValidTime(properties1->LastModified));
|
||||
EXPECT_EQ(properties1->LastModified, properties2->LastModified);
|
||||
|
||||
// Flush
|
||||
@ -376,6 +380,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
auto response = newFileClient->GetProperties();
|
||||
Files::DataLake::ReadFileOptions options1;
|
||||
options1.AccessConditions.IfModifiedSince = response->LastModified;
|
||||
EXPECT_TRUE(IsValidTime(response->LastModified));
|
||||
EXPECT_THROW(newFileClient->Read(options1), StorageException);
|
||||
Files::DataLake::ReadFileOptions options2;
|
||||
options2.AccessConditions.IfUnmodifiedSince = response->LastModified;
|
||||
@ -452,13 +457,16 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
options.Metadata = RandomMetadata();
|
||||
auto res
|
||||
= fileClient.UploadFrom(fileContent.data(), static_cast<std::size_t>(fileSize), options);
|
||||
auto lastModified = fileClient.GetProperties()->LastModified;
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(res->LastModified, lastModified);
|
||||
auto properties = *fileClient.GetProperties();
|
||||
EXPECT_EQ(properties.ContentLength, fileSize);
|
||||
EXPECT_EQ(properties.HttpHeaders, options.HttpHeaders);
|
||||
EXPECT_EQ(properties.Metadata, options.Metadata);
|
||||
EXPECT_EQ(properties.ETag, res->ETag);
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(properties.LastModified, res->LastModified);
|
||||
std::vector<uint8_t> downloadContent(static_cast<std::size_t>(fileSize), '\x00');
|
||||
fileClient.DownloadTo(downloadContent.data(), static_cast<std::size_t>(fileSize));
|
||||
@ -483,8 +491,10 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
fileWriter.Write(fileContent.data(), fileSize, 0);
|
||||
}
|
||||
auto res = fileClient.UploadFrom(tempFilename, options);
|
||||
auto lastModified = fileClient.GetProperties()->LastModified;
|
||||
EXPECT_FALSE(res->ETag.empty());
|
||||
EXPECT_FALSE(res->LastModified.empty());
|
||||
EXPECT_TRUE(IsValidTime(res->LastModified));
|
||||
EXPECT_EQ(res->LastModified, lastModified);
|
||||
auto properties = *fileClient.GetProperties();
|
||||
EXPECT_EQ(properties.ContentLength, fileSize);
|
||||
EXPECT_EQ(properties.HttpHeaders, options.HttpHeaders);
|
||||
|
||||
@ -241,13 +241,14 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
{
|
||||
std::string leaseId1 = CreateUniqueLeaseId();
|
||||
int32_t leaseDuration = 20;
|
||||
auto lastModified = m_pathClient->GetProperties()->LastModified;
|
||||
auto aLease = *m_pathClient->AcquireLease(leaseId1, leaseDuration);
|
||||
EXPECT_FALSE(aLease.ETag.empty());
|
||||
EXPECT_FALSE(aLease.LastModified.empty());
|
||||
EXPECT_FALSE(aLease.LastModified > lastModified);
|
||||
EXPECT_EQ(aLease.LeaseId, leaseId1);
|
||||
aLease = *m_pathClient->AcquireLease(leaseId1, leaseDuration);
|
||||
EXPECT_FALSE(aLease.ETag.empty());
|
||||
EXPECT_FALSE(aLease.LastModified.empty());
|
||||
EXPECT_FALSE(aLease.LastModified > lastModified);
|
||||
EXPECT_EQ(aLease.LeaseId, leaseId1);
|
||||
|
||||
auto properties = *m_pathClient->GetProperties();
|
||||
@ -255,36 +256,41 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
EXPECT_EQ(properties.LeaseStatus.GetValue(), Files::DataLake::Models::LeaseStatusType::Locked);
|
||||
EXPECT_FALSE(properties.LeaseDuration.GetValue().empty());
|
||||
|
||||
lastModified = properties.LastModified;
|
||||
auto rLease = *m_pathClient->RenewLease(leaseId1);
|
||||
EXPECT_FALSE(rLease.ETag.empty());
|
||||
EXPECT_FALSE(rLease.LastModified.empty());
|
||||
EXPECT_FALSE(rLease.LastModified > lastModified);
|
||||
EXPECT_EQ(rLease.LeaseId, leaseId1);
|
||||
|
||||
std::string leaseId2 = CreateUniqueLeaseId();
|
||||
EXPECT_NE(leaseId1, leaseId2);
|
||||
lastModified = m_pathClient->GetProperties()->LastModified;
|
||||
auto cLease = *m_pathClient->ChangeLease(leaseId1, leaseId2);
|
||||
EXPECT_FALSE(cLease.ETag.empty());
|
||||
EXPECT_FALSE(cLease.LastModified.empty());
|
||||
EXPECT_FALSE(cLease.LastModified > lastModified);
|
||||
EXPECT_EQ(cLease.LeaseId, leaseId2);
|
||||
|
||||
lastModified = m_pathClient->GetProperties()->LastModified;
|
||||
auto pathInfo = *m_pathClient->ReleaseLease(leaseId2);
|
||||
EXPECT_FALSE(pathInfo.ETag.empty());
|
||||
EXPECT_FALSE(pathInfo.LastModified.empty());
|
||||
EXPECT_FALSE(pathInfo.LastModified > lastModified);
|
||||
|
||||
lastModified = m_pathClient->GetProperties()->LastModified;
|
||||
aLease = *m_pathClient->AcquireLease(CreateUniqueLeaseId(), InfiniteLeaseDuration);
|
||||
properties = *m_pathClient->GetProperties();
|
||||
EXPECT_FALSE(properties.LeaseDuration.GetValue().empty());
|
||||
auto brokenLease = *m_pathClient->BreakLease();
|
||||
EXPECT_FALSE(brokenLease.ETag.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified > lastModified);
|
||||
EXPECT_EQ(brokenLease.LeaseTime, 0);
|
||||
|
||||
aLease = *m_pathClient->AcquireLease(CreateUniqueLeaseId(), leaseDuration);
|
||||
Files::DataLake::BreakPathLeaseOptions breakOptions;
|
||||
breakOptions.BreakPeriod = 30;
|
||||
lastModified = m_pathClient->GetProperties()->LastModified;
|
||||
brokenLease = *m_pathClient->BreakLease(breakOptions);
|
||||
EXPECT_FALSE(brokenLease.ETag.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified.empty());
|
||||
EXPECT_FALSE(brokenLease.LastModified > lastModified);
|
||||
EXPECT_NE(brokenLease.LeaseTime, 0);
|
||||
|
||||
Files::DataLake::BreakPathLeaseOptions options;
|
||||
|
||||
@ -11,14 +11,17 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
TEST_F(DataLakeFileSystemClientTest, DataLakeSasTest)
|
||||
{
|
||||
auto sasStartsOn = Azure::Core::DateTime::Now() - std::chrono::minutes(5);
|
||||
auto sasExpiredOn = Azure::Core::DateTime::Now() - std::chrono::minutes(1);
|
||||
auto sasExpiresOn = Azure::Core::DateTime::Now() + std::chrono::minutes(60);
|
||||
|
||||
std::string directory1Name = RandomString();
|
||||
std::string directory2Name = RandomString();
|
||||
std::string fileName = RandomString();
|
||||
Sas::DataLakeSasBuilder fileSasBuilder;
|
||||
fileSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp;
|
||||
fileSasBuilder.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
fileSasBuilder.ExpiresOn
|
||||
= ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(60));
|
||||
fileSasBuilder.StartsOn = sasStartsOn;
|
||||
fileSasBuilder.ExpiresOn = sasExpiresOn;
|
||||
fileSasBuilder.FileSystemName = m_fileSystemName;
|
||||
fileSasBuilder.Path = directory1Name + "/" + directory2Name + "/" + fileName;
|
||||
fileSasBuilder.Resource = Sas::DataLakeSasResource::File;
|
||||
@ -56,9 +59,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
serviceUri,
|
||||
std::make_shared<Azure::Identity::ClientSecretCredential>(
|
||||
AadTenantId(), AadClientId(), AadClientSecret()));
|
||||
auto userDelegationKey = *serviceClient1.GetUserDelegationKey(
|
||||
ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5)),
|
||||
ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(60)));
|
||||
auto userDelegationKey = *serviceClient1.GetUserDelegationKey(sasStartsOn, sasExpiresOn);
|
||||
|
||||
auto verify_file_read = [&](const std::string& sas) {
|
||||
EXPECT_NO_THROW(fileClient0.Create());
|
||||
@ -332,8 +333,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
// Expires
|
||||
{
|
||||
Sas::DataLakeSasBuilder builder2 = fileSasBuilder;
|
||||
builder2.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
builder2.ExpiresOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(1));
|
||||
builder2.StartsOn = sasStartsOn;
|
||||
builder2.ExpiresOn = sasExpiredOn;
|
||||
auto sasToken = builder2.GenerateSasToken(*keyCredential);
|
||||
EXPECT_THROW(verify_file_create(sasToken), StorageException);
|
||||
|
||||
@ -383,15 +384,15 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
options.AccessType = Blobs::Models::PublicAccessType::Blob;
|
||||
Blobs::Models::BlobSignedIdentifier identifier;
|
||||
identifier.Id = RandomString(64);
|
||||
identifier.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
identifier.ExpiresOn = ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(60));
|
||||
identifier.StartsOn = sasStartsOn;
|
||||
identifier.ExpiresOn = sasExpiresOn;
|
||||
identifier.Permissions = "r";
|
||||
options.SignedIdentifiers.emplace_back(identifier);
|
||||
containerClinet0.SetAccessPolicy(options);
|
||||
|
||||
Sas::DataLakeSasBuilder builder2 = fileSasBuilder;
|
||||
builder2.StartsOn.Reset();
|
||||
builder2.ExpiresOn.clear();
|
||||
builder2.ExpiresOn = Azure::Core::DateTime();
|
||||
builder2.SetPermissions(static_cast<Sas::DataLakeFileSystemSasPermissions>(0));
|
||||
builder2.Identifier = identifier.Id;
|
||||
|
||||
|
||||
@ -143,10 +143,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
= Azure::Storage::Details::ParseConnectionString(AdlsGen2ConnectionString()).KeyCredential;
|
||||
Sas::AccountSasBuilder accountSasBuilder;
|
||||
accountSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp;
|
||||
accountSasBuilder.StartsOn
|
||||
= ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
accountSasBuilder.ExpiresOn
|
||||
= ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(60));
|
||||
accountSasBuilder.StartsOn = Core::DateTime::Now() - std::chrono::minutes(5);
|
||||
accountSasBuilder.ExpiresOn = Core::DateTime::Now() + std::chrono::minutes(60);
|
||||
accountSasBuilder.Services = Sas::AccountSasServices::Blobs;
|
||||
accountSasBuilder.ResourceTypes = Sas::AccountSasResource::All;
|
||||
accountSasBuilder.SetPermissions(Sas::AccountSasPermissions::All);
|
||||
|
||||
@ -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* HeaderContentHash = "content-md5";
|
||||
constexpr static const char* HeaderContentHashMd5 = "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,10 @@ 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* 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* HeaderSourceContentHashCrc64 = "x-ms-source-content-crc64";
|
||||
constexpr static const char* HeaderSourceIfMatchHashCrc64 = "x-ms-source-if-match-crc64";
|
||||
constexpr static const char* HeaderSourceIfNoneMatchHashCrc64
|
||||
= "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 +106,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* HeaderTransactionalContentHash = "content-md5";
|
||||
constexpr static const char* HeaderTransactionalContentHashMd5 = "content-md5";
|
||||
constexpr static const char* HeaderContentEncoding = "content-encoding";
|
||||
constexpr static const char* HeaderCacheControl = "cache-control";
|
||||
constexpr static const char* HeaderContentDisposition = "content-disposition";
|
||||
@ -120,6 +121,7 @@ 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* HeaderTransactionalContentHashCrc64 = "x-ms-content-crc64";
|
||||
} // namespace Details
|
||||
namespace Models {
|
||||
struct ShareFileHttpHeaders
|
||||
@ -5351,7 +5353,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
if (createOptions.ContentMd5.HasValue())
|
||||
{
|
||||
request.AddHeader(
|
||||
Details::HeaderContentHash,
|
||||
Details::HeaderContentHashMd5,
|
||||
Storage::Details::ToBase64String(createOptions.ContentMd5.GetValue()));
|
||||
}
|
||||
if (createOptions.FileContentDisposition.HasValue())
|
||||
@ -5559,7 +5561,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
if (setHttpHeadersOptions.ContentMd5.HasValue())
|
||||
{
|
||||
request.AddHeader(
|
||||
Details::HeaderContentHash,
|
||||
Details::HeaderContentHashMd5,
|
||||
Storage::Details::ToBase64String(setHttpHeadersOptions.ContentMd5.GetValue()));
|
||||
}
|
||||
if (setHttpHeadersOptions.FileContentDisposition.HasValue())
|
||||
@ -5822,7 +5824,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
if (uploadRangeOptions.ContentMd5.HasValue())
|
||||
{
|
||||
request.AddHeader(
|
||||
Details::HeaderContentHash,
|
||||
Details::HeaderContentHashMd5,
|
||||
Storage::Details::ToBase64String(uploadRangeOptions.ContentMd5.GetValue()));
|
||||
}
|
||||
request.AddHeader(Details::HeaderVersion, uploadRangeOptions.ApiVersionParameter);
|
||||
@ -5881,21 +5883,21 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
if (uploadRangeFromUrlOptions.SourceContentCrc64.HasValue())
|
||||
{
|
||||
request.AddHeader(
|
||||
Details::HeaderSourceContentHash,
|
||||
Details::HeaderSourceContentHashCrc64,
|
||||
Storage::Details::ToBase64String(
|
||||
uploadRangeFromUrlOptions.SourceContentCrc64.GetValue()));
|
||||
}
|
||||
if (uploadRangeFromUrlOptions.SourceIfMatchCrc64.HasValue())
|
||||
{
|
||||
request.AddHeader(
|
||||
Details::HeaderSourceIfMatchHash,
|
||||
Details::HeaderSourceIfMatchHashCrc64,
|
||||
Storage::Details::ToBase64String(
|
||||
uploadRangeFromUrlOptions.SourceIfMatchCrc64.GetValue()));
|
||||
}
|
||||
if (uploadRangeFromUrlOptions.SourceIfNoneMatchCrc64.HasValue())
|
||||
{
|
||||
request.AddHeader(
|
||||
Details::HeaderSourceIfNoneMatchHash,
|
||||
Details::HeaderSourceIfNoneMatchHashCrc64,
|
||||
Storage::Details::ToBase64String(
|
||||
uploadRangeFromUrlOptions.SourceIfNoneMatchCrc64.GetValue()));
|
||||
}
|
||||
@ -6248,11 +6250,11 @@ 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::HeaderTransactionalContentHash)
|
||||
if (response.GetHeaders().find(Details::HeaderTransactionalContentHashMd5)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
result.TransactionalContentHash = Storage::Details::FromBase64String(
|
||||
response.GetHeaders().at(Details::HeaderTransactionalContentHash),
|
||||
response.GetHeaders().at(Details::HeaderTransactionalContentHashMd5),
|
||||
HashAlgorithm::Md5);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::HeaderContentEncoding)
|
||||
@ -6313,11 +6315,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
result.CopyStatus
|
||||
= CopyStatusTypeFromString(response.GetHeaders().at(Details::HeaderCopyStatus));
|
||||
}
|
||||
if (response.GetHeaders().find(Details::HeaderContentHash)
|
||||
if (response.GetHeaders().find(Details::HeaderContentHashMd5)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
result.HttpHeaders.ContentHash = Storage::Details::FromBase64String(
|
||||
response.GetHeaders().at(Details::HeaderContentHash), HashAlgorithm::Md5);
|
||||
response.GetHeaders().at(Details::HeaderContentHashMd5), HashAlgorithm::Md5);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::HeaderIsServerEncrypted)
|
||||
!= response.GetHeaders().end())
|
||||
@ -6384,11 +6386,11 @@ 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::HeaderTransactionalContentHash)
|
||||
if (response.GetHeaders().find(Details::HeaderTransactionalContentHashMd5)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
result.TransactionalContentHash = Storage::Details::FromBase64String(
|
||||
response.GetHeaders().at(Details::HeaderTransactionalContentHash),
|
||||
response.GetHeaders().at(Details::HeaderTransactionalContentHashMd5),
|
||||
HashAlgorithm::Md5);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::HeaderContentEncoding)
|
||||
@ -6449,11 +6451,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
result.CopyStatus
|
||||
= CopyStatusTypeFromString(response.GetHeaders().at(Details::HeaderCopyStatus));
|
||||
}
|
||||
if (response.GetHeaders().find(Details::HeaderContentHash)
|
||||
if (response.GetHeaders().find(Details::HeaderContentHashMd5)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
result.HttpHeaders.ContentHash = Storage::Details::FromBase64String(
|
||||
response.GetHeaders().at(Details::HeaderContentHash), HashAlgorithm::Md5);
|
||||
response.GetHeaders().at(Details::HeaderContentHashMd5), HashAlgorithm::Md5);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::HeaderIsServerEncrypted)
|
||||
!= response.GetHeaders().end())
|
||||
@ -6531,11 +6533,11 @@ 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::HeaderTransactionalContentHash)
|
||||
if (response.GetHeaders().find(Details::HeaderTransactionalContentHashMd5)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
result.HttpHeaders.ContentHash = Storage::Details::FromBase64String(
|
||||
response.GetHeaders().at(Details::HeaderTransactionalContentHash),
|
||||
response.GetHeaders().at(Details::HeaderTransactionalContentHashMd5),
|
||||
HashAlgorithm::Md5);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::HeaderContentEncoding)
|
||||
@ -6832,11 +6834,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
result.LastModified = Core::DateTime::Parse(
|
||||
response.GetHeaders().at(Details::HeaderLastModified),
|
||||
Core::DateTime::DateFormat::Rfc1123);
|
||||
if (response.GetHeaders().find(Details::HeaderTransactionalContentHash)
|
||||
if (response.GetHeaders().find(Details::HeaderTransactionalContentHashMd5)
|
||||
!= response.GetHeaders().end())
|
||||
{
|
||||
result.TransactionalContentHash = Storage::Details::FromBase64String(
|
||||
response.GetHeaders().at(Details::HeaderTransactionalContentHash),
|
||||
response.GetHeaders().at(Details::HeaderTransactionalContentHashMd5),
|
||||
HashAlgorithm::Md5);
|
||||
}
|
||||
if (response.GetHeaders().find(Details::HeaderRequestIsServerEncrypted)
|
||||
@ -6870,7 +6872,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
|
||||
response.GetHeaders().at(Details::HeaderLastModified),
|
||||
Core::DateTime::DateFormat::Rfc1123);
|
||||
result.TransactionalContentHash = Storage::Details::FromBase64String(
|
||||
response.GetHeaders().at(Details::HeaderTransactionalContentHash),
|
||||
response.GetHeaders().at(Details::HeaderTransactionalContentHashCrc64),
|
||||
HashAlgorithm::Crc64);
|
||||
result.IsServerEncrypted
|
||||
= response.GetHeaders().at(Details::HeaderRequestIsServerEncrypted) == "true";
|
||||
|
||||
@ -135,15 +135,16 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
|
||||
/**
|
||||
* @brief Optionally specify the time at which the shared access signature becomes
|
||||
* valid.
|
||||
* valid. This timestamp will be truncated to second.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> StartsOn;
|
||||
Azure::Core::Nullable<Azure::Core::DateTime> StartsOn;
|
||||
|
||||
/**
|
||||
* @brief The time at which the shared access signature becomes invalid. This field must
|
||||
* be omitted if it has been specified in an associated stored access policy.
|
||||
* be omitted if it has been specified in an associated stored access policy. This timestamp
|
||||
* will be truncated to second.
|
||||
*/
|
||||
std::string ExpiresOn;
|
||||
Azure::Core::DateTime ExpiresOn;
|
||||
|
||||
/**
|
||||
* @brief Specifies an IP address or a range of IP addresses from which to accept
|
||||
|
||||
@ -84,11 +84,17 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
std::string protocol = Details::SasProtocolToString(Protocol);
|
||||
std::string resource = ShareSasResourceToString(Resource);
|
||||
|
||||
std::string stringToSign = Permissions + "\n" + (StartsOn.HasValue() ? StartsOn.GetValue() : "")
|
||||
+ "\n" + ExpiresOn + "\n" + canonicalName + "\n" + Identifier + "\n"
|
||||
+ (IPRange.HasValue() ? IPRange.GetValue() : "") + "\n" + protocol + "\n"
|
||||
+ Storage::Details::DefaultSasVersion + "\n" + CacheControl + "\n" + ContentDisposition
|
||||
+ "\n" + ContentEncoding + "\n" + ContentLanguage + "\n" + ContentType;
|
||||
std::string startsOnStr = StartsOn.HasValue()
|
||||
? StartsOn.GetValue().GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate)
|
||||
: "";
|
||||
std::string expiresOnStr = Identifier.empty()
|
||||
? ExpiresOn.GetRfc3339String(Azure::Core::DateTime::TimeFractionFormat::Truncate)
|
||||
: "";
|
||||
|
||||
std::string stringToSign = Permissions + "\n" + startsOnStr + "\n" + expiresOnStr + "\n"
|
||||
+ canonicalName + "\n" + Identifier + "\n" + (IPRange.HasValue() ? IPRange.GetValue() : "")
|
||||
+ "\n" + protocol + "\n" + Storage::Details::DefaultSasVersion + "\n" + CacheControl + "\n"
|
||||
+ ContentDisposition + "\n" + ContentEncoding + "\n" + ContentLanguage + "\n" + ContentType;
|
||||
|
||||
std::string signature = Base64Encode(Storage::Details::HmacSha256(
|
||||
std::vector<uint8_t>(stringToSign.begin(), stringToSign.end()),
|
||||
@ -98,14 +104,13 @@ namespace Azure { namespace Storage { namespace Sas {
|
||||
builder.AppendQueryParameter(
|
||||
"sv", Storage::Details::UrlEncodeQueryParameter(Storage::Details::DefaultSasVersion));
|
||||
builder.AppendQueryParameter("spr", Storage::Details::UrlEncodeQueryParameter(protocol));
|
||||
if (StartsOn.HasValue())
|
||||
if (!startsOnStr.empty())
|
||||
{
|
||||
builder.AppendQueryParameter(
|
||||
"st", Storage::Details::UrlEncodeQueryParameter(StartsOn.GetValue()));
|
||||
builder.AppendQueryParameter("st", Storage::Details::UrlEncodeQueryParameter(startsOnStr));
|
||||
}
|
||||
if (!ExpiresOn.empty())
|
||||
if (!expiresOnStr.empty())
|
||||
{
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(ExpiresOn));
|
||||
builder.AppendQueryParameter("se", Storage::Details::UrlEncodeQueryParameter(expiresOnStr));
|
||||
}
|
||||
if (IPRange.HasValue())
|
||||
{
|
||||
|
||||
@ -9,12 +9,15 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
TEST_F(FileShareClientTest, FileSasTest)
|
||||
{
|
||||
auto sasStartsOn = Azure::Core::DateTime::Now() - std::chrono::minutes(5);
|
||||
auto sasExpiredOn = Azure::Core::DateTime::Now() - std::chrono::minutes(1);
|
||||
auto sasExpiresOn = Azure::Core::DateTime::Now() + std::chrono::minutes(60);
|
||||
|
||||
std::string fileName = RandomString();
|
||||
Sas::ShareSasBuilder fileSasBuilder;
|
||||
fileSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp;
|
||||
fileSasBuilder.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
fileSasBuilder.ExpiresOn
|
||||
= ToIso8601(std::chrono::system_clock::now() + std::chrono::minutes(60));
|
||||
fileSasBuilder.StartsOn = sasStartsOn;
|
||||
fileSasBuilder.ExpiresOn = sasExpiresOn;
|
||||
fileSasBuilder.ShareName = m_shareName;
|
||||
fileSasBuilder.FilePath = fileName;
|
||||
fileSasBuilder.Resource = Sas::ShareSasResource::File;
|
||||
@ -137,8 +140,8 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
// Expires
|
||||
{
|
||||
Sas::ShareSasBuilder builder2 = fileSasBuilder;
|
||||
builder2.StartsOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
builder2.ExpiresOn = ToIso8601(std::chrono::system_clock::now() - std::chrono::minutes(1));
|
||||
builder2.StartsOn = sasStartsOn;
|
||||
builder2.ExpiresOn = sasExpiredOn;
|
||||
auto sasToken = builder2.GenerateSasToken(*keyCredential);
|
||||
EXPECT_THROW(verifyFileRead(sasToken), StorageException);
|
||||
}
|
||||
@ -168,14 +171,14 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
{
|
||||
Files::Shares::Models::SignedIdentifier identifier;
|
||||
identifier.Id = RandomString(64);
|
||||
identifier.Policy.StartsOn = Core::DateTime::Now() - std::chrono::minutes(5);
|
||||
identifier.Policy.ExpiresOn = Core::DateTime::Now() + std::chrono::minutes(60);
|
||||
identifier.Policy.StartsOn = sasStartsOn;
|
||||
identifier.Policy.ExpiresOn = sasExpiresOn;
|
||||
identifier.Policy.Permission = "r";
|
||||
m_shareClient->SetAccessPolicy({identifier});
|
||||
|
||||
Sas::ShareSasBuilder builder2 = fileSasBuilder;
|
||||
builder2.StartsOn.Reset();
|
||||
builder2.ExpiresOn.clear();
|
||||
builder2.ExpiresOn = Azure::Core::DateTime();
|
||||
builder2.SetPermissions(static_cast<Sas::ShareSasPermissions>(0));
|
||||
builder2.Identifier = identifier.Id;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user