aliyun-oss 0.2.0

aliyun oss sdk
Documentation
//! URI encoding and endpoint URL generation.

/// Percent-encodes a URI path segment, preserving unreserved characters (`/`, `~`, `-`, `_`, `.`).
pub fn uri_encode(input: &str) -> String {
    let mut result = String::with_capacity(input.len() * 3);
    for byte in input.bytes() {
        match byte {
            b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' | b'/' => {
                result.push(byte as char);
            }
            _ => {
                result.push_str(&format!("%{:02X}", byte));
            }
        }
    }
    result
}

/// Constructs an HTTPS OSS endpoint URL from endpoint, optional bucket, and optional key.
pub fn oss_endpoint_url(endpoint: &str, bucket: Option<&str>, key: Option<&str>) -> String {
    match (bucket, key) {
        (Some(bucket), Some(key)) => {
            let encoded_key = uri_encode(key);
            format!("https://{}.{}/{}", bucket, endpoint, encoded_key)
        }
        (Some(bucket), None) => {
            format!("https://{}.{}", bucket, endpoint)
        }
        (None, None) => {
            format!("https://{}", endpoint)
        }
        (None, Some(_)) => {
            format!("https://{}", endpoint)
        }
    }
}

/// Like `oss_endpoint_url` but produces an HTTP (non-TLS) URL.
pub fn oss_endpoint_url_http(endpoint: &str, bucket: Option<&str>, key: Option<&str>) -> String {
    let url = oss_endpoint_url(endpoint, bucket, key);
    url.replacen("https://", "http://", 1)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn uri_encode_slash_not_encoded() {
        assert_eq!(uri_encode("/"), "/");
    }

    #[test]
    fn uri_encode_path_with_special_chars() {
        assert_eq!(
            uri_encode("/bucket/对象名.jpg"),
            "/bucket/%E5%AF%B9%E8%B1%A1%E5%90%8D.jpg"
        );
    }

    #[test]
    fn uri_encode_chinese_characters() {
        let encoded = uri_encode("对象名");
        assert_eq!(encoded, "%E5%AF%B9%E8%B1%A1%E5%90%8D");
        assert!(!encoded.contains("对象"));
    }

    #[test]
    fn uri_encode_tilde_not_encoded() {
        assert_eq!(uri_encode("~"), "~");
        assert_eq!(uri_encode("file~name.txt"), "file~name.txt");
    }

    #[test]
    fn uri_encode_space_encoded() {
        assert_eq!(uri_encode("a b"), "a%20b");
    }

    #[test]
    fn uri_encode_reserved_characters() {
        assert_eq!(uri_encode("a+b"), "a%2Bb");
        assert_eq!(uri_encode("a=b"), "a%3Db");
        assert_eq!(uri_encode("a@b"), "a%40b");
        assert_eq!(uri_encode("a:b"), "a%3Ab");
    }

    #[test]
    fn uri_encode_alphanumeric_and_safe_chars_not_encoded() {
        let encoded = uri_encode("abc-123_./~");
        assert_eq!(encoded, "abc-123_./~");
    }

    #[test]
    fn uri_encode_empty() {
        assert_eq!(uri_encode(""), "");
    }

    #[test]
    fn build_endpoint_url_with_bucket_and_object() {
        let url = oss_endpoint_url(
            "oss-cn-hangzhou.aliyuncs.com",
            Some("my-bucket"),
            Some("path/to/object.jpg"),
        );
        assert_eq!(
            url,
            "https://my-bucket.oss-cn-hangzhou.aliyuncs.com/path/to/object.jpg"
        );
    }

    #[test]
    fn build_endpoint_url_with_bucket_and_encoded_object() {
        let url = oss_endpoint_url(
            "oss-cn-hangzhou.aliyuncs.com",
            Some("my-bucket"),
            Some("文件 名.jpg"),
        );
        assert_eq!(
            url,
            "https://my-bucket.oss-cn-hangzhou.aliyuncs.com/%E6%96%87%E4%BB%B6%20%E5%90%8D.jpg"
        );
    }

    #[test]
    fn build_endpoint_url_without_bucket() {
        let url = oss_endpoint_url("oss-cn-hangzhou.aliyuncs.com", None, None);
        assert_eq!(url, "https://oss-cn-hangzhou.aliyuncs.com");
    }

    #[test]
    fn build_endpoint_url_with_bucket_only() {
        let url = oss_endpoint_url("oss-cn-hangzhou.aliyuncs.com", Some("my-bucket"), None);
        assert_eq!(url, "https://my-bucket.oss-cn-hangzhou.aliyuncs.com");
    }

    #[test]
    fn build_endpoint_url_http_variant() {
        let url =
            oss_endpoint_url_http("oss-cn-hangzhou.aliyuncs.com", Some("bucket"), Some("key"));
        assert!(url.starts_with("http://"));
        assert!(!url.starts_with("https://"));
        assert!(url.contains("bucket.oss-cn-hangzhou.aliyuncs.com"));
    }

    #[test]
    fn uri_encode_percent_already_encoded_preserved() {
        let encoded = uri_encode("%E5%AF%B9");
        assert_eq!(encoded, "%25E5%25AF%25B9");
    }
}