use std::{
borrow::Cow,
error::Error,
fmt::{self, Debug, Display, Formatter},
str::FromStr,
};
use chrono::{DateTime, TimeZone};
use http::header::{HeaderValue, InvalidHeaderValue, ToStrError};
use url::Url;
#[cfg(feature = "core")]
pub mod core;
pub mod object;
#[cfg(test)]
mod test;
use crate::consts::{TRUE1, TRUE2, TRUE3, TRUE4};
#[cfg(feature = "core")]
pub use self::core::{ContentRange, Query, QueryKey, QueryValue, SetOssQuery};
use self::object::{ObjectPathInner, SetObjectPath};
const OSS_DOMAIN_PREFIX: &str = "https://oss-";
#[allow(dead_code)]
const OSS_INTERNAL: &str = "-internal";
const OSS_DOMAIN_MAIN: &str = ".aliyuncs.com";
const OSS_HYPHEN: &str = "oss-";
const HANGZHOU: &str = "cn-hangzhou";
const SHANGHAI: &str = "cn-shanghai";
const QINGDAO: &str = "cn-qingdao";
const BEIJING: &str = "cn-beijing";
const ZHANGJIAKOU: &str = "cn-zhangjiakou";
const HONGKONG: &str = "cn-hongkong";
const SHENZHEN: &str = "cn-shenzhen";
const US_WEST1: &str = "us-west-1";
const US_EAST1: &str = "us-east-1";
const AP_SOUTH_EAST1: &str = "ap-southeast-1";
const HANGZHOU_L: &str = "hangzhou";
const SHANGHAI_L: &str = "shanghai";
const QINGDAO_L: &str = "qingdao";
const BEIJING_L: &str = "beijing";
const ZHANGJIAKOU_L: &str = "zhangjiakou";
const HONGKONG_L: &str = "hongkong";
const SHENZHEN_L: &str = "shenzhen";
const COM: &str = "com";
const ALIYUNCS: &str = "aliyuncs";
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct InnerKeyId<'a>(Cow<'a, str>);
pub type KeyId = InnerKeyId<'static>;
impl AsRef<str> for InnerKeyId<'_> {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Display for InnerKeyId<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl TryInto<HeaderValue> for InnerKeyId<'_> {
type Error = InvalidHeaderValue;
fn try_into(self) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::from_str(self.as_ref())
}
}
impl From<String> for KeyId {
fn from(s: String) -> KeyId {
Self(Cow::Owned(s))
}
}
impl<'a: 'b, 'b> From<&'a str> for InnerKeyId<'b> {
fn from(key_id: &'a str) -> Self {
Self(Cow::Borrowed(key_id))
}
}
impl<'a> InnerKeyId<'a> {
pub fn new(key_id: impl Into<Cow<'a, str>>) -> Self {
Self(key_id.into())
}
pub const fn from_static(key_id: &'static str) -> Self {
Self(Cow::Borrowed(key_id))
}
}
#[derive(Clone, PartialEq, Eq, Default)]
pub struct InnerKeySecret<'a>(Cow<'a, str>);
pub type KeySecret = InnerKeySecret<'static>;
impl Display for InnerKeySecret<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "******secret******")
}
}
impl Debug for InnerKeySecret<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("KeySecret").finish()
}
}
impl From<String> for KeySecret {
fn from(s: String) -> Self {
Self(Cow::Owned(s))
}
}
impl<'a: 'b, 'b> From<&'a str> for InnerKeySecret<'b> {
fn from(secret: &'a str) -> Self {
Self(Cow::Borrowed(secret))
}
}
impl<'a> InnerKeySecret<'a> {
pub fn new(secret: impl Into<Cow<'a, str>>) -> Self {
Self(secret.into())
}
pub const fn from_static(secret: &'static str) -> Self {
Self(Cow::Borrowed(secret))
}
#[cfg(test)]
pub(crate) fn as_str(&self) -> &str {
&self.0
}
#[inline]
pub fn encryption_string(
&self,
string: String,
) -> Result<String, hmac::digest::crypto_common::InvalidLength> {
self.encryption(string.as_bytes())
}
pub fn encryption(
&self,
data: &[u8],
) -> Result<String, hmac::digest::crypto_common::InvalidLength> {
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use hmac::{Hmac, Mac};
use sha1::Sha1;
type HmacSha1 = Hmac<Sha1>;
let secret = self.0.as_bytes();
let mut mac = HmacSha1::new_from_slice(secret)?;
mac.update(data);
let sha1 = mac.finalize().into_bytes();
Ok(STANDARD.encode(sha1))
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct EndPoint {
pub(crate) kind: EndPointKind,
pub(crate) is_internal: bool,
}
#[allow(non_upper_case_globals)]
impl EndPoint {
#[deprecated(since = "0.13.0", note = "replace with EndPoint::CN_HANGZHOU")]
pub const CnHangzhou: Self = Self {
kind: EndPointKind::CnHangzhou,
is_internal: false,
};
pub const CN_HANGZHOU: Self = Self {
kind: EndPointKind::CnHangzhou,
is_internal: false,
};
#[deprecated(since = "0.13.0", note = "replace with EndPoint::CN_SHANGHAI")]
pub const CnShanghai: Self = Self {
kind: EndPointKind::CnShanghai,
is_internal: false,
};
pub const CN_SHANGHAI: Self = Self {
kind: EndPointKind::CnShanghai,
is_internal: false,
};
#[deprecated(since = "0.13.0", note = "replace with EndPoint::CN_QINGDAO")]
pub const CnQingdao: Self = Self {
kind: EndPointKind::CnQingdao,
is_internal: false,
};
pub const CN_QINGDAO: Self = Self {
kind: EndPointKind::CnQingdao,
is_internal: false,
};
#[deprecated(since = "0.13.0", note = "replace with EndPoint::CN_BEIJING")]
pub const CnBeijing: Self = Self {
kind: EndPointKind::CnBeijing,
is_internal: false,
};
pub const CN_BEIJING: Self = Self {
kind: EndPointKind::CnBeijing,
is_internal: false,
};
#[deprecated(since = "0.13.0", note = "replace with EndPoint::CN_ZHANGJIAKOU")]
pub const CnZhangjiakou: Self = Self {
kind: EndPointKind::CnZhangjiakou,
is_internal: false,
};
pub const CN_ZHANGJIAKOU: Self = Self {
kind: EndPointKind::CnZhangjiakou,
is_internal: false,
};
#[deprecated(since = "0.13.0", note = "replace with EndPoint::CN_HONGKONG")]
pub const CnHongkong: Self = Self {
kind: EndPointKind::CnHongkong,
is_internal: false,
};
pub const CN_HONGKONG: Self = Self {
kind: EndPointKind::CnHongkong,
is_internal: false,
};
#[deprecated(since = "0.13.0", note = "replace with EndPoint::CN_SHENZHEN")]
pub const CnShenzhen: Self = Self {
kind: EndPointKind::CnShenzhen,
is_internal: false,
};
pub const CN_SHENZHEN: Self = Self {
kind: EndPointKind::CnShenzhen,
is_internal: false,
};
#[deprecated(since = "0.13.0", note = "replace with EndPoint::US_WEST_1")]
pub const UsWest1: Self = Self {
kind: EndPointKind::UsWest1,
is_internal: false,
};
pub const US_WEST_1: Self = Self {
kind: EndPointKind::UsWest1,
is_internal: false,
};
#[deprecated(since = "0.13.0", note = "replace with EndPoint::US_EAST_1")]
pub const UsEast1: Self = Self {
kind: EndPointKind::UsEast1,
is_internal: false,
};
pub const US_EAST_1: Self = Self {
kind: EndPointKind::UsEast1,
is_internal: false,
};
#[deprecated(since = "0.13.0", note = "replace with EndPoint::AP_SOUTH_EAST_1")]
pub const ApSouthEast1: Self = Self {
kind: EndPointKind::ApSouthEast1,
is_internal: false,
};
pub const AP_SOUTH_EAST_1: Self = Self {
kind: EndPointKind::ApSouthEast1,
is_internal: false,
};
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
#[non_exhaustive]
pub(crate) enum EndPointKind {
#[default]
CnHangzhou,
CnShanghai,
CnQingdao,
CnBeijing,
CnZhangjiakou, CnHongkong,
CnShenzhen,
UsWest1,
UsEast1,
ApSouthEast1,
Other(Cow<'static, str>),
}
impl AsRef<str> for EndPoint {
fn as_ref(&self) -> &str {
use EndPointKind::*;
match &self.kind {
CnHangzhou => HANGZHOU,
CnShanghai => SHANGHAI,
CnQingdao => QINGDAO,
CnBeijing => BEIJING,
CnZhangjiakou => ZHANGJIAKOU,
CnHongkong => HONGKONG,
CnShenzhen => SHENZHEN,
UsWest1 => US_WEST1,
UsEast1 => US_EAST1,
ApSouthEast1 => AP_SOUTH_EAST1,
Other(str) => str,
}
}
}
impl Display for EndPoint {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_ref())
}
}
impl TryFrom<String> for EndPoint {
type Error = InvalidEndPoint;
fn try_from(url: String) -> Result<Self, Self::Error> {
Self::new(&url)
}
}
impl<'a> TryFrom<&'a str> for EndPoint {
type Error = InvalidEndPoint;
fn try_from(url: &'a str) -> Result<Self, Self::Error> {
Self::new(url)
}
}
impl FromStr for EndPoint {
type Err = InvalidEndPoint;
fn from_str(url: &str) -> Result<Self, Self::Err> {
Self::new(url)
}
}
impl TryFrom<Url> for EndPoint {
type Error = InvalidEndPoint;
fn try_from(url: Url) -> Result<Self, Self::Error> {
use url::Host;
let domain = if let Some(Host::Domain(domain)) = url.host() {
domain
} else {
return Err(InvalidEndPoint { _priv: () });
};
let mut url_pieces = domain.rsplit('.');
match (url_pieces.next(), url_pieces.next()) {
(Some(COM), Some(ALIYUNCS)) => (),
_ => return Err(InvalidEndPoint { _priv: () }),
}
match url_pieces.next() {
Some(endpoint) => match EndPoint::from_host_piece(endpoint) {
Ok(end) => Ok(end),
_ => Err(InvalidEndPoint { _priv: () }),
},
_ => Err(InvalidEndPoint { _priv: () }),
}
}
}
impl<'a> EndPoint {
pub fn from_static(url: &'a str) -> Self {
Self::new(url).unwrap_or_else(|_| panic!("Unknown Endpoint :{}", url))
}
pub const unsafe fn from_static2(url: &'static str) -> Self {
Self {
kind: EndPointKind::Other(Cow::Borrowed(url)),
is_internal: false,
}
}
pub fn new(url: &'a str) -> Result<Self, InvalidEndPoint> {
const OSS_STR: &str = "oss";
use EndPointKind::*;
if url.is_empty() {
return Err(InvalidEndPoint { _priv: () });
}
let is_internal = url.ends_with(OSS_INTERNAL);
let url = if is_internal {
let len = url.len();
&url[..len - 9]
} else {
url
};
let kind = if url.contains(SHANGHAI_L) {
Ok(CnShanghai)
} else if url.contains(HANGZHOU_L) {
Ok(CnHangzhou)
} else if url.contains(QINGDAO_L) {
Ok(CnQingdao)
} else if url.contains(BEIJING_L) {
Ok(CnBeijing)
} else if url.contains(ZHANGJIAKOU_L) {
Ok(CnZhangjiakou)
} else if url.contains(HONGKONG_L) {
Ok(CnHongkong)
} else if url.contains(SHENZHEN_L) {
Ok(CnShenzhen)
} else if url.contains(US_WEST1) {
Ok(UsWest1)
} else if url.contains(US_EAST1) {
Ok(UsEast1)
} else if url.contains(AP_SOUTH_EAST1) {
Ok(ApSouthEast1)
} else {
if url.starts_with('-') || url.ends_with('-') || url.starts_with(OSS_STR) {
return Err(InvalidEndPoint { _priv: () });
}
if !url.chars().all(valid_oss_character) {
return Err(InvalidEndPoint { _priv: () });
}
Ok(Other(Cow::Owned(url.to_owned())))
};
kind.map(|kind| Self { kind, is_internal })
}
pub(crate) fn from_host_piece(url: &'a str) -> Result<Self, InvalidEndPoint> {
if !url.starts_with(OSS_HYPHEN) {
return Err(InvalidEndPoint { _priv: () });
}
Self::new(&url[4..])
}
pub fn from_env() -> Result<Self, InvalidEndPoint> {
let endpoint =
std::env::var("ALIYUN_ENDPOINT").map_err(|_| InvalidEndPoint { _priv: () })?;
let mut endpoint: EndPoint = endpoint
.parse()
.map_err(|_| InvalidEndPoint { _priv: () })?;
if let Ok(is_internal) = std::env::var("ALIYUN_OSS_INTERNAL") {
if is_internal == TRUE1
|| is_internal == TRUE2
|| is_internal == TRUE3
|| is_internal == TRUE4
{
endpoint.set_internal(true);
}
}
Ok(endpoint)
}
pub fn set_internal(&mut self, is_internal: bool) {
self.is_internal = is_internal;
}
pub fn to_url(&self) -> Url {
let mut url = String::from(OSS_DOMAIN_PREFIX);
url.push_str(self.as_ref());
if self.is_internal {
url.push_str(OSS_INTERNAL);
}
url.push_str(OSS_DOMAIN_MAIN);
Url::parse(&url).unwrap_or_else(|_| panic!("covert to url failed, endpoint: {}", url))
}
}
#[derive(PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct InvalidEndPoint {
pub(crate) _priv: (),
}
impl Debug for InvalidEndPoint {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("InvalidEndPoint").finish()
}
}
impl Error for InvalidEndPoint {}
impl fmt::Display for InvalidEndPoint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"endpoint must not with `-` prefix or `-` suffix or `oss-` prefix"
)
}
}
impl PartialEq<&str> for EndPoint {
#[inline]
fn eq(&self, other: &&str) -> bool {
&self.as_ref() == other
}
}
impl PartialEq<EndPoint> for &str {
#[inline]
fn eq(&self, other: &EndPoint) -> bool {
self == &other.as_ref()
}
}
impl PartialEq<Url> for EndPoint {
#[inline]
fn eq(&self, other: &Url) -> bool {
&self.to_url() == other
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BucketName(Cow<'static, str>);
impl AsRef<str> for BucketName {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Display for BucketName {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Default for BucketName {
fn default() -> BucketName {
#[allow(clippy::unwrap_used)]
BucketName::new("a").unwrap()
}
}
impl TryFrom<String> for BucketName {
type Error = InvalidBucketName;
fn try_from(s: String) -> Result<Self, Self::Error> {
Self::new(s)
}
}
impl<'a> TryFrom<&'a str> for BucketName {
type Error = InvalidBucketName;
fn try_from(bucket: &'a str) -> Result<Self, Self::Error> {
Self::from_static(bucket)
}
}
impl FromStr for BucketName {
type Err = InvalidBucketName;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_static(s)
}
}
impl<'a> BucketName {
pub fn new(bucket: impl Into<Cow<'static, str>>) -> Result<Self, InvalidBucketName> {
let bucket = bucket.into();
if bucket.is_empty() || bucket.starts_with('-') || bucket.ends_with('-') {
return Err(InvalidBucketName { _priv: () });
}
if !bucket.chars().all(valid_oss_character) {
return Err(InvalidBucketName { _priv: () });
}
Ok(Self(bucket))
}
pub fn from_env() -> Result<Self, InvalidBucketName> {
let string = std::env::var("ALIYUN_BUCKET").map_err(|_| InvalidBucketName { _priv: () })?;
string.parse()
}
pub fn from_static(bucket: &'a str) -> Result<Self, InvalidBucketName> {
if bucket.is_empty() || bucket.starts_with('-') || bucket.ends_with('-') {
return Err(InvalidBucketName { _priv: () });
}
if !bucket.chars().all(valid_oss_character) {
return Err(InvalidBucketName { _priv: () });
}
Ok(Self(Cow::Owned(bucket.to_owned())))
}
pub const unsafe fn from_static2(bucket: &'static str) -> Self {
Self(Cow::Borrowed(bucket))
}
}
fn valid_oss_character(c: char) -> bool {
match c {
_ if c.is_ascii_lowercase() => true,
_ if c.is_numeric() => true,
'-' => true,
_ => false,
}
}
impl PartialEq<&str> for BucketName {
#[inline]
fn eq(&self, other: &&str) -> bool {
&self.0 == other
}
}
impl PartialEq<BucketName> for &str {
#[inline]
fn eq(&self, other: &BucketName) -> bool {
self == &other.0
}
}
#[derive(PartialEq)]
#[non_exhaustive]
pub struct InvalidBucketName {
pub(crate) _priv: (),
}
impl Debug for InvalidBucketName {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("InvalidBucketName").finish()
}
}
impl Error for InvalidBucketName {}
impl fmt::Display for InvalidBucketName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"bucket name only allow `alphabet, digit, -`, and must not with `-` prefix or `-` suffix"
)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct InnerContentMd5<'a>(Cow<'a, str>);
pub type ContentMd5 = InnerContentMd5<'static>;
impl AsRef<str> for InnerContentMd5<'_> {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Display for InnerContentMd5<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl TryInto<HeaderValue> for InnerContentMd5<'_> {
type Error = InvalidHeaderValue;
fn try_into(self) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::from_str(self.as_ref())
}
}
impl TryInto<HeaderValue> for &InnerContentMd5<'_> {
type Error = InvalidHeaderValue;
fn try_into(self) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::from_str(self.as_ref())
}
}
impl From<String> for ContentMd5 {
fn from(s: String) -> Self {
Self(Cow::Owned(s))
}
}
impl<'a: 'b, 'b> From<&'a str> for InnerContentMd5<'b> {
fn from(value: &'a str) -> Self {
Self(Cow::Borrowed(value))
}
}
impl<'a> InnerContentMd5<'a> {
pub fn new(val: impl Into<Cow<'a, str>>) -> Self {
Self(val.into())
}
pub const fn from_static(val: &'static str) -> Self {
Self(Cow::Borrowed(val))
}
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct ContentType(Cow<'static, str>);
impl AsRef<str> for ContentType {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Display for ContentType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl TryInto<HeaderValue> for ContentType {
type Error = InvalidHeaderValue;
fn try_into(self) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::from_str(self.as_ref())
}
}
impl TryFrom<HeaderValue> for ContentType {
type Error = ToStrError;
fn try_from(value: HeaderValue) -> Result<Self, Self::Error> {
Ok(Self(Cow::Owned(value.to_str()?.to_owned())))
}
}
impl From<String> for ContentType {
fn from(s: String) -> Self {
Self(Cow::Owned(s))
}
}
impl ContentType {
pub fn new(val: impl Into<Cow<'static, str>>) -> Self {
Self(val.into())
}
pub const fn from_static(val: &'static str) -> Self {
Self(Cow::Borrowed(val))
}
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct InnerDate<'a>(Cow<'a, str>);
pub type Date = InnerDate<'static>;
impl AsRef<str> for InnerDate<'_> {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Display for InnerDate<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl TryInto<HeaderValue> for InnerDate<'_> {
type Error = InvalidHeaderValue;
fn try_into(self) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::from_str(self.as_ref())
}
}
impl<Tz: TimeZone> From<DateTime<Tz>> for Date
where
Tz::Offset: fmt::Display,
{
fn from(d: DateTime<Tz>) -> Self {
Self(Cow::Owned(d.format("%a, %d %b %Y %T GMT").to_string()))
}
}
impl<'a> InnerDate<'a> {
pub const unsafe fn from_static(val: &'static str) -> Self {
Self(Cow::Borrowed(val))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InnerCanonicalizedResource<'a>(Cow<'a, str>);
pub type CanonicalizedResource = InnerCanonicalizedResource<'static>;
impl AsRef<str> for InnerCanonicalizedResource<'_> {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Display for InnerCanonicalizedResource<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl TryInto<HeaderValue> for InnerCanonicalizedResource<'_> {
type Error = InvalidHeaderValue;
fn try_into(self) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::from_str(self.as_ref())
}
}
impl From<String> for CanonicalizedResource {
fn from(s: String) -> Self {
Self(Cow::Owned(s))
}
}
impl<'a: 'b, 'b> From<&'a str> for InnerCanonicalizedResource<'b> {
fn from(value: &'a str) -> Self {
Self(Cow::Borrowed(value))
}
}
impl Default for InnerCanonicalizedResource<'_> {
fn default() -> Self {
InnerCanonicalizedResource(Cow::Owned("/".to_owned()))
}
}
#[cfg(any(feature = "core", feature = "auth"))]
pub(crate) const CONTINUATION_TOKEN: &str = "continuation-token";
#[cfg(any(feature = "core", feature = "auth"))]
pub(crate) const BUCKET_INFO: &str = "bucketInfo";
#[cfg(any(feature = "core", feature = "auth"))]
const QUERY_KEYWORD: [&str; 2] = ["acl", BUCKET_INFO];
impl<'a> InnerCanonicalizedResource<'a> {
pub fn new(val: impl Into<Cow<'a, str>>) -> Self {
Self(val.into())
}
#[inline(always)]
pub fn from_endpoint() -> Self {
Self::default()
}
pub const fn from_static(val: &'static str) -> Self {
Self(Cow::Borrowed(val))
}
#[cfg(feature = "core")]
pub fn from_bucket<B: AsRef<BucketName>>(bucket: B, query: Option<&str>) -> Self {
match query {
Some(q) => {
if QUERY_KEYWORD.iter().any(|&str| str == q) {
return Self::new(format!("/{}/?{}", bucket.as_ref().as_ref(), q));
}
Self::new(format!("/{}/", bucket.as_ref().as_ref()))
}
None => Self::default(),
}
}
#[cfg(feature = "auth")]
pub fn from_bucket_name(bucket: &BucketName, query: Option<&str>) -> Self {
match query {
Some(q) => {
if QUERY_KEYWORD.iter().any(|&str| str == q) {
return Self::new(format!("/{}/?{}", bucket.as_ref(), q));
}
Self::new(format!("/{}/", bucket.as_ref()))
}
None => Self::default(),
}
}
#[cfg(feature = "core")]
#[inline]
pub fn from_bucket_query<B: AsRef<BucketName>>(bucket: B, query: &Query) -> Self {
Self::from_bucket_query2(bucket.as_ref(), query)
}
#[cfg(feature = "core")]
#[doc(hidden)]
pub fn from_bucket_query2(bucket: &BucketName, query: &Query) -> Self {
match query.get(QueryKey::CONTINUATION_TOKEN) {
Some(v) => Self::new(format!(
"/{}/?continuation-token={}",
bucket.as_ref(),
v.as_ref()
)),
None => Self::new(format!("/{}/", bucket.as_ref())),
}
}
#[cfg(feature = "core")]
pub(crate) fn from_object<
Q: IntoIterator<Item = (QueryKey, QueryValue)>,
B: AsRef<str>,
P: AsRef<str>,
>(
(bucket, path): (B, P),
query: Q,
) -> Self {
let query = Query::from_iter(query);
if query.is_empty() {
Self::new(format!("/{}/{}", bucket.as_ref(), path.as_ref()))
} else {
Self::new(format!(
"/{}/{}?{}",
bucket.as_ref(),
path.as_ref(),
query.to_url_query()
))
}
}
pub(crate) fn from_object_str(bucket: &str, path: &str) -> Self {
Self::new(format!("/{}/{}", bucket, path))
}
#[cfg(feature = "auth")]
pub(crate) fn from_object_without_query<B: AsRef<str>, P: AsRef<str>>(
bucket: B,
path: P,
) -> Self {
Self::new(format!("/{}/{}", bucket.as_ref(), path.as_ref()))
}
}
impl PartialEq<&str> for InnerCanonicalizedResource<'_> {
#[inline]
fn eq(&self, other: &&str) -> bool {
&self.0 == other
}
}
impl PartialEq<InnerCanonicalizedResource<'_>> for &str {
#[inline]
fn eq(&self, other: &InnerCanonicalizedResource<'_>) -> bool {
self == &other.0
}
}
pub fn get_url_resource(
endpoint: &EndPoint,
bucket: &BucketName,
path: &ObjectPathInner,
) -> (Url, CanonicalizedResource) {
let mut url = url_from_bucket(endpoint, bucket);
url.set_object_path(path);
let resource = CanonicalizedResource::from_object_str(bucket.as_ref(), path.as_ref());
(url, resource)
}
pub fn get_url_resource2<E: AsRef<EndPoint>, B: AsRef<BucketName>>(
endpoint: E,
bucket: B,
path: &ObjectPathInner,
) -> (Url, CanonicalizedResource) {
get_url_resource(endpoint.as_ref(), bucket.as_ref(), path)
}
pub(crate) fn url_from_bucket(endpoint: &EndPoint, bucket: &BucketName) -> Url {
let url = format!(
"https://{}.oss-{}.aliyuncs.com",
bucket.as_ref(),
endpoint.as_ref()
);
url.parse().unwrap_or_else(|_| {
unreachable!("covert to url failed, bucket: {bucket}, endpoint: {endpoint}")
})
}