1mod presign;
2use crate::error::S3Error;
3use awscreds::Credentials;
4use awsregion::Region;
5use http::HeaderMap;
6use std::collections::HashMap;
7use std::sync::{Arc, RwLock};
8use std::time::Duration;
9
10pub use std::io::Read;
11
12pub use presign::*;
13
14mod credentials;
15pub use credentials::*;
16
17mod tag;
18pub use tag::*;
19
20mod create;
21pub use create::*;
22
23mod list;
24pub use list::*;
25
26mod delete;
27pub use delete::*;
28
29mod copy;
30pub use copy::*;
31
32mod get;
33pub use get::*;
34
35mod put;
36pub use put::*;
37
38mod head;
39pub use head::*;
40
41mod utils;
42pub use utils::*;
43
44pub type Query = HashMap<String, String>;
45
46pub use crate::serde_types::{
47 BucketLocationResult, CompleteMultipartUploadData, CorsConfiguration, HeadObjectResult,
48 InitiateMultipartUploadResponse, ListBucketResult, ListMultipartUploadsResult, Part,
49};
50pub(crate) use crate::utils::error_from_response_data;
51pub use crate::utils::PutStreamResponse;
52
53pub use crate::request::Request;
54
55pub const CHUNK_SIZE: usize = 8_388_608; #[derive(Clone, Debug)]
72pub struct Bucket {
73 pub name: String,
74 pub region: Region,
75 pub credentials: Arc<RwLock<Credentials>>,
76 pub extra_headers: HeaderMap,
77 pub extra_query: Query,
78 pub request_timeout: Option<Duration>,
79 path_style: bool,
80 listobjects_v2: bool,
81}
82
83const DEFAULT_REQUEST_TIMEOUT: Option<Duration> = Some(Duration::from_secs(60));
84
85fn validate_expiry(expiry_secs: u32) -> Result<(), S3Error> {
86 if 604800 < expiry_secs {
87 return Err(S3Error::MaxExpiry(expiry_secs));
88 }
89 Ok(())
90}
91
92impl Bucket {
93 pub fn with_path_style(&self) -> Self {
94 Self {
95 name: self.name.clone(),
96 region: self.region.clone(),
97 credentials: self.credentials.clone(),
98 extra_headers: self.extra_headers.clone(),
99 extra_query: self.extra_query.clone(),
100 request_timeout: self.request_timeout,
101 path_style: true,
102 listobjects_v2: self.listobjects_v2,
103 }
104 }
105
106 pub fn with_extra_headers(&self, extra_headers: HeaderMap) -> Self {
107 Self {
108 name: self.name.clone(),
109 region: self.region.clone(),
110 credentials: self.credentials.clone(),
111 extra_headers,
112 extra_query: self.extra_query.clone(),
113 request_timeout: self.request_timeout,
114 path_style: self.path_style,
115 listobjects_v2: self.listobjects_v2,
116 }
117 }
118
119 pub fn with_extra_query(&self, extra_query: HashMap<String, String>) -> Self {
120 Self {
121 name: self.name.clone(),
122 region: self.region.clone(),
123 credentials: self.credentials.clone(),
124 extra_headers: self.extra_headers.clone(),
125 extra_query,
126 request_timeout: self.request_timeout,
127 path_style: self.path_style,
128 listobjects_v2: self.listobjects_v2,
129 }
130 }
131
132 pub fn with_request_timeout(&self, request_timeout: Duration) -> Self {
133 Self {
134 name: self.name.clone(),
135 region: self.region.clone(),
136 credentials: self.credentials.clone(),
137 extra_headers: self.extra_headers.clone(),
138 extra_query: self.extra_query.clone(),
139 request_timeout: Some(request_timeout),
140 path_style: self.path_style,
141 listobjects_v2: self.listobjects_v2,
142 }
143 }
144
145 pub fn with_listobjects_v1(&self) -> Self {
146 Self {
147 name: self.name.clone(),
148 region: self.region.clone(),
149 credentials: self.credentials.clone(),
150 extra_headers: self.extra_headers.clone(),
151 extra_query: self.extra_query.clone(),
152 request_timeout: self.request_timeout,
153 path_style: self.path_style,
154 listobjects_v2: false,
155 }
156 }
157
158 pub(crate) fn _tags_xml<S: AsRef<str>>(&self, tags: &[(S, S)]) -> String {
159 let mut s = String::new();
160 let content = tags
161 .iter()
162 .map(|(name, value)| {
163 format!(
164 "<Tag><Key>{}</Key><Value>{}</Value></Tag>",
165 name.as_ref(),
166 value.as_ref()
167 )
168 })
169 .fold(String::new(), |mut a, b| {
170 a.push_str(b.as_str());
171 a
172 });
173 s.push_str("<Tagging><TagSet>");
174 s.push_str(&content);
175 s.push_str("</TagSet></Tagging>");
176 s
177 }
178}