aboutsummaryrefslogtreecommitdiff
path: root/src/api
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2022-03-01 11:15:16 +0100
committerAlex Auvolat <alex@adnab.me>2022-03-01 11:15:16 +0100
commit8a5bbc3b0b1c6ab252d0c98950456a9d4cc2e9fe (patch)
treefc58f965981debc989108c39379dfca3c4da5e93 /src/api
parent97f245f218836c699088ab51d810f33ae947c903 (diff)
downloadgarage-8a5bbc3b0b1c6ab252d0c98950456a9d4cc2e9fe.tar.gz
garage-8a5bbc3b0b1c6ab252d0c98950456a9d4cc2e9fe.zip
More permissive OPTIONS on S3 APIv0.6.1better-cors
Diffstat (limited to 'src/api')
-rw-r--r--src/api/api_server.rs2
-rw-r--r--src/api/s3_cors.rs64
2 files changed, 48 insertions, 18 deletions
diff --git a/src/api/api_server.rs b/src/api/api_server.rs
index 5ac78bf4..322ea298 100644
--- a/src/api/api_server.rs
+++ b/src/api/api_server.rs
@@ -116,7 +116,7 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
return handle_post_object(garage, req, bucket_name.unwrap()).await;
}
if let Endpoint::Options = endpoint {
- return handle_options(garage, &req, bucket_name).await;
+ return handle_options_s3api(garage, &req, bucket_name).await;
}
let (api_key, content_sha256) = check_payload_signature(&garage, &req).await?;
diff --git a/src/api/s3_cors.rs b/src/api/s3_cors.rs
index 7dc48d8e..e3deaeda 100644
--- a/src/api/s3_cors.rs
+++ b/src/api/s3_cors.rs
@@ -100,33 +100,63 @@ pub async fn handle_put_cors(
.body(Body::empty())?)
}
-pub async fn handle_options(
+pub async fn handle_options_s3api(
garage: Arc<Garage>,
req: &Request<Body>,
bucket_name: Option<String>,
) -> Result<Response<Body>, Error> {
- let bucket = if let Some(bn) = bucket_name {
+ // FIXME: CORS rules of buckets with local aliases are
+ // not taken into account.
+
+ // If the bucket name is a global bucket name,
+ // we try to apply the CORS rules of that bucket.
+ // If a user has a local bucket name that has
+ // the same name, its CORS rules won't be applied
+ // and will be shadowed by the rules of the globally
+ // existing bucket (but this is inevitable because
+ // OPTIONS calls are not auhtenticated).
+ if let Some(bn) = bucket_name {
let helper = garage.bucket_helper();
- let bucket_id = helper
- .resolve_global_bucket_name(&bn)
- .await?
- .ok_or(Error::NoSuchBucket)?;
- garage
- .bucket_table
- .get(&EmptyKey, &bucket_id)
- .await?
- .filter(|b| !b.state.is_deleted())
- .ok_or(Error::NoSuchBucket)?
+ let bucket_id = helper.resolve_global_bucket_name(&bn).await?;
+ if let Some(id) = bucket_id {
+ let bucket = garage
+ .bucket_table
+ .get(&EmptyKey, &id)
+ .await?
+ .filter(|b| !b.state.is_deleted())
+ .ok_or(Error::NoSuchBucket)?;
+ handle_options_for_bucket(req, &bucket)
+ } else {
+ // If there is a bucket name in the request, but that name
+ // does not correspond to a global alias for a bucket,
+ // then it's either a non-existing bucket or a local bucket.
+ // We have no way of knowing, because the request is not
+ // authenticated and thus we can't resolve local aliases.
+ // We take the permissive approach of allowing everything,
+ // because we don't want to prevent web apps that use
+ // local bucket names from making API calls.
+ Ok(Response::builder()
+ .header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
+ .header(ACCESS_CONTROL_ALLOW_METHODS, "*")
+ .status(StatusCode::OK)
+ .body(Body::empty())?)
+ }
} else {
- // The only supported API call that doesn't use a bucket name is ListBuckets,
- // which we want to allow in all cases
- return Ok(Response::builder()
+ // If there is no bucket name in the request,
+ // we are doing a ListBuckets call, which we want to allow
+ // for all origins.
+ Ok(Response::builder()
.header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
.header(ACCESS_CONTROL_ALLOW_METHODS, "GET")
.status(StatusCode::OK)
- .body(Body::empty())?);
- };
+ .body(Body::empty())?)
+ }
+}
+pub fn handle_options_for_bucket(
+ req: &Request<Body>,
+ bucket: &Bucket,
+) -> Result<Response<Body>, Error> {
let origin = req
.headers()
.get("Origin")