aliyun_oss_rs/object/
head_object.rs

1use crate::common::format_gmt;
2use crate::{
3    Error,
4    request::{Oss, OssRequest},
5};
6use base64::{Engine, engine::general_purpose};
7use bytes::Bytes;
8use http::Method;
9use std::collections::HashMap;
10use time::OffsetDateTime;
11
12/// Retrieve the object's metadata
13///
14/// See the [Alibaba Cloud documentation](https://help.aliyun.com/document_detail/31984.html) for details
15pub struct HeadObject {
16    req: OssRequest,
17}
18impl HeadObject {
19    pub(super) fn new(oss: Oss) -> Self {
20        HeadObject {
21            req: OssRequest::new(oss, Method::HEAD),
22        }
23    }
24    /// If the provided time is earlier than the actual modification time, the request succeeds
25    ///
26    pub fn set_if_modified_since(mut self, if_modified_since: OffsetDateTime) -> Self {
27        self.req
28            .insert_header("If-Modified-Since", format_gmt(if_modified_since));
29        self
30    }
31    /// Require the specified time to be equal to or later than the object's last modification time
32    ///
33    pub fn set_if_unmodified_since(mut self, if_unmodified_since: OffsetDateTime) -> Self {
34        self.req
35            .insert_header("If-Unmodified-Since", format_gmt(if_unmodified_since));
36        self
37    }
38    /// Require the object's ETag to match the provided ETag
39    ///
40    /// The ETag verifies whether the data has changed and can be used to check data integrity
41    pub fn set_if_match(mut self, if_match: impl ToString) -> Self {
42        self.req.insert_header("If-Match", if_match);
43        self
44    }
45    /// Require the object's ETag to differ from the provided ETag
46    ///
47    pub fn set_if_none_match(mut self, if_none_match: impl ToString) -> Self {
48        self.req.insert_header("If-None-Match", if_none_match);
49        self
50    }
51    /// Send the request
52    ///
53    pub async fn send(self) -> Result<HashMap<String, String>, Error> {
54        // Build the HTTP request
55        let mut response = self.req.send_to_oss()?.await?;
56        // Parse the response
57        let status_code = response.status();
58        match status_code {
59            code if code.is_success() => {
60                let headers = response.headers_mut();
61                headers.remove("server");
62                headers.remove("date");
63                headers.remove("content-type");
64                headers.remove("content-length");
65                headers.remove("connection");
66                headers.remove("x-oss-request-id");
67                headers.remove("accept-ranges");
68                let result = headers
69                    .into_iter()
70                    .map(|(key, value)| {
71                        let key = key.to_string();
72                        let mut value = String::from_utf8(value.as_bytes().to_vec())
73                            .unwrap_or_else(|_| String::new());
74                        if &key == "etag" {
75                            value = value.trim_matches('"').to_owned();
76                        }
77                        (key, value)
78                    })
79                    .collect::<HashMap<String, String>>();
80                Ok(result)
81            }
82            _ => {
83                let x_oss_error = response.headers().get("x-oss-err").and_then(|header| {
84                    general_purpose::STANDARD
85                        .decode(header)
86                        .ok()
87                        .map(|v| Bytes::from(v))
88                });
89                match x_oss_error {
90                    None => Err(Error::OssInvalidError(status_code, Bytes::new())),
91                    Some(response_bytes) => {
92                        let oss_error = serde_xml_rs::from_reader(&*response_bytes);
93                        match oss_error {
94                            Ok(oss_error) => Err(Error::OssError(status_code, oss_error)),
95                            Err(_) => Err(Error::OssInvalidError(status_code, response_bytes)),
96                        }
97                    }
98                }
99            }
100        }
101    }
102}