Process CORS earlier in pipeline
This commit is contained in:
parent
54e02b4c3b
commit
8129a98291
4 changed files with 39 additions and 7 deletions
|
@ -111,9 +111,13 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
|
||||||
let (endpoint, bucket_name) = Endpoint::from_request(&req, bucket_name.map(ToOwned::to_owned))?;
|
let (endpoint, bucket_name) = Endpoint::from_request(&req, bucket_name.map(ToOwned::to_owned))?;
|
||||||
debug!("Endpoint: {:?}", endpoint);
|
debug!("Endpoint: {:?}", endpoint);
|
||||||
|
|
||||||
if let Endpoint::PostObject {} = endpoint {
|
// Some endpoints are processed early, before we even check for an API key
|
||||||
|
if let Endpoint::PostObject = endpoint {
|
||||||
return handle_post_object(garage, req, bucket_name.unwrap()).await;
|
return handle_post_object(garage, req, bucket_name.unwrap()).await;
|
||||||
}
|
}
|
||||||
|
if let Endpoint::Options = endpoint {
|
||||||
|
return handle_options(garage, &req, bucket_name).await;
|
||||||
|
}
|
||||||
|
|
||||||
let (api_key, content_sha256) = check_payload_signature(&garage, &req).await?;
|
let (api_key, content_sha256) = check_payload_signature(&garage, &req).await?;
|
||||||
let api_key = api_key.ok_or_else(|| {
|
let api_key = api_key.ok_or_else(|| {
|
||||||
|
@ -161,7 +165,6 @@ async fn handler_inner(garage: Arc<Garage>, req: Request<Body>) -> Result<Respon
|
||||||
};
|
};
|
||||||
|
|
||||||
let resp = match endpoint {
|
let resp = match endpoint {
|
||||||
Endpoint::Options => handle_options(&req, &bucket).await,
|
|
||||||
Endpoint::HeadObject {
|
Endpoint::HeadObject {
|
||||||
key, part_number, ..
|
key, part_number, ..
|
||||||
} => handle_head(garage, &req, bucket_id, &key, part_number).await,
|
} => handle_head(garage, &req, bucket_id, &key, part_number).await,
|
||||||
|
|
|
@ -100,7 +100,33 @@ pub async fn handle_put_cors(
|
||||||
.body(Body::empty())?)
|
.body(Body::empty())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_options(req: &Request<Body>, bucket: &Bucket) -> Result<Response<Body>, Error> {
|
pub async fn handle_options(
|
||||||
|
garage: Arc<Garage>,
|
||||||
|
req: &Request<Body>,
|
||||||
|
bucket_name: Option<String>,
|
||||||
|
) -> Result<Response<Body>, Error> {
|
||||||
|
let bucket = 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)?
|
||||||
|
} 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()
|
||||||
|
.header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
|
||||||
|
.header(ACCESS_CONTROL_ALLOW_METHODS, "GET")
|
||||||
|
.status(StatusCode::OK)
|
||||||
|
.body(Body::empty())?);
|
||||||
|
};
|
||||||
|
|
||||||
let origin = req
|
let origin = req
|
||||||
.headers()
|
.headers()
|
||||||
.get("Origin")
|
.get("Origin")
|
||||||
|
|
|
@ -414,8 +414,7 @@ pub enum Endpoint {
|
||||||
// It's intended to be used with HTML forms, using a multipart/form-data body.
|
// It's intended to be used with HTML forms, using a multipart/form-data body.
|
||||||
// It works a lot like presigned requests, but everything is in the form instead
|
// It works a lot like presigned requests, but everything is in the form instead
|
||||||
// of being query parameters of the URL, so authenticating it is a bit different.
|
// of being query parameters of the URL, so authenticating it is a bit different.
|
||||||
PostObject {
|
PostObject,
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
impl Endpoint {
|
impl Endpoint {
|
||||||
|
@ -430,7 +429,11 @@ impl Endpoint {
|
||||||
let path = uri.path().trim_start_matches('/');
|
let path = uri.path().trim_start_matches('/');
|
||||||
let query = uri.query();
|
let query = uri.query();
|
||||||
if bucket.is_none() && path.is_empty() {
|
if bucket.is_none() && path.is_empty() {
|
||||||
return Ok((Self::ListBuckets, None));
|
if *req.method() == Method::OPTIONS {
|
||||||
|
return Ok((Self::Options, None));
|
||||||
|
} else {
|
||||||
|
return Ok((Self::ListBuckets, None));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (bucket, key) = if let Some(bucket) = bucket {
|
let (bucket, key) = if let Some(bucket) = bucket {
|
||||||
|
|
|
@ -133,7 +133,7 @@ async fn serve_file(garage: Arc<Garage>, req: &Request<Body>) -> Result<Response
|
||||||
);
|
);
|
||||||
|
|
||||||
let ret_doc = match *req.method() {
|
let ret_doc = match *req.method() {
|
||||||
Method::OPTIONS => handle_options(req, &bucket).await,
|
Method::OPTIONS => handle_options(garage.clone(), req, Some(bucket_name.to_string())).await,
|
||||||
Method::HEAD => handle_head(garage.clone(), req, bucket_id, &key, None).await,
|
Method::HEAD => handle_head(garage.clone(), req, bucket_id, &key, None).await,
|
||||||
Method::GET => handle_get(garage.clone(), req, bucket_id, &key, None).await,
|
Method::GET => handle_get(garage.clone(), req, bucket_id, &key, None).await,
|
||||||
_ => Err(ApiError::BadRequest("HTTP method not supported".into())),
|
_ => Err(ApiError::BadRequest("HTTP method not supported".into())),
|
||||||
|
|
Loading…
Reference in a new issue