Support website publishing #7

Merged
lx merged 61 commits from feature/website into master 2021-01-15 16:49:51 +00:00
4 changed files with 41 additions and 5 deletions
Showing only changes of commit 2765291796 - Show all commits

View file

@ -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_region = "garage" # set this to anything. S3 API calls will fail if they are not made against the region set here.
[s3_web] [s3_web]
web_bind_addr = "[::1]:3902" bind_addr = "[::1]:3902"
root_domain = ".garage.tld"
index = "index.html"
``` ```
Build Garage using `cargo build --release`. Build Garage using `cargo build --release`.

View file

@ -19,3 +19,4 @@ s3_region = "garage" # set this to anything. S3 API calls will fail if they a
[s3_web] [s3_web]
bind_addr = "[::1]:3902" bind_addr = "[::1]:3902"
root_domain = ".garage.tld" root_domain = ".garage.tld"
index = "index.html"

View file

@ -56,6 +56,7 @@ pub struct ApiConfig {
pub struct WebConfig { pub struct WebConfig {
pub bind_addr: SocketAddr, pub bind_addr: SocketAddr,
pub root_domain: String, pub root_domain: String,
pub index: String,
} }
fn default_max_concurrent_rpc_requests() -> usize { fn default_max_concurrent_rpc_requests() -> usize {

View file

@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::Arc; use std::sync::Arc;
@ -55,17 +56,18 @@ async fn handler(
// Get path // Get path
let path = req.uri().path().to_string(); 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 let object = garage
.object_table .object_table
.get(&bucket.to_string(), &key.to_string()) .get(&bucket.to_string(), &key.to_string())
.await? .await?
.ok_or(Error::NotFound)?; .ok_or(Error::NotFound)?;
info!("Selected bucket: \"{}\", selected key: \"{}\"", bucket, key);
Ok(Response::new(Body::from("hello world\n"))) 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] &host[..cursor]
} }
/// Path to key
quentin marked this conversation as resolved Outdated
Outdated
Review

NO!! expect makes us crash (panic) if the condition is not verified, this is not acceptable (we don't want to assume that authority is well formed, maybe hyper checks it for us but maybe not and we don't want to take risks)

NO!! `expect` makes us crash (panic) if the condition is not verified, this is not acceptable (we don't want to assume that authority is well formed, maybe hyper checks it for us but maybe not and we don't want to take risks)
///
/// 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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -170,4 +193,13 @@ mod tests {
assert_eq!(host_to_bucket("garage.tld", ".garage.tld"), "garage.tld"); 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(())
}
} }