Merge pull request 'api_server.rs: Adapted to use query string per Caddy upstream change' (#491) from jpds/garage:fix-caddy-ask-domain-query-string into main

Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/491
This commit is contained in:
Alex 2023-01-30 10:50:47 +00:00
commit 4d3a5f29e0
2 changed files with 82 additions and 37 deletions

View file

@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::Arc; use std::sync::Arc;
@ -81,29 +82,32 @@ impl AdminApiServer {
&self, &self,
req: Request<Body>, req: Request<Body>,
) -> Result<Response<Body>, Error> { ) -> Result<Response<Body>, Error> {
let has_domain_header = req.headers().contains_key("domain"); let query_params: HashMap<String, String> = req
.uri()
.query()
.map(|v| {
url::form_urlencoded::parse(v.as_bytes())
.into_owned()
.collect()
})
.unwrap_or_else(HashMap::new);
if !has_domain_header { let has_domain_key = query_params.contains_key("domain");
return Err(Error::bad_request("No domain header found"));
if !has_domain_key {
return Err(Error::bad_request("No domain query string found"));
} }
let domain = &req let domain = query_params
.headers()
.get("domain") .get("domain")
.ok_or_internal_error("Could not parse domain header")?; .ok_or_internal_error("Could not parse domain query string")?;
let domain_string = String::from(
domain
.to_str()
.ok_or_bad_request("Invalid characters found in domain header")?,
);
let bucket_id = self let bucket_id = self
.garage .garage
.bucket_helper() .bucket_helper()
.resolve_global_bucket_name(&domain_string) .resolve_global_bucket_name(&domain)
.await? .await?
.ok_or(HelperError::NoSuchBucket(domain_string))?; .ok_or(HelperError::NoSuchBucket(domain.to_string()))?;
let bucket = self let bucket = self
.garage .garage
@ -115,12 +119,16 @@ impl AdminApiServer {
let bucket_website_config = bucket_state.website_config.get(); let bucket_website_config = bucket_state.website_config.get();
match bucket_website_config { match bucket_website_config {
Some(_v) => Ok(Response::builder() Some(_v) => {
.status(StatusCode::OK) Ok(Response::builder()
.body(Body::from("Bucket authorized for website hosting"))?), .status(StatusCode::OK)
None => Err(Error::bad_request( .body(Body::from(format!(
"Bucket is not authorized for website hosting", "Bucket '{domain}' is authorized for website hosting"
)), )))?)
}
None => Err(Error::bad_request(format!(
"Bucket '{domain}' is not authorized for website hosting"
))),
} }
} }

View file

@ -56,8 +56,11 @@ async fn test_website() {
let admin_req = || { let admin_req = || {
Request::builder() Request::builder()
.method("GET") .method("GET")
.uri(format!("http://127.0.0.1:{}/check", ctx.garage.admin_port)) .uri(format!(
.header("domain", BCKT_NAME.to_string()) "http://127.0.0.1:{0}/check?domain={1}",
ctx.garage.admin_port,
BCKT_NAME.to_string()
))
.body(Body::empty()) .body(Body::empty())
.unwrap() .unwrap()
}; };
@ -69,7 +72,7 @@ async fn test_website() {
res_body, res_body,
json!({ json!({
"code": "InvalidRequest", "code": "InvalidRequest",
"message": "Bad request: Bucket is not authorized for website hosting", "message": "Bad request: Bucket 'my-website' is not authorized for website hosting",
"region": "garage-integ-test", "region": "garage-integ-test",
"path": "/check", "path": "/check",
}) })
@ -91,8 +94,11 @@ async fn test_website() {
let admin_req = || { let admin_req = || {
Request::builder() Request::builder()
.method("GET") .method("GET")
.uri(format!("http://127.0.0.1:{}/check", ctx.garage.admin_port)) .uri(format!(
.header("domain", BCKT_NAME.to_string()) "http://127.0.0.1:{0}/check?domain={1}",
ctx.garage.admin_port,
BCKT_NAME.to_string()
))
.body(Body::empty()) .body(Body::empty())
.unwrap() .unwrap()
}; };
@ -101,7 +107,7 @@ async fn test_website() {
assert_eq!(admin_resp.status(), StatusCode::OK); assert_eq!(admin_resp.status(), StatusCode::OK);
assert_eq!( assert_eq!(
to_bytes(admin_resp.body_mut()).await.unwrap().as_ref(), to_bytes(admin_resp.body_mut()).await.unwrap().as_ref(),
b"Bucket authorized for website hosting" format!("Bucket '{BCKT_NAME}' is authorized for website hosting").as_bytes()
); );
ctx.garage ctx.garage
@ -120,8 +126,11 @@ async fn test_website() {
let admin_req = || { let admin_req = || {
Request::builder() Request::builder()
.method("GET") .method("GET")
.uri(format!("http://127.0.0.1:{}/check", ctx.garage.admin_port)) .uri(format!(
.header("domain", BCKT_NAME.to_string()) "http://127.0.0.1:{0}/check?domain={1}",
ctx.garage.admin_port,
BCKT_NAME.to_string()
))
.body(Body::empty()) .body(Body::empty())
.unwrap() .unwrap()
}; };
@ -133,7 +142,7 @@ async fn test_website() {
res_body, res_body,
json!({ json!({
"code": "InvalidRequest", "code": "InvalidRequest",
"message": "Bad request: Bucket is not authorized for website hosting", "message": "Bad request: Bucket 'my-website' is not authorized for website hosting",
"region": "garage-integ-test", "region": "garage-integ-test",
"path": "/check", "path": "/check",
}) })
@ -408,7 +417,7 @@ async fn test_website_check_website_enabled() {
res_body, res_body,
json!({ json!({
"code": "InvalidRequest", "code": "InvalidRequest",
"message": "Bad request: No domain header found", "message": "Bad request: No domain query string found",
"region": "garage-integ-test", "region": "garage-integ-test",
"path": "/check", "path": "/check",
}) })
@ -417,8 +426,34 @@ async fn test_website_check_website_enabled() {
let admin_req = || { let admin_req = || {
Request::builder() Request::builder()
.method("GET") .method("GET")
.uri(format!("http://127.0.0.1:{}/check", ctx.garage.admin_port)) .uri(format!(
.header("domain", "foobar") "http://127.0.0.1:{}/check?domain=",
ctx.garage.admin_port
))
.body(Body::empty())
.unwrap()
};
let admin_resp = client.request(admin_req()).await.unwrap();
assert_eq!(admin_resp.status(), StatusCode::NOT_FOUND);
let res_body = json_body(admin_resp).await;
assert_json_eq!(
res_body,
json!({
"code": "NoSuchBucket",
"message": "Bucket not found: ",
"region": "garage-integ-test",
"path": "/check",
})
);
let admin_req = || {
Request::builder()
.method("GET")
.uri(format!(
"http://127.0.0.1:{}/check?domain=foobar",
ctx.garage.admin_port
))
.body(Body::empty()) .body(Body::empty())
.unwrap() .unwrap()
}; };
@ -439,20 +474,22 @@ async fn test_website_check_website_enabled() {
let admin_req = || { let admin_req = || {
Request::builder() Request::builder()
.method("GET") .method("GET")
.uri(format!("http://127.0.0.1:{}/check", ctx.garage.admin_port)) .uri(format!(
.header("domain", "") "http://127.0.0.1:{}/check?domain=%E2%98%B9",
ctx.garage.admin_port
))
.body(Body::empty()) .body(Body::empty())
.unwrap() .unwrap()
}; };
let admin_resp = client.request(admin_req()).await.unwrap(); let admin_resp = client.request(admin_req()).await.unwrap();
assert_eq!(admin_resp.status(), StatusCode::BAD_REQUEST); assert_eq!(admin_resp.status(), StatusCode::NOT_FOUND);
let res_body = json_body(admin_resp).await; let res_body = json_body(admin_resp).await;
assert_json_eq!( assert_json_eq!(
res_body, res_body,
json!({ json!({
"code": "InvalidRequest", "code": "NoSuchBucket",
"message": "Bad request: Invalid characters found in domain header: failed to convert header to a str", "message": "Bucket not found: ☹",
"region": "garage-integ-test", "region": "garage-integ-test",
"path": "/check", "path": "/check",
}) })