Skip to main content

bws_rs/service/
s3.rs

1use std::{
2    collections::HashMap,
3    fmt::{Debug, Display},
4    io::Write,
5    str::FromStr,
6    sync::Mutex,
7};
8static OWNER_ID: &str = "ffffffffffffffff";
9pub type DateTime = chrono::DateTime<chrono::Utc>;
10pub struct Error(String);
11impl From<String> for Error {
12    fn from(value: String) -> Self {
13        Self(value)
14    }
15}
16impl From<&str> for Error {
17    fn from(value: &str) -> Self {
18        Self(value.to_string())
19    }
20}
21
22impl Display for Error {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        f.write_str(&self.0)
25    }
26}
27impl Debug for Error {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        f.debug_tuple("Error").field(&self.0).finish()
30    }
31}
32impl std::error::Error for Error {}
33pub trait VRequest: crate::authorization::v4::VHeader {
34    fn method(&self) -> String;
35    fn url_path(&self) -> String;
36    fn get_query(&self, k: &str) -> Option<String>;
37    fn all_query(&self, cb: impl FnMut(&str, &str) -> bool);
38}
39pub trait BodyWriter {
40    type BodyWriter<'a>: crate::utils::io::PollWrite + Send + Unpin
41    where
42        Self: 'a;
43    fn get_body_writer<'b>(
44        &'b mut self,
45    ) -> std::pin::Pin<
46        Box<dyn 'b + Send + std::future::Future<Output = Result<Self::BodyWriter<'_>, String>>>,
47    >;
48}
49pub trait BodyReader {
50    type BodyReader: crate::utils::io::PollRead + Send;
51    fn get_body_reader<'b>(
52        self,
53    ) -> std::pin::Pin<
54        Box<dyn 'b + Send + std::future::Future<Output = Result<Self::BodyReader, String>>>,
55    >;
56}
57pub trait HeaderTaker {
58    type Head: crate::authorization::v4::VHeader;
59    fn take_header(&self) -> Self::Head;
60}
61pub trait VRequestPlus: VRequest {
62    fn body<'a>(
63        self,
64    ) -> std::pin::Pin<
65        Box<dyn 'a + Send + std::future::Future<Output = Result<Vec<u8>, std::io::Error>>>,
66    >;
67}
68pub trait VResponse: crate::authorization::v4::VHeader + BodyWriter {
69    fn set_status(&mut self, status: u16);
70    fn send_header(&mut self);
71}
72
73#[derive(Default, Debug, Serialize)]
74pub struct HeadObjectResult {
75    #[serde(rename = "AcceptRanges")]
76    pub accept_ranges: Option<String>,
77    #[serde(rename = "ArchiveStatus")]
78    pub archive_status: Option<String>, // 可用枚举替代
79    #[serde(rename = "BucketKeyEnabled")]
80    pub bucket_key_enabled: Option<bool>,
81    #[serde(rename = "CacheControl")]
82    pub cache_control: Option<String>,
83    #[serde(rename = "ChecksumCRC32")]
84    pub checksum_crc32: Option<String>,
85    #[serde(rename = "ChecksumCRC32C")]
86    pub checksum_crc32c: Option<String>,
87    #[serde(rename = "ChecksumCRC64")]
88    pub checksum_crc64: Option<String>,
89    #[serde(rename = "ChecksumSHA1")]
90    pub checksum_sha1: Option<String>,
91    #[serde(rename = "ChecksumSHA256")]
92    pub checksum_sha256: Option<String>,
93    #[serde(rename = "ChecksumType")]
94    pub checksum_type: Option<String>,
95    #[serde(rename = "ContentDisposition")]
96    pub content_disposition: Option<String>,
97    #[serde(rename = "ContentEncoding")]
98    pub content_encoding: Option<String>,
99    #[serde(rename = "ContentLanguage")]
100    pub content_language: Option<String>,
101    #[serde(rename = "ContentLength")]
102    pub content_length: Option<usize>,
103    #[serde(rename = "ContentRange")]
104    pub content_range: Option<String>,
105    #[serde(rename = "ContentType")]
106    pub content_type: Option<String>,
107    #[serde(rename = "DeleteMarker")]
108    pub delete_marker: Option<bool>,
109    #[serde(rename = "ETag")]
110    pub etag: Option<String>,
111    #[serde(rename = "Expiration")]
112    pub expiration: Option<String>,
113    #[serde(rename = "Expires")]
114    pub expires: Option<String>, // 原是 `time.Time`,可转换为 ISO8601 字符串
115    #[serde(rename = "ExpiresString")]
116    pub expires_string: Option<String>,
117    #[serde(rename = "LastModified")]
118    pub last_modified: Option<String>, // 可考虑使用 chrono::DateTime 类型
119    #[serde(rename = "Metadata")]
120    pub metadata: Option<HashMap<String, String>>,
121    #[serde(rename = "MissingMeta")]
122    pub missing_meta: Option<i32>,
123    #[serde(rename = "ObjectLockLegalHoldStatus")]
124    pub object_lock_legal_hold_status: Option<String>,
125    #[serde(rename = "ObjectLockMode")]
126    pub object_lock_mode: Option<String>,
127    #[serde(rename = "ObjectLockRetainUntilDate")]
128    pub object_lock_retain_until_date: Option<String>,
129    #[serde(rename = "PartsCount")]
130    pub parts_count: Option<i32>,
131    #[serde(rename = "ReplicationStatus")]
132    pub replication_status: Option<String>,
133    #[serde(rename = "RequestCharged")]
134    pub request_charged: Option<String>,
135    #[serde(rename = "Restore")]
136    pub restore: Option<String>,
137    #[serde(rename = "SSECustomerAlgorithm")]
138    pub sse_customer_algorithm: Option<String>,
139    #[serde(rename = "SSECustomerKeyMD5")]
140    pub sse_customer_key_md5: Option<String>,
141    #[serde(rename = "SSEKMSKeyId")]
142    pub sse_kms_key_id: Option<String>,
143    #[serde(rename = "ServerSideEncryption")]
144    pub server_side_encryption: Option<String>,
145    #[serde(rename = "StorageClass")]
146    pub storage_class: Option<String>,
147    #[serde(rename = "VersionId")]
148    pub version_id: Option<String>,
149    #[serde(rename = "WebsiteRedirectLocation")]
150    pub website_redirect_location: Option<String>,
151}
152
153pub trait HeadHandler {
154    fn lookup<'a>(
155        &self,
156        bucket: &str,
157        object: &str,
158    ) -> std::pin::Pin<
159        Box<
160            dyn 'a
161                + Send
162                + Sync
163                + std::future::Future<Output = Result<Option<HeadObjectResult>, Error>>,
164        >,
165    >;
166}
167#[derive(Default)]
168pub struct GetObjectOption {
169    // pub range:(Option<usize>,Option<usize>),
170    // pub accept_encoding:Option<Vec<String>>,
171}
172
173pub trait GetObjectHandler: HeadHandler {
174    fn handle<'a>(
175        &'a self,
176        bucket: &str,
177        object: &str,
178        opt: GetObjectOption,
179        out: tokio::sync::Mutex<
180            std::pin::Pin<Box<dyn 'a + Send + crate::utils::io::PollWrite + Unpin>>,
181        >,
182    ) -> std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Result<(), String>>>>;
183}
184extern crate serde;
185use serde::Serialize;
186use sha1::Digest;
187use tokio::io::AsyncSeekExt;
188
189use crate::utils::io::PollWrite;
190
191#[derive(Debug, Serialize)]
192#[serde(rename_all = "PascalCase")]
193#[serde(rename = "ListBucketResult")]
194pub struct ListObjectResult {
195    pub name: String,
196    pub prefix: Option<String>,
197    pub key_count: Option<u32>,
198    pub max_keys: Option<u32>,
199    pub delimiter: Option<String>,
200    pub is_truncated: bool,
201    #[serde(default)]
202    pub contents: Vec<ListObjectContent>,
203    #[serde(default)]
204    pub common_prefixes: Vec<CommonPrefix>,
205}
206
207#[derive(Debug, Serialize)]
208#[serde(rename_all = "PascalCase")]
209pub struct ListObjectContent {
210    pub key: String,
211    pub last_modified: Option<String>,
212    pub etag: Option<String>,
213    pub size: u64,
214    pub storage_class: Option<String>,
215    pub owner: Option<Owner>,
216}
217
218#[derive(Debug, Serialize)]
219#[serde(rename = "ListAllMyBucketsResult")]
220#[serde(rename_all = "PascalCase")]
221pub struct ListAllMyBucketsResult {
222    #[serde(
223        rename = "xmlns",
224        default = "s3_namespace",
225        skip_serializing_if = "String::is_empty"
226    )]
227    pub xmlns: String,
228
229    pub owner: Owner,
230
231    pub buckets: Buckets,
232}
233#[derive(Debug, Serialize)]
234pub struct Buckets {
235    #[serde(rename = "Bucket")]
236    pub bucket: Vec<Bucket>,
237}
238
239#[derive(Debug, Serialize)]
240#[serde(rename_all = "PascalCase")]
241pub struct Bucket {
242    pub name: String,
243    pub creation_date: String,
244    pub bucket_region: String,
245}
246
247#[derive(Debug, Serialize)]
248#[serde(rename_all = "PascalCase")]
249pub struct Owner {
250    pub id: String,
251    pub display_name: String,
252}
253
254#[derive(Debug, Serialize)]
255#[serde(rename_all = "PascalCase")]
256pub struct CommonPrefix {
257    pub prefix: String,
258}
259
260#[derive(Debug, Serialize)]
261#[serde(rename_all = "PascalCase")]
262pub struct ListObjectOption {
263    pub bucket: String,
264
265    #[serde(skip_serializing_if = "Option::is_none")]
266    pub continuation_token: Option<String>,
267
268    #[serde(skip_serializing_if = "Option::is_none")]
269    pub delimiter: Option<String>,
270
271    #[serde(skip_serializing_if = "Option::is_none")]
272    pub encoding_type: Option<String>, // Usually "url"
273
274    #[serde(skip_serializing_if = "Option::is_none")]
275    pub expected_bucket_owner: Option<String>,
276
277    #[serde(skip_serializing_if = "Option::is_none")]
278    pub fetch_owner: Option<bool>,
279
280    #[serde(skip_serializing_if = "Option::is_none")]
281    pub max_keys: Option<i32>,
282
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub optional_object_attributes: Option<Vec<String>>, // e.g. ["RestoreStatus"]
285
286    #[serde(skip_serializing_if = "Option::is_none")]
287    pub prefix: Option<String>,
288
289    #[serde(skip_serializing_if = "Option::is_none")]
290    pub request_payer: Option<String>, // e.g. "requester"
291
292    #[serde(skip_serializing_if = "Option::is_none")]
293    pub start_after: Option<String>,
294}
295
296pub trait ListObjectHandler {
297    fn handle<'a>(
298        &'a self,
299        opt: &'a ListObjectOption,
300        bucket: &'a str,
301    ) -> std::pin::Pin<
302        Box<dyn 'a + Send + std::future::Future<Output = Result<Vec<ListObjectContent>, String>>>,
303    >;
304}
305pub fn handle_head_object<T: VRequest, F: VResponse, E: HeadHandler>(
306    req: &T,
307    resp: &mut F,
308    handler: &E,
309) {
310    todo!()
311}
312pub async fn handle_get_object<T: VRequest, F: VResponse>(
313    req: T,
314    resp: &mut F,
315    handler: &std::sync::Arc<dyn GetObjectHandler + Send + Sync>,
316) {
317    use tokio::io::AsyncWriteExt;
318    if req.method() != "GET" {
319        resp.set_status(405);
320        resp.send_header();
321        return;
322    }
323    let rpath = req.url_path();
324    let raw = rpath.trim_matches('/');
325    let r = raw.find('/');
326    if r.is_none() {
327        resp.set_status(400);
328        resp.send_header();
329        return;
330    }
331    let opt = GetObjectOption::default();
332    let next = r.unwrap();
333    let bucket = &raw[..next];
334    let object = &raw[next + 1..];
335
336    let head = handler.lookup(bucket, object).await;
337    if let Err(e) = head {
338        log::error!("lookup {bucket} {object} error: {e}");
339        resp.set_status(500);
340        resp.send_header();
341        return;
342    }
343    let head = head.unwrap();
344    if head.is_none() {
345        log::info!("not found {bucket} {object}");
346        resp.set_status(404);
347        resp.send_header();
348        return;
349    }
350    //send header info to client
351    let head = head.unwrap();
352    if let Some(v) = head.content_length {
353        resp.set_header("content-length", v.to_string().as_str())
354    }
355    if let Some(v) = head.etag {
356        resp.set_header("etag", &v)
357    }
358    if let Some(v) = head.content_type {
359        resp.set_header("content-type", &v)
360    }
361    if let Some(v) = head.last_modified {
362        resp.set_header("last-modified", &v)
363    }
364    //
365    resp.set_status(200);
366    resp.send_header();
367    let ret = {
368        match resp.get_body_writer().await {
369            Ok(body) => {
370                let ret = handler
371                    .handle(bucket, object, opt, tokio::sync::Mutex::new(Box::pin(body)))
372                    .await;
373                if let Err(err) = ret {
374                    Err(err)
375                } else {
376                    Ok(())
377                }
378            }
379            Err(err) => Err(err),
380        }
381    };
382    if let Err(err) = ret {
383        log::error!("body handle error {err}");
384        resp.set_status(500);
385    }
386}
387
388//query list-type=2, return ListObjectResult
389pub async fn handle_get_list_object<T: VRequest, F: VResponse>(
390    req: T,
391    resp: &mut F,
392    handler: &std::sync::Arc<dyn ListObjectHandler + Send + Sync>,
393) {
394    if req.method() != "GET" {
395        resp.set_status(405);
396        resp.send_header();
397        return;
398    }
399    let rpath = req.url_path();
400    let bucket = rpath.trim_matches('/').to_string();
401    let opt = ListObjectOption {
402        bucket: bucket.clone(),
403        continuation_token: req.get_query("continuation-token"),
404        delimiter: req.get_query("delimiter"),
405        expected_bucket_owner: req.get_query("expected-bucket-owner"),
406        max_keys: req
407            .get_query("max-keys")
408            .and_then(|v| v.parse::<i32>().ok()),
409        optional_object_attributes: None, //todo: support option_object_attributes on v2
410        request_payer: req.get_header("x-amz-request-layer"),
411        start_after: req.get_query("start-after"),
412        encoding_type: req.get_query("encoding-type"),
413        fetch_owner: req.get_query("fetch-owner").and_then(|v| {
414            if v == "true" {
415                Some(true)
416            } else if v == "false" {
417                Some(false)
418            } else {
419                None
420            }
421        }),
422        prefix: req.get_query("prefix"),
423    };
424    let ret = handler.handle(&opt, rpath.trim_matches('/')).await;
425    match ret {
426        Ok(ans) => {
427            let result = ListObjectResult {
428                name: bucket,
429                prefix: opt.prefix,
430                key_count: Some(ans.len() as u32),
431                max_keys: opt.max_keys.map(|v| v as u32),
432                delimiter: opt.delimiter,
433                is_truncated: false,
434                contents: ans,
435                common_prefixes: vec![],
436            };
437            match quick_xml::se::to_string(&result) {
438                Ok(data) => {
439                    resp.set_header("content-type", "application/xml");
440                    resp.set_header("content-length", data.len().to_string().as_str());
441                    resp.set_status(200);
442                    resp.send_header();
443                    let ret = match resp.get_body_writer().await {
444                        Ok(mut body) => {
445                            if let Err(err) = body.poll_write(data.as_bytes()).await {
446                                log::info!("write to response body error {err}");
447                            }
448                            Ok(())
449                        }
450                        Err(err) => Err(err),
451                    };
452                    if let Err(err) = ret {
453                        log::error!("write body error {err}");
454                        resp.set_status(500);
455                        resp.send_header();
456                        return;
457                    }
458                    // resp.get_body_writer().map_ok_or_else(
459                    //     |e| log::error!("get_body_writer error:{e}"),
460                    //     |mut bw| {
461                    //         let _ = bw.write_all(data.as_bytes());
462                    //     },
463                    // );
464                }
465                Err(err) => {
466                    log::error!("xml marshal failed {err}");
467                }
468            }
469        }
470        Err(err) => log::error!("get_list_object error {err}"),
471    }
472}
473
474pub trait ListBucketHandler {
475    fn handle<'a>(
476        &'a self,
477        opt: &'a ListBucketsOption,
478    ) -> std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Result<Vec<Bucket>, String>>>>;
479}
480pub trait GetBucketLocationHandler {
481    fn handle<'a>(
482        &'a self,
483        loc: Option<&'a str>,
484    ) -> std::pin::Pin<
485        Box<dyn 'a + Send + std::future::Future<Output = Result<Option<&'static str>, ()>>>,
486    > {
487        Box::pin(async { Ok(Some("us-west-1")) })
488    }
489}
490#[derive(Debug)]
491pub struct ListBucketsOption {
492    pub bucket_region: Option<String>,
493    pub continuation_token: Option<String>,
494    pub max_buckets: Option<i32>,
495    pub prefix: Option<String>,
496}
497pub async fn handle_get_list_buckets<T: VRequest, F: VResponse>(
498    req: T,
499    resp: &mut F,
500    handler: &std::sync::Arc<dyn ListBucketHandler + Send + Sync>,
501) {
502    if req.method() != "GET" {
503        resp.set_status(405);
504        resp.send_header();
505        return;
506    }
507    let opt = ListBucketsOption {
508        bucket_region: req.get_query("bucket-region"),
509        continuation_token: req.get_query("continuation-token"),
510        max_buckets: req
511            .get_query("max-buckets")
512            .and_then(|v| v.parse::<i32>().ok()),
513        prefix: req.get_query("prefix"),
514    };
515    match handler.handle(&opt).await {
516        Ok(v) => {
517            let res = ListAllMyBucketsResult {
518                xmlns: r#"xmlns="http://s3.amazonaws.com/doc/2006-03-01/""#.to_string(),
519                owner: Owner {
520                    id: OWNER_ID.to_string(),
521                    display_name: "bws".to_string(),
522                },
523                buckets: Buckets { bucket: v },
524            };
525            match quick_xml::se::to_string(&res) {
526                Ok(v) => match resp.get_body_writer().await {
527                    Ok(mut w) => {
528                        if let Err(err) = w.poll_write(v.as_bytes()).await {
529                            log::info!("write to client body error {err}");
530                        }
531                    }
532                    Err(e) => log::error!("get_body_writer error: {e}"),
533                },
534                Err(e) => {
535                    resp.set_status(500);
536                    resp.send_header();
537                    log::error!("xml serde error: {e}")
538                }
539            }
540        }
541        Err(e) => {
542            log::info!("listbucket handle error: {e}");
543            resp.set_status(500);
544            resp.send_header();
545        }
546    }
547}
548#[derive(Default)]
549pub struct PutObjectOption {
550    // pub acl: ObjectCannedACL,
551    pub cache_control: Option<String>,
552    pub checksum_algorithm: Option<ChecksumAlgorithm>,
553    pub checksum_crc32: Option<String>,
554    pub checksum_crc32c: Option<String>,
555    pub checksum_crc64nvme: Option<String>,
556    pub checksum_sha1: Option<String>,
557    pub checksum_sha256: Option<String>,
558    pub content_disposition: Option<String>,
559    pub content_encoding: Option<String>,
560    pub content_language: Option<String>,
561    pub content_length: Option<i64>,
562    pub content_md5: Option<String>,
563    pub content_type: Option<String>,
564    pub expected_bucket_owner: Option<String>,
565    pub expires: Option<DateTime>,
566    pub grant_full_control: Option<String>,
567    pub grant_read: Option<String>,
568    pub if_match: Option<String>,
569    pub if_none_match: Option<String>,
570    // pub metadata: Option<HashMap<String, String>>,
571    pub object_lock_legal_hold_status: Option<ObjectLockLegalHoldStatus>,
572    pub object_lock_mode: Option<ObjectLockMode>,
573    pub object_lock_retain_until_date: Option<DateTime>,
574    pub request_payer: Option<RequestPayer>,
575    pub storage_class: Option<String>,
576    // pub tagging: Option<String>,
577    // pub website_redirect_location: Option<String>,
578    pub write_offset_bytes: Option<i64>,
579}
580impl PutObjectOption {
581    pub fn invalid(&self) -> bool {
582        if self.content_length.is_none() {
583            return false;
584        } else if self.content_md5.is_none() {
585            return false;
586        }
587        true
588    }
589}
590
591#[derive(Debug, PartialEq)]
592pub enum ChecksumAlgorithm {
593    Crc32,
594    Crc32c,
595    Sha1,
596    Sha256,
597    Crc64nvme,
598}
599
600impl std::str::FromStr for ChecksumAlgorithm {
601    type Err = String;
602
603    fn from_str(s: &str) -> Result<Self, Self::Err> {
604        match s {
605            "CRC32" => Ok(ChecksumAlgorithm::Crc32),
606            "CRC32C" => Ok(ChecksumAlgorithm::Crc32c),
607            "SHA1" => Ok(ChecksumAlgorithm::Sha1),
608            "SHA256" => Ok(ChecksumAlgorithm::Sha256),
609            "CRC64NVME" => Ok(ChecksumAlgorithm::Crc64nvme),
610            _ => Err(format!("Invalid checksum algorithm: {}", s)),
611        }
612    }
613}
614
615#[derive(Debug)]
616pub enum RequestPayer {
617    Requester,
618}
619impl std::str::FromStr for RequestPayer {
620    type Err = Error;
621    fn from_str(s: &str) -> Result<Self, Self::Err> {
622        match s {
623            "requester" => Ok(RequestPayer::Requester),
624            _ => Err(Error(format!("Invalid RequestPayer value: {}", s))),
625        }
626    }
627}
628#[derive(Debug)]
629pub enum ObjectLockMode {
630    Governance,
631    Compliance,
632}
633impl std::str::FromStr for ObjectLockMode {
634    type Err = Error;
635    fn from_str(s: &str) -> Result<Self, Self::Err> {
636        match s {
637            "GOVERNANCE" => Ok(ObjectLockMode::Governance),
638            "COMPLIANCE" => Ok(ObjectLockMode::Compliance),
639            _ => Err(Error(format!("Invalid ObjectLockMode value: {}", s))),
640        }
641    }
642}
643#[derive(Debug)]
644pub enum ObjectLockLegalHoldStatus {
645    On,
646    Off,
647}
648impl std::str::FromStr for ObjectLockLegalHoldStatus {
649    type Err = Error;
650    fn from_str(s: &str) -> Result<Self, Self::Err> {
651        match s {
652            "ON" => Ok(ObjectLockLegalHoldStatus::On),
653            "OFF" => Ok(ObjectLockLegalHoldStatus::Off),
654            _ => Err(Error(format!(
655                "Invalid ObjectLockLegalHoldStatus value: {}",
656                s
657            ))),
658        }
659    }
660}
661
662pub trait PutObjectHandler {
663    fn handle<'a>(
664        &'a self,
665        opt: &PutObjectOption,
666        bucket: &'a str,
667        object: &'a str,
668        body: &'a mut (dyn tokio::io::AsyncRead + Unpin + Send),
669    ) -> std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Result<(), String>>>>;
670}
671pub async fn handle_put_object<T: VRequest + BodyReader, F: VResponse>(
672    mut v4head: crate::authorization::v4::V4Head,
673    mut req: T,
674    resp: &mut F,
675    handler: &std::sync::Arc<dyn PutObjectHandler + Send + Sync>,
676) {
677    if req.method() != "PUT" {
678        resp.set_status(405);
679        resp.send_header();
680        return;
681    }
682    let url_path = req.url_path();
683    let url_path = url_path.trim_matches('/');
684    let ret = url_path.find('/');
685    if ret.is_none() {
686        resp.set_status(400);
687        resp.send_header();
688        return;
689    }
690    let next = ret.unwrap();
691    let bucket = &url_path[..next];
692    let object = &url_path[next + 1..];
693    let opt = PutObjectOption {
694        cache_control: req.get_header("cache-control"),
695        checksum_algorithm: req
696            .get_header("checksum-algorithm")
697            .and_then(|v| ChecksumAlgorithm::from_str(&v).ok()),
698        checksum_crc32: req.get_header("x-amz-checksum-crc32"),
699        checksum_crc32c: req.get_header("x-amz-checksum-crc32c"),
700        checksum_crc64nvme: req.get_header("x-amz-checksum-crc64vme"),
701        checksum_sha1: req.get_header("x-amz-checksum-sha1"),
702        checksum_sha256: req.get_header("x-amz-checksum-sha256"),
703        content_disposition: req.get_header("content-disposition"),
704        content_encoding: req.get_header("cotent-encoding"),
705        content_language: req.get_header("content-language"),
706        content_length: req
707            .get_header("content-length")
708            .and_then(|v| v.parse::<i64>().map_or(Some(-1), Some)),
709        content_md5: req.get_header("content-md5"),
710        content_type: req.get_header("content-type"),
711        expected_bucket_owner: req.get_header("x-amz-expected-bucket-owner"),
712        expires: req.get_header("expire").and_then(|v| {
713            chrono::NaiveDateTime::parse_from_str(&v, "%a, %d %b %Y %H:%M:%S GMT")
714                .map_or(None, |v| {
715                    Some(chrono::DateTime::from_naive_utc_and_offset(v, chrono::Utc))
716                })
717        }),
718        grant_full_control: req.get_header("x-amz-grant-full-control"),
719        grant_read: req.get_header("x-amz-grant-read"),
720        if_match: req.get_header("if-match"),
721        if_none_match: req.get_header("if-none-match"),
722        // metadata: todo!(),
723        object_lock_legal_hold_status: req
724            .get_header("x-amz-object-lock-legal-hold-status")
725            .and_then(|v| ObjectLockLegalHoldStatus::from_str(&v).ok()),
726        object_lock_mode: req
727            .get_header("x-amz-object-lock-mode")
728            .and_then(|v| ObjectLockMode::from_str(&v).ok()),
729        object_lock_retain_until_date: req
730            .get_header("x-amz-object-lock-retain_until_date")
731            .and_then(|v| {
732                chrono::NaiveDateTime::parse_from_str(&v, "%a, %d %b %Y %H:%M:%S GMT")
733                    .map_or(None, |v| {
734                        Some(chrono::DateTime::from_naive_utc_and_offset(v, chrono::Utc))
735                    })
736            }),
737        request_payer: req
738            .get_header("x-amz-request-payer")
739            .and_then(|v| RequestPayer::from_str(&v).ok()),
740        storage_class: req.get_header("x-amz-storage-class"),
741        // tagging: todo!(),
742        // website_redirect_location: todo!(),
743        write_offset_bytes: req
744            .get_header("x-amz-write-offset-bytes")
745            .and_then(|v| v.parse::<i64>().ok()),
746    };
747
748    //todo:parse from body,then derive into handle
749    enum ContentSha256 {
750        Hash(String),
751        Streaming,
752    }
753    let content_sha256 = req.get_header("x-amz-content-sha256").map_or_else(
754        || None,
755        |content_sha256| {
756            if content_sha256.as_str() == "STREAMING-AWS4-HMAC-SHA256-PAYLOAD" {
757                Some(ContentSha256::Streaming)
758            } else {
759                Some(ContentSha256::Hash(content_sha256))
760            }
761        },
762    );
763    if content_sha256.is_none() {
764        resp.set_status(403);
765        return;
766    }
767    let content_sha256 = content_sha256.unwrap();
768    let ret = req.get_body_reader().await;
769    if let Err(err) = ret {
770        resp.set_status(500);
771        resp.send_header();
772        log::error!("get body reader error: {err}");
773        return;
774    }
775    let r = ret.unwrap();
776    let ret: Result<(), String> = match content_sha256 {
777        ContentSha256::Hash(cs) => {
778            if opt.content_length.is_none() {
779                resp.set_status(403);
780                resp.send_header();
781                return;
782            }
783            let content_length = opt.content_length.unwrap() as usize;
784            if content_length <= 10 << 20 {
785                let mut buff = vec![0u8; content_length];
786                match parse_body(r, &mut buff, &cs, content_length).await {
787                    Ok(_) => {
788                        let mut buff = tokio::io::BufReader::new(std::io::Cursor::new(buff));
789                        handler.handle(&opt, bucket, object, &mut buff).await
790                    }
791                    Err(err) => match err {
792                        ParseBodyError::HashNoMatch => {
793                            log::warn!("put object hash not match");
794                            resp.set_status(400);
795                            resp.send_header();
796                            return;
797                        }
798                        ParseBodyError::ContentLengthIncorrect => {
799                            log::warn!("content length invalid");
800                            resp.set_status(400);
801                            resp.send_header();
802                            return;
803                        }
804                        ParseBodyError::Io(err) => {
805                            log::error!("parse body io error {err}");
806                            resp.set_status(500);
807                            resp.send_header();
808                            return;
809                        }
810                    },
811                }
812            } else {
813                match tokio::fs::OpenOptions::new()
814                    .create_new(true)
815                    .write(true)
816                    .read(true)
817                    .mode(0o644)
818                    .open(format!(".sys_bws/{}", cs))
819                    .await
820                {
821                    Ok(mut fd) => match parse_body(r, &mut fd, &cs, content_length).await {
822                        Ok(_) => {
823                            if let Err(err) = fd.seek(std::io::SeekFrom::Start(0)).await {
824                                log::error!("fd seek failed {err}");
825                                resp.set_status(500);
826                                resp.send_header();
827                                return;
828                            }
829                            handler.handle(&opt, bucket, object, &mut fd).await
830                        }
831                        Err(err) => match err {
832                            ParseBodyError::HashNoMatch => {
833                                log::warn!("put object hash not match");
834                                resp.set_status(400);
835                                resp.send_header();
836                                return;
837                            }
838                            ParseBodyError::ContentLengthIncorrect => {
839                                log::warn!("content length invalid");
840                                resp.set_status(400);
841                                resp.send_header();
842                                return;
843                            }
844                            ParseBodyError::Io(err) => {
845                                log::error!("parse body io error {err}");
846                                resp.set_status(500);
847                                resp.send_header();
848                                return;
849                            }
850                        },
851                    },
852                    Err(err) => {
853                        log::error!("open local path error {err}");
854                        resp.set_status(500);
855                        resp.send_header();
856                        return;
857                    }
858                }
859            }
860        }
861        ContentSha256::Streaming => {
862            let file_name = crate::random_str!(4);
863            let file_name = format!(".sys_bws/{}", file_name);
864            let ret = match tokio::fs::OpenOptions::new()
865                .create_new(true)
866                .write(true)
867                .read(true)
868                .mode(0o644)
869                .open(file_name.as_str())
870                .await
871            {
872                Ok(mut fd) => crate::utils::chunk_parse(r, &mut fd, v4head.hasher()).await,
873                Err(err) => {
874                    log::error!("open local temp file error {err}");
875                    resp.set_status(500);
876                    resp.send_header();
877                    return;
878                }
879            };
880            if let Err(err) = ret {
881                tokio::fs::remove_file(file_name.as_str())
882                    .await
883                    .unwrap_or_else(|err| log::error!("remove file {file_name} error {err}"));
884                match err {
885                    crate::utils::ChunkParseError::HashNoMatch => {
886                        log::warn!("accept hash no match request");
887                        resp.set_status(400);
888                        resp.send_header();
889                        return;
890                    }
891                    crate::utils::ChunkParseError::IllegalContent => {
892                        log::warn!("accept illegal content request");
893                        resp.set_status(400);
894                        resp.send_header();
895                        return;
896                    }
897                    crate::utils::ChunkParseError::Io(err) => {
898                        log::error!("local io error {err}");
899                        resp.set_status(500);
900                        resp.send_header();
901                        return;
902                    }
903                }
904            }
905            match tokio::fs::OpenOptions::new()
906                .read(true)
907                .open(file_name.as_str())
908                .await
909            {
910                Ok(mut fd) => {
911                    let ret = handler.handle(&opt, bucket, object, &mut fd).await;
912                    tokio::fs::remove_file(file_name.as_str())
913                        .await
914                        .unwrap_or_else(|err| log::error!("remove file {file_name} error {err}"));
915                    ret
916                }
917                Err(err) => {
918                    log::error!("open file {file_name} error {err}");
919                    resp.set_status(500);
920                    resp.send_header();
921                    tokio::fs::remove_file(file_name.as_str())
922                        .await
923                        .unwrap_or_else(|err| log::error!("remove file {file_name} error {err}"));
924                    return;
925                }
926            }
927        }
928    };
929    //
930    match ret {
931        Ok(_) => {
932            resp.set_status(200);
933            resp.send_header();
934        }
935        Err(err) => {
936            resp.set_status(500);
937            resp.send_header();
938            log::error!("put object handle error: {err}");
939        }
940    }
941}
942pub struct DeleteObjectOption {}
943pub trait DeleteObjectHandler {
944    fn handle<'a>(
945        &'a self,
946        opt: &'a DeleteObjectOption,
947        object: &'a str,
948    ) -> std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Result<(), String>>>>;
949}
950
951pub async fn handle_delete_object<T: VRequest, F: VResponse>(
952    req: T,
953    resp: &mut F,
954    handler: &std::sync::Arc<dyn DeleteObjectHandler + Send + Sync>,
955) {
956    let opt = DeleteObjectOption {};
957    let url_path = req.url_path();
958    if let Err(e) = handler.handle(&opt, url_path.trim_matches('/')).await {
959        resp.set_status(500);
960        log::info!("delete object handler error: {e}");
961    } else {
962        resp.set_status(204);
963    }
964}
965pub struct MultiUploadObjectCompleteOption {
966    pub if_match: Option<String>,
967    pub if_none_match: Option<String>,
968}
969pub trait MultiUploadObjectHandler {
970    fn handle_create_session<'a>(
971        &'a self,
972        bucket: &'a str,
973        key: &'a str,
974    ) -> std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Result<String, ()>>>>;
975    ///return etag
976    fn handle_upload_part<'a>(
977        &'a self,
978        bucket: &'a str,
979        key: &'a str,
980        upload_id: &'a str,
981        part_number: u32,
982        body: &'a mut (dyn tokio::io::AsyncRead + Unpin + Send),
983    ) -> std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Result<String, ()>>>>;
984    fn handle_complete<'a>(
985        &'a self,
986        bucket: &'a str,
987        key: &'a str,
988        upload_id: &'a str,
989        //(etag,part number)
990        data: &'a [(&'a str, u32)],
991        opts: MultiUploadObjectCompleteOption,
992    ) -> std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Result<String, ()>>>>;
993    fn handle_abort<'a>(
994        &'a self,
995        bucket: &'a str,
996        key: &'a str,
997        upload_id: &'a str,
998    ) -> std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Result<(), ()>>>>;
999}
1000pub async fn handle_multipart_create_session<T: VRequest, F: VResponse>(
1001    req: T,
1002    resp: &mut F,
1003    handler: &std::sync::Arc<dyn MultiUploadObjectHandler + Send + Sync>,
1004) {
1005    let raw_path = req.url_path();
1006    let raw = raw_path
1007        .trim_start_matches('/')
1008        .splitn(2, '/')
1009        .collect::<Vec<&str>>();
1010    if raw.len() != 2 {
1011        resp.set_status(400);
1012        resp.send_header();
1013        return;
1014    }
1015    let bucket = raw[0];
1016    let key = raw[1];
1017    match handler.handle_create_session(bucket, key).await {
1018        Ok(upload_id) => {
1019            #[derive(Debug, serde::Serialize)]
1020            #[serde(rename_all = "PascalCase")]
1021            pub struct MultipartInitResponse<'a> {
1022                #[serde(rename = "Bucket")]
1023                pub bucket: &'a str,
1024                #[serde(rename = "Key")]
1025                pub key: &'a str,
1026                #[serde(rename = "UploadId")]
1027                pub upload_id: &'a str,
1028            }
1029            let r = MultipartInitResponse {
1030                bucket,
1031                key,
1032                upload_id: &upload_id,
1033            };
1034            let is_err = match quick_xml::se::to_string(&r) {
1035                Ok(content) => match resp.get_body_writer().await {
1036                    Ok(mut w) => {
1037                        let _ = w.poll_write(content.as_bytes()).await;
1038                        None
1039                    }
1040                    Err(err) => {
1041                        log::error!("get body writer error {err}");
1042                        Some(())
1043                    }
1044                },
1045                Err(err) => {
1046                    log::error!("xml encode error {err}");
1047                    Some(())
1048                }
1049            };
1050            if is_err.is_some() {
1051                resp.set_status(500);
1052                resp.send_header();
1053            }
1054        }
1055        Err(_) => {
1056            log::error!("handle create session error");
1057            resp.set_status(500);
1058            resp.send_header();
1059        }
1060    }
1061}
1062pub async fn handle_multipart_upload_part<T: VRequest + BodyReader + HeaderTaker, F: VResponse>(
1063    req: T,
1064    resp: &mut F,
1065    handler: &std::sync::Arc<dyn MultiUploadObjectHandler + Send + Sync>,
1066) {
1067    let upload_id = req.get_query("uploadId");
1068    let part_number = req.get_query("partNumber");
1069    if upload_id.is_none() || part_number.is_none() {
1070        resp.set_status(400);
1071    } else {
1072        let ret = u32::from_str_radix(part_number.unwrap().as_str(), 10);
1073        if ret.is_err() {
1074            resp.set_status(400);
1075            return;
1076        }
1077        let part_number = ret.unwrap();
1078        let raw_path = req.url_path();
1079        let raw = raw_path
1080            .trim_start_matches('/')
1081            .splitn(2, '/')
1082            .collect::<Vec<&str>>();
1083        if raw.len() != 2 {
1084            resp.set_status(400);
1085            return;
1086        }
1087        let header = req.take_header();
1088        let body_reader = match req.get_body_reader().await {
1089            Ok(body_reader) => body_reader,
1090            Err(err) => {
1091                log::error!("get body reader failed {err}");
1092                resp.set_status(500);
1093                resp.send_header();
1094                return;
1095            }
1096        };
1097        let (body, release) = match get_body_stream(body_reader, &header).await {
1098            Ok(data) => data,
1099            Err(err) => {
1100                log::error!("get body stream error {err}");
1101                resp.set_status(500);
1102                resp.send_header();
1103                return;
1104            }
1105        };
1106        let ret = match body {
1107            StreamType::File(mut file) => {
1108                handler
1109                    .handle_upload_part(
1110                        raw[0],
1111                        raw[1],
1112                        upload_id.unwrap().as_str(),
1113                        part_number,
1114                        &mut file,
1115                    )
1116                    .await
1117            }
1118            StreamType::Buff(mut buf_reader) => {
1119                handler
1120                    .handle_upload_part(
1121                        raw[0],
1122                        raw[1],
1123                        upload_id.unwrap().as_str(),
1124                        part_number,
1125                        &mut buf_reader,
1126                    )
1127                    .await
1128            }
1129        };
1130        if let Some(release) = release {
1131            release.await;
1132        }
1133        if let Ok(etag) = ret {
1134            resp.set_header("etag", &etag);
1135        } else {
1136            resp.set_status(500);
1137            resp.send_header();
1138        }
1139    }
1140}
1141pub async fn handle_multipart_complete_session<T: VRequestPlus, F: VResponse>(
1142    req: T,
1143    resp: &mut F,
1144    handler: &std::sync::Arc<dyn MultiUploadObjectHandler + Send + Sync>,
1145) {
1146    let raw_path = req.url_path();
1147    let raw = raw_path
1148        .trim_start_matches('/')
1149        .splitn(2, '/')
1150        .collect::<Vec<&str>>();
1151    if raw.len() != 2 {
1152        resp.set_status(400);
1153        resp.send_header();
1154        return;
1155    }
1156    let bucket = raw[0];
1157    let key = raw[1];
1158    let upload_id = req.get_query("uploadId");
1159    if let Some(upload_id) = upload_id {
1160        #[derive(Debug, serde::Deserialize)]
1161        #[serde(rename_all = "PascalCase")]
1162        pub struct CompleteMultiPartUploadRequest {
1163            #[serde(rename = "Part")]
1164            pub parts: Vec<CompletedPart>,
1165        }
1166        #[derive(Debug, serde::Deserialize)]
1167        #[serde(rename_all = "PascalCase")]
1168        pub struct CompletedPart {
1169            #[serde(rename = "ETag")]
1170            pub etag: String,
1171            #[serde(rename = "PartNumber")]
1172            pub part_number: u32,
1173        }
1174        match req.body().await {
1175            Ok(body) => {
1176                match quick_xml::de::from_str::<CompleteMultiPartUploadRequest>(unsafe {
1177                    std::str::from_utf8_unchecked(&body)
1178                }) {
1179                    Ok(upload_request) => {
1180                        let data = upload_request
1181                            .parts
1182                            .iter()
1183                            .map(|data| (data.etag.as_str(), data.part_number))
1184                            .collect::<Vec<(&str, u32)>>();
1185                        match handler
1186                            .handle_complete(
1187                                bucket,
1188                                key,
1189                                &upload_id,
1190                                &data,
1191                                MultiUploadObjectCompleteOption {
1192                                    if_match: None,
1193                                    if_none_match: None,
1194                                },
1195                            )
1196                            .await
1197                        {
1198                            Ok(etag) => {
1199                                use serde::{Deserialize, Serialize};
1200                                #[derive(Debug, Serialize, Deserialize)]
1201                                #[serde(rename_all = "PascalCase")]
1202                                pub struct CompleteMultipartUploadResponse<'a> {
1203                                    #[serde(rename = "Location")]
1204                                    pub location: &'a str,
1205                                    #[serde(rename = "Bucket")]
1206                                    pub bucket: &'a str,
1207                                    #[serde(rename = "Key")]
1208                                    pub key: &'a str,
1209                                    #[serde(rename = "ETag")]
1210                                    pub etag: &'a str,
1211                                }
1212                                let r = CompleteMultipartUploadResponse {
1213                                    location: "",
1214                                    bucket,
1215                                    key,
1216                                    etag: &etag,
1217                                };
1218                                match quick_xml::se::to_string(&r) {
1219                                    Ok(content) => {
1220                                        let err = match resp.get_body_writer().await {
1221                                            Ok(mut w) => {
1222                                                let _ = w.poll_write(content.as_bytes()).await;
1223                                                None
1224                                            }
1225                                            Err(err) => Some(err),
1226                                        };
1227                                        if let Some(err) = err {
1228                                            log::error!("get body writer error {err}");
1229                                            resp.set_status(500);
1230                                            resp.send_header();
1231                                        }
1232                                    }
1233                                    Err(err) => {
1234                                        log::error!("quick xml encode error {err}");
1235                                        resp.set_status(500);
1236                                        resp.send_header();
1237                                    }
1238                                }
1239                            }
1240                            Err(_) => {
1241                                log::error!("handle_complete error");
1242                                resp.set_status(500);
1243                                resp.send_header();
1244                            }
1245                        }
1246                    }
1247                    Err(_) => {
1248                        resp.set_status(400);
1249                        resp.send_header();
1250                    }
1251                }
1252            }
1253            Err(err) => {
1254                log::error!("read body error {err}");
1255                resp.set_status(500);
1256                resp.send_header();
1257            }
1258        }
1259    } else {
1260        resp.set_status(400);
1261        resp.send_header();
1262    }
1263}
1264pub async fn handle_multipart_abort_session<T: VRequest, F: VResponse>(
1265    req: T,
1266    resp: &mut F,
1267    handler: &std::sync::Arc<dyn MultiUploadObjectHandler + Send + Sync>,
1268) {
1269    todo!()
1270}
1271pub struct CreateBucketOption {
1272    pub grant_full_control: Option<String>,
1273    pub grant_read: Option<String>,
1274    pub grant_read_acp: Option<String>,
1275    pub grant_write: Option<String>,
1276    pub grant_write_acp: Option<String>,
1277    pub object_lock_enabled_for_bucket: Option<bool>,
1278    pub object_ownership: Option<ObjectOwnership>,
1279}
1280pub enum ObjectOwnership {
1281    BucketOwnerPreferred,
1282    ObjectWriter,
1283    BucketOwnerEnforced,
1284}
1285impl FromStr for ObjectOwnership {
1286    type Err = Error;
1287
1288    fn from_str(s: &str) -> Result<Self, Self::Err> {
1289        match s {
1290            "BucketOwnerPreferred" => Ok(ObjectOwnership::BucketOwnerPreferred),
1291            "ObjectWriter" => Ok(ObjectOwnership::ObjectWriter),
1292            "BucketOwnerEnforced" => Ok(ObjectOwnership::BucketOwnerEnforced),
1293            _ => Err(Error(s.to_string())),
1294        }
1295    }
1296}
1297pub struct CreateBucketConfiguration {
1298    pub bucket: Option<BucketInfo>,
1299    pub location: Option<LocationInfo>,
1300    pub location_constraint: Option<BucketLocationConstraint>,
1301}
1302pub struct BucketInfo {
1303    pub data_redundancy: DataRedundancy,
1304    pub bucket_type: BucketType,
1305}
1306#[derive(Debug, Clone, PartialEq, Eq)]
1307pub enum DataRedundancy {
1308    SingleAvailabilityZone,
1309    SingleLocalZone,
1310    Unknown(String),
1311}
1312
1313impl From<&str> for DataRedundancy {
1314    fn from(s: &str) -> Self {
1315        match s {
1316            "SingleAvailabilityZone" => Self::SingleAvailabilityZone,
1317            "SingleLocalZone" => Self::SingleLocalZone,
1318            other => Self::Unknown(other.to_string()),
1319        }
1320    }
1321}
1322impl Display for DataRedundancy {
1323    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1324        f.write_str(
1325            match self {
1326                DataRedundancy::SingleAvailabilityZone => "SingleAvailabilityZone".to_string(),
1327                DataRedundancy::SingleLocalZone => "SingleLocalZone".to_string(),
1328                DataRedundancy::Unknown(s) => s.clone(),
1329            }
1330            .as_str(),
1331        )
1332    }
1333}
1334#[derive(Debug, Clone, PartialEq, Eq)]
1335pub enum BucketType {
1336    Directory,
1337    Unknown(String),
1338}
1339
1340impl From<&str> for BucketType {
1341    fn from(s: &str) -> Self {
1342        match s {
1343            "Directory" => Self::Directory,
1344            other => Self::Unknown(other.to_string()),
1345        }
1346    }
1347}
1348
1349impl Display for BucketType {
1350    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1351        f.write_str(
1352            match self {
1353                Self::Directory => "Directory".to_string(),
1354                Self::Unknown(s) => s.clone(),
1355            }
1356            .as_str(),
1357        )
1358    }
1359}
1360
1361pub struct LocationInfo {
1362    pub name: Option<String>,
1363    pub location_type: LocationType,
1364}
1365
1366pub enum LocationType {
1367    AvailabilityZone,
1368    LocalZone,
1369}
1370#[derive(Debug, Clone, PartialEq, Eq)]
1371pub enum BucketLocationConstraint {
1372    AfSouth1,
1373    ApEast1,
1374    ApNortheast1,
1375    ApNortheast2,
1376    ApNortheast3,
1377    ApSouth1,
1378    ApSouth2,
1379    ApSoutheast1,
1380    ApSoutheast2,
1381    ApSoutheast3,
1382    ApSoutheast4,
1383    ApSoutheast5,
1384    CaCentral1,
1385    CnNorth1,
1386    CnNorthwest1,
1387    Eu,
1388    EuCentral1,
1389    EuCentral2,
1390    EuNorth1,
1391    EuSouth1,
1392    EuSouth2,
1393    EuWest1,
1394    EuWest2,
1395    EuWest3,
1396    IlCentral1,
1397    MeCentral1,
1398    MeSouth1,
1399    SaEast1,
1400    UsEast2,
1401    UsGovEast1,
1402    UsGovWest1,
1403    UsWest1,
1404    UsWest2,
1405    Unknown(String),
1406}
1407impl From<&str> for BucketLocationConstraint {
1408    fn from(s: &str) -> Self {
1409        match s {
1410            "af-south-1" => Self::AfSouth1,
1411            "ap-east-1" => Self::ApEast1,
1412            "ap-northeast-1" => Self::ApNortheast1,
1413            "ap-northeast-2" => Self::ApNortheast2,
1414            "ap-northeast-3" => Self::ApNortheast3,
1415            "ap-south-1" => Self::ApSouth1,
1416            "ap-south-2" => Self::ApSouth2,
1417            "ap-southeast-1" => Self::ApSoutheast1,
1418            "ap-southeast-2" => Self::ApSoutheast2,
1419            "ap-southeast-3" => Self::ApSoutheast3,
1420            "ap-southeast-4" => Self::ApSoutheast4,
1421            "ap-southeast-5" => Self::ApSoutheast5,
1422            "ca-central-1" => Self::CaCentral1,
1423            "cn-north-1" => Self::CnNorth1,
1424            "cn-northwest-1" => Self::CnNorthwest1,
1425            "EU" => Self::Eu,
1426            "eu-central-1" => Self::EuCentral1,
1427            "eu-central-2" => Self::EuCentral2,
1428            "eu-north-1" => Self::EuNorth1,
1429            "eu-south-1" => Self::EuSouth1,
1430            "eu-south-2" => Self::EuSouth2,
1431            "eu-west-1" => Self::EuWest1,
1432            "eu-west-2" => Self::EuWest2,
1433            "eu-west-3" => Self::EuWest3,
1434            "il-central-1" => Self::IlCentral1,
1435            "me-central-1" => Self::MeCentral1,
1436            "me-south-1" => Self::MeSouth1,
1437            "sa-east-1" => Self::SaEast1,
1438            "us-east-2" => Self::UsEast2,
1439            "us-gov-east-1" => Self::UsGovEast1,
1440            "us-gov-west-1" => Self::UsGovWest1,
1441            "us-west-1" => Self::UsWest1,
1442            "us-west-2" => Self::UsWest2,
1443            other => Self::Unknown(other.to_string()),
1444        }
1445    }
1446}
1447
1448impl Display for BucketLocationConstraint {
1449    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1450        f.write_str(match self {
1451            Self::AfSouth1 => "af-south-1",
1452            Self::ApEast1 => "ap-east-1",
1453            Self::ApNortheast1 => "ap-northeast-1",
1454            Self::ApNortheast2 => "ap-northeast-2",
1455            Self::ApNortheast3 => "ap-northeast-3",
1456            Self::ApSouth1 => "ap-south-1",
1457            Self::ApSouth2 => "ap-south-2",
1458            Self::ApSoutheast1 => "ap-southeast-1",
1459            Self::ApSoutheast2 => "ap-southeast-2",
1460            Self::ApSoutheast3 => "ap-southeast-3",
1461            Self::ApSoutheast4 => "ap-southeast-4",
1462            Self::ApSoutheast5 => "ap-southeast-5",
1463            Self::CaCentral1 => "ca-central-1",
1464            Self::CnNorth1 => "cn-north-1",
1465            Self::CnNorthwest1 => "cn-northwest-1",
1466            Self::Eu => "EU",
1467            Self::EuCentral1 => "eu-central-1",
1468            Self::EuCentral2 => "eu-central-2",
1469            Self::EuNorth1 => "eu-north-1",
1470            Self::EuSouth1 => "eu-south-1",
1471            Self::EuSouth2 => "eu-south-2",
1472            Self::EuWest1 => "eu-west-1",
1473            Self::EuWest2 => "eu-west-2",
1474            Self::EuWest3 => "eu-west-3",
1475            Self::IlCentral1 => "il-central-1",
1476            Self::MeCentral1 => "me-central-1",
1477            Self::MeSouth1 => "me-south-1",
1478            Self::SaEast1 => "sa-east-1",
1479            Self::UsEast2 => "us-east-2",
1480            Self::UsGovEast1 => "us-gov-east-1",
1481            Self::UsGovWest1 => "us-gov-west-1",
1482            Self::UsWest1 => "us-west-1",
1483            Self::UsWest2 => "us-west-2",
1484            Self::Unknown(s) => s,
1485        })
1486    }
1487}
1488
1489pub trait CreateBucketHandler {
1490    fn handle<'a>(
1491        &'a self,
1492        opt: &'a CreateBucketOption,
1493        bucket: &'a str,
1494    ) -> std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Result<(), String>>>>;
1495}
1496pub async fn handle_create_bucket<T: VRequest, F: VResponse>(
1497    req: T,
1498    resp: &mut F,
1499    handler: &std::sync::Arc<dyn CreateBucketHandler + Send + Sync>,
1500) {
1501    if req.method() != "PUT" {
1502        resp.set_status(405);
1503        resp.send_header();
1504        return;
1505    }
1506
1507    let opt = CreateBucketOption {
1508        grant_full_control: req.get_header("x-amz-grant-full-control"),
1509        grant_read: req.get_header("x-amz-grant-read"),
1510        grant_read_acp: req.get_header("x-amz-grant-read-acp"),
1511        grant_write: req.get_header("x-amz-grant-write"),
1512        grant_write_acp: req.get_header("x-amz-grant-write-acp"),
1513        object_lock_enabled_for_bucket: req
1514            .get_header("x-amz-bucket-object-lock-enabled")
1515            .and_then(|v| {
1516                if v == "true" {
1517                    Some(true)
1518                } else if v == "false" {
1519                    Some(false)
1520                } else {
1521                    None
1522                }
1523            }),
1524        object_ownership: req
1525            .get_header("x-amz-object-ownership")
1526            .and_then(|v| v.parse().ok()),
1527    };
1528    let url_path = req.url_path();
1529    if let Err(e) = handler.handle(&opt, url_path.trim_matches('/')).await {
1530        resp.set_status(500);
1531        log::info!("delete object handler error: {e}")
1532    }
1533}
1534
1535pub struct DeleteBucketOption {
1536    pub expected_owner: Option<String>,
1537}
1538pub trait DeleteBucketHandler {
1539    fn handle<'a>(
1540        &'a self,
1541        opt: &'a DeleteBucketOption,
1542        bucket: &'a str,
1543    ) -> std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Result<(), String>>>>;
1544}
1545
1546pub async fn handle_delete_bucket<T: VRequest, F: VResponse>(
1547    req: T,
1548    resp: &mut F,
1549    handler: &std::sync::Arc<dyn DeleteBucketHandler + Send + Sync>,
1550) {
1551    if req.method() != "DELETE" {
1552        resp.set_status(405);
1553        resp.send_header();
1554        return;
1555    }
1556    let opt = DeleteBucketOption {
1557        expected_owner: req.get_header("x-amz-expected-bucket-owner"),
1558    };
1559    let url_path = req.url_path();
1560    match handler.handle(&opt, url_path.trim_matches('/')).await {
1561        Ok(_) => {
1562            resp.set_status(204);
1563            resp.send_header();
1564        }
1565        Err(e) => {
1566            resp.set_status(500);
1567            log::error!("delete object handler error: {e}")
1568        }
1569    }
1570}
1571
1572//utils
1573#[derive(Debug)]
1574enum ParseBodyError {
1575    HashNoMatch,
1576    ContentLengthIncorrect,
1577    Io(String),
1578}
1579impl Display for ParseBodyError {
1580    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1581        f.write_str(match self {
1582            ParseBodyError::HashNoMatch => "hash no match",
1583            ParseBodyError::ContentLengthIncorrect => "content length incorrect",
1584            ParseBodyError::Io(err) => err.as_str(),
1585        })
1586    }
1587}
1588impl std::error::Error for ParseBodyError {}
1589enum StreamType {
1590    File(tokio::fs::File),
1591    Buff(tokio::io::BufReader<std::io::Cursor<Vec<u8>>>),
1592}
1593async fn get_body_stream<
1594    T: crate::utils::io::PollRead + Send,
1595    H: crate::authorization::v4::VHeader,
1596>(
1597    src: T,
1598    header: &H,
1599) -> Result<
1600    (
1601        StreamType,
1602        Option<std::pin::Pin<Box<dyn Send + std::future::Future<Output = ()>>>>,
1603    ),
1604    ParseBodyError,
1605> {
1606    let cl = header.get_header("content-length");
1607    let acs = header
1608        .get_header("x-amz-content-sha256")
1609        .ok_or(ParseBodyError::HashNoMatch)?;
1610    if let Some(cl) = cl {
1611        let cl = cl
1612            .as_str()
1613            .parse::<usize>()
1614            .or(Err(ParseBodyError::ContentLengthIncorrect))?;
1615        if acs.as_str() != "STREAMING-AWS4-HMAC-SHA256-PAYLOAD" {
1616            if cl <= 10 << 20 {
1617                let mut buff = vec![0u8; cl];
1618                parse_body(src, &mut buff, &acs, cl).await?;
1619                return Ok((
1620                    StreamType::Buff(tokio::io::BufReader::new(std::io::Cursor::new(buff))),
1621                    None,
1622                ));
1623            } else {
1624                let file_name = format!(".sys_bws/{}", crate::random_str!(4));
1625                let mut fd = tokio::fs::OpenOptions::new()
1626                    .create_new(true)
1627                    .write(true)
1628                    .mode(0o644)
1629                    .open(file_name.as_str())
1630                    .await
1631                    .map_err(|err| ParseBodyError::Io(err.to_string()))?;
1632                parse_body(src, &mut fd, &acs, cl).await?;
1633                drop(fd);
1634                match tokio::fs::OpenOptions::new()
1635                    .read(true)
1636                    .open(file_name.as_str())
1637                    .await
1638                {
1639                    Ok(fd) => {
1640                        return Ok((
1641                            StreamType::File(fd),
1642                            Some({
1643                                Box::pin(async move {
1644                                    let _ = tokio::fs::remove_file(file_name.as_str()).await;
1645                                })
1646                            }),
1647                        ))
1648                    }
1649                    Err(err) => {
1650                        let _ = tokio::fs::remove_file(file_name.as_str()).await;
1651                        return Err(ParseBodyError::Io(err.to_string()));
1652                    }
1653                }
1654                // return Ok(())
1655            }
1656        }
1657    }
1658    //chunk
1659    todo!()
1660}
1661
1662async fn parse_body<
1663    T: crate::utils::io::PollRead + Send,
1664    E: tokio::io::AsyncWrite + Send + Unpin,
1665>(
1666    mut src: T,
1667    dst: &mut E,
1668    content_sha256: &str,
1669    mut content_length: usize,
1670) -> Result<(), ParseBodyError> {
1671    use tokio::io::AsyncWriteExt;
1672    let mut hsh = sha2::Sha256::new();
1673    // if content length > 10MB, it will store on disk instead memory
1674    while let Some(buff) = src.poll_read().await.map_err(ParseBodyError::Io)? {
1675        let buff_len = buff.len();
1676        if content_length < buff_len {
1677            return Err(ParseBodyError::ContentLengthIncorrect);
1678        }
1679        content_length -= buff_len;
1680        let _ = hsh.write_all(&buff);
1681        dst.write_all(&buff)
1682            .await
1683            .map_err(|err| ParseBodyError::Io(format!("write error {err}")))?;
1684    }
1685    let ret = hsh.finalize();
1686    let real_sha256 = hex::encode(ret);
1687    if real_sha256.as_str() != content_sha256 {
1688        Err(ParseBodyError::HashNoMatch)
1689    } else {
1690        Ok(())
1691    }
1692}
1693
1694async fn parse_streaming_body<
1695    T: crate::utils::io::PollRead + Send,
1696    E: tokio::io::AsyncWrite + Send + Unpin,
1697>(
1698    mut src: T,
1699    dst: &mut E,
1700    content_sha256: &str,
1701) -> Result<(), ParseBodyError> {
1702    todo!()
1703}
1704// #[cfg(test)]
1705// mod req_test {
1706//     use std::{collections::HashMap, sync::RwLock};
1707//     static FAKE_ETAG: &str = "ffffffffffffffff";
1708//     struct HttpRequest {
1709//         url_path: String,
1710//         query: Vec<(String, String)>,
1711//         method: String,
1712//         headers: HashMap<String, String>,
1713//     }
1714//     impl crate::authorization::v4::VHeader for HttpRequest {
1715//         fn get_header(&self, key: &str) -> Option<String> {
1716//             self.headers
1717//                 .get(key)
1718//                 .map_or_else(|| None, |v| Some(v.clone()))
1719//         }
1720
1721//         fn set_header(&mut self, key: &str, val: &str) {
1722//             self.headers.insert(key.to_string(), val.to_string());
1723//         }
1724
1725//         fn delete_header(&mut self, key: &str) {
1726//             self.headers.remove(key);
1727//         }
1728
1729//         fn rng_header(&self, mut cb: impl FnMut(&str, &str) -> bool) {
1730//             self.headers.iter().all(|(k, v)| cb(k, v));
1731//         }
1732//     }
1733//     impl super::VRequest for HttpRequest {
1734//         fn method(&self) -> String {
1735//             self.method.clone()
1736//         }
1737
1738//         fn url_path(&self) -> String {
1739//             self.url_path.clone()
1740//         }
1741
1742//         fn get_query(&self, target: &str) -> Option<String> {
1743//             let ans: Vec<_> = self.query.iter().filter(|(k, v)| k == target).collect();
1744//             if !ans.is_empty() {
1745//                 Some(ans.first().unwrap().1.clone())
1746//             } else {
1747//                 None
1748//             }
1749//         }
1750
1751//         fn all_query(&self, mut cb: impl FnMut(&str, &str) -> bool) {
1752//             self.query.iter().all(|(k, v)| cb(k, v));
1753//         }
1754//     }
1755//     #[derive(Default)]
1756//     struct HttpResponse {
1757//         status: u16,
1758//         headers: HashMap<String, String>,
1759//         body: Vec<u8>,
1760//     }
1761//     impl crate::authorization::v4::VHeader for HttpResponse {
1762//         fn get_header(&self, key: &str) -> Option<String> {
1763//             self.headers
1764//                 .get(key)
1765//                 .map_or_else(|| None, |v| Some(v.clone()))
1766//         }
1767
1768//         fn set_header(&mut self, key: &str, val: &str) {
1769//             self.headers.insert(key.to_string(), val.to_string());
1770//         }
1771
1772//         fn delete_header(&mut self, key: &str) {
1773//             self.headers.remove(key);
1774//         }
1775
1776//         fn rng_header(&self, mut cb: impl FnMut(&str, &str) -> bool) {
1777//             self.headers.iter().all(|(k, v)| cb(k, v));
1778//         }
1779//     }
1780//     struct VecWriter<'a>(&'a mut Vec<u8>);
1781//     impl<'a> std::io::Write for VecWriter<'_> {
1782//         fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1783//             self.0.extend_from_slice(buf);
1784//             Ok(buf.len())
1785//         }
1786
1787//         fn flush(&mut self) -> std::io::Result<()> {
1788//             Ok(())
1789//         }
1790//     }
1791//     impl super::BodyWriter for HttpResponse {
1792//         type BodyWriter<'a> = VecWriter<'a>;
1793
1794//         fn get_body_writer(&mut self) -> Result<Self::BodyWriter<'_>, String> {
1795//             Ok(VecWriter(&mut self.body))
1796//         }
1797//     }
1798//     impl super::VResponse for HttpResponse {
1799//         fn set_status(&mut self, status: u16) {
1800//             if self.status != 0 {
1801//                 return;
1802//             }
1803//             self.status = status;
1804//         }
1805
1806//         fn send_header(&mut self) {}
1807//     }
1808
1809//     pub struct ListBucket(Vec<String>);
1810//     impl super::ListObjectHandler for ListBucket {
1811//         fn handle(
1812//             &self,
1813//             _: &super::ListObjectOption,
1814//             bucket: &str,
1815//         ) -> Result<Vec<super::ListObjectContent>, String> {
1816//             let last_modified = chrono::Utc::now().to_rfc2822();
1817//             Ok(self
1818//                 .0
1819//                 .iter()
1820//                 .filter_map(|v| {
1821//                     if v.starts_with(bucket) {
1822//                         return Some(super::ListObjectContent {
1823//                             key: v.trim_start_matches(bucket).to_string(),
1824//                             last_modified: Some(last_modified.clone()),
1825//                             etag: Some("801cbd6952577c28310fd5002670132a".to_string()),
1826//                             size: 20,
1827//                             owner: Some(super::Owner {
1828//                                 id: "123456789".to_string(),
1829//                                 display_name: "root".to_string(),
1830//                             }),
1831//                             storage_class: Some("standard".to_string()),
1832//                         });
1833//                     }
1834//                     None
1835//                 })
1836//                 .collect())
1837//         }
1838//     }
1839
1840//     impl super::ListBucketHandler for ListBucket {
1841//         fn handle(
1842//             &self,
1843//             opt: &super::ListBucketsOption,
1844//         ) -> Result<Vec<super::Bucket>, String> {
1845//             let date = chrono::Utc::now().to_rfc2822();
1846//             Ok(self
1847//                 .0
1848//                 .iter()
1849//                 .map(|v| super::Bucket {
1850//                     name: v.find('/').map_or(v.clone(), |next| v[..next].to_string()),
1851//                     creation_date: date.clone(),
1852//                     bucket_region: "us-east-1".to_string(),
1853//                 })
1854//                 .collect())
1855//         }
1856//     }
1857
1858//     #[test]
1859//     fn list_object() {
1860//         let lb = ListBucket(vec![
1861//             "test/hello.txt".to_string(),
1862//             "test/test.dat".to_string(),
1863//             "one/jack.json".to_string(),
1864//             "one/jim.json".to_string(),
1865//         ]);
1866//         let hm = HashMap::default();
1867//         let req = HttpRequest {
1868//             url_path: "/test".to_string(),
1869//             query: vec![],
1870//             method: "GET".to_string(),
1871//             headers: hm,
1872//         };
1873//         let mut resp = HttpResponse {
1874//             status: 0,
1875//             headers: HashMap::default(),
1876//             body: vec![],
1877//         };
1878//         super::handle_get_list_object(&req, &mut resp, &lb);
1879//         String::from_utf8(resp.body)
1880//             .map_or_else(|e| eprintln!("not ascii {e}"), |v| println!("{v}"));
1881//     }
1882//     #[test]
1883//     fn list_buckets() {
1884//         let hm = HashMap::default();
1885//         let req = HttpRequest {
1886//             url_path: "/".to_string(),
1887//             query: vec![],
1888//             method: "GET".to_string(),
1889//             headers: hm,
1890//         };
1891//         let mut resp = HttpResponse {
1892//             status: 0,
1893//             headers: HashMap::default(),
1894//             body: vec![],
1895//         };
1896//         let lb = ListBucket(vec![
1897//             "test/hello.txt".to_string(),
1898//             "test/test.dat".to_string(),
1899//             "one/jack.json".to_string(),
1900//             "one/jim.json".to_string(),
1901//         ]);
1902//         super::handle_get_list_buckets(&req, &mut resp, &lb);
1903//         String::from_utf8(resp.body)
1904//             .map_or_else(|e| eprintln!("not ascii {e}"), |v| println!("{v}"));
1905//     }
1906
1907//     impl super::CreateBucketHandler for RwLock<ListBucket> {
1908//         fn handle(
1909//             &self,
1910//             opt: &super::CreateBucketOption,
1911//             bucket: &str,
1912//         ) -> Result<(), String> {
1913//             self.write().map_or(
1914//                 Err(Box::new(super::Error("write lock failed".to_string()))),
1915//                 |mut raw| {
1916//                     for v in raw.0.iter() {
1917//                         if v == bucket {
1918//                             return Ok(());
1919//                         }
1920//                     }
1921//                     raw.0.push(bucket.to_string());
1922//                     Ok(())
1923//                 },
1924//             )
1925//         }
1926//     }
1927//     impl super::DeleteBucketHandler for RwLock<ListBucket> {
1928//         fn handle(
1929//             &self,
1930//             opt: &super::DeleteBucketOption,
1931//             bucket: &str,
1932//         ) -> Result<(), String> {
1933//             self.write().map_or(
1934//                 Err(Box::new(super::Error("write lock failed".to_string()))),
1935//                 |mut v| {
1936//                     let mut index = 0;
1937//                     let mut remove_index = -1;
1938//                     for vv in v.0.iter() {
1939//                         if vv == bucket {
1940//                             remove_index = index;
1941//                             break;
1942//                         }
1943//                         index += 1;
1944//                     }
1945//                     if remove_index >= 0 {
1946//                         v.0.remove(remove_index as usize);
1947//                     }
1948//                     Ok(())
1949//                 },
1950//             )
1951//         }
1952//     }
1953//     #[test]
1954//     fn create_bucket() {
1955//         let hm = HashMap::default();
1956//         let mut req = HttpRequest {
1957//             url_path: "/t10".to_string(),
1958//             query: vec![],
1959//             method: "PUT".to_string(),
1960//             headers: hm,
1961//         };
1962//         let mut resp = HttpResponse {
1963//             status: 0,
1964//             headers: HashMap::default(),
1965//             body: vec![],
1966//         };
1967//         let lb = ListBucket(vec![]);
1968//         let lb = RwLock::new(lb);
1969//         super::handle_create_bucket(&req, &mut resp, &lb);
1970//         assert!(
1971//             lb.read().expect("read lock error").0.len() == 1,
1972//             "create bucket failed {}",
1973//             resp.status
1974//         );
1975//         req.method = "DELETE".to_string();
1976//         resp = HttpResponse {
1977//             status: 0,
1978//             headers: HashMap::default(),
1979//             body: vec![],
1980//         };
1981//         super::handle_delete_bucket(&req, &mut resp, &lb);
1982//         assert!(
1983//             lb.read().unwrap().0.is_empty(),
1984//             "delete failed {}",
1985//             resp.status
1986//         );
1987//     }
1988//     impl super::LookupHandler for HashMap<String, String> {
1989//         fn lookup(
1990//             &self,
1991//             bucket: &str,
1992//             object: &str,
1993//         ) -> Result<Option<super::HeadObjectResult>, super::Error> {
1994//             let ret = self.get(object);
1995//             if let None = ret {
1996//                 return Ok(None);
1997//             }
1998//             let info = ret.unwrap();
1999//             Ok(Some(super::HeadObjectResult {
2000//                 content_length: Some(info.len()),
2001//                 content_type: Some("text/plain".to_string()),
2002//                 etag: Some(FAKE_ETAG.to_string()),
2003//                 last_modified: Some(chrono::Utc::now().to_rfc2822().to_string()),
2004//                 ..Default::default()
2005//             }))
2006//         }
2007//     }
2008//     impl super::GetObjectHandler for HashMap<String, String> {
2009//         fn handle(
2010//             &self,
2011//             bucket: &str,
2012//             object: &str,
2013//             mut out: impl FnMut(&[u8]) -> Result<(), String>,
2014//         ) -> Result<(), String> {
2015//             let ret = self.get(object);
2016//             if let None = ret {
2017//                 return Err(Box::new(super::Error("content not found".to_string())));
2018//             }
2019//             let info = ret.unwrap();
2020//             out(info.as_bytes())
2021//         }
2022//     }
2023
2024//     #[test]
2025//     fn get_object() {
2026//         let hm = HashMap::default();
2027//         let req = HttpRequest {
2028//             url_path: "/test/test.txt".to_string(),
2029//             query: vec![],
2030//             method: "GET".to_string(),
2031//             headers: hm,
2032//         };
2033//         let mut resp = HttpResponse::default();
2034//         let mut objstore = HashMap::default();
2035//         objstore.insert("test.txt".to_string(), "im test!".to_string());
2036//         super::handle_get_object(&req, &mut resp, &objstore);
2037//         assert!(
2038//             resp.status == 200,
2039//             "response status is not 200 {}",
2040//             resp.status
2041//         );
2042//         let val = String::from_utf8(resp.body).map_or("NoAscii".to_string(), |v| v);
2043//         assert!(
2044//             val == "im test!",
2045//             "response content is not 'im test!' got {}",
2046//             val
2047//         );
2048
2049//         let mut resp = HttpResponse::default();
2050//         let mut objstore = HashMap::default();
2051//         objstore.insert("hello.txt".to_string(), "im test!".to_string());
2052//         super::handle_get_object(&req, &mut resp, &objstore);
2053//         assert!(
2054//             resp.status == 404,
2055//             "response status is not 404 {}",
2056//             resp.status
2057//         );
2058//     }
2059//     #[test]
2060//     fn put_and_delete_object() {}
2061// }