From 26bc8079050a52be9a12d02fc49fe20645660c78 Mon Sep 17 00:00:00 2001 From: trinity-1686a Date: Tue, 10 Jun 2025 20:42:59 +0200 Subject: [PATCH] put web error in a basic webpage before, it was a plain string, with an xml content type this caused browsers to show very ugly and meaningless pages --- src/garage/tests/s3/website.rs | 42 ++++++++++++++++++++++++++++++++++ src/web/web_server.rs | 24 +++++++++++++++++-- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/garage/tests/s3/website.rs b/src/garage/tests/s3/website.rs index 6d37eee8..bbac3de5 100644 --- a/src/garage/tests/s3/website.rs +++ b/src/garage/tests/s3/website.rs @@ -606,3 +606,45 @@ async fn test_website_puny() { ); } } + +#[tokio::test] +async fn test_website_object_not_found() { + const BCKT_NAME: &str = "not-found"; + let ctx = common::context(); + let _bucket = ctx.create_bucket(BCKT_NAME); + + let client = Client::builder(TokioExecutor::new()).build_http(); + + let req = |suffix| { + Request::builder() + .method("GET") + .uri(format!("http://127.0.0.1:{}/", ctx.garage.web_port)) + .header("Host", format!("{}{}", BCKT_NAME, suffix)) + .body(Body::new(Bytes::new())) + .unwrap() + }; + + ctx.garage + .command() + .args(["bucket", "website", "--allow", BCKT_NAME]) + .quiet() + .expect_success_status("Could not allow website on bucket"); + + let resp = client.request(req("")).await.unwrap(); + assert_eq!(resp.status(), StatusCode::NOT_FOUND); + // the error we return by default are *not* xml + assert_eq!( + resp.headers().get(http::header::CONTENT_TYPE).unwrap(), + "text/html; charset=utf-8" + ); + let result = String::from_utf8( + resp.into_body() + .collect() + .await + .unwrap() + .to_bytes() + .to_vec(), + ) + .unwrap(); + assert!(result.contains("not found")); +} diff --git a/src/web/web_server.rs b/src/web/web_server.rs index 242f7801..ea02ab0f 100644 --- a/src/web/web_server.rs +++ b/src/web/web_server.rs @@ -397,10 +397,30 @@ fn error_to_res(e: Error) -> Response> { // was a HEAD request or we couldn't get the error document) // We do NOT enter this code path when returning the bucket's // error document (this is handled in serve_file) - let body = string_body(format!("{}\n", e)); - let mut http_error = Response::new(body); + let mut body_str = format!( + r"{http_code} {code_text} +

{http_code} {code_text}

", + http_code = e.http_status_code().as_u16(), + code_text = e.http_status_code().canonical_reason().unwrap_or("Unknown"), + ); + if let Error::ApiError(ref err) = e { + body_str.push_str(&format!( + r" +", + s3_code = err.aws_code(), + s3_message = err, + )); + } + let mut http_error = Response::new(string_body(body_str)); *http_error.status_mut() = e.http_status_code(); e.add_headers(http_error.headers_mut()); + http_error.headers_mut().insert( + http::header::CONTENT_TYPE, + "text/html; charset=utf-8".parse().unwrap(), + ); http_error }