rusoto_s3/custom/
util.rs

1use crate::generated::{
2    DeleteObjectRequest, GetObjectRequest, PutObjectRequest, UploadPartRequest,
3};
4use rusoto_core::credential::AwsCredentials;
5use rusoto_core::param::{Params, ServiceParams};
6use rusoto_core::region::Region;
7use rusoto_core::signature;
8use rusoto_core::signature::SignedRequest;
9use std::time::Duration;
10/// URL encodes an S3 object key. This is necessary for `copy_object` and `upload_part_copy`,
11/// which require the `copy_source` field to be URL encoded.
12///
13/// # Examples
14///
15/// ```
16/// use rusoto_s3::CopyObjectRequest;
17///
18/// let request = CopyObjectRequest {
19///     bucket: "my-bucket".to_owned(),
20///     key: "my-key".to_owned(),
21///     copy_source: rusoto_s3::util::encode_key("other-buckét/key-to-cöpy"),
22///     ..Default::default()
23/// };
24/// ```
25pub fn encode_key<T: AsRef<str>>(key: T) -> String {
26    signature::encode_uri_path(key.as_ref())
27}
28
29macro_rules! add_headers {
30    (
31        $input:ident , $req:ident ; $p:ident , $e:expr ; $( $t:tt )*
32    ) => (
33        {
34            if let Some(ref $p) = $input.$p {
35                $req.add_header($e, &$p.to_string());
36            }
37            add_headers! { $input, $req; $( $t )* }
38        }
39    );
40    (
41        $input:pat , $req:expr ;
42    ) => ({
43    });
44}
45
46macro_rules! add_params {
47    (
48        $input:ident , $params:ident ; $p:ident , $e:expr ; $( $t:tt )*
49    ) => (
50        {
51            if let Some(ref $p) = $input.$p {
52                $params.put($e, &$p);
53            }
54            add_params! { $input, $params; $( $t )* }
55        }
56    );
57    (
58        $input:pat , $req:expr ;
59    ) => ({
60    });
61}
62
63pub struct PreSignedRequestOption {
64    pub expires_in: Duration,
65}
66
67impl Default for PreSignedRequestOption {
68    fn default() -> Self {
69        Self {
70            expires_in: Duration::from_secs(3600),
71        }
72    }
73}
74
75pub trait PreSignedRequest {
76    /// http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
77    fn get_presigned_url(
78        &self,
79        region: &Region,
80        credentials: &AwsCredentials,
81        option: &PreSignedRequestOption,
82    ) -> String;
83}
84
85impl PreSignedRequest for GetObjectRequest {
86    /// https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html
87    fn get_presigned_url(
88        &self,
89        region: &Region,
90        credentials: &AwsCredentials,
91        option: &PreSignedRequestOption,
92    ) -> String {
93        let request_uri = format!("/{bucket}/{key}", bucket = self.bucket, key = self.key);
94        let mut request = SignedRequest::new("GET", "s3", &region, &request_uri);
95        let mut params = Params::new();
96
97        add_headers!(
98            self, request;
99            range, "Range";
100            if_modified_since, "If-Modified-Since";
101            if_unmodified_since, "If-Unmodified-Since";
102            if_match, "If-Match";
103            if_none_match, "If-None-Match";
104            sse_customer_algorithm, "x-amz-server-side-encryption-customer-algorithm";
105            sse_customer_key, "x-amz-server-side-encryption-customer-key";
106            sse_customer_key_md5, "x-amz-server-side-encryption-customer-key-MD5";
107        );
108
109        add_params!(
110            self, params;
111            part_number, "partNumber";
112            response_content_type, "response-content-type";
113            response_content_language, "response-content-language";
114            response_expires, "response-expires";
115            response_cache_control, "response-cache-control";
116            response_content_disposition, "response-content-disposition";
117            response_content_encoding, "response-content-encoding";
118            version_id, "versionId";
119        );
120
121        request.set_params(params);
122        request.generate_presigned_url(credentials, &option.expires_in, false)
123    }
124}
125
126impl PreSignedRequest for PutObjectRequest {
127    /// https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html
128    fn get_presigned_url(
129        &self,
130        region: &Region,
131        credentials: &AwsCredentials,
132        option: &PreSignedRequestOption,
133    ) -> String {
134        let request_uri = format!("/{bucket}/{key}", bucket = self.bucket, key = self.key);
135        let mut request = SignedRequest::new("PUT", "s3", &region, &request_uri);
136
137        add_headers!(
138            self, request;
139            cache_control, "Cache-Control";
140            content_disposition, "Content-Disposition";
141            content_encoding, "Content-Encoding";
142            content_length, "Content-Length";
143            content_md5, "Content-MD5";
144            content_type, "Content-Type";
145            // AWS document has Expect parameter but PutObjectRequest does'nt have it.
146            //expect, "Expect";
147            expires, "Expires";
148            storage_class, "x-amz-storage-class";
149            tagging, "x-amz-tagging";
150            website_redirect_location, "x-amz-website-redirect-location";
151            acl, "x-amz-acl";
152            grant_read, "x-amz-grant-read";
153            // AWS document has x-amz-grant-write parameter but PutObjectRequest does'nt have it.
154            //grant_write, "x-amz-grant-write";
155            grant_read_acp, "x-amz-grant-read-acp";
156            grant_write_acp, "x-amz-grant-write-acp";
157            grant_full_control, "x-amz-grant-full-control";
158            server_side_encryption, "x-amz-server-side-encryption";
159            ssekms_key_id, "x-amz-server-side-encryption-aws-kms-key-id";
160            // AWS document has x-amz-server-side-encryption-context parameter but PutObjectRequest does'nt have it.
161            //kms_context, "x-amz-server-side-encryption-context";
162            sse_customer_algorithm, "x-amz-server-side-encryption-customer-algorithm";
163            sse_customer_key, "x-amz-server-side-encryption-customer-key";
164            sse_customer_key_md5, "x-amz-server-side-encryption-customer-key-MD5";
165        );
166
167        if let Some(ref metadata) = self.metadata {
168            for (header_name, header_value) in metadata.iter() {
169                let header = format!("x-amz-meta-{}", header_name);
170                request.add_header(header, header_value);
171            }
172        }
173
174        request.generate_presigned_url(credentials, &option.expires_in, false)
175    }
176}
177
178impl PreSignedRequest for DeleteObjectRequest {
179    /// https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectDELETE.html
180    fn get_presigned_url(
181        &self,
182        region: &Region,
183        credentials: &AwsCredentials,
184        option: &PreSignedRequestOption,
185    ) -> String {
186        let request_uri = format!("/{bucket}/{key}", bucket = self.bucket, key = self.key);
187        let mut request = SignedRequest::new("DELETE", "s3", &region, &request_uri);
188        let mut params = Params::new();
189
190        add_headers!(
191            self, request;
192            mfa, "x-amz-mfa";
193        );
194
195        add_params!(
196            self, params;
197            version_id, "versionId";
198        );
199
200        request.set_params(params);
201        request.generate_presigned_url(credentials, &option.expires_in, false)
202    }
203}
204
205impl PreSignedRequest for UploadPartRequest {
206    /// https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadUploadPart.html
207    fn get_presigned_url(
208        &self,
209        region: &Region,
210        credentials: &AwsCredentials,
211        option: &PreSignedRequestOption,
212    ) -> String {
213        let request_uri = format!("/{bucket}/{key}", bucket = self.bucket, key = self.key);
214        let mut request = SignedRequest::new("PUT", "s3", &region, &request_uri);
215
216        request.add_param("partNumber", &self.part_number.to_string());
217        request.add_param("uploadId", &self.upload_id);
218
219        add_headers!(
220            self, request;
221            content_length, "Content-Length";
222            content_md5, "Content-MD5";
223            sse_customer_algorithm, "x-amz-server-side-encryption-customer-algorithm";
224            sse_customer_key, "x-amz-server-side-encryption-customer-key";
225            sse_customer_key_md5, "x-amz-server-side-encryption-customer-key-MD5";
226            request_payer, "x-amz-request-payer";
227        );
228
229        request.generate_presigned_url(credentials, &option.expires_in, false)
230    }
231}