s3/bucket/utils.rs
1use std::str::FromStr;
2
3use http::HeaderName;
4
5use crate::bucket::*;
6use crate::command::Command;
7use crate::request::RequestImpl;
8
9impl Bucket {
10 /// Get path_style field of the Bucket struct
11 pub fn is_path_style(&self) -> bool {
12 self.path_style
13 }
14
15 /// Get negated path_style field of the Bucket struct
16 pub fn is_subdomain_style(&self) -> bool {
17 !self.path_style
18 }
19
20 /// Configure bucket to use path-style urls and headers
21 pub fn set_path_style(&mut self) {
22 self.path_style = true;
23 }
24
25 /// Configure bucket to use subdomain style urls and headers \[default\]
26 pub fn set_subdomain_style(&mut self) {
27 self.path_style = false;
28 }
29
30 /// Configure bucket to apply this request timeout to all HTTP
31 /// requests, or no (infinity) timeout if `None`. Defaults to
32 /// 30 seconds.
33 ///
34 /// Only the [`hyper`] backend obeys this option;
35 /// async code may instead await with a timeout.
36 pub fn set_request_timeout(&mut self, timeout: Option<Duration>) {
37 self.request_timeout = timeout;
38 }
39
40 /// Configure bucket to use the older ListObjects API
41 ///
42 /// If your provider doesn't support the ListObjectsV2 interface, set this to
43 /// use the v1 ListObjects interface instead. This is currently needed at least
44 /// for Google Cloud Storage.
45 pub fn set_listobjects_v1(&mut self) {
46 self.listobjects_v2 = false;
47 }
48
49 /// Configure bucket to use the newer ListObjectsV2 API
50 pub fn set_listobjects_v2(&mut self) {
51 self.listobjects_v2 = true;
52 }
53
54 /// Get a reference to the name of the S3 bucket.
55 pub fn name(&self) -> String {
56 self.name.to_string()
57 }
58
59 // Get a reference to the hostname of the S3 API endpoint.
60 pub fn host(&self) -> String {
61 if self.path_style {
62 self.path_style_host()
63 } else {
64 self.subdomain_style_host()
65 }
66 }
67
68 pub fn url(&self) -> String {
69 if self.path_style {
70 format!(
71 "{}://{}/{}",
72 self.scheme(),
73 self.path_style_host(),
74 self.name()
75 )
76 } else {
77 format!("{}://{}", self.scheme(), self.subdomain_style_host())
78 }
79 }
80
81 /// Get a paths-style reference to the hostname of the S3 API endpoint.
82 pub fn path_style_host(&self) -> String {
83 self.region.host()
84 }
85
86 pub fn subdomain_style_host(&self) -> String {
87 format!("{}.{}", self.name, self.region.host())
88 }
89
90 // pub fn self_host(&self) -> String {
91 // format!("{}.{}", self.name, self.region.host())
92 // }
93
94 pub fn scheme(&self) -> String {
95 self.region.scheme()
96 }
97
98 /// Get the region this object will connect to.
99 pub fn region(&self) -> Region {
100 self.region.clone()
101 }
102
103 /// Get a reference to the AWS access key.
104 pub fn access_key(&self) -> Result<Option<String>, S3Error> {
105 Ok(self
106 .credentials()
107 .try_read()
108 .map_err(|_| S3Error::RLCredentials)?
109 .access_key
110 .clone()
111 .map(|key| key.replace('\n', "")))
112 }
113
114 /// Get a reference to the AWS secret key.
115 pub fn secret_key(&self) -> Result<Option<String>, S3Error> {
116 Ok(self
117 .credentials()
118 .try_read()
119 .map_err(|_| S3Error::RLCredentials)?
120 .secret_key
121 .clone()
122 .map(|key| key.replace('\n', "")))
123 }
124
125 /// Get a reference to the AWS security token.
126 pub fn security_token(&self) -> Result<Option<String>, S3Error> {
127 Ok(self
128 .credentials()
129 .try_read()
130 .map_err(|_| S3Error::RLCredentials)?
131 .security_token
132 .clone())
133 }
134
135 /// Get a reference to the AWS session token.
136 pub fn session_token(&self) -> Result<Option<String>, S3Error> {
137 Ok(self
138 .credentials()
139 .try_read()
140 .map_err(|_| S3Error::RLCredentials)?
141 .session_token
142 .clone())
143 }
144
145 /// Get a reference to the full [`Credentials`](struct.Credentials.html)
146 /// object used by this `Bucket`.
147 pub fn credentials(&self) -> Arc<RwLock<Credentials>> {
148 self.credentials.clone()
149 }
150
151 /// Change the credentials used by the Bucket.
152 pub fn set_credentials(&mut self, credentials: Credentials) {
153 self.credentials = Arc::new(RwLock::new(credentials));
154 }
155
156 /// Add an extra header to send with requests to S3.
157 ///
158 /// Add an extra header to send with requests. Note that the library
159 /// already sets a number of headers - headers set with this method will be
160 /// overridden by the library headers:
161 /// * Host
162 /// * Content-Type
163 /// * Date
164 /// * Content-Length
165 /// * Authorization
166 /// * X-Amz-Content-Sha256
167 /// * X-Amz-Date
168 pub fn add_header(&mut self, key: &str, value: &str) {
169 self.extra_headers
170 .insert(HeaderName::from_str(key).unwrap(), value.parse().unwrap());
171 }
172
173 /// Get a reference to the extra headers to be passed to the S3 API.
174 pub fn extra_headers(&self) -> &HeaderMap {
175 &self.extra_headers
176 }
177
178 /// Get a mutable reference to the extra headers to be passed to the S3
179 /// API.
180 pub fn extra_headers_mut(&mut self) -> &mut HeaderMap {
181 &mut self.extra_headers
182 }
183
184 /// Add an extra query pair to the URL used for S3 API access.
185 pub fn add_query(&mut self, key: &str, value: &str) {
186 self.extra_query.insert(key.into(), value.into());
187 }
188
189 /// Get a reference to the extra query pairs to be passed to the S3 API.
190 pub fn extra_query(&self) -> &Query {
191 &self.extra_query
192 }
193
194 /// Get a mutable reference to the extra query pairs to be passed to the S3
195 /// API.
196 pub fn extra_query_mut(&mut self) -> &mut Query {
197 &mut self.extra_query
198 }
199
200 pub fn request_timeout(&self) -> Option<Duration> {
201 self.request_timeout
202 }
203
204 /// Get Bucket location.
205 ///
206 /// # Example:
207 ///
208 /// ```no_run
209 /// use s3::bucket::Bucket;
210 /// use s3::creds::Credentials;
211 /// use anyhow::Result;
212 ///
213 /// # #[tokio::main]
214 /// # async fn main() -> Result<()> {
215 ///
216 /// let bucket_name = "rust-s3-test";
217 /// let region = "us-east-1".parse()?;
218 /// let credentials = Credentials::default()?;
219 /// let bucket = Bucket::new(bucket_name, region, credentials)?;
220 ///
221 /// let (region, status_code) = bucket.location().await?;
222 /// #
223 /// # Ok(())
224 /// # }
225 /// ```
226 pub async fn location(&self) -> Result<(Region, u16), S3Error> {
227 let request = RequestImpl::new(self, "?location", Command::GetBucketLocation)?;
228 let response_data = request.response_data(false).await?;
229 let region_string = String::from_utf8_lossy(response_data.as_slice());
230 let region = match quick_xml::de::from_reader(region_string.as_bytes()) {
231 Ok(r) => {
232 let location_result: BucketLocationResult = r;
233 location_result.region.parse()?
234 }
235 Err(e) => {
236 if response_data.status_code() == 200 {
237 Region::Custom {
238 region: "Custom".to_string(),
239 endpoint: "".to_string(),
240 }
241 } else {
242 Region::Custom {
243 region: format!("Error encountered : {}", e),
244 endpoint: "".to_string(),
245 }
246 }
247 }
248 };
249 Ok((region, response_data.status_code()))
250 }
251}