s3_signer/multipart_upload/
part_upload_url.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Deserialize, Serialize)]
4pub struct PartUploadQueryParameters {
5 pub bucket: String,
6 pub path: String,
7}
8
9#[derive(Debug, Deserialize, Serialize)]
10#[cfg_attr(feature = "server", derive(utoipa::ToSchema))]
11pub struct PartUploadResponse {
12 pub presigned_url: String,
13}
14
15#[cfg(feature = "server")]
16pub(crate) mod server {
17 use super::{PartUploadQueryParameters, PartUploadResponse};
18 use crate::{to_ok_json_response, S3Configuration};
19 use rusoto_credential::AwsCredentials;
20 use rusoto_s3::{
21 util::{PreSignedRequest, PreSignedRequestOption},
22 UploadPartRequest,
23 };
24 use warp::{
25 hyper::{Body, Response},
26 Filter, Rejection, Reply,
27 };
28
29 #[utoipa::path(
31 get,
32 context_path = "/multipart-upload",
33 path = "/{upload_id}/part/{part_number}",
34 tag = "Multipart upload",
35 responses(
36 (
37 status = 200,
38 description = "Returns the pre-signed URL for getting an object",
39 content_type = "application/json",
40 body = PartUploadResponse
41 ),
42 ),
43 params(
44 ("upload_id" = String, Path, description = "ID of the upload"),
45 ("part_number" = i64, Path, description = "Index number of the part to upload"),
46 ("bucket" = String, Query, description = "Name of the bucket"),
47 ("path" = String, Query, description = "Key of the object to get")
48 ),
49 )]
50 pub(crate) fn route(
51 s3_configuration: &S3Configuration,
52 ) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone {
53 let s3_configuration = s3_configuration.clone();
54 warp::path!(String / "part" / i64)
55 .and(warp::get())
56 .and(warp::query::<PartUploadQueryParameters>())
57 .and(warp::any().map(move || s3_configuration.clone()))
58 .and_then(
59 |upload_id: String,
60 part_number: i64,
61 parameters: PartUploadQueryParameters,
62 s3_configuration: S3Configuration| async move {
63 handle_part_upload_presigned_url(
64 &s3_configuration,
65 parameters.bucket,
66 parameters.path,
67 upload_id,
68 part_number,
69 )
70 .await
71 },
72 )
73 }
74
75 async fn handle_part_upload_presigned_url(
76 s3_configuration: &S3Configuration,
77 bucket: String,
78 key: String,
79 upload_id: String,
80 part_number: i64,
81 ) -> Result<Response<Body>, Rejection> {
82 log::info!(
83 "Upload part: upload_id={}, part_number={}",
84 upload_id,
85 part_number,
86 );
87 let request = UploadPartRequest {
88 bucket,
89 key,
90 upload_id,
91 part_number,
92 ..Default::default()
93 };
94
95 let credentials = AwsCredentials::from(s3_configuration);
96
97 let presigned_url = request.get_presigned_url(
98 s3_configuration.region(),
99 &credentials,
100 &PreSignedRequestOption::default(),
101 );
102
103 let response = PartUploadResponse { presigned_url };
104 to_ok_json_response(&response)
105 }
106}