diff options
author | Quentin <quentin@deuxfleurs.fr> | 2020-11-11 19:48:01 +0100 |
---|---|---|
committer | Quentin <quentin@deuxfleurs.fr> | 2020-11-11 19:48:01 +0100 |
commit | 2765291796de1b94401e462dc5136fdfce867596 (patch) | |
tree | b068e58074cb9f16039f1af1bb6cede0ea60253c | |
parent | d445c4ef9cd6835ec7e2e543e9e462adcd0f58bf (diff) | |
download | garage-2765291796de1b94401e462dc5136fdfce867596.tar.gz garage-2765291796de1b94401e462dc5136fdfce867596.zip |
Build path correctly
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | config.dev.toml | 1 | ||||
-rw-r--r-- | src/util/config.rs | 1 | ||||
-rw-r--r-- | src/web/web_server.rs | 40 |
4 files changed, 41 insertions, 5 deletions
@@ -76,7 +76,9 @@ api_bind_addr = "[::1]:3900" # the S3 API port, HTTP without TLS. Add a reverse s3_region = "garage" # set this to anything. S3 API calls will fail if they are not made against the region set here. [s3_web] -web_bind_addr = "[::1]:3902" +bind_addr = "[::1]:3902" +root_domain = ".garage.tld" +index = "index.html" ``` Build Garage using `cargo build --release`. diff --git a/config.dev.toml b/config.dev.toml index 88378e50..215bc50c 100644 --- a/config.dev.toml +++ b/config.dev.toml @@ -19,3 +19,4 @@ s3_region = "garage" # set this to anything. S3 API calls will fail if they a [s3_web] bind_addr = "[::1]:3902" root_domain = ".garage.tld" +index = "index.html" diff --git a/src/util/config.rs b/src/util/config.rs index 72f7c319..f4c841b7 100644 --- a/src/util/config.rs +++ b/src/util/config.rs @@ -56,6 +56,7 @@ pub struct ApiConfig { pub struct WebConfig { pub bind_addr: SocketAddr, pub root_domain: String, + pub index: String, } fn default_max_concurrent_rpc_requests() -> usize { diff --git a/src/web/web_server.rs b/src/web/web_server.rs index cbb2aaac..16b27cef 100644 --- a/src/web/web_server.rs +++ b/src/web/web_server.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::net::SocketAddr; use std::sync::Arc; @@ -55,17 +56,18 @@ async fn handler( // Get path let path = req.uri().path().to_string(); - let key = percent_encoding::percent_decode_str(&path).decode_utf8()?; + let index = &garage.config.s3_web.index; + let key = path_to_key(&path, &index)?; - // Get bucket descriptor + info!("Selected bucket: \"{}\", selected key: \"{}\"", bucket, key); + + // Get bucket descriptor let object = garage .object_table .get(&bucket.to_string(), &key.to_string()) .await? .ok_or(Error::NotFound)?; - info!("Selected bucket: \"{}\", selected key: \"{}\"", bucket, key); - Ok(Response::new(Body::from("hello world\n"))) } @@ -121,6 +123,27 @@ fn host_to_bucket<'a>(host: &'a str, root: &str) -> &'a str { &host[..cursor] } +/// Path to key +/// +/// Convert the provided path to the internal key +/// When a path ends with "/", we append the index name to match traditional web server behavior +/// which is also AWS S3 behavior. +fn path_to_key<'a>(path: &'a str, index: &str) -> Result<Cow<'a, str>, Error> { + let path_utf8 = percent_encoding::percent_decode_str(&path).decode_utf8()?; + match path_utf8.chars().last() { + None => Err(Error::BadRequest(format!( + "Path must have at least a character" + ))), + Some('/') => { + let mut key = String::with_capacity(path_utf8.len() + index.len()); + key.push_str(&path_utf8); + key.push_str(index); + Ok(key.into()) + } + Some(_) => Ok(path_utf8.into()), + } +} + #[cfg(test)] mod tests { use super::*; @@ -170,4 +193,13 @@ mod tests { assert_eq!(host_to_bucket("garage.tld", ".garage.tld"), "garage.tld"); } + + #[test] + fn path_to_key_test() -> Result<(), Error> { + assert_eq!(path_to_key("/file%20.jpg", "index.html")?, "/file .jpg"); + assert_eq!(path_to_key("/%20t/", "index.html")?, "/ t/index.html"); + assert_eq!(path_to_key("/", "index.html")?, "/index.html"); + assert!(path_to_key("", "index.html").is_err()); + Ok(()) + } } |