1use crate::serde_types::CompleteMultipartUploadData;
2
3use crate::EMPTY_PAYLOAD_SHA;
4use sha2::{Digest, Sha256};
5
6pub enum HttpMethod {
7 Delete,
8 Get,
9 Put,
10 Post,
11 Head,
12}
13
14use std::fmt;
15
16impl fmt::Display for HttpMethod {
17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 match self {
19 HttpMethod::Delete => write!(f, "DELETE"),
20 HttpMethod::Get => write!(f, "GET"),
21 HttpMethod::Post => write!(f, "POST"),
22 HttpMethod::Put => write!(f, "PUT"),
23 HttpMethod::Head => write!(f, "HEAD"),
24 }
25 }
26}
27use crate::bucket_ops::BucketConfiguration;
28use http::HeaderMap;
29
30#[derive(Clone, Debug)]
31pub struct Multipart<'a> {
32 part_number: u32,
33 upload_id: &'a str,
34}
35
36impl<'a> Multipart<'a> {
37 pub fn query_string(&self) -> String {
38 format!(
39 "?partNumber={}&uploadId={}",
40 self.part_number, self.upload_id
41 )
42 }
43
44 pub fn new(part_number: u32, upload_id: &'a str) -> Self {
45 Multipart {
46 part_number,
47 upload_id,
48 }
49 }
50}
51
52#[derive(Clone, Debug)]
53pub enum Command<'a> {
54 HeadObject,
55 DeleteObject,
56 DeleteObjectTagging,
57 GetObject,
58 GetObjectTorrent,
59 GetObjectRange {
60 start: u64,
61 end: Option<u64>,
62 },
63 GetObjectTagging,
64 PutObject {
65 content: &'a [u8],
66 content_type: &'a str,
67 multipart: Option<Multipart<'a>>,
68 },
69 PutObjectTagging {
70 tags: &'a str,
71 },
72 ListMultipartUploads {
73 prefix: Option<&'a str>,
74 delimiter: Option<&'a str>,
75 key_marker: Option<String>,
76 max_uploads: Option<usize>,
77 },
78 ListBucket {
79 prefix: String,
80 delimiter: Option<String>,
81 continuation_token: Option<String>,
82 start_after: Option<String>,
83 max_keys: Option<usize>,
84 },
85 GetBucketLocation,
86 PresignGet {
87 expiry_secs: u32,
88 },
89 PresignPut {
90 expiry_secs: u32,
91 custom_headers: Option<HeaderMap>,
92 },
93 InitiateMultipartUpload,
94 UploadPart {
95 part_number: u32,
96 content: &'a [u8],
97 upload_id: &'a str,
98 },
99 AbortMultipartUpload {
100 upload_id: &'a str,
101 },
102 CompleteMultipartUpload {
103 upload_id: &'a str,
104 data: CompleteMultipartUploadData,
105 },
106 CreateBucket {
107 config: BucketConfiguration,
108 },
109 DeleteBucket,
110}
111
112impl<'a> Command<'a> {
113 pub fn http_verb(&self) -> HttpMethod {
114 match *self {
115 Command::GetObject
116 | Command::GetObjectTorrent
117 | Command::GetObjectRange { .. }
118 | Command::ListBucket { .. }
119 | Command::GetBucketLocation
120 | Command::GetObjectTagging
121 | Command::ListMultipartUploads { .. }
122 | Command::PresignGet { .. } => HttpMethod::Get,
123 Command::PutObject { .. }
124 | Command::PutObjectTagging { .. }
125 | Command::PresignPut { .. }
126 | Command::UploadPart { .. }
127 | Command::CreateBucket { .. } => HttpMethod::Put,
128 Command::DeleteObject
129 | Command::DeleteObjectTagging
130 | Command::AbortMultipartUpload { .. }
131 | Command::DeleteBucket => HttpMethod::Delete,
132 Command::InitiateMultipartUpload | Command::CompleteMultipartUpload { .. } => {
133 HttpMethod::Post
134 }
135 Command::HeadObject => HttpMethod::Head,
136 }
137 }
138
139 pub fn content_length(&self) -> usize {
140 match &self {
141 Command::PutObject { content, .. } => content.len(),
142 Command::PutObjectTagging { tags } => tags.len(),
143 Command::UploadPart { content, .. } => content.len(),
144 Command::CompleteMultipartUpload { data, .. } => data.len(),
145 Command::CreateBucket { config } => {
146 if let Some(payload) = config.location_constraint_payload() {
147 Vec::from(payload).len()
148 } else {
149 0
150 }
151 }
152 _ => 0,
153 }
154 }
155
156 pub fn content_type(&self) -> String {
157 match self {
158 Command::PutObject { content_type, .. } => content_type.to_string(),
159 Command::CompleteMultipartUpload { .. } => "application/xml".into(),
160 _ => "text/plain".into(),
161 }
162 }
163
164 pub fn sha256(&self) -> String {
165 match &self {
166 Command::PutObject { content, .. } => {
167 let mut sha = Sha256::default();
168 sha.update(content);
169 hex::encode(sha.finalize().as_slice())
170 }
171 Command::PutObjectTagging { tags } => {
172 let mut sha = Sha256::default();
173 sha.update(tags.as_bytes());
174 hex::encode(sha.finalize().as_slice())
175 }
176 Command::CompleteMultipartUpload { data, .. } => {
177 let mut sha = Sha256::default();
178 sha.update(data.to_string().as_bytes());
179 hex::encode(sha.finalize().as_slice())
180 }
181 Command::CreateBucket { config } => {
182 if let Some(payload) = config.location_constraint_payload() {
183 let mut sha = Sha256::default();
184 sha.update(payload.as_bytes());
185 hex::encode(sha.finalize().as_slice())
186 } else {
187 EMPTY_PAYLOAD_SHA.into()
188 }
189 }
190 _ => EMPTY_PAYLOAD_SHA.into(),
191 }
192 }
193}