Add FromStr instance to BaseURL (#51)

This commit is contained in:
Aditya Manthramurthy 2023-09-26 18:18:07 -07:00 committed by GitHub
parent e5f6b16051
commit 4958c01f4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 151 deletions

View File

@ -5,64 +5,9 @@ MinIO Rust SDK is Simple Storage Service (aka S3) client to perform bucket and o
For a complete list of APIs and examples, please take a look at the [MinIO Rust Client API Reference](https://minio-rs.min.io/)
## Example:: file-uploader.rs
```rust
use minio::s3::args::{BucketExistsArgs, MakeBucketArgs, UploadObjectArgs};
use minio::s3::client::Client;
use minio::s3::creds::StaticProvider;
use minio::s3::http::BaseUrl;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let base_url = BaseUrl::from_string("https://play.min.io".to_string()).unwrap();
[Upload a file to MinIO](examples/file-uploader.rs)
let static_provider = StaticProvider::new(
"Q3AM3UQ867SPQQA43P2F",
"zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG",
None,
);
let client = Client::new(
base_url.clone(),
Some(Box::new(static_provider)),
None,
None,
)
.unwrap();
let bucket_name = "asiatrip";
// Check 'asiatrip' bucket exist or not.
let exists = client
.bucket_exists(&BucketExistsArgs::new(&bucket_name).unwrap())
.await
.unwrap();
// Make 'asiatrip' bucket if not exist.
if !exists {
client
.make_bucket(&MakeBucketArgs::new(&bucket_name).unwrap())
.await
.unwrap();
}
// Upload '/home/user/Photos/asiaphotos.zip' as object name
// 'asiaphotos-2015.zip' to bucket 'asiatrip'.
client
.upload_object(
&mut UploadObjectArgs::new(
&bucket_name,
"asiaphotos-2015.zip",
"/home/user/Photos/asiaphotos.zip",
)
.unwrap(),
)
.await
.unwrap();
println!("'/home/user/Photos/asiaphotos.zip' is successfully uploaded as object 'asiaphotos-2015.zip' to bucket 'asiatrip'.");
Ok(())
}
```
## License
This SDK is distributed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0), see [LICENSE](https://github.com/minio/minio-rs/blob/master/LICENSE) for more information.

View File

@ -5,7 +5,7 @@ use minio::s3::http::BaseUrl;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let base_url = BaseUrl::from_string("https://play.min.io".to_string()).unwrap();
let base_url = "https://play.min.io".parse::<BaseUrl>()?;
let static_provider = StaticProvider::new(
"Q3AM3UQ867SPQQA43P2F",

View File

@ -224,7 +224,7 @@ impl Client {
/// use minio::s3::client::Client;
/// use minio::s3::creds::StaticProvider;
/// use minio::s3::http::BaseUrl;
/// let mut base_url = BaseUrl::from_string("play.min.io".to_string()).unwrap();
/// let mut base_url: BaseUrl = "play.min.io".parse().unwrap();
/// let static_provider = StaticProvider::new(
/// "Q3AM3UQ867SPQQA43P2F",
/// "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG",

View File

@ -24,6 +24,7 @@ use hyper::Uri;
use lazy_static::lazy_static;
use regex::Regex;
use std::fmt;
use std::str::FromStr;
const AWS_S3_PREFIX: &str = r"^(((bucket\.|accesspoint\.)vpce(-[a-z_\d]+)+\.s3\.)|([a-z_\d-]{1,63}\.)s3-control(-[a-z_\d]+)*\.|(s3(-[a-z_\d]+)*\.))";
@ -217,6 +218,107 @@ pub struct BaseUrl {
pub virtual_style: bool,
}
impl FromStr for BaseUrl {
type Err = Error;
/// Convert a string to a BaseUrl.
///
/// Enables use of [`str`]'s [`parse`] method to create a [`BaseUrl`].
///
/// # Examples
///
/// ```
/// use minio::s3::http::BaseUrl;
/// use std::str::FromStr;
///
/// // Get base URL from host name
/// let base_url = "play.min.io".parse::<BaseUrl>().unwrap();
/// let base_url = BaseUrl::from_str("play.min.io").unwrap();
/// // Get base URL from host:port
/// let base_url: BaseUrl = "play.minio.io:9000".parse().unwrap();
/// // Get base URL from IPv4 address
/// let base_url: BaseUrl = "http://192.168.124.63:9000".parse().unwrap();
/// // Get base URL from IPv6 address
/// let base_url: BaseUrl = "[0:0:0:0:0:ffff:c0a8:7c3f]:9000".parse().unwrap();
/// ```
fn from_str(s: &str) -> Result<Self, Self::Err> {
let url = s.parse::<Uri>()?;
let https = match url.scheme() {
None => true,
Some(scheme) => match scheme.as_str() {
"http" => false,
"https" => true,
_ => {
return Err(Error::InvalidBaseUrl(String::from(
"scheme must be http or https",
)))
}
},
};
let mut host = match url.host() {
Some(h) => h,
_ => {
return Err(Error::InvalidBaseUrl(String::from(
"valid host must be provided",
)))
}
};
let ipv6host = "[".to_string() + host + "]";
if host.parse::<std::net::Ipv6Addr>().is_ok() {
host = &ipv6host;
}
let mut port = match url.port() {
Some(p) => p.as_u16(),
_ => 0u16,
};
if (https && port == 443) || (!https && port == 80) {
port = 0u16;
}
if url.path() != "/" && url.path() != "" {
return Err(Error::InvalidBaseUrl(String::from(
"path must be empty for base URL",
)));
}
if url.query().is_some() {
return Err(Error::InvalidBaseUrl(String::from(
"query must be none for base URL",
)));
}
let mut region = String::new();
let mut aws_s3_prefix = String::new();
let mut aws_domain_suffix = String::new();
let mut dualstack: bool = false;
get_aws_info(
&host.to_string(),
https,
&mut region,
&mut aws_s3_prefix,
&mut aws_domain_suffix,
&mut dualstack,
)?;
let virtual_style = !aws_domain_suffix.is_empty() || host.ends_with("aliyuncs.com");
Ok(BaseUrl {
https,
host: host.to_string(),
port,
region,
aws_s3_prefix,
aws_domain_suffix,
dualstack,
virtual_style,
})
}
}
impl BaseUrl {
/// Checks base URL is AWS host
pub fn is_aws_host(&self) -> bool {
@ -363,96 +465,4 @@ impl BaseUrl {
Ok(url)
}
/// Returns a base URL from given host string
///
/// # Examples
///
/// ```
/// use minio::s3::http::BaseUrl;
/// // Get base URL from host name
/// let base_url = BaseUrl::from_string("play.min.io".to_string()).unwrap();
/// // Get base URL from host:port
/// let base_url = BaseUrl::from_string("play.minio.io:9000".to_string()).unwrap();
/// // Get base URL from IPv4 address
/// let base_url = BaseUrl::from_string("http://192.168.124.63:9000".to_string()).unwrap();
/// // Get base URL from IPv6 address
/// let base_url = BaseUrl::from_string("[0:0:0:0:0:ffff:c0a8:7c3f]:9000".to_string()).unwrap();
/// ```
pub fn from_string(s: String) -> Result<BaseUrl, Error> {
let url = s.parse::<Uri>()?;
let https = match url.scheme() {
None => true,
Some(scheme) => match scheme.as_str() {
"http" => false,
"https" => true,
_ => {
return Err(Error::InvalidBaseUrl(String::from(
"scheme must be http or https",
)))
}
},
};
let mut host = match url.host() {
Some(h) => h,
_ => {
return Err(Error::InvalidBaseUrl(String::from(
"valid host must be provided",
)))
}
};
let ipv6host = "[".to_string() + host + "]";
if host.parse::<std::net::Ipv6Addr>().is_ok() {
host = &ipv6host;
}
let mut port = match url.port() {
Some(p) => p.as_u16(),
_ => 0u16,
};
if (https && port == 443) || (!https && port == 80) {
port = 0u16;
}
if url.path() != "/" && url.path() != "" {
return Err(Error::InvalidBaseUrl(String::from(
"path must be empty for base URL",
)));
}
if url.query().is_some() {
return Err(Error::InvalidBaseUrl(String::from(
"query must be none for base URL",
)));
}
let mut region = String::new();
let mut aws_s3_prefix = String::new();
let mut aws_domain_suffix = String::new();
let mut dualstack: bool = false;
get_aws_info(
&host.to_string(),
https,
&mut region,
&mut aws_s3_prefix,
&mut aws_domain_suffix,
&mut dualstack,
)?;
let virtual_style = !aws_domain_suffix.is_empty() || host.ends_with("aliyuncs.com");
Ok(BaseUrl {
https,
host: host.to_string(),
port,
region,
aws_s3_prefix,
aws_domain_suffix,
dualstack,
virtual_style,
})
}
}

View File

@ -1155,7 +1155,7 @@ async fn s3_tests() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let ignore_cert_check = std::env::var("IGNORE_CERT_CHECK").is_ok();
let region = std::env::var("SERVER_REGION").ok();
let mut base_url = BaseUrl::from_string(host).unwrap();
let mut base_url: BaseUrl = host.parse().unwrap();
base_url.https = secure;
if let Some(v) = region {
base_url.region = v;