Azure::Response BlobClient::Download()

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;
  }