s3/
bucket_ops.rs

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