1use crate::generated::models::{
7 AppendBlobClientAppendBlockFromUrlOptions, AppendBlobClientAppendBlockFromUrlResult,
8 AppendBlobClientAppendBlockOptions, AppendBlobClientAppendBlockResult,
9 AppendBlobClientCreateOptions, AppendBlobClientCreateResult, AppendBlobClientSealOptions,
10 AppendBlobClientSealResult,
11};
12use azure_core::{
13 base64,
14 error::CheckSuccessOptions,
15 fmt::SafeDebug,
16 http::{
17 ClientOptions, Method, NoFormat, Pipeline, PipelineSendOptions, Request, RequestContent,
18 Response, Url, UrlExt,
19 },
20 time::to_rfc7231,
21 tracing, Bytes, Result,
22};
23
24#[tracing::client]
25pub struct AppendBlobClient {
26 pub(crate) endpoint: Url,
27 pub(crate) pipeline: Pipeline,
28 pub(crate) version: String,
29}
30
31#[derive(Clone, SafeDebug)]
33pub struct AppendBlobClientOptions {
34 pub client_options: ClientOptions,
36 pub version: String,
38}
39
40impl AppendBlobClient {
41 #[tracing::function("Storage.Blob.AppendBlobClient.appendBlock")]
86 pub async fn append_block(
87 &self,
88 body: RequestContent<Bytes, NoFormat>,
89 content_length: u64,
90 options: Option<AppendBlobClientAppendBlockOptions<'_>>,
91 ) -> Result<Response<AppendBlobClientAppendBlockResult, NoFormat>> {
92 let options = options.unwrap_or_default();
93 let ctx = options.method_options.context.to_borrowed();
94 let mut url = self.endpoint.clone();
95 let mut query_builder = url.query_builder();
96 query_builder.append_pair("comp", "appendblock");
97 if let Some(timeout) = options.timeout {
98 query_builder.set_pair("timeout", timeout.to_string());
99 }
100 query_builder.build();
101 let mut request = Request::new(url, Method::Put);
102 request.insert_header("content-length", content_length.to_string());
103 if let Some(transactional_content_md5) = options.transactional_content_md5 {
104 request.insert_header("content-md5", base64::encode(transactional_content_md5));
105 }
106 request.insert_header("content-type", "application/octet-stream");
107 if let Some(if_match) = options.if_match.as_ref() {
108 request.insert_header("if-match", if_match.to_string());
109 }
110 if let Some(if_modified_since) = options.if_modified_since {
111 request.insert_header("if-modified-since", to_rfc7231(&if_modified_since));
112 }
113 if let Some(if_none_match) = options.if_none_match.as_ref() {
114 request.insert_header("if-none-match", if_none_match.to_string());
115 }
116 if let Some(if_unmodified_since) = options.if_unmodified_since {
117 request.insert_header("if-unmodified-since", to_rfc7231(&if_unmodified_since));
118 }
119 if let Some(append_position) = options.append_position {
120 request.insert_header("x-ms-blob-condition-appendpos", append_position.to_string());
121 }
122 if let Some(max_size) = options.max_size {
123 request.insert_header("x-ms-blob-condition-maxsize", max_size.to_string());
124 }
125 if let Some(transactional_content_crc64) = options.transactional_content_crc64 {
126 request.insert_header(
127 "x-ms-content-crc64",
128 base64::encode(transactional_content_crc64),
129 );
130 }
131 if let Some(encryption_algorithm) = options.encryption_algorithm.as_ref() {
132 request.insert_header(
133 "x-ms-encryption-algorithm",
134 encryption_algorithm.to_string(),
135 );
136 }
137 if let Some(encryption_key) = options.encryption_key.as_ref() {
138 request.insert_header("x-ms-encryption-key", encryption_key);
139 }
140 if let Some(encryption_key_sha256) = options.encryption_key_sha256.as_ref() {
141 request.insert_header("x-ms-encryption-key-sha256", encryption_key_sha256);
142 }
143 if let Some(encryption_scope) = options.encryption_scope.as_ref() {
144 request.insert_header("x-ms-encryption-scope", encryption_scope);
145 }
146 if let Some(if_tags) = options.if_tags.as_ref() {
147 request.insert_header("x-ms-if-tags", if_tags);
148 }
149 if let Some(lease_id) = options.lease_id.as_ref() {
150 request.insert_header("x-ms-lease-id", lease_id);
151 }
152 request.insert_header("x-ms-version", &self.version);
153 request.set_body(body);
154 let rsp = self
155 .pipeline
156 .send(
157 &ctx,
158 &mut request,
159 Some(PipelineSendOptions {
160 check_success: CheckSuccessOptions {
161 success_codes: &[201],
162 },
163 ..Default::default()
164 }),
165 )
166 .await?;
167 Ok(rsp.into())
168 }
169
170 #[tracing::function("Storage.Blob.AppendBlobClient.appendBlockFromUrl")]
215 pub async fn append_block_from_url(
216 &self,
217 source_url: String,
218 content_length: u64,
219 options: Option<AppendBlobClientAppendBlockFromUrlOptions<'_>>,
220 ) -> Result<Response<AppendBlobClientAppendBlockFromUrlResult, NoFormat>> {
221 let options = options.unwrap_or_default();
222 let ctx = options.method_options.context.to_borrowed();
223 let mut url = self.endpoint.clone();
224 let mut query_builder = url.query_builder();
225 query_builder.append_pair("comp", "appendblock");
226 if let Some(timeout) = options.timeout {
227 query_builder.set_pair("timeout", timeout.to_string());
228 }
229 query_builder.build();
230 let mut request = Request::new(url, Method::Put);
231 request.insert_header("content-length", content_length.to_string());
232 if let Some(transactional_content_md5) = options.transactional_content_md5 {
233 request.insert_header("content-md5", base64::encode(transactional_content_md5));
234 }
235 if let Some(if_match) = options.if_match.as_ref() {
236 request.insert_header("if-match", if_match.to_string());
237 }
238 if let Some(if_modified_since) = options.if_modified_since {
239 request.insert_header("if-modified-since", to_rfc7231(&if_modified_since));
240 }
241 if let Some(if_none_match) = options.if_none_match.as_ref() {
242 request.insert_header("if-none-match", if_none_match.to_string());
243 }
244 if let Some(if_unmodified_since) = options.if_unmodified_since {
245 request.insert_header("if-unmodified-since", to_rfc7231(&if_unmodified_since));
246 }
247 if let Some(append_position) = options.append_position {
248 request.insert_header("x-ms-blob-condition-appendpos", append_position.to_string());
249 }
250 if let Some(max_size) = options.max_size {
251 request.insert_header("x-ms-blob-condition-maxsize", max_size.to_string());
252 }
253 request.insert_header("x-ms-copy-source", source_url);
254 if let Some(copy_source_authorization) = options.copy_source_authorization.as_ref() {
255 request.insert_header("x-ms-copy-source-authorization", copy_source_authorization);
256 }
257 if let Some(encryption_algorithm) = options.encryption_algorithm.as_ref() {
258 request.insert_header(
259 "x-ms-encryption-algorithm",
260 encryption_algorithm.to_string(),
261 );
262 }
263 if let Some(encryption_key) = options.encryption_key.as_ref() {
264 request.insert_header("x-ms-encryption-key", encryption_key);
265 }
266 if let Some(encryption_key_sha256) = options.encryption_key_sha256.as_ref() {
267 request.insert_header("x-ms-encryption-key-sha256", encryption_key_sha256);
268 }
269 if let Some(encryption_scope) = options.encryption_scope.as_ref() {
270 request.insert_header("x-ms-encryption-scope", encryption_scope);
271 }
272 if let Some(file_request_intent) = options.file_request_intent.as_ref() {
273 request.insert_header("x-ms-file-request-intent", file_request_intent.to_string());
274 }
275 if let Some(if_tags) = options.if_tags.as_ref() {
276 request.insert_header("x-ms-if-tags", if_tags);
277 }
278 if let Some(lease_id) = options.lease_id.as_ref() {
279 request.insert_header("x-ms-lease-id", lease_id);
280 }
281 if let Some(source_content_crc64) = options.source_content_crc64 {
282 request.insert_header(
283 "x-ms-source-content-crc64",
284 base64::encode(source_content_crc64),
285 );
286 }
287 if let Some(source_content_md5) = options.source_content_md5 {
288 request.insert_header(
289 "x-ms-source-content-md5",
290 base64::encode(source_content_md5),
291 );
292 }
293 if let Some(source_encryption_algorithm) = options.source_encryption_algorithm.as_ref() {
294 request.insert_header(
295 "x-ms-source-encryption-algorithm",
296 source_encryption_algorithm.to_string(),
297 );
298 }
299 if let Some(source_encryption_key) = options.source_encryption_key.as_ref() {
300 request.insert_header("x-ms-source-encryption-key", source_encryption_key);
301 }
302 if let Some(source_encryption_key_sha256) = options.source_encryption_key_sha256.as_ref() {
303 request.insert_header(
304 "x-ms-source-encryption-key-sha256",
305 source_encryption_key_sha256,
306 );
307 }
308 if let Some(source_if_match) = options.source_if_match.as_ref() {
309 request.insert_header("x-ms-source-if-match", source_if_match.to_string());
310 }
311 if let Some(source_if_modified_since) = options.source_if_modified_since {
312 request.insert_header(
313 "x-ms-source-if-modified-since",
314 to_rfc7231(&source_if_modified_since),
315 );
316 }
317 if let Some(source_if_none_match) = options.source_if_none_match.as_ref() {
318 request.insert_header(
319 "x-ms-source-if-none-match",
320 source_if_none_match.to_string(),
321 );
322 }
323 if let Some(source_if_unmodified_since) = options.source_if_unmodified_since {
324 request.insert_header(
325 "x-ms-source-if-unmodified-since",
326 to_rfc7231(&source_if_unmodified_since),
327 );
328 }
329 if let Some(source_range) = options.source_range.as_ref() {
330 request.insert_header("x-ms-source-range", source_range.to_string());
331 }
332 request.insert_header("x-ms-version", &self.version);
333 let rsp = self
334 .pipeline
335 .send(
336 &ctx,
337 &mut request,
338 Some(PipelineSendOptions {
339 check_success: CheckSuccessOptions {
340 success_codes: &[201],
341 },
342 ..Default::default()
343 }),
344 )
345 .await?;
346 Ok(rsp.into())
347 }
348
349 #[tracing::function("Storage.Blob.AppendBlobClient.create")]
390 pub async fn create(
391 &self,
392 options: Option<AppendBlobClientCreateOptions<'_>>,
393 ) -> Result<Response<AppendBlobClientCreateResult, NoFormat>> {
394 let options = options.unwrap_or_default();
395 let ctx = options.method_options.context.to_borrowed();
396 let mut url = self.endpoint.clone();
397 let mut query_builder = url.query_builder();
398 if let Some(timeout) = options.timeout {
399 query_builder.set_pair("timeout", timeout.to_string());
400 }
401 query_builder.build();
402 let mut request = Request::new(url, Method::Put);
403 request.insert_header("content-length", "0");
404 if let Some(if_match) = options.if_match.as_ref() {
405 request.insert_header("if-match", if_match.to_string());
406 }
407 if let Some(if_modified_since) = options.if_modified_since {
408 request.insert_header("if-modified-since", to_rfc7231(&if_modified_since));
409 }
410 if let Some(if_none_match) = options.if_none_match.as_ref() {
411 request.insert_header("if-none-match", if_none_match.to_string());
412 }
413 if let Some(if_unmodified_since) = options.if_unmodified_since {
414 request.insert_header("if-unmodified-since", to_rfc7231(&if_unmodified_since));
415 }
416 if let Some(blob_cache_control) = options.blob_cache_control.as_ref() {
417 request.insert_header("x-ms-blob-cache-control", blob_cache_control);
418 }
419 if let Some(blob_content_disposition) = options.blob_content_disposition.as_ref() {
420 request.insert_header("x-ms-blob-content-disposition", blob_content_disposition);
421 }
422 if let Some(blob_content_encoding) = options.blob_content_encoding.as_ref() {
423 request.insert_header("x-ms-blob-content-encoding", blob_content_encoding);
424 }
425 if let Some(blob_content_language) = options.blob_content_language.as_ref() {
426 request.insert_header("x-ms-blob-content-language", blob_content_language);
427 }
428 if let Some(blob_content_md5) = options.blob_content_md5 {
429 request.insert_header("x-ms-blob-content-md5", base64::encode(blob_content_md5));
430 }
431 if let Some(blob_content_type) = options.blob_content_type.as_ref() {
432 request.insert_header("x-ms-blob-content-type", blob_content_type);
433 }
434 request.insert_header("x-ms-blob-type", "AppendBlob");
435 if let Some(encryption_algorithm) = options.encryption_algorithm.as_ref() {
436 request.insert_header(
437 "x-ms-encryption-algorithm",
438 encryption_algorithm.to_string(),
439 );
440 }
441 if let Some(encryption_key) = options.encryption_key.as_ref() {
442 request.insert_header("x-ms-encryption-key", encryption_key);
443 }
444 if let Some(encryption_key_sha256) = options.encryption_key_sha256.as_ref() {
445 request.insert_header("x-ms-encryption-key-sha256", encryption_key_sha256);
446 }
447 if let Some(encryption_scope) = options.encryption_scope.as_ref() {
448 request.insert_header("x-ms-encryption-scope", encryption_scope);
449 }
450 if let Some(if_tags) = options.if_tags.as_ref() {
451 request.insert_header("x-ms-if-tags", if_tags);
452 }
453 if let Some(immutability_policy_mode) = options.immutability_policy_mode.as_ref() {
454 request.insert_header(
455 "x-ms-immutability-policy-mode",
456 immutability_policy_mode.to_string(),
457 );
458 }
459 if let Some(immutability_policy_expiry) = options.immutability_policy_expiry {
460 request.insert_header(
461 "x-ms-immutability-policy-until-date",
462 to_rfc7231(&immutability_policy_expiry),
463 );
464 }
465 if let Some(lease_id) = options.lease_id.as_ref() {
466 request.insert_header("x-ms-lease-id", lease_id);
467 }
468 if let Some(legal_hold) = options.legal_hold {
469 request.insert_header("x-ms-legal-hold", legal_hold.to_string());
470 }
471 if let Some(metadata) = options.metadata.as_ref() {
472 for (k, v) in metadata {
473 request.insert_header(format!("x-ms-meta-{k}"), v);
474 }
475 }
476 if let Some(blob_tags_string) = options.blob_tags_string.as_ref() {
477 request.insert_header("x-ms-tags", blob_tags_string);
478 }
479 request.insert_header("x-ms-version", &self.version);
480 let rsp = self
481 .pipeline
482 .send(
483 &ctx,
484 &mut request,
485 Some(PipelineSendOptions {
486 check_success: CheckSuccessOptions {
487 success_codes: &[201],
488 },
489 ..Default::default()
490 }),
491 )
492 .await?;
493 Ok(rsp.into())
494 }
495
496 #[tracing::function("Storage.Blob.AppendBlobClient.seal")]
533 pub async fn seal(
534 &self,
535 options: Option<AppendBlobClientSealOptions<'_>>,
536 ) -> Result<Response<AppendBlobClientSealResult, NoFormat>> {
537 let options = options.unwrap_or_default();
538 let ctx = options.method_options.context.to_borrowed();
539 let mut url = self.endpoint.clone();
540 let mut query_builder = url.query_builder();
541 query_builder.append_pair("comp", "seal");
542 if let Some(timeout) = options.timeout {
543 query_builder.set_pair("timeout", timeout.to_string());
544 }
545 query_builder.build();
546 let mut request = Request::new(url, Method::Put);
547 if let Some(if_match) = options.if_match.as_ref() {
548 request.insert_header("if-match", if_match.to_string());
549 }
550 if let Some(if_modified_since) = options.if_modified_since {
551 request.insert_header("if-modified-since", to_rfc7231(&if_modified_since));
552 }
553 if let Some(if_none_match) = options.if_none_match.as_ref() {
554 request.insert_header("if-none-match", if_none_match.to_string());
555 }
556 if let Some(if_unmodified_since) = options.if_unmodified_since {
557 request.insert_header("if-unmodified-since", to_rfc7231(&if_unmodified_since));
558 }
559 if let Some(append_position) = options.append_position {
560 request.insert_header("x-ms-blob-condition-appendpos", append_position.to_string());
561 }
562 if let Some(lease_id) = options.lease_id.as_ref() {
563 request.insert_header("x-ms-lease-id", lease_id);
564 }
565 request.insert_header("x-ms-version", &self.version);
566 let rsp = self
567 .pipeline
568 .send(
569 &ctx,
570 &mut request,
571 Some(PipelineSendOptions {
572 check_success: CheckSuccessOptions {
573 success_codes: &[200],
574 },
575 ..Default::default()
576 }),
577 )
578 .await?;
579 Ok(rsp.into())
580 }
581}
582
583pub(crate) const DEFAULT_VERSION: &str = "2026-04-06";
585
586impl Default for AppendBlobClientOptions {
587 fn default() -> Self {
588 Self {
589 client_options: ClientOptions::default(),
590 version: String::from(DEFAULT_VERSION),
591 }
592 }
593}