PutRangeFromUrl support in file service. (#1530)

* PutRangeFromUrl support

* Update share_file_client.cpp
This commit is contained in:
Kan Tang 2021-02-01 14:05:59 +08:00 committed by GitHub
parent 942bbeee38
commit 517b8e6245
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 174 additions and 7 deletions

View File

@ -4,6 +4,7 @@
### New Features
- Added support for `UploadRangeFromUri` in file client.
- Added support for `SetProperties` in share client. This API supports update share tier and adjusting share's quota.
- Added support to get share's tier status in `ListSharesSinglePage` and `GetProperties`.

View File

@ -297,6 +297,21 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
const ForceCloseAllShareFileHandlesOptions& options
= ForceCloseAllShareFileHandlesOptions()) const;
/**
* @brief Upload a range from the source URI to this file's specific range.
* @param sourceUri The source URI of the content to be uploaded.
* @param sourceRange The source URI's range to be uploaded to file.
* @param range The range of the file this source to be uploaded from.
* @param options Optional parameters to upload a range to file.
* @return Azure::Core::Response<Models::UploadFileRangeFromUriResult> containing the returned
* information.
*/
Azure::Core::Response<Models::UploadFileRangeFromUriResult> UploadRangeFromUri(
const std::string& sourceUri,
const Azure::Core::Http::Range& sourceRange,
const Azure::Core::Http::Range& range,
const UploadFileRangeFromUriOptions& options = UploadFileRangeFromUriOptions()) const;
private:
Azure::Core::Http::Url m_shareFileUrl;
std::shared_ptr<Azure::Core::Http::HttpPipeline> m_pipeline;

View File

