1use serde::Deserialize;
2use std::str::FromStr;
3
4#[derive(Clone, Debug)]
5pub(crate) struct Multipart<'a> {
6 part_number: u32,
7 upload_id: &'a str,
8}
9
10impl<'a> Multipart<'a> {
11 pub fn query_string(&self) -> String {
12 format!(
13 "?partNumber={}&uploadId={}",
14 self.part_number, self.upload_id
15 )
16 }
17
18 pub fn new(part_number: u32, upload_id: &'a str) -> Self {
19 Multipart {
20 part_number,
21 upload_id,
22 }
23 }
24}
25
26#[derive(Deserialize, Debug, Clone)]
27pub struct Owner {
28 #[serde(rename = "DisplayName")]
29 pub display_name: Option<String>,
31 #[serde(rename = "ID")]
32 pub id: String,
34}
35
36#[derive(Deserialize, Debug, Clone)]
37pub struct Object {
38 #[serde(rename = "LastModified")]
39 pub last_modified: String,
41 #[serde(rename = "ETag")]
42 pub e_tag: Option<String>,
45 #[serde(rename = "StorageClass")]
46 pub storage_class: Option<String>,
48 #[serde(rename = "Key")]
49 pub key: String,
51 #[serde(rename = "Owner")]
52 pub owner: Option<Owner>,
54 #[serde(rename = "Size")]
55 pub size: u64,
57}
58
59#[derive(Deserialize, Debug, Clone)]
60pub struct CommonPrefix {
61 #[serde(rename = "Prefix")]
62 pub prefix: String,
64}
65
66#[derive(Deserialize, Debug, Default, Clone)]
68pub struct HeadObjectResult {
69 #[serde(rename = "AcceptRanges")]
70 pub accept_ranges: Option<String>,
72 #[serde(rename = "CacheControl")]
73 pub cache_control: Option<String>,
75 #[serde(rename = "ContentDisposition")]
76 pub content_disposition: Option<String>,
78 #[serde(rename = "ContentEncoding")]
79 pub content_encoding: Option<String>,
81 #[serde(rename = "ContentLanguage")]
82 pub content_language: Option<String>,
84 #[serde(rename = "ContentLength")]
85 pub content_length: Option<u64>,
87 #[serde(rename = "ContentType")]
88 pub content_type: Option<String>,
90 #[serde(rename = "DeleteMarker")]
91 pub delete_marker: Option<bool>,
93 #[serde(rename = "ETag")]
94 pub e_tag: Option<String>,
96 #[serde(rename = "Expiration")]
97 pub expiration: Option<String>,
100 #[serde(rename = "Expires")]
101 pub expires: Option<String>,
103 #[serde(rename = "LastModified")]
104 pub last_modified: Option<String>,
106 #[serde(rename = "Metadata", default)]
107 pub metadata: Option<::std::collections::HashMap<String, String>>,
109 #[serde(rename = "MissingMeta")]
110 pub missing_meta: Option<i64>,
113 #[serde(rename = "ObjectLockLegalHoldStatus")]
114 pub object_lock_legal_hold_status: Option<String>,
117 #[serde(rename = "ObjectLockMode")]
118 pub object_lock_mode: Option<String>,
120 #[serde(rename = "ObjectLockRetainUntilDate")]
121 pub object_lock_retain_until_date: Option<String>,
124 #[serde(rename = "PartsCount")]
125 pub parts_count: Option<i64>,
127 #[serde(rename = "ReplicationStatus")]
128 pub replication_status: Option<String>,
130 #[serde(rename = "RequestCharged")]
131 pub request_charged: Option<String>,
132 #[serde(rename = "Restore")]
133 pub restore: Option<String>,
136 #[serde(rename = "SseCustomerAlgorithm")]
137 pub sse_customer_algorithm: Option<String>,
139 #[serde(rename = "SseCustomerKeyMd5")]
140 pub sse_customer_key_md5: Option<String>,
142 #[serde(rename = "SsekmsKeyId")]
143 pub ssekms_key_id: Option<String>,
145 #[serde(rename = "ServerSideEncryption")]
146 pub server_side_encryption: Option<String>,
149 #[serde(rename = "StorageClass")]
150 pub storage_class: Option<String>,
152 #[serde(rename = "VersionId")]
153 pub version_id: Option<String>,
155 #[serde(rename = "WebsiteRedirectLocation")]
156 pub website_redirect_location: Option<String>,
158}
159
160trait GetAndConvertHeaders {
161 fn get_and_convert<T: FromStr>(&self, header: &str) -> Option<T>;
162 fn get_string(&self, header: &str) -> Option<String>;
163}
164
165impl GetAndConvertHeaders for http::header::HeaderMap {
166 fn get_and_convert<T: FromStr>(&self, header: &str) -> Option<T> {
167 self.get(header)?.to_str().ok()?.parse::<T>().ok()
168 }
169 fn get_string(&self, header: &str) -> Option<String> {
170 Some(self.get(header)?.to_str().ok()?.to_owned())
171 }
172}
173
174impl From<&http::HeaderMap> for HeadObjectResult {
175 fn from(headers: &http::HeaderMap) -> Self {
176 let mut result = HeadObjectResult {
177 accept_ranges: headers.get_string("accept-ranges"),
178 cache_control: headers.get_string("Cache-Control"),
179 content_disposition: headers.get_string("Content-Disposition"),
180 content_encoding: headers.get_string("Content-Encoding"),
181 content_language: headers.get_string("Content-Language"),
182 content_length: headers.get_and_convert("Content-Length"),
183 content_type: headers.get_string("Content-Type"),
184 delete_marker: headers.get_and_convert("x-amz-delete-marker"),
185 e_tag: headers.get_string("ETag"),
186 expiration: headers.get_string("x-amz-expiration"),
187 expires: headers.get_string("Expires"),
188 last_modified: headers.get_string("Last-Modified"),
189 ..Default::default()
190 };
191 let mut values = ::std::collections::HashMap::new();
192 for (key, value) in headers.iter() {
193 if key.as_str().starts_with("x-amz-meta-") {
194 if let Ok(value) = value.to_str() {
195 values.insert(
196 key.as_str()["x-amz-meta-".len()..].to_owned(),
197 value.to_owned(),
198 );
199 }
200 }
201 }
202 result.metadata = Some(values);
203 result.missing_meta = headers.get_and_convert("x-amz-missing-meta");
204 result.object_lock_legal_hold_status = headers.get_string("x-amz-object-lock-legal-hold");
205 result.object_lock_mode = headers.get_string("x-amz-object-lock-mode");
206 result.object_lock_retain_until_date =
207 headers.get_string("x-amz-object-lock-retain-until-date");
208 result.parts_count = headers.get_and_convert("x-amz-mp-parts-count");
209 result.replication_status = headers.get_string("x-amz-replication-status");
210 result.request_charged = headers.get_string("x-amz-request-charged");
211 result.restore = headers.get_string("x-amz-restore");
212 result.sse_customer_algorithm =
213 headers.get_string("x-amz-server-side-encryption-customer-algorithm");
214 result.sse_customer_key_md5 =
215 headers.get_string("x-amz-server-side-encryption-customer-key-MD5");
216 result.ssekms_key_id = headers.get_string("x-amz-server-side-encryption-aws-kms-key-id");
217 result.server_side_encryption = headers.get_string("x-amz-server-side-encryption");
218 result.storage_class = headers.get_string("x-amz-storage-class");
219 result.version_id = headers.get_string("x-amz-version-id");
220 result.website_redirect_location = headers.get_string("x-amz-website-redirect-location");
221 result
222 }
223}
224
225#[derive(Deserialize, Debug, Clone)]
226pub struct ListBucketResult {
227 #[serde(rename = "Name")]
228 pub name: String,
230 #[serde(rename = "Delimiter")]
231 pub delimiter: Option<String>,
233 #[serde(rename = "MaxKeys")]
234 pub max_keys: Option<i32>,
236 #[serde(rename = "Prefix")]
237 pub prefix: Option<String>,
239 #[serde(rename = "ContinuationToken")] #[serde(alias = "Marker")] pub continuation_token: Option<String>,
244 #[serde(rename = "EncodingType")]
245 pub encoding_type: Option<String>,
247 #[serde(default, rename = "IsTruncated")]
248 pub is_truncated: bool,
257 #[serde(rename = "NextContinuationToken", default)] #[serde(alias = "NextMarker")] pub next_continuation_token: Option<String>,
260 #[serde(rename = "Contents", default)]
261 pub contents: Vec<Object>,
263 #[serde(rename = "CommonPrefixes", default)]
264 pub common_prefixes: Option<Vec<CommonPrefix>>,
267}
268
269#[derive(Deserialize, Debug)]
270pub(crate) struct InitiateMultipartUploadResponse {
271 #[serde(rename = "Bucket")]
272 _bucket: String,
273 #[serde(rename = "Key")]
274 pub key: String,
275 #[serde(rename = "UploadId")]
276 pub upload_id: String,
277}
278
279#[derive(Debug)]
280pub struct PutStreamResponse {
281 pub status_code: u16,
282 pub uploaded_bytes: usize,
283}