diff --git a/nexus/src/external_api/console_api.rs b/nexus/src/external_api/console_api.rs index 818271c8cae..00ef172d1e7 100644 --- a/nexus/src/external_api/console_api.rs +++ b/nexus/src/external_api/console_api.rs @@ -624,7 +624,7 @@ fn with_gz_ext(path: Vec) -> Vec { return path; } - let mut new_path = path.clone(); + let mut new_path = path; let last = new_path.pop().unwrap(); // we know there's one there new_path.push(format!("{last}.gz")); new_path @@ -645,7 +645,7 @@ pub async fn asset( let path = path_params.into_inner().path; // bail unless the extension is allowed - let filename = path.last().ok_or(not_found("no path"))?; + let filename = path.last().ok_or_else(|| not_found("no path"))?; let ext = PathBuf::from(filename) .extension() .map(|ext| ext.to_os_string()) @@ -659,14 +659,21 @@ pub async fn asset( .console_config .static_dir .as_ref() - .ok_or(not_found("static_dir undefined"))? + .ok_or_else(|| not_found("static_dir undefined"))? .join("assets"); + let request = &rqctx.request.lock().await; + let accept_encoding = request.headers().get(http::header::ACCEPT_ENCODING); + + let accept_gz = accept_encoding.map_or(false, |val| { + val.to_str().map_or(false, |s| s.contains("gzip")) + }); + let path_gz = with_gz_ext(path.clone()); - // try to find the gzipped version, fall back to non-gz - let (file, gzipped) = match find_file(path_gz, &assets_dir) { - Ok(file) => (file, true), + // try to find the gzipped version (if accepted), fall back to non-gz + let (file, gzipped) = match (accept_gz, find_file(path_gz, &assets_dir)) { + (true, Ok(gzipped_file)) => (gzipped_file, true), _ => (find_file(path, &assets_dir)?, false), }; diff --git a/nexus/tests/integration_tests/console_api.rs b/nexus/tests/integration_tests/console_api.rs index a8fb90415fe..fdcf7e3fdf0 100644 --- a/nexus/tests/integration_tests/console_api.rs +++ b/nexus/tests/integration_tests/console_api.rs @@ -195,10 +195,32 @@ async fn test_assets(cptestctx: &ControlPlaneTestContext) { .expect("failed to get existing file"); assert_eq!(resp.body, "hello there".as_bytes()); + // make sure we're not including the gzip header on non-gzipped files + assert_eq!(resp.headers.get(http::header::CONTENT_ENCODING), None); - // file with existing gzipped version is returned + // file with only gzipped version 404s if request doesn't have accept-encoding: gzip + let _ = RequestBuilder::new(&testctx, Method::GET, "/assets/gzip-only.txt") + .expect_status(Some(StatusCode::NOT_FOUND)) + .execute() + .await + .expect("failed to 404 on gzip file without accept-encoding: gzip"); + + // file with only gzipped version is returned if request accepts gzip let resp = - RequestBuilder::new(&testctx, Method::GET, "/assets/gzipped.txt") + RequestBuilder::new(&testctx, Method::GET, "/assets/gzip-only.txt") + .header(http::header::ACCEPT_ENCODING, "gzip") + .expect_status(Some(StatusCode::OK)) + .expect_response_header(http::header::CONTENT_ENCODING, "gzip") + .execute() + .await + .expect("failed to get existing file"); + + assert_eq!(resp.body, "nothing but gzip".as_bytes()); + + // file with both gzip and not returns gzipped if request accepts gzip + let resp = + RequestBuilder::new(&testctx, Method::GET, "/assets/gzip-and-not.txt") + .header(http::header::ACCEPT_ENCODING, "gzip") .expect_status(Some(StatusCode::OK)) .expect_response_header(http::header::CONTENT_ENCODING, "gzip") .execute() @@ -206,6 +228,18 @@ async fn test_assets(cptestctx: &ControlPlaneTestContext) { .expect("failed to get existing file"); assert_eq!(resp.body, "pretend this is gzipped beep boop".as_bytes()); + + // returns non-gzipped if request doesn't accept gzip + let resp = + RequestBuilder::new(&testctx, Method::GET, "/assets/gzip-and-not.txt") + .expect_status(Some(StatusCode::OK)) + .execute() + .await + .expect("failed to get existing file"); + + assert_eq!(resp.body, "not gzipped but I know a guy".as_bytes()); + // make sure we're not including the gzip header on non-gzipped files + assert_eq!(resp.headers.get(http::header::CONTENT_ENCODING), None); } #[tokio::test] diff --git a/nexus/tests/static/assets/gzip-and-not.txt b/nexus/tests/static/assets/gzip-and-not.txt new file mode 100644 index 00000000000..d95fa1e9038 --- /dev/null +++ b/nexus/tests/static/assets/gzip-and-not.txt @@ -0,0 +1 @@ +not gzipped but I know a guy \ No newline at end of file diff --git a/nexus/tests/static/assets/gzipped.txt.gz b/nexus/tests/static/assets/gzip-and-not.txt.gz similarity index 100% rename from nexus/tests/static/assets/gzipped.txt.gz rename to nexus/tests/static/assets/gzip-and-not.txt.gz diff --git a/nexus/tests/static/assets/gzip-only.txt.gz b/nexus/tests/static/assets/gzip-only.txt.gz new file mode 100644 index 00000000000..f3909518533 --- /dev/null +++ b/nexus/tests/static/assets/gzip-only.txt.gz @@ -0,0 +1 @@ +nothing but gzip \ No newline at end of file