1use super::types_rs::*;
6use crate::oss::Client;
7use crate::oss::Error;
8use crate::oss::sign_v4::HTTPVerb;
9use crate::oss::utils::{
10 PresignParams, compute_md5_from_file, generate_presigned_url, get_content_md5,
11 get_request_header, hmac_sha256_bytes, into_request_failed_error,
12 parse_get_object_response_header, parse_xml_response, utc_date_str, utc_date_time_str,
13 validate_object_name,
14};
15use base64::{Engine, engine::general_purpose};
16use bytes::Bytes;
17use reqwest::header::HeaderMap;
18use reqwest::{Body, StatusCode};
19use serde_json::{Map, Value};
20use std::collections::HashMap;
21use std::path::Path;
22use time::OffsetDateTime;
23use time::format_description::well_known::Iso8601;
24use tokio::io::AsyncWriteExt;
25use tokio_stream::{Stream, StreamExt};
26use tokio_util::io::ReaderStream;
27
28impl<'a> PutObject<'a> {
29 pub async fn send(
33 &self,
34 object_name: &'a str,
35 object: PutObjectBody<'a>,
36 ) -> Result<PutObjectResponseHeader, Error> {
37 validate_object_name(object_name)?;
38
39 let client = self.client;
40 let request_url = url::Url::parse(&format!(
41 "https://{}.{}/{}", client.bucket, client.endpoint, object_name
43 ))
44 .unwrap();
45
46 let mut req_header_map: HashMap<String, String> =
47 serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap();
48 match &object {
50 PutObjectBody::Bytes(bytes) => {
51 req_header_map.insert("content-md5".to_owned(), get_content_md5(bytes.as_slice()));
52 req_header_map.insert("content-length".to_owned(), bytes.len().to_string());
53 }
54 PutObjectBody::FilePath(path) => {
55 let file_size = std::fs::metadata(path)?.len();
56 req_header_map.insert("content-length".to_owned(), file_size.to_string());
57 let md5_str = compute_md5_from_file(path).await?;
58 req_header_map.insert("content-md5".to_owned(), md5_str);
59 }
60 }
61
62 if !self.custom_metas.is_empty() {
64 let custom_meta_map = self
65 .custom_metas
66 .iter()
67 .map(|(k, v)| (k.clone(), v.clone()))
68 .collect::<HashMap<_, _>>();
69 req_header_map.extend(custom_meta_map);
70 };
71
72 if let Some(oss_callback) = &self.callback {
73 let callback_base64 =
74 general_purpose::STANDARD.encode(serde_json::to_string(oss_callback).unwrap());
75 req_header_map.insert("x-oss-callback".to_owned(), callback_base64);
77 if !oss_callback.callback_body.callback_var.is_empty() {
78 let callback_var_map = oss_callback
79 .callback_body
80 .callback_var
81 .iter()
82 .map(|(_, k, v)| (k, v))
83 .collect::<HashMap<_, _>>();
84 let callback_var_base64 = general_purpose::STANDARD
85 .encode(serde_json::to_string(&callback_var_map).unwrap());
86 req_header_map.insert("x-oss-callback-var".to_owned(), callback_var_base64);
88 }
89 }
90
91 let creds = client.credentials_provider.load().await?;
92 if let Some(token) = &creds.sts_security_token {
94 req_header_map.insert("x-oss-security-token".to_owned(), token.clone());
95 }
96
97 let header_map = get_request_header(
98 &creds.access_key_id,
99 &creds.access_key_secret,
100 req_header_map,
101 &request_url,
102 HTTPVerb::Put,
103 &client.region,
104 Some(&client.bucket),
105 );
106
107 let data = match object {
108 PutObjectBody::Bytes(bytes) => Body::from(bytes),
109 PutObjectBody::FilePath(path) => {
110 let file = tokio::fs::File::open(path).await?;
111 let stream = ReaderStream::new(file);
112 Body::wrap_stream(stream)
113 }
114 };
115
116 let resp = client
117 .http_client
118 .put(request_url)
119 .headers(header_map)
120 .body(data)
121 .send()
122 .await?;
123 if resp.status() != StatusCode::OK {
127 return Err(into_request_failed_error(resp).await);
128 }
129
130 let header = resp.headers();
131 let content_md5 = header
132 .get("Content-MD5")
133 .unwrap()
134 .to_str()
135 .unwrap()
136 .to_owned();
137 let x_oss_hash_crc64ecma = header
138 .get("x-oss-hash-crc64ecma")
139 .unwrap()
140 .to_str()
141 .unwrap()
142 .to_owned();
143 let x_oss_version_id = header
144 .get("x-oss-version-id")
145 .map(|v| v.to_str().unwrap().to_owned());
146
147 Ok(PutObjectResponseHeader {
148 content_md5,
149 x_oss_hash_crc64ecma,
150 x_oss_version_id,
151 })
152 }
153
154 pub async fn generate_presigned_url(
173 &self,
174 object_name: &str,
175 expires: i32,
176 ) -> Result<String, Error> {
177 validate_object_name(object_name)?;
178
179 let client = self.client;
180 let mut base_url = url::Url::parse(&format!(
181 "https://{}.{}/{}",
182 client.bucket, client.endpoint, object_name
183 ))
184 .unwrap();
185
186 if let Some(oss_callback) = &self.callback {
188 let callback_base64 =
189 general_purpose::STANDARD.encode(serde_json::to_string(oss_callback).unwrap());
190 base_url
191 .query_pairs_mut()
192 .append_pair("callback", &callback_base64);
193 if !oss_callback.callback_body.callback_var.is_empty() {
194 let callback_var_map = oss_callback
195 .callback_body
196 .callback_var
197 .iter()
198 .map(|(_, k, v)| (k, v))
199 .collect::<HashMap<_, _>>();
200 let callback_var_base64 = general_purpose::STANDARD
201 .encode(serde_json::to_string(&callback_var_map).unwrap());
202 base_url
203 .query_pairs_mut()
204 .append_pair("callback-var", &callback_var_base64);
205 }
206 }
207
208 let creds = client.credentials_provider.load().await?;
209 if let Some(token) = &creds.sts_security_token {
211 base_url
212 .query_pairs_mut()
213 .append_pair("x-oss-security-token", token);
214 }
215
216 let mut header_map: HashMap<String, String> =
217 serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap();
218 if !self.custom_metas.is_empty() {
219 let custom_meta_map = self
220 .custom_metas
221 .iter()
222 .map(|(k, v)| (k.clone(), v.clone()))
223 .collect::<HashMap<_, _>>();
224 header_map.extend(custom_meta_map);
225 };
226
227 let presigned_params = PresignParams {
228 access_key_id: &creds.access_key_id,
229 access_key_secret: &creds.access_key_secret,
230 header_map,
231 presigned_url: base_url,
232 http_verb: HTTPVerb::Put,
233 url_expires: expires,
234 bucket: &client.bucket,
235 signing_region: &client.region,
236 };
237 let signed_url = generate_presigned_url(presigned_params);
238 Ok(signed_url)
239 }
240}
241
242impl PostObject<'_> {
243 pub async fn generate_policy(
254 self,
255 expiration: OffsetDateTime,
256 ) -> Result<GeneratePolicyResult, Error> {
257 let policy_expiration = expiration.to_utc().format(&Iso8601::DEFAULT).unwrap();
258 let now = OffsetDateTime::now_utc();
259 let date = utc_date_str(&now);
261 let date_time = utc_date_time_str(&now);
262 let client = self.client;
263 let creds = client.credentials_provider.load().await?;
264 let credential = format!(
265 "{}/{}/{}/oss/aliyun_v4_request",
266 creds.access_key_id, date, client.region
267 );
268
269 let mut callback_b64 = None;
271 let mut callback_var = None;
272 if let Some(oss_callback) = &self.callback {
273 callback_b64 = Some(
274 general_purpose::STANDARD.encode(serde_json::to_string(oss_callback).unwrap()),
275 );
276 if !oss_callback.callback_body.callback_var.is_empty() {
277 let callback_var_map = oss_callback
278 .callback_body
279 .callback_var
280 .iter()
281 .map(|(_, k, v)| (k.clone(), v.clone()))
282 .collect::<HashMap<_, _>>();
283 callback_var = Some(callback_var_map);
284 }
285 }
286
287 let policy = PostPolicy {
288 expiration: policy_expiration,
289 conditions: PostPolicyCondition {
290 bucket: self.bucket,
291 x_oss_signature_version: "OSS4-HMAC-SHA256".to_owned(),
292 x_oss_credential: credential.clone(),
293 x_oss_security_token: creds.sts_security_token.clone(),
294 x_oss_date: date_time.clone(),
295 content_length_range: self.content_length_range,
296 key: self.key,
297 success_action_status: self.success_action_status,
298 content_type: self.content_type,
299 cache_control: self.cache_control,
300 expires: self.expires,
301 content_disposition: self.content_disposition,
302 content_encoding: self.content_encoding,
303 x_oss_object_acl: self.x_oss_object_acl,
304 x_oss_server_side_encryption_key_id: self.x_oss_server_side_encryption_key_id,
305 x_oss_server_side_data_encryption: self.x_oss_server_side_data_encryption,
306 x_oss_content_type: self.x_oss_content_type,
307 x_oss_forbid_overwrite: self.x_oss_forbid_overwrite,
308 x_oss_storage_class: self.x_oss_storage_class,
309 success_action_redirect: self.success_action_redirect,
310 custom_metas: self.custom_metas,
311 callback_b64: callback_b64.as_deref(),
312 callback_var: callback_var.as_ref(),
313 },
314 };
315 let policy_str = serde_json::to_string(&policy).unwrap();
316 let encoded_policy = general_purpose::STANDARD.encode(policy_str.as_bytes());
317 let date_key = hmac_sha256_bytes(
318 format!("aliyun_v4{}", creds.access_key_secret).as_bytes(),
319 &date,
320 );
321 let date_region_key = hmac_sha256_bytes(&date_key, &client.region);
322 let date_region_service_key = hmac_sha256_bytes(&date_region_key, "oss");
323 let signing_key = hmac_sha256_bytes(&date_region_service_key, "aliyun_v4_request");
324 let signature = hex::encode(hmac_sha256_bytes(&signing_key, &encoded_policy));
325
326 Ok(GeneratePolicyResult {
327 policy: encoded_policy,
328 x_oss_signature: signature,
329 x_oss_date: date_time,
330 x_oss_credential: credential,
331 x_oss_signature_version: "OSS4-HMAC-SHA256".to_owned(),
332 x_oss_security_token: creds.sts_security_token.clone(),
333 callback: callback_b64,
334 callback_var,
335 })
336 }
337}
338
339impl GetObject<'_> {
340 pub async fn receive_bytes(
344 &self,
345 object_name: &str,
346 ) -> Result<(Bytes, GetObjectResponseHeader, HeaderMap), Error> {
347 let (resp, response_header, header) = self.get_response(object_name).await?;
348 let data = resp.bytes().await?;
349
350 Ok((data, response_header, header))
351 }
352
353 pub async fn receive_bytes_stream(
354 &self,
355 object_name: &str,
356 ) -> Result<
357 (
358 impl Stream<Item = Result<Bytes, Error>> + use<>,
359 GetObjectResponseHeader,
360 HeaderMap,
361 ),
362 Error,
363 > {
364 let (resp, response_header, header) = self.get_response(object_name).await?;
365 let byte_stream = resp.bytes_stream().map(|item| item.map_err(Error::Reqwest));
366 Ok((byte_stream, response_header, header))
367 }
368
369 pub async fn download_to_file(
370 &self,
371 object_name: &str,
372 file_path: &Path,
373 ) -> Result<(GetObjectResponseHeader, HeaderMap), Error> {
374 let (mut resp, response_header, header) = self.get_response(object_name).await?;
375
376 let mut file = tokio::fs::File::create(file_path).await?;
377 while let Some(chunk) = resp.chunk().await? {
378 file.write_all(&chunk).await?;
379 }
380 file.flush().await?;
381
382 Ok((response_header, header))
383 }
384
385 pub async fn generate_presigned_url(
395 &self,
396 object_name: &str,
397 expires: i32,
398 ) -> Result<String, Error> {
399 validate_object_name(object_name)?;
400
401 let client = self.client;
402 let mut base_url = url::Url::parse(&format!(
403 "https://{}.{}/{}",
404 client.bucket, client.endpoint, object_name
405 ))
406 .unwrap();
407 let query_map: HashMap<String, String> =
409 serde_json::from_value(serde_json::to_value(self.queries_part()).unwrap()).unwrap();
410 for (k, v) in query_map.iter() {
411 base_url.query_pairs_mut().append_pair(k, v);
412 }
413 let creds = client.credentials_provider.load().await?;
414 if let Some(token) = &creds.sts_security_token {
415 base_url
416 .query_pairs_mut()
417 .append_pair("x-oss-security-token", token);
418 }
419
420 let header_map: HashMap<String, String> =
421 serde_json::from_value(serde_json::to_value(self.headers_part()).unwrap()).unwrap();
422 let presigned_params = PresignParams {
423 access_key_id: &creds.access_key_id,
424 access_key_secret: &creds.access_key_secret,
425 header_map,
426 presigned_url: base_url,
427 http_verb: HTTPVerb::Get,
428 url_expires: expires,
429 bucket: &client.bucket,
430 signing_region: &client.region,
431 };
432 let signed_url = generate_presigned_url(presigned_params);
433 Ok(signed_url)
434 }
435
436 async fn get_response(
437 &self,
438 object_name: &str,
439 ) -> Result<(reqwest::Response, GetObjectResponseHeader, HeaderMap), Error> {
440 validate_object_name(object_name)?;
441
442 let client = self.client;
443 let mut request_url = url::Url::parse(&format!(
444 "https://{}.{}/{}",
445 client.bucket, client.endpoint, object_name
446 ))
447 .unwrap();
448 let query_map: HashMap<String, String> =
449 serde_json::from_value(serde_json::to_value(self.queries_part()).unwrap()).unwrap();
450 for (k, v) in query_map.iter() {
451 request_url.query_pairs_mut().append_pair(k, v);
452 }
453
454 let mut req_header_map: HashMap<String, String> =
455 serde_json::from_value(serde_json::to_value(self.headers_part()).unwrap()).unwrap();
456 let creds = client.credentials_provider.load().await?;
457 if let Some(token) = &creds.sts_security_token {
458 req_header_map.insert("x-oss-security-token".to_owned(), token.clone());
459 }
460 let header_map = get_request_header(
461 &creds.access_key_id,
462 &creds.access_key_secret,
463 req_header_map,
464 &request_url,
465 HTTPVerb::Get,
466 &client.region,
467 Some(&client.bucket),
468 );
469
470 let resp = client
471 .http_client
472 .get(request_url)
473 .headers(header_map)
474 .send()
475 .await?;
476
477 let status = resp.status();
478 if !status.is_success() {
479 return Err(into_request_failed_error(resp).await);
480 }
481
482 let header = resp.headers().clone();
483 let (mut response_header, custom_meta_map) =
484 parse_get_object_response_header::<GetObjectResponseHeader>(&header);
485 if !custom_meta_map.is_empty() {
486 response_header.custom_x_oss_meta = custom_meta_map;
487 }
488
489 Ok((resp, response_header, header))
490 }
491}
492
493impl CopyObject<'_> {
494 pub async fn send(
497 &self,
498 dest_bucket: &str,
499 dest_object_name: &str,
500 ) -> Result<CopyObjectResult, Error> {
501 validate_object_name(dest_object_name)?;
502
503 let client = self.client;
504 let request_url = url::Url::parse(&format!(
505 "https://{}.{}/{}",
506 dest_bucket, client.endpoint, dest_object_name
507 ))
508 .unwrap();
509
510 let mut req_header_map: HashMap<String, String> =
511 serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap();
512 let creds = client.credentials_provider.load().await?;
513 if let Some(token) = &creds.sts_security_token {
514 req_header_map.insert("x-oss-security-token".to_owned(), token.clone());
515 }
516 let header_map = get_request_header(
517 &creds.access_key_id,
518 &creds.access_key_secret,
519 req_header_map,
520 &request_url,
521 HTTPVerb::Put,
522 &client.region,
523 Some(&client.bucket),
524 );
525
526 let resp = client
527 .http_client
528 .put(request_url)
529 .headers(header_map)
530 .send()
531 .await?;
532
533 let data = parse_xml_response(resp).await?;
534 Ok(data)
535 }
536}
537
538impl AppendObject<'_> {
539 pub async fn send(
542 &self,
543 object_name: &str,
544 position: u64,
545 data: Vec<u8>,
546 ) -> Result<(u64, String), Error> {
547 validate_object_name(object_name)?;
548
549 let client = self.client;
550 let request_url = url::Url::parse_with_params(
551 &format!(
552 "https://{}.{}/{}",
553 client.bucket, client.endpoint, object_name
554 ),
555 [("append", ""), ("position", &position.to_string())],
556 )
557 .unwrap();
558
559 let mut req_header_map: HashMap<String, String> =
560 serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap();
561
562 if !self.custom_metas.is_empty() {
563 let custom_meta_map = self
564 .custom_metas
565 .iter()
566 .map(|(k, v)| (k.clone(), v.clone()))
567 .collect::<HashMap<_, _>>();
568 req_header_map.extend(custom_meta_map);
569 }
570
571 req_header_map.insert("content-md5".to_owned(), get_content_md5(&data));
572 req_header_map.insert("content-length".to_owned(), data.len().to_string());
573
574 let creds = client.credentials_provider.load().await?;
575 if let Some(token) = &creds.sts_security_token {
576 req_header_map.insert("x-oss-security-token".to_owned(), token.clone());
577 }
578
579 let header_map = get_request_header(
580 &creds.access_key_id,
581 &creds.access_key_secret,
582 req_header_map,
583 &request_url,
584 HTTPVerb::Post,
585 &client.region,
586 Some(&client.bucket),
587 );
588
589 let resp = client
590 .http_client
591 .post(request_url)
592 .headers(header_map)
593 .body(data)
594 .send()
595 .await?;
596
597 if !resp.status().is_success() {
598 return Err(into_request_failed_error(resp).await);
599 }
600
601 let next_position = resp
602 .headers()
603 .get("x-oss-next-append-position")
604 .unwrap()
605 .to_str()
606 .unwrap()
607 .parse::<u64>()
608 .unwrap();
609 let response_hash = resp
610 .headers()
611 .get("x-oss-hash-crc64ecma")
612 .unwrap()
613 .to_str()
614 .unwrap()
615 .to_owned();
616
617 Ok((next_position, response_hash))
618 }
619}
620
621impl DeleteMultipleObjects<'_> {
622 pub async fn send(&self) -> Result<Option<DeleteResult>, Error> {
625 let client = self.client;
626
627 let request_url = url::Url::parse(&format!(
628 "https://{}.{}/?delete",
629 client.bucket, client.endpoint
630 ))
631 .unwrap();
632 let delete_req = DeleteMultipleObjectsRequest {
633 quiet: self.quiet,
634 object: &self.objects,
635 };
636 let req_body = quick_xml::se::to_string_with_root("Delete", &delete_req).unwrap();
637 let mut req_header_map = HashMap::new();
638 if let Some(encoding_type) = self.encoding_type {
639 req_header_map.insert("encoding-type".to_owned(), encoding_type.to_owned());
640 }
641 req_header_map.insert("content-length".to_owned(), req_body.len().to_string());
642 req_header_map.insert(
643 "content-md5".to_owned(),
644 get_content_md5(req_body.as_bytes()),
645 );
646
647 let creds = client.credentials_provider.load().await?;
648 if let Some(token) = &creds.sts_security_token {
649 req_header_map.insert("x-oss-security-token".to_owned(), token.clone());
650 }
651
652 let header_map = get_request_header(
653 &creds.access_key_id,
654 &creds.access_key_secret,
655 req_header_map,
656 &request_url,
657 HTTPVerb::Post,
658 &client.region,
659 Some(&client.bucket),
660 );
661
662 let resp = client
663 .http_client
664 .post(request_url)
665 .headers(header_map)
666 .body(req_body)
667 .send()
668 .await?;
669
670 let data = parse_xml_response(resp).await?;
672 Ok(data)
673 }
674}
675
676impl HeadObject<'_> {
677 pub async fn send(
678 &self,
679 object_name: &str,
680 ) -> Result<(HeadObjectResponseHeader, HeaderMap), Error> {
681 validate_object_name(object_name)?;
682
683 let client = self.client;
684 let request_url = url::Url::parse(&format!(
685 "https://{}.{}/{}",
686 client.bucket, client.endpoint, object_name
687 ))
688 .unwrap();
689
690 let mut req_header_map: HashMap<String, String> =
691 serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap();
692 let creds = client.credentials_provider.load().await?;
693 if let Some(token) = &creds.sts_security_token {
694 req_header_map.insert("x-oss-security-token".to_owned(), token.clone());
695 }
696
697 let header_map = get_request_header(
698 &creds.access_key_id,
699 &creds.access_key_secret,
700 req_header_map,
701 &request_url,
702 HTTPVerb::Head,
703 &client.region,
704 Some(&client.bucket),
705 );
706
707 let resp = client
708 .http_client
709 .head(request_url)
710 .headers(header_map)
711 .send()
712 .await?;
713
714 let status = resp.status();
715 if !status.is_success() {
716 return Err(into_request_failed_error(resp).await);
717 }
718
719 let header = resp.headers().clone();
720 let (mut response_header, custom_meta_map) =
721 parse_get_object_response_header::<HeadObjectResponseHeader>(&header);
722 if !custom_meta_map.is_empty() {
723 response_header.custom_x_oss_meta = custom_meta_map;
724 }
725 Ok((response_header, header))
726 }
727}
728
729impl Client {
731 pub fn put_object(&self) -> PutObjectBuilder<'_> {
732 PutObject::builder(self)
733 }
734
735 pub fn post_object(&self) -> PostObjectBuilder<'_> {
736 PostObject::builder(self)
737 }
738
739 pub fn get_object(&self) -> GetObjectBuilder<'_> {
740 GetObject::builder(self)
741 }
742
743 pub fn copy_object(&self) -> CopyObjectBuilder<'_> {
744 CopyObject::builder(self)
745 }
746
747 pub fn append_object(&self) -> AppendObjectBuilder<'_> {
748 AppendObject::builder(self)
749 }
750
751 pub async fn delete_object(
753 &self,
754 object_name: &str,
755 ) -> Result<DeleteObjectResponseHeader, Error> {
756 validate_object_name(object_name)?;
757
758 let request_url = url::Url::parse(&format!(
759 "https://{}.{}/{}",
760 self.bucket, self.endpoint, object_name
761 ))
762 .unwrap();
763
764 let creds = self.credentials_provider.load().await?;
765 let mut req_header_map = HashMap::new();
766 if let Some(token) = &creds.sts_security_token {
767 req_header_map.insert("x-oss-security-token".to_owned(), token.clone());
768 }
769
770 let header_map = get_request_header(
771 &creds.access_key_id,
772 &creds.access_key_secret,
773 req_header_map,
774 &request_url,
775 HTTPVerb::Delete,
776 &self.region,
777 Some(&self.bucket),
778 );
779
780 let resp = self
781 .http_client
782 .delete(request_url)
783 .headers(header_map)
784 .send()
785 .await?;
786
787 if !resp.status().is_success() {
788 return Err(into_request_failed_error(resp).await);
789 }
790
791 let x_oss_delete_marker = resp
792 .headers()
793 .get("x-oss-delete-marker")
794 .map(|v| v.to_str().unwrap().parse::<bool>().unwrap());
795 let x_oss_version_id = resp
796 .headers()
797 .get("x-oss-version-id")
798 .map(|v| v.to_str().unwrap().to_owned());
799
800 Ok(DeleteObjectResponseHeader {
801 x_oss_delete_marker,
802 x_oss_version_id,
803 })
804 }
805
806 pub fn delete_multiple_objects(&self) -> DeleteMultipleObjectsBuilder<'_> {
807 DeleteMultipleObjects::builder(self)
808 }
809
810 pub fn head_object(&self) -> HeadObjectBuilder<'_> {
811 HeadObject::builder(self)
812 }
813
814 pub async fn get_object_meta(
817 &self,
818 object_name: &str,
819 ) -> Result<GetObjectMetaResponseHeader, Error> {
820 validate_object_name(object_name)?;
821
822 let request_url = url::Url::parse(&format!(
823 "https://{}.{}/{}?objectMeta",
824 self.bucket, self.endpoint, object_name
825 ))
826 .unwrap();
827
828 let creds = self.credentials_provider.load().await?;
829 let mut req_header_map = HashMap::new();
830 if let Some(token) = &creds.sts_security_token {
831 req_header_map.insert("x-oss-security-token".to_owned(), token.clone());
832 }
833 let header_map = get_request_header(
834 &creds.access_key_id,
835 &creds.access_key_secret,
836 req_header_map,
837 &request_url,
838 HTTPVerb::Head,
839 &self.region,
840 Some(&self.bucket),
841 );
842
843 let resp = self
844 .http_client
845 .head(request_url)
846 .headers(header_map)
847 .send()
848 .await?;
849
850 let status = resp.status();
851 if !status.is_success() {
852 return Err(into_request_failed_error(resp).await);
853 }
854
855 let mut response_header = Map::new();
856 for (name, val) in resp.headers().iter() {
857 let name_s = name.as_str();
858 if let Ok(s) = val.to_str() {
859 response_header.insert(name_s.to_string(), Value::String(s.to_string()));
860 }
861 }
862
863 let data = serde_json::from_value(Value::Object(response_header)).unwrap();
864 Ok(data)
865 }
866}