in sdk/storage/azure-storage-blobs/src/blob_client.cpp [166:314]
Azure::Response<Models::DownloadBlobResult> BlobClient::Download(
const DownloadBlobOptions& options,
const Azure::Core::Context& context) const
{
_detail::BlobClient::DownloadBlobOptions protocolLayerOptions;
if (options.Range.HasValue())
{
std::string rangeStr = "bytes=" + std::to_string(options.Range.Value().Offset) + "-";
if (options.Range.Value().Length.HasValue())
{
rangeStr += std::to_string(
options.Range.Value().Offset + options.Range.Value().Length.Value() - 1);
}
protocolLayerOptions.Range = rangeStr;
}
if (options.RangeHashAlgorithm.HasValue())
{
if (options.RangeHashAlgorithm.Value() == HashAlgorithm::Md5)
{
protocolLayerOptions.RangeGetContentMD5 = true;
}
else if (options.RangeHashAlgorithm.Value() == HashAlgorithm::Crc64)
{
protocolLayerOptions.RangeGetContentCRC64 = true;
}
}
protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId;
protocolLayerOptions.IfModifiedSince = options.AccessConditions.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince;
protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch;
protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch;
protocolLayerOptions.IfTags = options.AccessConditions.TagConditions;
{
bool includeUserPrincipalName = false;
if (context.TryGetValue(
_detail::DataLakeInteroperabilityExtraOptionsKey, includeUserPrincipalName))
{
protocolLayerOptions.UserPrincipalName = includeUserPrincipalName;
}
}
if (m_customerProvidedKey.HasValue())
{
protocolLayerOptions.EncryptionKey = m_customerProvidedKey.Value().Key;
protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.Value().KeyHash;
protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.Value().Algorithm.ToString();
}
auto downloadResponse = _detail::BlobClient::Download(
*m_pipeline, m_blobUrl, protocolLayerOptions, _internal::WithReplicaStatus(context));
{
// In case network failure during reading the body
const Azure::ETag eTag = downloadResponse.Value.Details.ETag;
const std::string client_request_id
= downloadResponse.RawResponse->GetHeaders().find(_internal::HttpHeaderClientRequestId)
== downloadResponse.RawResponse->GetHeaders().end()
? std::string()
: downloadResponse.RawResponse->GetHeaders().at(_internal::HttpHeaderClientRequestId);
auto retryFunction =
[this, options, eTag, client_request_id](
int64_t retryOffset,
const Azure::Core::Context& context) -> std::unique_ptr<Azure::Core::IO::BodyStream> {
DownloadBlobOptions newOptions = options;
newOptions.Range = Core::Http::HttpRange();
newOptions.Range.Value().Offset
= (options.Range.HasValue() ? options.Range.Value().Offset : 0) + retryOffset;
if (options.Range.HasValue() && options.Range.Value().Length.HasValue())
{
newOptions.Range.Value().Length = options.Range.Value().Length.Value() - retryOffset;
}
newOptions.AccessConditions.IfMatch = eTag;
return std::move(
Download(
newOptions,
context.WithValue(_internal::ReliableStreamClientRequestIdKey, client_request_id))
.Value.BodyStream);
};
_internal::ReliableStreamOptions reliableStreamOptions;
reliableStreamOptions.MaxRetryRequests = _internal::ReliableStreamRetryCount;
downloadResponse.Value.BodyStream = std::make_unique<_internal::ReliableStream>(
std::move(downloadResponse.Value.BodyStream), reliableStreamOptions, retryFunction);
}
if (downloadResponse.RawResponse->GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok)
{
downloadResponse.Value.BlobSize = std::stoll(
downloadResponse.RawResponse->GetHeaders().at(_internal::HttpHeaderContentLength));
downloadResponse.Value.ContentRange.Offset = 0;
downloadResponse.Value.ContentRange.Length = downloadResponse.Value.BlobSize;
}
else if (
downloadResponse.RawResponse->GetStatusCode()
== Azure::Core::Http::HttpStatusCode::PartialContent)
{
const std::string& contentRange
= downloadResponse.RawResponse->GetHeaders().at(_internal::HttpHeaderContentRange);
auto bytes_pos = contentRange.find("bytes ");
auto dash_pos = contentRange.find("-", bytes_pos + 6);
auto slash_pos = contentRange.find("/", dash_pos + 1);
const int64_t rangeStartOffset = std::stoll(
std::string(contentRange.begin() + bytes_pos + 6, contentRange.begin() + dash_pos));
const int64_t rangeEndOffset = std::stoll(
std::string(contentRange.begin() + dash_pos + 1, contentRange.begin() + slash_pos));
downloadResponse.Value.ContentRange
= Azure::Core::Http::HttpRange{rangeStartOffset, rangeEndOffset - rangeStartOffset + 1};
downloadResponse.Value.BlobSize = std::stoll(contentRange.substr(slash_pos + 1));
}
if (downloadResponse.Value.BlobType == Models::BlobType::AppendBlob
&& !downloadResponse.Value.Details.IsSealed.HasValue())
{
downloadResponse.Value.Details.IsSealed = false;
}
if (downloadResponse.Value.Details.VersionId.HasValue()
&& !downloadResponse.Value.Details.IsCurrentVersion.HasValue())
{
downloadResponse.Value.Details.IsCurrentVersion = false;
}
{
std::map<std::string, std::vector<Models::ObjectReplicationRule>> orPropertiesMap;
for (auto i = downloadResponse.RawResponse->GetHeaders().lower_bound("x-ms-or-");
i != downloadResponse.RawResponse->GetHeaders().end()
&& i->first.substr(0, 8) == "x-ms-or-";
++i)
{
const std::string& header = i->first;
auto underscorePos = header.find('_', 8);
if (underscorePos == std::string::npos)
{
continue;
}
std::string policyId = std::string(header.begin() + 8, header.begin() + underscorePos);
std::string ruleId = header.substr(underscorePos + 1);
Models::ObjectReplicationRule rule;
rule.RuleId = std::move(ruleId);
rule.ReplicationStatus = Models::ObjectReplicationStatus(i->second);
orPropertiesMap[policyId].emplace_back(std::move(rule));
}
for (auto& property : orPropertiesMap)
{
Models::ObjectReplicationPolicy policy;
policy.PolicyId = property.first;
policy.Rules = std::move(property.second);
downloadResponse.Value.Details.ObjectReplicationSourceProperties.emplace_back(
std::move(policy));
}
}
return downloadResponse;
}