s3/
bucket_ops.rs

1use crate::error::S3Error;
2use crate::{Bucket, Region};
3
4/// [AWS Documentation](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL)
5#[allow(dead_code)]
6#[derive(Clone, Debug)]
7enum CannedBucketAcl {
8    Private,
9    PublicRead,
10    PublicReadWrite,
11    AuthenticatedRead,
12}
13
14use http::header::HeaderName;
15use http::HeaderMap;
16use std::fmt;
17
18impl fmt::Display for CannedBucketAcl {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            CannedBucketAcl::Private => write!(f, "private"),
22            CannedBucketAcl::PublicRead => write!(f, "public-read"),
23            CannedBucketAcl::PublicReadWrite => write!(f, "public-read-write"),
24            CannedBucketAcl::AuthenticatedRead => write!(f, "authenticated-read"),
25        }
26    }
27}
28
29/// [AWS Documentation](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html)
30#[allow(dead_code)]
31#[derive(Clone, Debug)]
32enum BucketAcl {
33    Id { id: String },
34    Uri { uri: String },
35    Email { email: String },
36}
37
38impl fmt::Display for BucketAcl {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            BucketAcl::Id { id } => write!(f, "id=\"{}\"", id),
42            BucketAcl::Uri { uri } => write!(f, "uri=\"{}\"", uri),
43            BucketAcl::Email { email } => write!(f, "email=\"{}\"", email),
44        }
45    }
46}
47
48#[derive(Clone, Debug)]
49pub struct BucketConfiguration {
50    acl: CannedBucketAcl,
51    object_lock_enabled: bool,
52    grant_full_control: Option<Vec<BucketAcl>>,
53    grant_read: Option<Vec<BucketAcl>>,
54    grant_read_acp: Option<Vec<BucketAcl>>,
55    grant_write: Option<Vec<BucketAcl>>,
56    grant_write_acp: Option<Vec<BucketAcl>>,
57    location_constraint: Option<Region>,
58}
59
60impl Default for BucketConfiguration {
61    fn default() -> Self {
62        BucketConfiguration::private()
63    }
64}
65
66fn acl_list(acl: &[BucketAcl]) -> String {
67    acl.iter()
68        .map(|x| x.to_string())
69        .collect::<Vec<String>>()
70        .join(",")
71}
72
73impl BucketConfiguration {
74    pub fn public() -> Self {
75        BucketConfiguration {
76            acl: CannedBucketAcl::PublicReadWrite,
77            object_lock_enabled: false,
78            grant_full_control: None,
79            grant_read: None,
80            grant_read_acp: None,
81            grant_write: None,
82            grant_write_acp: None,
83            location_constraint: None,
84        }
85    }
86
87    pub fn private() -> Self {
88        BucketConfiguration {
89            acl: CannedBucketAcl::Private,
90            object_lock_enabled: false,
91            grant_full_control: None,
92            grant_read: None,
93            grant_read_acp: None,
94            grant_write: None,
95            grant_write_acp: None,
96            location_constraint: None,
97        }
98    }
99
100    pub fn set_region(&mut self, region: Region) {
101        self.set_location_constraint(region)
102    }
103
104    pub fn set_location_constraint(&mut self, region: Region) {
105        self.location_constraint = Some(region)
106    }
107
108    pub fn location_constraint_payload(&self) -> Option<String> {
109        if let Some(ref location_constraint) = self.location_constraint {
110            if location_constraint == &Region::UsEast1 {
111                return None;
112            }
113            Some(format!(
114                "<CreateBucketConfiguration><LocationConstraint>{}</LocationConstraint></CreateBucketConfiguration>",
115                location_constraint
116            ))
117        } else {
118            None
119        }
120    }
121
122    pub fn add_headers(&self, headers: &mut HeaderMap) -> Result<(), S3Error> {
123        headers.insert(
124            HeaderName::from_static("x-amz-acl"),
125            self.acl.to_string().parse()?,
126        );
127        if self.object_lock_enabled {
128            headers.insert(
129                HeaderName::from_static("x-amz-bucket-object-lock-enabled"),
130                "Enabled".to_string().parse()?,
131            );
132        }
133        if let Some(ref value) = self.grant_full_control {
134            headers.insert(
135                HeaderName::from_static("x-amz-grant-full-control"),
136                acl_list(value).parse()?,
137            );
138        }
139        if let Some(ref value) = self.grant_read {
140            headers.insert(
141                HeaderName::from_static("x-amz-grant-read"),
142                acl_list(value).parse()?,
143            );
144        }
145        if let Some(ref value) = self.grant_read_acp {
146            headers.insert(
147                HeaderName::from_static("x-amz-grant-read-acp"),
148                acl_list(value).parse()?,
149            );
150        }
151        if let Some(ref value) = self.grant_write {
152            headers.insert(
153                HeaderName::from_static("x-amz-grant-write"),
154                acl_list(value).parse()?,
155            );
156        }
157        if let Some(ref value) = self.grant_write_acp {
158            headers.insert(
159                HeaderName::from_static("x-amz-grant-write-acp"),
160                acl_list(value).parse()?,
161            );
162        }
163        Ok(())
164    }
165}
166
167#[allow(dead_code)]
168pub struct CreateBucketResponse {
169    pub bucket: Bucket,
170    pub response_text: String,
171    pub response_code: u16,
172}
173
174impl CreateBucketResponse {
175    pub fn success(&self) -> bool {
176        self.response_code == 200
177    }
178}