Loading Cargo.lock +83 −2 Original line number Diff line number Diff line Loading @@ -480,6 +480,60 @@ dependencies = [ "tracing", ] [[package]] name = "axum" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8" dependencies = [ "axum-core", "bytes", "form_urlencoded", "futures-util", "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.6.0", "hyper-util", "itoa", "matchit", "memchr", "mime", "percent-encoding", "pin-project-lite", "rustversion", "serde", "serde_json", "serde_path_to_error", "serde_urlencoded", "sync_wrapper", "tokio", "tower", "tower-layer", "tower-service", "tracing", ] [[package]] name = "axum-core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733" dependencies = [ "bytes", "futures-util", "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", "rustversion", "sync_wrapper", "tower-layer", "tower-service", "tracing", ] [[package]] name = "backtrace" version = "0.3.74" Loading Loading @@ -1335,6 +1389,7 @@ dependencies = [ "hyper 1.6.0", "pin-project-lite", "tokio", "tower-service", ] [[package]] Loading Loading @@ -1584,6 +1639,12 @@ dependencies = [ "regex-automata 0.1.10", ] [[package]] name = "matchit" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "md-5" version = "0.10.6" Loading Loading @@ -2052,11 +2113,13 @@ dependencies = [ "arrayvec", "async-trait", "atoi", "axum", "base64-simd", "block-buffer 0.11.0-rc.3", "bytes", "bytestring", "chrono", "const-str", "crc32c", "crc32fast", "crc64fast-nvme", Loading @@ -2078,6 +2141,7 @@ dependencies = [ "pin-project-lite", "quick-xml", "serde", "serde_json", "serde_urlencoded", "sha1 0.11.0-pre.4", "sha2 0.11.0-pre.4", Loading Loading @@ -2329,9 +2393,9 @@ dependencies = [ [[package]] name = "serde_json" version = "1.0.139" version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "indexmap", "itoa", Loading @@ -2340,6 +2404,16 @@ dependencies = [ "serde", ] [[package]] name = "serde_path_to_error" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" dependencies = [ "itoa", "serde", ] [[package]] name = "serde_urlencoded" version = "0.7.1" Loading Loading @@ -2656,8 +2730,14 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", "pin-project-lite", "sync_wrapper", "tokio", "tower-layer", "tower-service", "tracing", ] [[package]] Loading @@ -2678,6 +2758,7 @@ version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", "tracing-attributes", "tracing-core", Loading crates/s3s/Cargo.toml +3 −0 Original line number Diff line number Diff line Loading @@ -67,7 +67,10 @@ std-next = "0.1.1" sync_wrapper = { version = "1.0.1", default-features = false } tokio = { version = "1.40.0", features = ["time"] } crc64fast-nvme = "1.2.0" const-str = "0.6.2" [dev-dependencies] axum = "0.8.1" serde_json = "1.0.140" tokio = { version = "1.40.0", features = ["full"] } tokio-util = { version = "0.7.13", features = ["io"] } crates/s3s/examples/axum.rs 0 → 100644 +125 −0 Original line number Diff line number Diff line use s3s::route::S3Route; use s3s::{Body, S3Request, S3Response, S3Result}; use axum::http; use http::{Extensions, HeaderMap, Method, StatusCode, Uri}; use tower::Service; pub struct CustomRoute { router: axum::Router, } impl CustomRoute { #[must_use] pub fn build() -> Self { Self { router: self::handlers::register(), } } } #[derive(Debug, Clone)] pub struct Extra { pub credentials: Option<s3s::auth::Credentials>, pub region: Option<String>, pub service: Option<String>, } fn convert_request(req: S3Request<Body>) -> http::Request<Body> { let (mut parts, _) = http::Request::new(Body::empty()).into_parts(); parts.method = req.method; parts.uri = req.uri; parts.headers = req.headers; parts.extensions = req.extensions; parts.extensions.insert(Extra { credentials: req.credentials, region: req.region, service: req.service, }); http::Request::from_parts(parts, req.input) } fn convert_response(resp: http::Response<axum::body::Body>) -> S3Response<(StatusCode, Body)> { let (parts, body) = resp.into_parts(); let mut s3_resp = S3Response::new((parts.status, Body::http_body_unsync(body))); s3_resp.headers = parts.headers; s3_resp.extensions = parts.extensions; s3_resp } #[async_trait::async_trait] impl S3Route for CustomRoute { fn is_match(&self, _method: &Method, uri: &Uri, _headers: &HeaderMap, _extensions: &mut Extensions) -> bool { let path = uri.path(); let prefix = const_str::concat!(self::handlers::PREFIX, "/"); path.starts_with(prefix) } async fn check_access(&self, req: &mut S3Request<Body>) -> S3Result<()> { if req.credentials.is_none() { tracing::debug!("anonymous access"); } Ok(()) // allow all requests } async fn call(&self, req: S3Request<Body>) -> S3Result<S3Response<(StatusCode, Body)>> { let mut service = self.router.clone().into_service::<Body>(); let req = convert_request(req); let result = service.call(req).await; match result { Ok(resp) => Ok(convert_response(resp)), Err(e) => match e {}, } } } mod handlers { use std::collections::HashMap; use axum::Json; use axum::Router; use axum::body::Body; use axum::extract::Path; use axum::extract::Query; use axum::extract::Request; use axum::http::Response; use axum::response; use axum::routing::get; use axum::routing::post; pub async fn echo(req: Request) -> Response<Body> { Response::new(req.into_body()) } pub async fn hello() -> &'static str { "Hello, World!" } pub async fn show_path(Path(path): Path<String>) -> String { path } pub async fn show_query(Query(query): Query<HashMap<String, String>>) -> String { format!("{query:?}") } pub async fn show_json(Json(json): Json<serde_json::Value>) -> response::Json<serde_json::Value> { tracing::debug!(?json); response::Json(json) } pub const PREFIX: &str = "/custom"; pub fn register() -> Router { let router = Router::new() .route("/echo", post(echo)) .route("/hello", get(hello)) .route("/show_path/{*path}", get(show_path)) .route("/show_query", get(show_query)) .route("/show_json", post(show_json)); Router::new().nest(PREFIX, router) } } fn main() {} crates/s3s/src/route.rs +2 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,8 @@ use hyper::StatusCode; use hyper::Uri; use hyper::http::Extensions; // TODO: Refactor S3Request and S3Response to support custom route better #[async_trait::async_trait] pub trait S3Route: Send + Sync + 'static { fn is_match(&self, method: &Method, uri: &Uri, headers: &HeaderMap, extensions: &mut Extensions) -> bool; Loading Loading
Cargo.lock +83 −2 Original line number Diff line number Diff line Loading @@ -480,6 +480,60 @@ dependencies = [ "tracing", ] [[package]] name = "axum" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8" dependencies = [ "axum-core", "bytes", "form_urlencoded", "futures-util", "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.6.0", "hyper-util", "itoa", "matchit", "memchr", "mime", "percent-encoding", "pin-project-lite", "rustversion", "serde", "serde_json", "serde_path_to_error", "serde_urlencoded", "sync_wrapper", "tokio", "tower", "tower-layer", "tower-service", "tracing", ] [[package]] name = "axum-core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733" dependencies = [ "bytes", "futures-util", "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", "rustversion", "sync_wrapper", "tower-layer", "tower-service", "tracing", ] [[package]] name = "backtrace" version = "0.3.74" Loading Loading @@ -1335,6 +1389,7 @@ dependencies = [ "hyper 1.6.0", "pin-project-lite", "tokio", "tower-service", ] [[package]] Loading Loading @@ -1584,6 +1639,12 @@ dependencies = [ "regex-automata 0.1.10", ] [[package]] name = "matchit" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "md-5" version = "0.10.6" Loading Loading @@ -2052,11 +2113,13 @@ dependencies = [ "arrayvec", "async-trait", "atoi", "axum", "base64-simd", "block-buffer 0.11.0-rc.3", "bytes", "bytestring", "chrono", "const-str", "crc32c", "crc32fast", "crc64fast-nvme", Loading @@ -2078,6 +2141,7 @@ dependencies = [ "pin-project-lite", "quick-xml", "serde", "serde_json", "serde_urlencoded", "sha1 0.11.0-pre.4", "sha2 0.11.0-pre.4", Loading Loading @@ -2329,9 +2393,9 @@ dependencies = [ [[package]] name = "serde_json" version = "1.0.139" version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "indexmap", "itoa", Loading @@ -2340,6 +2404,16 @@ dependencies = [ "serde", ] [[package]] name = "serde_path_to_error" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" dependencies = [ "itoa", "serde", ] [[package]] name = "serde_urlencoded" version = "0.7.1" Loading Loading @@ -2656,8 +2730,14 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", "pin-project-lite", "sync_wrapper", "tokio", "tower-layer", "tower-service", "tracing", ] [[package]] Loading @@ -2678,6 +2758,7 @@ version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", "tracing-attributes", "tracing-core", Loading
crates/s3s/Cargo.toml +3 −0 Original line number Diff line number Diff line Loading @@ -67,7 +67,10 @@ std-next = "0.1.1" sync_wrapper = { version = "1.0.1", default-features = false } tokio = { version = "1.40.0", features = ["time"] } crc64fast-nvme = "1.2.0" const-str = "0.6.2" [dev-dependencies] axum = "0.8.1" serde_json = "1.0.140" tokio = { version = "1.40.0", features = ["full"] } tokio-util = { version = "0.7.13", features = ["io"] }
crates/s3s/examples/axum.rs 0 → 100644 +125 −0 Original line number Diff line number Diff line use s3s::route::S3Route; use s3s::{Body, S3Request, S3Response, S3Result}; use axum::http; use http::{Extensions, HeaderMap, Method, StatusCode, Uri}; use tower::Service; pub struct CustomRoute { router: axum::Router, } impl CustomRoute { #[must_use] pub fn build() -> Self { Self { router: self::handlers::register(), } } } #[derive(Debug, Clone)] pub struct Extra { pub credentials: Option<s3s::auth::Credentials>, pub region: Option<String>, pub service: Option<String>, } fn convert_request(req: S3Request<Body>) -> http::Request<Body> { let (mut parts, _) = http::Request::new(Body::empty()).into_parts(); parts.method = req.method; parts.uri = req.uri; parts.headers = req.headers; parts.extensions = req.extensions; parts.extensions.insert(Extra { credentials: req.credentials, region: req.region, service: req.service, }); http::Request::from_parts(parts, req.input) } fn convert_response(resp: http::Response<axum::body::Body>) -> S3Response<(StatusCode, Body)> { let (parts, body) = resp.into_parts(); let mut s3_resp = S3Response::new((parts.status, Body::http_body_unsync(body))); s3_resp.headers = parts.headers; s3_resp.extensions = parts.extensions; s3_resp } #[async_trait::async_trait] impl S3Route for CustomRoute { fn is_match(&self, _method: &Method, uri: &Uri, _headers: &HeaderMap, _extensions: &mut Extensions) -> bool { let path = uri.path(); let prefix = const_str::concat!(self::handlers::PREFIX, "/"); path.starts_with(prefix) } async fn check_access(&self, req: &mut S3Request<Body>) -> S3Result<()> { if req.credentials.is_none() { tracing::debug!("anonymous access"); } Ok(()) // allow all requests } async fn call(&self, req: S3Request<Body>) -> S3Result<S3Response<(StatusCode, Body)>> { let mut service = self.router.clone().into_service::<Body>(); let req = convert_request(req); let result = service.call(req).await; match result { Ok(resp) => Ok(convert_response(resp)), Err(e) => match e {}, } } } mod handlers { use std::collections::HashMap; use axum::Json; use axum::Router; use axum::body::Body; use axum::extract::Path; use axum::extract::Query; use axum::extract::Request; use axum::http::Response; use axum::response; use axum::routing::get; use axum::routing::post; pub async fn echo(req: Request) -> Response<Body> { Response::new(req.into_body()) } pub async fn hello() -> &'static str { "Hello, World!" } pub async fn show_path(Path(path): Path<String>) -> String { path } pub async fn show_query(Query(query): Query<HashMap<String, String>>) -> String { format!("{query:?}") } pub async fn show_json(Json(json): Json<serde_json::Value>) -> response::Json<serde_json::Value> { tracing::debug!(?json); response::Json(json) } pub const PREFIX: &str = "/custom"; pub fn register() -> Router { let router = Router::new() .route("/echo", post(echo)) .route("/hello", get(hello)) .route("/show_path/{*path}", get(show_path)) .route("/show_query", get(show_query)) .route("/show_json", post(show_json)); Router::new().nest(PREFIX, router) } } fn main() {}
crates/s3s/src/route.rs +2 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,8 @@ use hyper::StatusCode; use hyper::Uri; use hyper::http::Extensions; // TODO: Refactor S3Request and S3Response to support custom route better #[async_trait::async_trait] pub trait S3Route: Send + Sync + 'static { fn is_match(&self, method: &Method, uri: &Uri, headers: &HeaderMap, extensions: &mut Extensions) -> bool; Loading