Skip to main content

ali_oss_rs/blocking/
presign.rs

1use crate::{
2    presign::SignedOssRequest,
3    presign_common::{build_presign_get_request, PresignGetOptions},
4    request::OssRequest,
5    util::{self, get_iso8601_date_time_string},
6};
7
8use super::Client;
9
10impl Client {
11    /// Presign URL for GET request without any additional headers supported, for brower mostly
12    pub fn presign_url<S1, S2>(&self, bucket_name: S1, object_key: S2, options: PresignGetOptions) -> String
13    where
14        S1: AsRef<str>,
15        S2: AsRef<str>,
16    {
17        let mut request = build_presign_get_request(bucket_name.as_ref(), object_key.as_ref(), &options);
18
19        let date_time_string = request.query.get("x-oss-date").unwrap().clone();
20        let date_string = &date_time_string[..8];
21
22        let credential = format!("{}/{}/{}/oss/aliyun_v4_request", self.access_key_id, date_string, self.region);
23
24        request = request.add_query("x-oss-credential", &credential);
25
26        if let Some(s) = &self.sts_token {
27            request = request.add_query("x-oss-security-token", s);
28        }
29
30        let canonical_request = request.build_canonical_request();
31
32        let canonical_request_hash = util::sha256(canonical_request.as_bytes());
33
34        let string_to_sign = format!(
35            "OSS4-HMAC-SHA256\n{}\n{}/{}/oss/aliyun_v4_request\n{}",
36            date_time_string,
37            date_string,
38            self.region,
39            hex::encode(&canonical_request_hash)
40        );
41
42        let sig = self.calculate_signature(&string_to_sign, date_string);
43
44        request = request.add_query("x-oss-signature", &sig);
45
46        let uri = request.build_request_uri();
47        let query_string = request.build_canonical_query_string();
48
49        let domain_name = if request.bucket_name.is_empty() {
50            format!("{}://{}{}", self.scheme, self.endpoint, uri)
51        } else {
52            format!("{}://{}.{}{}", self.scheme, request.bucket_name, self.endpoint, uri)
53        };
54
55        if query_string.is_empty() {
56            domain_name
57        } else {
58            format!("{}?{}", domain_name, query_string)
59        }
60    }
61
62    pub fn presign_raw_request(&self, mut oss_request: OssRequest) -> SignedOssRequest {
63        let date_header = "x-oss-date".to_string();
64        {
65            oss_request.headers_mut().entry(date_header.clone()).or_insert(get_iso8601_date_time_string());
66        }
67
68        let date_time_string = oss_request.headers.get(&date_header).unwrap().to_string();
69        let date_string = &date_time_string[..8];
70
71        if let Some(s) = &self.sts_token {
72            if !oss_request.headers.contains_key("x-oss-security-token") {
73                oss_request = oss_request.add_header("x-oss-security-token", s);
74            }
75        }
76        let additional_headers = oss_request.build_additional_headers();
77        let string_to_sign = oss_request.build_string_to_sign(&self.region);
78
79        log::debug!("string to sign: \n--------\n{}\n--------", string_to_sign);
80
81        let sig = self.calculate_signature(&string_to_sign, date_string);
82
83        log::debug!("signature: {}", sig);
84
85        let auth_string = format!(
86            "OSS4-HMAC-SHA256 Credential={}/{}/{}/oss/aliyun_v4_request,{}Signature={}",
87            self.access_key_id,
88            date_string,
89            self.region,
90            if additional_headers.is_empty() {
91                "".to_string()
92            } else {
93                format!("{},", additional_headers)
94            },
95            sig
96        );
97
98        oss_request = oss_request.add_header("authorization", &auth_string);
99
100        let uri = oss_request.build_request_uri();
101        let query_string = oss_request.build_canonical_query_string();
102
103        let url = if oss_request.bucket_name.is_empty() {
104            format!("{}://{}{}", self.scheme, self.endpoint, uri)
105        } else {
106            format!("{}://{}.{}{}", self.scheme, oss_request.bucket_name, self.endpoint, uri)
107        };
108
109        let url = if query_string.is_empty() { url } else { format!("{}?{}", url, query_string) };
110
111        SignedOssRequest {
112            url,
113            headers: oss_request.headers,
114        }
115    }
116}