aboutsummaryrefslogtreecommitdiff
path: root/src/api/api_server.rs
diff options
context:
space:
mode:
authorTrinity Pointard <trinity.pointard@gmail.com>2021-11-11 14:12:22 +0100
committerGitea <gitea@fake.local>2021-11-16 15:41:41 +0100
commit02158ee666390b0da964af09ce2e894e13e29fc5 (patch)
treef0f0f5abb251482b76641fa9dec3e64324daf970 /src/api/api_server.rs
parent57df9c6e2d806c55d29faffaac241a153c0d9bcb (diff)
downloadgarage-02158ee666390b0da964af09ce2e894e13e29fc5.tar.gz
garage-02158ee666390b0da964af09ce2e894e13e29fc5.zip
fix issue where list on vhost-bucket would list bucket instead of bucket content
Diffstat (limited to 'src/api/api_server.rs')
-rw-r--r--src/api/api_server.rs102
1 files changed, 29 insertions, 73 deletions
diff --git a/src/api/api_server.rs b/src/api/api_server.rs
index 2217be1a..ab690c30 100644
--- a/src/api/api_server.rs
+++ b/src/api/api_server.rs
@@ -84,9 +84,6 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
let path = req.uri().path().to_string();
let path = percent_encoding::percent_decode_str(&path).decode_utf8()?;
let (api_key, content_sha256) = check_signature(&garage, &req).await?;
- if path == "/" {
- return handle_list_buckets(&api_key);
- }
let authority = req
.headers()
@@ -94,14 +91,20 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
.ok_or_else(|| Error::BadRequest("HOST header required".to_owned()))?
.to_str()?;
- // Get bucket
let host = authority_to_host(authority)?;
- let (bucket, key) = parse_bucket_key(
- &path,
- Some(&host),
- garage.config.s3_api.root_domain.as_deref(),
- )?;
+ let bucket = garage
+ .config
+ .s3_api
+ .root_domain
+ .as_ref()
+ .and_then(|root_domain| host_to_bucket(&host, &root_domain));
+
+ if path == "/" && bucket.is_none() {
+ return handle_list_buckets(&api_key);
+ }
+
+ let (bucket, key) = parse_bucket_key(&path, bucket)?;
let allowed = match req.method() {
&Method::HEAD | &Method::GET => api_key.allow_read(bucket),
_ => api_key.allow_write(bucket),
@@ -152,7 +155,7 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
let copy_source = req.headers().get("x-amz-copy-source").unwrap().to_str()?;
let copy_source =
percent_encoding::percent_decode_str(copy_source).decode_utf8()?;
- let (source_bucket, source_key) = parse_bucket_key(&copy_source, None, None)?;
+ let (source_bucket, source_key) = parse_bucket_key(&copy_source, None)?;
if !api_key.allow_read(source_bucket) {
return Err(Error::Forbidden(format!(
"Reading from bucket {} not allowed for this key",
@@ -260,24 +263,21 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
}
}
-/// Extract the bucket name and the key name from an HTTP path
+/// Extract the bucket name and the key name from an HTTP path and possibly Host header
///
/// S3 internally manages only buckets and keys. This function splits
/// an HTTP path to get the corresponding bucket name and key.
fn parse_bucket_key<'a>(
path: &'a str,
- host: Option<&'a str>,
- root: Option<&str>,
+ host_bucket: Option<&'a str>,
) -> Result<(&'a str, Option<&'a str>), Error> {
let path = path.trim_start_matches('/');
- if host.and(root).is_some() {
- if let Some(bucket) = host_to_bucket(host.unwrap(), root.unwrap()) {
- if !path.is_empty() {
- return Ok((bucket, Some(path)));
- } else {
- return Ok((bucket, None));
- }
+ if let Some(bucket) = host_bucket {
+ if !path.is_empty() {
+ return Ok((bucket, Some(path)));
+ } else {
+ return Ok((bucket, None));
}
}
@@ -304,7 +304,7 @@ mod tests {
#[test]
fn parse_bucket_containing_a_key() -> Result<(), Error> {
- let (bucket, key) = parse_bucket_key("/my_bucket/a/super/file.jpg", None, None)?;
+ let (bucket, key) = parse_bucket_key("/my_bucket/a/super/file.jpg", None)?;
assert_eq!(bucket, "my_bucket");
assert_eq!(key.expect("key must be set"), "a/super/file.jpg");
Ok(())
@@ -312,10 +312,10 @@ mod tests {
#[test]
fn parse_bucket_containing_no_key() -> Result<(), Error> {
- let (bucket, key) = parse_bucket_key("/my_bucket/", None, None)?;
+ let (bucket, key) = parse_bucket_key("/my_bucket/", None)?;
assert_eq!(bucket, "my_bucket");
assert!(key.is_none());
- let (bucket, key) = parse_bucket_key("/my_bucket", None, None)?;
+ let (bucket, key) = parse_bucket_key("/my_bucket", None)?;
assert_eq!(bucket, "my_bucket");
assert!(key.is_none());
Ok(())
@@ -323,74 +323,30 @@ mod tests {
#[test]
fn parse_bucket_containing_no_bucket() {
- let parsed = parse_bucket_key("", None, None);
+ let parsed = parse_bucket_key("", None);
assert!(parsed.is_err());
- let parsed = parse_bucket_key("/", None, None);
+ let parsed = parse_bucket_key("/", None);
assert!(parsed.is_err());
- let parsed = parse_bucket_key("////", None, None);
+ let parsed = parse_bucket_key("////", None);
assert!(parsed.is_err());
}
#[test]
fn parse_bucket_with_vhost_and_key() -> Result<(), Error> {
- let (bucket, key) = parse_bucket_key(
- "/a/super/file.jpg",
- Some("my-bucket.garage.tld"),
- Some("garage.tld"),
- )?;
+ let (bucket, key) = parse_bucket_key("/a/super/file.jpg", Some("my-bucket"))?;
assert_eq!(bucket, "my-bucket");
assert_eq!(key.expect("key must be set"), "a/super/file.jpg");
-
- let (bucket, key) = parse_bucket_key(
- "/my_bucket/a/super/file.jpg",
- Some("not-garage.tld"),
- Some("garage.tld"),
- )?;
- assert_eq!(bucket, "my_bucket");
- assert_eq!(key.expect("key must be set"), "a/super/file.jpg");
Ok(())
}
#[test]
fn parse_bucket_with_vhost_no_key() -> Result<(), Error> {
- let (bucket, key) = parse_bucket_key("", Some("my-bucket.garage.tld"), Some("garage.tld"))?;
+ let (bucket, key) = parse_bucket_key("", Some("my-bucket"))?;
assert_eq!(bucket, "my-bucket");
assert!(key.is_none());
- let (bucket, key) =
- parse_bucket_key("/", Some("my-bucket.garage.tld"), Some("garage.tld"))?;
+ let (bucket, key) = parse_bucket_key("/", Some("my-bucket"))?;
assert_eq!(bucket, "my-bucket");
assert!(key.is_none());
Ok(())
}
-
- #[test]
- fn parse_bucket_missmatch_vhost() {
- let test_vec = [
- "/my_bucket/a/super/file.jpg",
- "/my_bucket/",
- "/my_bucket",
- "",
- "/",
- "////",
- ];
- let eq = |l, r| match (l, r) {
- (Ok(l), Ok(r)) => l == r,
- (Err(_), Err(_)) => true,
- _ => false,
- };
- for test in test_vec {
- assert!(eq(
- parse_bucket_key(test, None, None),
- parse_bucket_key(test, Some("bucket.garage.tld"), None)
- ));
- assert!(eq(
- parse_bucket_key(test, None, None),
- parse_bucket_key(test, None, Some("garage.tld"))
- ));
- assert!(eq(
- parse_bucket_key(test, None, None),
- parse_bucket_key(test, Some("not-garage.tld"), Some("garage.tld"))
- ));
- }
- }
}