diff options
author | Alex Auvolat <alex@adnab.me> | 2022-01-07 16:23:04 +0100 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2022-01-24 11:58:00 +0100 |
commit | ea7fb901ebc316bba53d248a2f8bd7a3455f5791 (patch) | |
tree | 31da306e4c0b866bb9cc4241d6b01eac6c74bd49 /src/web/web_server.rs | |
parent | 820924534ab3eb0b2544a594881591559e7c45a5 (diff) | |
download | garage-ea7fb901ebc316bba53d248a2f8bd7a3455f5791.tar.gz garage-ea7fb901ebc316bba53d248a2f8bd7a3455f5791.zip |
Implement {Put,Get,Delete}BucketCors and CORS in general
- OPTIONS request against API endpoint
- Returning corresponding CORS headers on API calls
- Returning corresponding CORS headers on website GET's
Diffstat (limited to 'src/web/web_server.rs')
-rw-r--r-- | src/web/web_server.rs | 112 |
1 files changed, 60 insertions, 52 deletions
diff --git a/src/web/web_server.rs b/src/web/web_server.rs index 834f31e8..491ffdd3 100644 --- a/src/web/web_server.rs +++ b/src/web/web_server.rs @@ -11,8 +11,9 @@ use hyper::{ use crate::error::*; -use garage_api::error::{Error as ApiError, OkOrBadRequest}; +use garage_api::error::{Error as ApiError, OkOrBadRequest, OkOrInternalError}; use garage_api::helpers::{authority_to_host, host_to_bucket}; +use garage_api::s3_cors::{add_cors_headers, find_matching_cors_rule}; use garage_api::s3_get::{handle_get, handle_head}; use garage_model::garage::Garage; @@ -138,63 +139,70 @@ async fn serve_file(garage: Arc<Garage>, req: &Request<Body>) -> Result<Response } .map_err(Error::from); - if let Err(error) = ret_doc { - if *req.method() == Method::HEAD || !error.http_status_code().is_client_error() { - // Do not return the error document in the following cases: - // - the error is not a 4xx error code - // - the request is a HEAD method - // In this case we just return the error code and the error message in the body, - // by relying on err_to_res that is called above when we return an Err. - return Err(error); - } + match ret_doc { + Err(error) => { + // For a HEAD method, and for non-4xx errors, + // we don't return the error document as content, + // we return above and just return the error message + // by relying on err_to_res that is called when we return an Err. + if *req.method() == Method::HEAD || !error.http_status_code().is_client_error() { + return Err(error); + } - // Same if no error document is set: just return the error directly - let error_document = match &website_config.error_document { - Some(ed) => ed.trim_start_matches('/').to_owned(), - None => return Err(error), - }; - - // We want to return the error document - // Create a fake HTTP request with path = the error document - let req2 = Request::builder() - .uri(format!("http://{}/{}", host, &error_document)) - .body(Body::empty()) - .unwrap(); - - match handle_get(garage, &req2, bucket_id, &error_document).await { - Ok(mut error_doc) => { - // The error won't be logged back in handle_request, - // so log it here - info!( - "{} {} {} {}", - req.method(), - req.uri(), - error.http_status_code(), - error - ); - - *error_doc.status_mut() = error.http_status_code(); - error.add_headers(error_doc.headers_mut()); - - // Preserve error message in a special header - for error_line in error.to_string().split('\n') { - if let Ok(v) = HeaderValue::from_bytes(error_line.as_bytes()) { - error_doc.headers_mut().append("X-Garage-Error", v); + // If no error document is set: just return the error directly + let error_document = match &website_config.error_document { + Some(ed) => ed.trim_start_matches('/').to_owned(), + None => return Err(error), + }; + + // We want to return the error document + // Create a fake HTTP request with path = the error document + let req2 = Request::builder() + .uri(format!("http://{}/{}", host, &error_document)) + .body(Body::empty()) + .unwrap(); + + match handle_get(garage, &req2, bucket_id, &error_document).await { + Ok(mut error_doc) => { + // The error won't be logged back in handle_request, + // so log it here + info!( + "{} {} {} {}", + req.method(), + req.uri(), + error.http_status_code(), + error + ); + + *error_doc.status_mut() = error.http_status_code(); + error.add_headers(error_doc.headers_mut()); + + // Preserve error message in a special header + for error_line in error.to_string().split('\n') { + if let Ok(v) = HeaderValue::from_bytes(error_line.as_bytes()) { + error_doc.headers_mut().append("X-Garage-Error", v); + } } - } - Ok(error_doc) + Ok(error_doc) + } + Err(error_doc_error) => { + warn!( + "Couldn't get error document {} for bucket {:?}: {}", + error_document, bucket_id, error_doc_error + ); + Err(error) + } } - Err(error_doc_error) => { - warn!( - "Couldn't get error document {} for bucket {:?}: {}", - error_document, bucket_id, error_doc_error - ); - Err(error) + } + Ok(mut resp) => { + // Maybe add CORS headers + if let Some(rule) = find_matching_cors_rule(&bucket, req)? { + add_cors_headers(&mut resp, rule) + .ok_or_internal_error("Invalid bucket CORS configuration")?; } + Ok(resp) } - } else { - ret_doc } } |