This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 099458fba feat(services/s3): Add detect_region support for S3Builder
(#2634)
099458fba is described below
commit 099458fbaf2e878f8f7fd3a1a12e31b6fb2ab720
Author: parkma99 <[email protected]>
AuthorDate: Fri Jul 14 20:46:36 2023 +0800
feat(services/s3): Add detect_region support for S3Builder (#2634)
* add detect_region code
* update by tips
* update
---
core/src/services/s3/backend.rs | 69 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/core/src/services/s3/backend.rs b/core/src/services/s3/backend.rs
index cade3c53f..236781794 100644
--- a/core/src/services/s3/backend.rs
+++ b/core/src/services/s3/backend.rs
@@ -517,6 +517,69 @@ impl S3Builder {
self
}
+
+ /// a helper function to make it easier to find region
+ /// Reference: [Amazon S3 HeadBucket
API](https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_HeadBucket.html)
+ /// # Args
+ ///
+ /// endpoint: the endpoint of S3 service
+ ///
+ /// bucket: the bucket of S3 service
+ /// # Return
+ /// if get the region of given inputs, return Some(region)
+ /// else return None
+ ///
+ /// # Usage
+ /// let b = S3Builder::default();
+ /// let region = b.detect_region("https://s3.amazonaws.com",
"buckets").await;
+ pub async fn detect_region(&self, endpoint: &str, bucket: &str) ->
Option<String> {
+ let mut endpoint = if endpoint.starts_with("http") {
+ endpoint.to_string()
+ } else {
+ // Prefix https if endpoint doesn't start with scheme.
+ format!("https://{}", endpoint)
+ };
+
+ endpoint = endpoint.replace(&format!("//{0}.", bucket), "//");
+ let url = format!("{0}/{1}", endpoint, bucket);
+
+ debug!("backend detect region with url: {url}");
+
+ let req = match http::Request::head(&url).body(AsyncBody::Empty) {
+ Ok(reg) => reg,
+ Err(_) => return None,
+ };
+
+ let client = match HttpClient::new() {
+ Ok(client) => client,
+ Err(_) => return None,
+ };
+ let res = match client.send(req).await {
+ Ok(res) => res,
+ Err(_) => return None,
+ };
+
+ debug!(
+ "auto detect region got response: status {:?}, header: {:?}",
+ res.status(),
+ res.headers()
+ );
+
+ match res.status() {
+ // The endpoint works, return with not changed endpoint and
+ // default region.
+ StatusCode::OK | StatusCode::FORBIDDEN |
StatusCode::MOVED_PERMANENTLY => {
+ let region =
res.headers().get("x-amz-bucket-region").unwrap().to_str();
+ if let Ok(regin) = region {
+ Some(regin.to_string())
+ } else {
+ None
+ }
+ }
+ // Unexpected status code
+ _ => None,
+ }
+ }
}
impl Builder for S3Builder {
@@ -1049,4 +1112,10 @@ mod tests {
assert_eq!(endpoint, "https://test.s3.us-east-2.amazonaws.com");
}
}
+ #[tokio::test]
+ async fn test_detect_region() {
+ let b = S3Builder::default();
+ let region = b.detect_region("https://s3.amazonaws.com",
"buckets").await;
+ assert_eq!(region, Some("us-east-1".to_string()))
+ }
}