Support website publishing #7
4 changed files with 41 additions and 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`.
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
quentin marked this conversation as resolved
Outdated
|
||||
///
|
||||
/// 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(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue
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)