diff --git a/sdk/storage/azure-storage-blobs/CHANGELOG.md b/sdk/storage/azure-storage-blobs/CHANGELOG.md index d05a08daf..05fc861e7 100644 --- a/sdk/storage/azure-storage-blobs/CHANGELOG.md +++ b/sdk/storage/azure-storage-blobs/CHANGELOG.md @@ -66,6 +66,7 @@ - Rename `Models::DeleteSnapshotsOption::Only` to `Models::DeleteSnapshotsOption::OnlySnapshots`. - Rename `SourceConditions` in API options to `SourceAccessConditions`. - Remove Blob Batch. +- `DownloadBlobResult::Content-Range` is changed to an `Azure::Core::Http::Range`, an extra field `BlobSize` is added. ## 12.0.0-beta.5 (2020-11-13) diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/protocol/blob_rest_client.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/protocol/blob_rest_client.hpp index b1ab1870a..70048cbf3 100644 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/protocol/blob_rest_client.hpp +++ b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/protocol/blob_rest_client.hpp @@ -954,7 +954,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::DateTime CreatedOn; Azure::Core::Nullable ExpiriesOn; Azure::Core::Nullable LastAccessedOn; - Azure::Core::Nullable ContentRange; + Azure::Core::Http::Range ContentRange; + int64_t BlobSize = 0; BlobHttpHeaders HttpHeaders; Storage::Metadata Metadata; Azure::Core::Nullable SequenceNumber; // only for page blob @@ -4958,10 +4959,34 @@ namespace Azure { namespace Storage { namespace Blobs { x_ms_last_access_time__iterator->second, Azure::Core::DateTime::DateFormat::Rfc1123); } - auto content_range__iterator = httpResponse.GetHeaders().find("content-range"); - if (content_range__iterator != httpResponse.GetHeaders().end()) + auto content_range_iterator = httpResponse.GetHeaders().find("content-range"); + if (content_range_iterator != httpResponse.GetHeaders().end()) { - response.ContentRange = content_range__iterator->second; + const std::string& content_range = content_range_iterator->second; + auto bytes_pos = content_range.find("bytes "); + auto dash_pos = content_range.find("-", bytes_pos + 6); + auto slash_pos = content_range.find("/", dash_pos + 1); + int64_t range_start_offset = std::stoll(std::string( + content_range.begin() + bytes_pos + 6, content_range.begin() + dash_pos)); + int64_t range_end_offset = std::stoll(std::string( + content_range.begin() + dash_pos + 1, content_range.begin() + slash_pos)); + response.ContentRange = Azure::Core::Http::Range{ + range_start_offset, range_end_offset - range_start_offset + 1}; + } + else + { + response.ContentRange = Azure::Core::Http::Range{ + 0, std::stoll(httpResponse.GetHeaders().at("content-length"))}; + } + if (content_range_iterator != httpResponse.GetHeaders().end()) + { + const std::string& content_range = content_range_iterator->second; + auto slash_pos = content_range.find("/"); + response.BlobSize = std::stoll(content_range.substr(slash_pos + 1)); + } + else + { + response.BlobSize = std::stoll(httpResponse.GetHeaders().at("content-length")); } auto x_ms_blob_sequence_number__iterator = httpResponse.GetHeaders().find("x-ms-blob-sequence-number"); diff --git a/sdk/storage/azure-storage-blobs/src/blob_client.cpp b/sdk/storage/azure-storage-blobs/src/blob_client.cpp index e726b3300..4d10e1b22 100644 --- a/sdk/storage/azure-storage-blobs/src/blob_client.cpp +++ b/sdk/storage/azure-storage-blobs/src/blob_client.cpp @@ -245,8 +245,7 @@ namespace Azure { namespace Storage { namespace Blobs { int64_t blobRangeSize; if (firstChunkOptions.Range.HasValue()) { - blobSize = std::stoll(firstChunk->ContentRange.GetValue().substr( - firstChunk->ContentRange.GetValue().find('/') + 1)); + blobSize = firstChunk->BlobSize; blobRangeSize = blobSize - firstChunkOffset; if (options.Range.HasValue() && options.Range.GetValue().Length.HasValue()) { @@ -375,8 +374,7 @@ namespace Azure { namespace Storage { namespace Blobs { int64_t blobRangeSize; if (firstChunkOptions.Range.HasValue()) { - blobSize = std::stoll(firstChunk->ContentRange.GetValue().substr( - firstChunk->ContentRange.GetValue().find('/') + 1)); + blobSize = firstChunk->BlobSize; blobRangeSize = blobSize - firstChunkOffset; if (options.Range.HasValue() && options.Range.GetValue().Length.HasValue()) { diff --git a/sdk/storage/azure-storage-blobs/test/block_blob_client_test.cpp b/sdk/storage/azure-storage-blobs/test/block_blob_client_test.cpp index bcc29bbe2..c82b7e02d 100644 --- a/sdk/storage/azure-storage-blobs/test/block_blob_client_test.cpp +++ b/sdk/storage/azure-storage-blobs/test/block_blob_client_test.cpp @@ -79,6 +79,9 @@ namespace Azure { namespace Storage { namespace Test { TEST_F(BlockBlobClientTest, UploadDownload) { auto res = m_blockBlobClient->Download(); + EXPECT_EQ(res->BlobSize, static_cast(m_blobContent.size())); + EXPECT_EQ(res->ContentRange.Offset, 0); + EXPECT_EQ(res->ContentRange.Length.GetValue(), static_cast(m_blobContent.size())); EXPECT_EQ(ReadBodyStream(res->BodyStream), m_blobContent); EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderRequestId).empty()); EXPECT_FALSE(res.GetRawResponse().GetHeaders().at(Details::HttpHeaderDate).empty()); @@ -99,7 +102,9 @@ namespace Azure { namespace Storage { namespace Test { m_blobContent.begin() + static_cast( options.Range.GetValue().Offset + options.Range.GetValue().Length.GetValue()))); - EXPECT_FALSE(res->ContentRange.GetValue().empty()); + EXPECT_EQ(res->ContentRange.Offset, options.Range.GetValue().Offset); + EXPECT_EQ(res->ContentRange.Length.GetValue(), options.Range.GetValue().Length.GetValue()); + EXPECT_EQ(res->BlobSize, static_cast(m_blobContent.size())); } TEST_F(BlockBlobClientTest, DISABLED_LastAccessTime) diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp index beaf85bcd..40fe80e9f 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp @@ -323,7 +323,12 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { Models::ReadFileResult ret; ret.Body = std::move(result->BodyStream); ret.HttpHeaders = FromBlobHttpHeaders(std::move(result->HttpHeaders)); - ret.ContentRange = std::move(result->ContentRange); + // FIXME + if (result.GetRawResponse().GetHeaders().find("content-range") + != result.GetRawResponse().GetHeaders().end()) + { + ret.ContentRange = result.GetRawResponse().GetHeaders().at("content-range"); + } ret.TransactionalContentHash = std::move(result->TransactionalContentHash); ret.ETag = std::move(result->ETag); ret.LastModified = std::move(result->LastModified);