@@ -36,10 +36,10 @@ use bytes::Bytes;
36
36
use futures:: stream:: BoxStream ;
37
37
use futures:: { StreamExt , TryStreamExt } ;
38
38
use itertools:: Itertools ;
39
+ use reqwest:: Method ;
39
40
use serde:: { Deserialize , Serialize } ;
40
41
use snafu:: { ensure, OptionExt , ResultExt , Snafu } ;
41
- use std:: str:: FromStr ;
42
- use std:: sync:: Arc ;
42
+ use std:: { str:: FromStr , sync:: Arc , time:: Duration } ;
43
43
use tokio:: io:: AsyncWrite ;
44
44
use tracing:: info;
45
45
use url:: Url ;
@@ -210,6 +210,57 @@ impl AmazonS3 {
210
210
& self . client . config ( ) . credentials
211
211
}
212
212
213
+ /// Create a URL containing the relevant [AWS SigV4] query parameters that authorize a request
214
+ /// via `method` to the resource at `path` valid for the duration specified in `expires_in`.
215
+ ///
216
+ /// [AWS SigV4]: https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html
217
+ ///
218
+ /// # Example
219
+ ///
220
+ /// This example returns a URL that will enable a user to upload a file to
221
+ /// "some-folder/some-file.txt" in the next hour.
222
+ ///
223
+ /// ```
224
+ /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
225
+ /// use object_store::{aws::AmazonS3Builder, path::Path};
226
+ /// use reqwest::Method;
227
+ /// use std::time::Duration;
228
+ ///
229
+ /// let region = "us-east-1";
230
+ /// let s3 = AmazonS3Builder::new()
231
+ /// .with_region(region)
232
+ /// .with_bucket_name("my-bucket")
233
+ /// .with_access_key_id("my-access-key-id")
234
+ /// .with_secret_access_key("my-secret-access-key")
235
+ /// .build()?;
236
+ ///
237
+ /// let url = s3.signed_url(
238
+ /// Method::PUT,
239
+ /// &Path::from("some-folder/some-file.txt"),
240
+ /// Duration::from_secs(60 * 60)
241
+ /// ).await?;
242
+ /// # Ok(())
243
+ /// # }
244
+ /// ```
245
+ pub async fn signed_url (
246
+ & self ,
247
+ method : Method ,
248
+ path : & Path ,
249
+ expires_in : Duration ,
250
+ ) -> Result < Url > {
251
+ let credential = self . credentials ( ) . get_credential ( ) . await ?;
252
+ let authorizer =
253
+ AwsAuthorizer :: new ( & credential, "s3" , & self . client . config ( ) . region ) ;
254
+
255
+ let path_url = self . path_url ( path) ;
256
+ let mut url =
257
+ Url :: parse ( & path_url) . context ( UnableToParseUrlSnafu { url : path_url } ) ?;
258
+
259
+ authorizer. sign ( method, & mut url, expires_in) ;
260
+
261
+ Ok ( url)
262
+ }
263
+
213
264
/// Create a full URL to the resource specified by `path` with this instance's configuration.
214
265
pub fn path_url ( & self , path : & Path ) -> String {
215
266
self . client . config ( ) . path_url ( path)
0 commit comments