Skip to main content

azure_storage_blob/models/
download_result.rs

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT License.
3
4use azure_core::{
5    base64,
6    fmt::SafeDebug,
7    http::{
8        headers::{HeaderName, Headers},
9        response::AsyncResponseBody,
10        AsyncRawResponse, Etag,
11    },
12    time::parse_rfc7231,
13};
14use std::collections::HashMap;
15use time::OffsetDateTime;
16
17use crate::generated::models::{
18    BlobType, CopyStatus, ImmutabilityPolicyMode, LeaseDuration, LeaseState, LeaseStatus,
19};
20
21/// Result of a `BlobClient::download()` operation.
22///
23/// The full blob content over the requested range is streamed via [`body`](Self::body).
24/// All other fields: [`properties`](Self::properties), and [`headers`](Self::headers), are parsed
25/// from the **initial response**.
26#[derive(SafeDebug)]
27pub struct BlobClientDownloadResult {
28    /// The blob content stream.
29    pub body: AsyncResponseBody,
30
31    /// Blob properties parsed from the initial response.
32    pub properties: BlobDownloadProperties,
33
34    /// All headers from the initial response.
35    ///
36    /// Use this to access headers that are not surfaced as named fields, such as
37    /// `x-ms-request-id`, `x-ms-client-request-id`, and more.
38    pub headers: Headers,
39}
40
41/// Result of a `BlobClient::download_into()` operation.
42#[derive(SafeDebug)]
43pub struct BlobClientDownloadIntoResult {
44    /// The length of data written to the provided buffer.
45    pub len: usize,
46
47    /// Blob properties parsed from the initial response.
48    pub properties: BlobDownloadProperties,
49
50    /// All headers from the initial response.
51    ///
52    /// Use this to access headers that are not surfaced as named fields, such as
53    /// `x-ms-request-id`, `x-ms-client-request-id`, and more.
54    pub headers: Headers,
55}
56
57/// Blob properties parsed from the initial response headers of a `BlobClient::download()` operation.
58#[derive(SafeDebug)]
59pub struct BlobDownloadProperties {
60    /// The blob's ETag (`ETag` header).
61    pub etag: Option<Etag>,
62
63    /// Date/time the blob was last modified (`Last-Modified` header).
64    pub last_modified: Option<OffsetDateTime>,
65
66    /// Date/time the blob was created (`x-ms-creation-time` header).
67    pub created_on: Option<OffsetDateTime>,
68
69    /// Date/time the blob was last read or written (`x-ms-last-access-time` header).
70    pub last_accessed: Option<OffsetDateTime>,
71
72    /// Number of bytes in the response body (`Content-Length` header).
73    ///
74    /// For a full-blob download this equals the total blob size. For a ranged or partitioned
75    /// download, this is the byte count of the initial response.
76    pub content_length: Option<u64>,
77
78    /// The content type of the blob (`Content-Type` header).
79    pub content_type: Option<String>,
80
81    /// The cache control directive for the blob (`Cache-Control` header).
82    pub cache_control: Option<String>,
83
84    /// The content disposition of the blob (`Content-Disposition` header).
85    pub content_disposition: Option<String>,
86
87    /// The content encoding of the blob (`Content-Encoding` header).
88    pub content_encoding: Option<String>,
89
90    /// The content language of the blob (`Content-Language` header).
91    pub content_language: Option<String>,
92
93    /// MD5 hash of the response content (`Content-MD5` header).
94    ///
95    /// For full-blob reads this covers the entire blob. For ranged reads it covers only the
96    /// returned range. To get the MD5 of the full blob content for a ranged read, see
97    /// [`blob_content_md5`](Self::blob_content_md5).
98    pub content_md5: Option<Vec<u8>>,
99
100    /// CRC-64 hash for the downloaded range (`x-ms-content-crc64` header).
101    ///
102    /// Only returned for ranged reads (when [`range`](crate::models::BlobClientDownloadOptions::range) is set)
103    /// and only when [`range_get_content_crc64`](crate::models::BlobClientDownloadOptions::range_get_content_crc64) is `true`.
104    /// The range must be 4 MiB or smaller, otherwise the service rejects the request.
105    pub content_crc64: Option<Vec<u8>>,
106
107    /// MD5 hash of the full blob content (`x-ms-blob-content-md5` header).
108    ///
109    /// Only returned for ranged reads. This is the hash of the complete blob, not just the
110    /// requested range.
111    pub blob_content_md5: Option<Vec<u8>>,
112
113    /// The type of blob (`x-ms-blob-type` header): BlockBlob, PageBlob, or AppendBlob.
114    pub blob_type: Option<BlobType>,
115
116    /// Current sequence number for a page blob (`x-ms-blob-sequence-number` header).
117    pub blob_sequence_number: Option<i64>,
118
119    /// Number of committed blocks, returned only for append blobs
120    /// (`x-ms-blob-committed-block-count` header).
121    pub blob_committed_block_count: Option<i32>,
122
123    /// Whether this append blob has been sealed (`x-ms-blob-sealed` header).
124    pub is_sealed: Option<bool>,
125
126    /// User-defined metadata on the blob (all `x-ms-meta-*` headers).
127    pub metadata: HashMap<String, String>,
128
129    /// Version ID of the blob, if versioning is enabled (`x-ms-version-id` header).
130    pub version_id: Option<String>,
131
132    /// State of the blob's lease (`x-ms-lease-state` header).
133    pub lease_state: Option<LeaseState>,
134
135    /// Status of the blob's lease (`x-ms-lease-status` header).
136    pub lease_status: Option<LeaseStatus>,
137
138    /// Duration type of the lease (`x-ms-lease-duration` header).
139    pub lease_duration: Option<LeaseDuration>,
140
141    /// Whether the blob has a legal hold (`x-ms-legal-hold` header).
142    pub legal_hold: Option<bool>,
143
144    /// The immutability policy mode (`x-ms-immutability-policy-mode` header).
145    pub immutability_policy_mode: Option<ImmutabilityPolicyMode>,
146
147    /// The immutability policy expiry time (`x-ms-immutability-policy-until-date` header).
148    pub immutability_policy_expires_on: Option<OffsetDateTime>,
149
150    /// Completion time of the last copy operation (`x-ms-copy-completion-time` header).
151    pub copy_completed_on: Option<OffsetDateTime>,
152
153    /// String identifier for the last copy operation (`x-ms-copy-id` header).
154    pub copy_id: Option<String>,
155
156    /// Progress of an in-progress copy operation (`x-ms-copy-progress` header).
157    pub copy_progress: Option<String>,
158
159    /// URL of the source blob for the last copy operation (`x-ms-copy-source` header).
160    pub copy_source: Option<String>,
161
162    /// State of the copy operation (`x-ms-copy-status` header).
163    pub copy_status: Option<CopyStatus>,
164
165    /// Description of a failed or aborted copy operation (`x-ms-copy-status-description` header).
166    pub copy_status_description: Option<String>,
167
168    /// Destination policy ID for object replication (`x-ms-or-policy-id` header).
169    pub object_replication_policy_id: Option<String>,
170
171    /// Object replication rules and their statuses (all `x-ms-or-*` headers).
172    pub object_replication_rules: HashMap<String, String>,
173
174    /// Number of tags on the blob (`x-ms-tag-count` header).
175    pub tag_count: Option<i64>,
176
177    /// The name of the encryption scope used to encrypt the blob (`x-ms-encryption-scope` header).
178    pub encryption_scope: Option<String>,
179
180    /// Base64-encoded SHA-256 hash of the customer-provided encryption key
181    /// used to encrypt the blob (`x-ms-encryption-key-sha256` header).
182    pub encryption_key_sha256: Option<String>,
183}
184
185impl BlobClientDownloadResult {
186    /// Constructs a `BlobClientDownloadResult` by parsing headers from the initial response.
187    pub(crate) fn from_headers(response: AsyncRawResponse) -> azure_core::Result<Self> {
188        let (_, headers, body) = response.deconstruct();
189        let properties = BlobDownloadProperties::from_headers(&headers)?;
190        Ok(Self {
191            body,
192            properties,
193            headers,
194        })
195    }
196}
197
198impl BlobDownloadProperties {
199    pub(crate) fn from_headers(headers: &Headers) -> azure_core::Result<Self> {
200        let (metadata, object_replication_rules) =
201            crate::parsers::parse_metadata_and_replication_headers(headers);
202        Ok(Self {
203            etag: headers.get_optional_as(&HeaderName::from_static("etag"))?,
204            last_modified: headers
205                .get_optional_with(&HeaderName::from_static("last-modified"), |h| {
206                    parse_rfc7231(h.as_str())
207                })?,
208            created_on: headers
209                .get_optional_with(&HeaderName::from_static("x-ms-creation-time"), |h| {
210                    parse_rfc7231(h.as_str())
211                })?,
212            last_accessed: headers
213                .get_optional_with(&HeaderName::from_static("x-ms-last-access-time"), |h| {
214                    parse_rfc7231(h.as_str())
215                })?,
216            content_length: headers.get_optional_as(&HeaderName::from_static("content-length"))?,
217            content_type: headers.get_optional_as(&HeaderName::from_static("content-type"))?,
218            cache_control: headers.get_optional_as(&HeaderName::from_static("cache-control"))?,
219            content_disposition: headers
220                .get_optional_as(&HeaderName::from_static("content-disposition"))?,
221            content_encoding: headers
222                .get_optional_as(&HeaderName::from_static("content-encoding"))?,
223            content_language: headers
224                .get_optional_as(&HeaderName::from_static("content-language"))?,
225            content_md5: headers
226                .get_optional_with(&HeaderName::from_static("content-md5"), |h| {
227                    base64::decode(h.as_str())
228                })?,
229            content_crc64: headers
230                .get_optional_with(&HeaderName::from_static("x-ms-content-crc64"), |h| {
231                    base64::decode(h.as_str())
232                })?,
233            blob_content_md5: headers
234                .get_optional_with(&HeaderName::from_static("x-ms-blob-content-md5"), |h| {
235                    base64::decode(h.as_str())
236                })?,
237            blob_type: headers.get_optional_as(&HeaderName::from_static("x-ms-blob-type"))?,
238            blob_sequence_number: headers
239                .get_optional_as(&HeaderName::from_static("x-ms-blob-sequence-number"))?,
240            blob_committed_block_count: headers
241                .get_optional_as(&HeaderName::from_static("x-ms-blob-committed-block-count"))?,
242            is_sealed: headers.get_optional_as(&HeaderName::from_static("x-ms-blob-sealed"))?,
243            version_id: headers.get_optional_as(&HeaderName::from_static("x-ms-version-id"))?,
244            lease_state: headers.get_optional_as(&HeaderName::from_static("x-ms-lease-state"))?,
245            lease_status: headers.get_optional_as(&HeaderName::from_static("x-ms-lease-status"))?,
246            lease_duration: headers
247                .get_optional_as(&HeaderName::from_static("x-ms-lease-duration"))?,
248            legal_hold: headers.get_optional_as(&HeaderName::from_static("x-ms-legal-hold"))?,
249            immutability_policy_mode: headers
250                .get_optional_as(&HeaderName::from_static("x-ms-immutability-policy-mode"))?,
251            immutability_policy_expires_on: headers.get_optional_with(
252                &HeaderName::from_static("x-ms-immutability-policy-until-date"),
253                |h| parse_rfc7231(h.as_str()),
254            )?,
255            copy_completed_on: headers
256                .get_optional_with(&HeaderName::from_static("x-ms-copy-completion-time"), |h| {
257                    parse_rfc7231(h.as_str())
258                })?,
259            copy_id: headers.get_optional_as(&HeaderName::from_static("x-ms-copy-id"))?,
260            copy_progress: headers
261                .get_optional_as(&HeaderName::from_static("x-ms-copy-progress"))?,
262            copy_source: headers.get_optional_as(&HeaderName::from_static("x-ms-copy-source"))?,
263            copy_status: headers.get_optional_as(&HeaderName::from_static("x-ms-copy-status"))?,
264            copy_status_description: headers
265                .get_optional_as(&HeaderName::from_static("x-ms-copy-status-description"))?,
266            object_replication_policy_id: headers
267                .get_optional_as(&HeaderName::from_static("x-ms-or-policy-id"))?,
268            tag_count: headers.get_optional_as(&HeaderName::from_static("x-ms-tag-count"))?,
269            encryption_scope: headers
270                .get_optional_as(&HeaderName::from_static("x-ms-encryption-scope"))?,
271            encryption_key_sha256: headers
272                .get_optional_as(&HeaderName::from_static("x-ms-encryption-key-sha256"))?,
273            metadata,
274            object_replication_rules,
275        })
276    }
277}