Unverified Commit c94f3147 authored by Nugine's avatar Nugine Committed by GitHub
Browse files

feat(s3s/host): add S3Host (#178)

parent 75bc2ffe
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ use s3s_fs::FileSystem;
use s3s_fs::Result;

use s3s::auth::SimpleAuth;
use s3s::host::SingleDomain;
use s3s::service::S3ServiceBuilder;

use std::io::IsTerminal;
@@ -103,7 +104,7 @@ async fn run(opt: Opt) -> Result {

        // Enable parsing virtual-hosted-style requests
        if let Some(domain_name) = opt.domain_name {
            b.set_base_domain(domain_name);
            b.set_host(SingleDomain::new(domain_name));
            info!("virtual-hosted-style requests are enabled");
        }

+2 −1
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
)]

use s3s::auth::SimpleAuth;
use s3s::host::SingleDomain;
use s3s::service::S3ServiceBuilder;
use s3s_fs::FileSystem;

@@ -64,7 +65,7 @@ fn config() -> &'static SdkConfig {
        let service = {
            let mut b = S3ServiceBuilder::new(fs);
            b.set_auth(SimpleAuth::from_single(cred.access_key_id(), cred.secret_access_key()));
            b.set_base_domain(DOMAIN_NAME);
            b.set_host(SingleDomain::new(DOMAIN_NAME));
            b.build()
        };

+2 −1
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
#![deny(clippy::all, clippy::pedantic)]

use s3s::auth::SimpleAuth;
use s3s::host::SingleDomain;
use s3s::service::S3ServiceBuilder;
use tokio::net::TcpListener;

@@ -66,7 +67,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {

        // Enable parsing virtual-hosted-style requests
        if let Some(domain_name) = opt.domain_name {
            b.set_base_domain(domain_name);
            b.set_host(SingleDomain::new(domain_name));
        }

        b.build()

crates/s3s/src/host.rs

0 → 100644
+76 −0
Original line number Diff line number Diff line
use crate::error::S3Result;

use std::borrow::Cow;

#[derive(Debug, Clone)]
pub struct VirtualHost<'a> {
    domain: Cow<'a, str>,
    bucket: Option<Cow<'a, str>>,
    // pub(crate) region: Option<Cow<'a, str>>,
}

impl<'a> VirtualHost<'a> {
    pub fn new(domain: impl Into<Cow<'a, str>>) -> Self {
        Self {
            domain: domain.into(),
            bucket: None,
        }
    }

    pub fn with_bucket(domain: impl Into<Cow<'a, str>>, bucket: impl Into<Cow<'a, str>>) -> Self {
        Self {
            domain: domain.into(),
            bucket: Some(bucket.into()),
        }
    }

    #[inline]
    #[must_use]
    pub fn domain(&self) -> &str {
        self.domain.as_ref()
    }

    #[inline]
    #[must_use]
    pub fn bucket(&self) -> Option<&str> {
        self.bucket.as_deref()
    }
}

pub trait S3Host: Send + Sync + 'static {
    /// Parses the `Host` header of the HTTP request.
    ///
    /// # Errors
    /// Returns an error if the `Host` is invalid for this service.
    fn parse_host_header<'a>(&'a self, host: &'a str) -> S3Result<VirtualHost<'a>>;
}

pub struct SingleDomain {
    base_domain: String,
}

impl SingleDomain {
    #[must_use]
    pub fn new(base_domain: impl Into<String>) -> Self {
        Self {
            base_domain: base_domain.into(),
        }
    }
}

impl S3Host for SingleDomain {
    fn parse_host_header<'a>(&'a self, host: &'a str) -> S3Result<VirtualHost<'a>> {
        let base_domain = self.base_domain.as_str();

        if host == base_domain {
            return Ok(VirtualHost::new(base_domain));
        }

        if let Some(bucket) = host.strip_suffix(&self.base_domain).and_then(|h| h.strip_suffix('.')) {
            return Ok(VirtualHost::with_bucket(base_domain, bucket));
        };

        let bucket = host.to_ascii_lowercase();
        Ok(VirtualHost::with_bucket(host, bucket))
    }
}
+3 −4
Original line number Diff line number Diff line
@@ -35,16 +35,15 @@ mod sig_v2;
mod sig_v4;
mod xml;

pub mod header;

pub mod auth;
pub mod checksum;
pub mod dto;
pub mod header;
pub mod host;
pub mod path;
pub mod service;
pub mod stream;

pub mod checksum;

pub use self::error::*;
pub use self::http::Body;
pub use self::request::S3Request;
Loading