From be59a63c62574d28e5b7322ef349e8da2c1461a9 Mon Sep 17 00:00:00 2001 From: Benjamin Swart Date: Tue, 3 Sep 2024 22:42:50 +0300 Subject: [PATCH 1/5] Add support for serving precompressed static files without an extension (#504) --- test-files/extensionless_precompressed | 1 + test-files/extensionless_precompressed.gz | Bin 0 -> 57 bytes tower-http/src/content_encoding.rs | 2 +- .../src/services/fs/serve_dir/open_file.rs | 24 ++++++++++++++---- tower-http/src/services/fs/serve_dir/tests.rs | 23 +++++++++++++++++ 5 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 test-files/extensionless_precompressed create mode 100644 test-files/extensionless_precompressed.gz diff --git a/test-files/extensionless_precompressed b/test-files/extensionless_precompressed new file mode 100644 index 00000000..032a5d4d --- /dev/null +++ b/test-files/extensionless_precompressed @@ -0,0 +1 @@ +Content. diff --git a/test-files/extensionless_precompressed.gz b/test-files/extensionless_precompressed.gz new file mode 100644 index 0000000000000000000000000000000000000000..3322cc24a37f5eb0e45d93114bdeae0a06d568dc GIT binary patch literal 57 zcmb2|=HNJ$ay^ZKIkloBHLo}`KQAY>xH!I`C^b1h7f2Qtr=~CzpF6MZc~<-4V MJD(MDGB7Xz0E)~OiU0rr literal 0 HcmV?d00001 diff --git a/tower-http/src/content_encoding.rs b/tower-http/src/content_encoding.rs index a0e60a3c..91c21d45 100644 --- a/tower-http/src/content_encoding.rs +++ b/tower-http/src/content_encoding.rs @@ -142,7 +142,7 @@ pub(crate) struct QValue(u16); ))] impl QValue { #[inline] - fn one() -> Self { + pub(crate) fn one() -> Self { Self(1000) } diff --git a/tower-http/src/services/fs/serve_dir/open_file.rs b/tower-http/src/services/fs/serve_dir/open_file.rs index 01c1e2f9..f182d422 100644 --- a/tower-http/src/services/fs/serve_dir/open_file.rs +++ b/tower-http/src/services/fs/serve_dir/open_file.rs @@ -181,16 +181,16 @@ fn preferred_encoding( if let Some(file_extension) = preferred_encoding.and_then(|encoding| encoding.to_file_extension()) { - let new_extension = path - .extension() - .map(|extension| { - let mut os_string = extension.to_os_string(); + let new_file_name = path + .file_name() + .map(|file_name| { + let mut os_string = file_name.to_os_string(); os_string.push(file_extension); os_string }) .unwrap_or_else(|| file_extension.to_os_string()); - path.set_extension(new_extension); + path.set_file_name(new_file_name); } preferred_encoding @@ -319,3 +319,17 @@ fn append_slash_on_path(uri: Uri) -> Uri { uri_builder.build().unwrap() } + +#[test] +fn preferred_encoding_with_extension() { + let mut path = PathBuf::from("hello.txt"); + preferred_encoding(&mut path, &[(Encoding::Gzip, QValue::one())]); + assert_eq!(path, PathBuf::from("hello.txt.gz")); +} + +#[test] +fn preferred_encoding_without_extension() { + let mut path = PathBuf::from("hello"); + preferred_encoding(&mut path, &[(Encoding::Gzip, QValue::one())]); + assert_eq!(path, PathBuf::from("hello.gz")); +} diff --git a/tower-http/src/services/fs/serve_dir/tests.rs b/tower-http/src/services/fs/serve_dir/tests.rs index d0d3952c..f77caf5a 100644 --- a/tower-http/src/services/fs/serve_dir/tests.rs +++ b/tower-http/src/services/fs/serve_dir/tests.rs @@ -252,6 +252,29 @@ async fn missing_precompressed_variant_fallbacks_to_uncompressed_for_head_reques assert!(res.into_body().frame().await.is_none()); } +#[tokio::test] +async fn precompressed_without_extension() { + let svc = ServeDir::new("../test-files").precompressed_gzip(); + + let request = Request::builder() + .uri("/extensionless_precompressed") + .header("Accept-Encoding", "gzip") + .body(Body::empty()) + .unwrap(); + let res = svc.oneshot(request).await.unwrap(); + + assert_eq!(res.status(), StatusCode::OK); + + assert_eq!(res.headers()["content-type"], "application/octet-stream"); + assert_eq!(res.headers()["content-encoding"], "gzip"); + + let body = res.into_body().collect().await.unwrap().to_bytes(); + let mut decoder = GzDecoder::new(&body[..]); + let mut decompressed = String::new(); + decoder.read_to_string(&mut decompressed).unwrap(); + assert!(decompressed.starts_with("Content.")); +} + #[tokio::test] async fn access_to_sub_dirs() { let svc = ServeDir::new(".."); From 69f5ca09c4f060893eef2fcbb47acb93c8b5babc Mon Sep 17 00:00:00 2001 From: Benjamin Swart Date: Tue, 3 Sep 2024 22:57:06 +0300 Subject: [PATCH 2/5] Add test for precompressed fallback in case of no extension in original path --- .../extensionless_precompressed_missing | 1 + tower-http/src/services/fs/serve_dir/tests.rs | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 test-files/extensionless_precompressed_missing diff --git a/test-files/extensionless_precompressed_missing b/test-files/extensionless_precompressed_missing new file mode 100644 index 00000000..032a5d4d --- /dev/null +++ b/test-files/extensionless_precompressed_missing @@ -0,0 +1 @@ +Content. diff --git a/tower-http/src/services/fs/serve_dir/tests.rs b/tower-http/src/services/fs/serve_dir/tests.rs index f77caf5a..a03c50e0 100644 --- a/tower-http/src/services/fs/serve_dir/tests.rs +++ b/tower-http/src/services/fs/serve_dir/tests.rs @@ -275,6 +275,27 @@ async fn precompressed_without_extension() { assert!(decompressed.starts_with("Content.")); } +#[tokio::test] +async fn missing_precompressed_without_extension_fallbacks_to_uncompressed() { + let svc = ServeDir::new("../test-files").precompressed_gzip(); + + let request = Request::builder() + .uri("/extensionless_precompressed_missing") + .header("Accept-Encoding", "gzip") + .body(Body::empty()) + .unwrap(); + let res = svc.oneshot(request).await.unwrap(); + + assert_eq!(res.status(), StatusCode::OK); + + assert_eq!(res.headers()["content-type"], "application/octet-stream"); + assert!(res.headers().get("content-encoding").is_none()); + + let body = res.into_body().collect().await.unwrap().to_bytes(); + let body = String::from_utf8(body.to_vec()).unwrap(); + assert!(body.starts_with("Content.")); +} + #[tokio::test] async fn access_to_sub_dirs() { let svc = ServeDir::new(".."); From f2db21d8c788a16df9caa130e18d582d8c8bf5ee Mon Sep 17 00:00:00 2001 From: Benjamin Swart Date: Thu, 19 Sep 2024 17:24:56 +0200 Subject: [PATCH 3/5] Check entire body in extensionless precompressed file tests --- tower-http/src/services/fs/serve_dir/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tower-http/src/services/fs/serve_dir/tests.rs b/tower-http/src/services/fs/serve_dir/tests.rs index a03c50e0..b9bc295e 100644 --- a/tower-http/src/services/fs/serve_dir/tests.rs +++ b/tower-http/src/services/fs/serve_dir/tests.rs @@ -272,7 +272,7 @@ async fn precompressed_without_extension() { let mut decoder = GzDecoder::new(&body[..]); let mut decompressed = String::new(); decoder.read_to_string(&mut decompressed).unwrap(); - assert!(decompressed.starts_with("Content.")); + assert_eq!(&decompressed, "Content.\n"); } #[tokio::test] @@ -293,7 +293,7 @@ async fn missing_precompressed_without_extension_fallbacks_to_uncompressed() { let body = res.into_body().collect().await.unwrap().to_bytes(); let body = String::from_utf8(body.to_vec()).unwrap(); - assert!(body.starts_with("Content.")); + assert_eq!(&body, "Content.\n"); } #[tokio::test] From 531ee68d072cefa0c9a31238ba5ef5d41754ea76 Mon Sep 17 00:00:00 2001 From: Benjamin Swart Date: Thu, 19 Sep 2024 17:29:33 +0200 Subject: [PATCH 4/5] Mention fix of extensionless precompressed file serving in changelog --- tower-http/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tower-http/CHANGELOG.md b/tower-http/CHANGELOG.md index e4da30fe..542f07b5 100644 --- a/tower-http/CHANGELOG.md +++ b/tower-http/CHANGELOG.md @@ -12,8 +12,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `body` module is disabled except for `catch-panic`, `decompression-*`, `fs`, or `limit` features (BREAKING) ([#477]) - Update to `tower` 0.5 ([#503]) +## Fixed + +- **fs:** Precompression of static files now supports files without a file extension ([#507]) + [#477]: https://github.com/tower-rs/tower-http/pull/477 [#503]: https://github.com/tower-rs/tower-http/pull/503 +[#507]: https://github.com/tower-rs/tower-http/pull/507 # 0.5.2 From 7dedf263ea5d6d9b45832b5a3b95fa5475d810fd Mon Sep 17 00:00:00 2001 From: Benjamin Swart Date: Thu, 19 Sep 2024 17:42:31 +0200 Subject: [PATCH 5/5] Remove trailing newline from extensionless precompressed test files --- test-files/extensionless_precompressed | 2 +- test-files/extensionless_precompressed.gz | Bin 57 -> 56 bytes test-files/extensionless_precompressed_missing | 2 +- tower-http/src/services/fs/serve_dir/tests.rs | 9 +++++++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/test-files/extensionless_precompressed b/test-files/extensionless_precompressed index 032a5d4d..fffc22b4 100644 --- a/test-files/extensionless_precompressed +++ b/test-files/extensionless_precompressed @@ -1 +1 @@ -Content. +Content. \ No newline at end of file diff --git a/test-files/extensionless_precompressed.gz b/test-files/extensionless_precompressed.gz index 3322cc24a37f5eb0e45d93114bdeae0a06d568dc..0dcede2295ecafc885dd8715ee4441934a9ad71a 100644 GIT binary patch delta 24 fcmcDtV3+Ua;JD=SW+J;f7c)afTv!AL0|Ns9P5uRa delta 25 hcmcDpWS8&e;5e0XeImO$_hTl8