@ -652,18 +652,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
LeaseAccessConditions AccessConditions;
};
struct UploadFileRangeFromUrlOptions
struct UploadFileRangeFromUriOptions
{
/**
* @brief Context for cancelling long running operations.
*/
Azure::Core::Context Context;
/**
* @brief The range of the source file.
*/
Azure::Core::Nullable<Core::Http::Range> SourceRange;
/**
* @brief Specify the crc64 calculated for the range of bytes that must be read from the copy
* source.

View File

@ -154,7 +154,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { names
using SetShareFileMetadataResult = Details::FileSetMetadataResult;
using UploadShareFileRangeResult = Details::FileUploadRangeResult;
using ClearShareFileRangeResult = Details::FileUploadRangeResult;
using UploadFileRangeFromUrlResult = Details::FileUploadRangeFromUrlResult;
using UploadFileRangeFromUriResult = Details::FileUploadRangeFromUrlResult;
using GetShareFileRangeListResult = Details::FileGetRangeListResult;
using ListShareFileHandlesSinglePageResult = ListShareDirectoryHandlesSinglePageResult;
using ForceCloseAllShareFileHandlesResult = Details::FileForceCloseHandlesResult;

View File

@ -1009,4 +1009,60 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
return Azure::Core::Response<Models::UploadShareFileFromResult>(
std::move(result), createResult.ExtractRawResponse());
}
Azure::Core::Response<Models::UploadFileRangeFromUriResult> ShareFileClient::UploadRangeFromUri(
const std::string& sourceUri,
const Azure::Core::Http::Range& sourceRange,
const Azure::Core::Http::Range& range,
const UploadFileRangeFromUriOptions& options) const
{
if (!sourceRange.Length.HasValue())
{
// sourceRange must have length to perform this operation.
std::abort();
}
int64_t destLength = sourceRange.Length.GetValue();
if (range.Length.HasValue())
{
// Let server decide the behavior if the length does not match.
destLength = range.Length.GetValue();
}
auto protocolLayerOptions = Details::ShareRestClient::File::UploadRangeFromUrlOptions();
protocolLayerOptions.TargetRange = std::string("bytes=") + std::to_string(range.Offset)
+ std::string("-") + std::to_string(range.Offset + destLength - 1);
protocolLayerOptions.ContentLength = 0;
protocolLayerOptions.CopySource = sourceUri;
protocolLayerOptions.LeaseIdOptional = options.AccessConditions.LeaseId;
if (options.SourceContentHash.HasValue()
&& options.SourceContentHash.GetValue().Algorithm == HashAlgorithm::Md5)
{
// SourceContentHash now only supports Crc64 hash algorithm.
std::abort();
}
protocolLayerOptions.SourceContentCrc64 = options.SourceContentHash;
if (options.SourceAccessCondition.IfMatchContentHash.HasValue()
&& options.SourceAccessCondition.IfMatchContentHash.GetValue().Algorithm
== HashAlgorithm::Md5)
{
// IfMatchContentHash now only supports Crc64 hash algorithm.
std::abort();
}
protocolLayerOptions.SourceIfMatchCrc64 = options.SourceAccessCondition.IfMatchContentHash;
if (options.SourceAccessCondition.IfNoneMatchContentHash.HasValue()
&& options.SourceAccessCondition.IfNoneMatchContentHash.GetValue().Algorithm
== HashAlgorithm::Md5)
{
// IfNoneMatchContentHash now only supports Crc64 hash algorithm.
std::abort();
}
protocolLayerOptions.SourceIfNoneMatchCrc64
= options.SourceAccessCondition.IfNoneMatchContentHash;
protocolLayerOptions.SourceRange = std::string("bytes=") + std::to_string(sourceRange.Offset)
+ std::string("-") + std::to_string(sourceRange.Offset + sourceRange.Length.GetValue() - 1);
protocolLayerOptions.XMsWrite = Models::FileRangeWriteFromUrlType::Update;
return Details::ShareRestClient::File::UploadRangeFromUrl(
m_shareFileUrl, *m_pipeline, options.Context, protocolLayerOptions);
}
}}}} // namespace Azure::Storage::Files::Shares

View File

@ -798,4 +798,104 @@ namespace Azure { namespace Storage { namespace Test {
FAIL();
}
TEST_F(FileShareFileClientTest, UploadRangeFromUri)
{
size_t fileSize = 1 * 1024 * 1024;
std::string fileName = RandomString();
auto fileContent = RandomBuffer(fileSize);
auto memBodyStream = Core::Http::MemoryBodyStream(fileContent);
auto sourceFileClient = m_shareClient->GetRootDirectoryClient().GetFileClient(fileName);
sourceFileClient.Create(fileSize);
EXPECT_NO_THROW(sourceFileClient.UploadRange(0, &memBodyStream));
auto destFileClient = m_shareClient->GetRootDirectoryClient().GetFileClient(RandomString(10));
destFileClient.Create(fileSize * 4);
Azure::Core::Http::Range sourceRange;
Azure::Core::Http::Range destRange;
sourceRange.Length = fileSize;
destRange.Offset = fileSize;
destRange.Length = fileSize;
// Get the SAS of the file
Sas::ShareSasBuilder fileSasBuilder;
fileSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp;
fileSasBuilder.StartsOn = std::chrono::system_clock::now() - std::chrono::minutes(5);
fileSasBuilder.ExpiresOn = std::chrono::system_clock::now() + std::chrono::minutes(60);
fileSasBuilder.ShareName = m_shareName;
fileSasBuilder.FilePath = fileName;
fileSasBuilder.Resource = Sas::ShareSasResource::File;
fileSasBuilder.SetPermissions(Sas::ShareSasPermissions::Read);
std::string sourceSas = fileSasBuilder.GenerateSasToken(
*Details::ParseConnectionString(StandardStorageConnectionString()).KeyCredential);
Files::Shares::Models::UploadFileRangeFromUriResult uploadResult;
EXPECT_NO_THROW(
uploadResult = *destFileClient.UploadRangeFromUri(
sourceFileClient.GetUrl() + sourceSas, sourceRange, destRange));
Files::Shares::Models::DownloadShareFileResult result;
Files::Shares::DownloadShareFileOptions downloadOptions;
downloadOptions.Range = destRange;
EXPECT_NO_THROW(result = destFileClient.Download(downloadOptions).ExtractValue());
auto resultBuffer = Core::Http::BodyStream::ReadToEnd(Core::Context(), *(result.BodyStream));
EXPECT_EQ(fileContent, resultBuffer);
Files::Shares::Models::GetShareFileRangeListResult getRangeResult;
EXPECT_NO_THROW(getRangeResult = destFileClient.GetRangeList().ExtractValue());
EXPECT_EQ(1U, getRangeResult.Ranges.size());
EXPECT_EQ(static_cast<int64_t>(fileSize), getRangeResult.Ranges[0].Offset);
EXPECT_TRUE(getRangeResult.Ranges[0].Length.HasValue());
EXPECT_EQ(static_cast<int64_t>(fileSize), getRangeResult.Ranges[0].Length.GetValue());
// source access condition works.
std::vector<uint8_t> invalidCrc64(
uploadResult.TransactionalContentHash.Value.begin(),
uploadResult.TransactionalContentHash.Value.begin()
+ uploadResult.TransactionalContentHash.Value.size() / 2);
{
Files::Shares::UploadFileRangeFromUriOptions uploadRangeOptions;
uploadRangeOptions.SourceAccessCondition.IfNoneMatchContentHash
= uploadResult.TransactionalContentHash;
EXPECT_THROW(
uploadResult = *destFileClient.UploadRangeFromUri(
sourceFileClient.GetUrl() + sourceSas, sourceRange, destRange, uploadRangeOptions),
StorageException);
// Below code seems to be triggering a server bug. Uncomment when server resolves the issue.
// uploadRangeOptions.SourceAccessCondition.IfNoneMatchContentHash.GetValue().Value
// = invalidCrc64;
// EXPECT_NO_THROW(
// uploadResult = *destFileClient.UploadRangeFromUri(
// sourceFileClient.GetUrl() + sourceSas, sourceRange, destRange, uploadRangeOptions));
}
{
Files::Shares::UploadFileRangeFromUriOptions uploadRangeOptions;
uploadRangeOptions.SourceAccessCondition.IfMatchContentHash
= uploadResult.TransactionalContentHash;
EXPECT_NO_THROW(
uploadResult = *destFileClient.UploadRangeFromUri(
sourceFileClient.GetUrl() + sourceSas, sourceRange, destRange, uploadRangeOptions));
// Below code seems to be triggering a server high latency. Uncomment when server resolves the
// issue.
// uploadRangeOptions.SourceAccessCondition.IfMatchContentHash.GetValue().Value =
// invalidCrc64;
// EXPECT_THROW(
// uploadResult = *destFileClient.UploadRangeFromUri(
// sourceFileClient.GetUrl() + sourceSas, sourceRange, destRange, uploadRangeOptions),
// StorageException);
}
{
Files::Shares::UploadFileRangeFromUriOptions uploadRangeOptions;
uploadRangeOptions.SourceContentHash = uploadResult.TransactionalContentHash;
EXPECT_NO_THROW(
uploadResult = *destFileClient.UploadRangeFromUri(
sourceFileClient.GetUrl() + sourceSas, sourceRange, destRange, uploadRangeOptions));
// Below code seems to be triggering a server high latency. Uncomment when server resolves the
// issue.
// uploadRangeOptions.SourceContentHash.GetValue().Value = invalidCrc64;
// EXPECT_THROW(
// uploadResult = *destFileClient.UploadRangeFromUri(
// sourceFileClient.GetUrl() + sourceSas, sourceRange, destRange, uploadRangeOptions),
// StorageException);
}
}
}}} // namespace Azure::Storage::Test