From e67e4c4901228ff38cbe6c83d86fc620f8c70a8a Mon Sep 17 00:00:00 2001 From: Jose Quintana Date: Wed, 14 Aug 2024 00:10:12 +0200 Subject: [PATCH 1/8] docs: v2.32.2 [skip ci] --- docs/content/download-and-install.md | 106 +++++++++--------- docs/content/download-and-install.template.md | 2 +- scripts/installer.sh | 2 +- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/docs/content/download-and-install.md b/docs/content/download-and-install.md index 9df856e2..cd4c026a 100644 --- a/docs/content/download-and-install.md +++ b/docs/content/download-and-install.md @@ -1,13 +1,13 @@ # Download and Install -Latest **v2.32.1** release `2024-07-20` ([changelog](https://github.com/static-web-server/static-web-server/releases/tag/v2.32.1), [sha256sum](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-SHA256SUM)) +Latest **v2.32.2** release `2024-08-13` ([changelog](https://github.com/static-web-server/static-web-server/releases/tag/v2.32.2), [sha256sum](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-SHA256SUM)) @@ -31,7 +31,7 @@ curl --proto '=https' --tlsv1.2 -sSfL https://get.static-web-server.net | sh Alternatively, you can install a specific version of SWS to a custom location by setting environment variables. ```sh -export SWS_INSTALL_VERSION="2.31.0" # full list at https://github.com/static-web-server/static-web-server/tags +export SWS_INSTALL_VERSION="2.32.2" # full list at https://github.com/static-web-server/static-web-server/tags export SWS_INSTALL_DIR="~/.local/bin" curl --proto '=https' --tlsv1.2 -sSfL https://get.static-web-server.net | sh ``` @@ -115,69 +115,69 @@ Pre-compiled binaries grouped by CPU architectures. ### x86_64 -- [static-web-server-v2.32.1-x86_64-apple-darwin.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-x86_64-apple-darwin.tar.gz)
-**SHA256SUM:** `4849197ca742cec18fc0bd3994e3abcc639225c65af0309a23d8d9ab0206ddbc` -- [static-web-server-v2.32.1-x86_64-pc-windows-gnu.zip](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-x86_64-pc-windows-gnu.zip)
-**SHA256SUM:** `cbb506052535c17a1a042caf25c2ff76354d4de6a96cda605060bee502182cd3` -- [static-web-server-v2.32.1-x86_64-pc-windows-msvc.zip](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-x86_64-pc-windows-msvc.zip)
-**SHA256SUM:** `b5ceba7fb0ebdf930efcc4e1b358dc82ef7b07e5b07f007f118488e79fac2647` -- [static-web-server-v2.32.1-x86_64-unknown-freebsd.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-x86_64-unknown-freebsd.tar.gz)
-**SHA256SUM:** `f57320b1b108ef1839f38a470ad92a76e998e78842352e7150dc893e4666b106` -- [static-web-server-v2.32.1-x86_64-unknown-linux-gnu.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-x86_64-unknown-linux-gnu.tar.gz)
-**SHA256SUM:** `7f10a4601c82f2eda5227abf79edc2df5ba61a221c35a6e45878878c96875cee` -- [static-web-server-v2.32.1-x86_64-unknown-linux-musl.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-x86_64-unknown-linux-musl.tar.gz)
-**SHA256SUM:** `3594e490229b10fafe5c849addc8bcb777f1c69123d9d1a5ed731f6ae57cdf95` -- [static-web-server-v2.32.1-x86_64-unknown-netbsd.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-x86_64-unknown-netbsd.tar.gz)
-**SHA256SUM:** `4caa4a376055d9678edd9a89ace0693a1d2d323b5330392b2eccd35aac3ea7d0` -- [static-web-server-v2.32.1-x86_64-unknown-illumos.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-x86_64-unknown-illumos.tar.gz)
-**SHA256SUM:** `36ccad543873728b80546b3611a13728d557b15fb652b65ff14e36345f28bfc4` +- [static-web-server-v2.32.2-x86_64-apple-darwin.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-x86_64-apple-darwin.tar.gz)
+**SHA256SUM:** `4f4d987e9e4d9b30657837682c871ef9d62b17c0e3b6e1b3b4a95135c3f187c4` +- [static-web-server-v2.32.2-x86_64-pc-windows-gnu.zip](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-x86_64-pc-windows-gnu.zip)
+**SHA256SUM:** `a6ede027164565750d4b6281264af78447e55c293d371e03293d0ba81318ac61` +- [static-web-server-v2.32.2-x86_64-pc-windows-msvc.zip](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-x86_64-pc-windows-msvc.zip)
+**SHA256SUM:** `c4a213af197961a316884a5b1078feb50b130c5ed352545f7f7eeba58adcc6a4` +- [static-web-server-v2.32.2-x86_64-unknown-freebsd.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-x86_64-unknown-freebsd.tar.gz)
+**SHA256SUM:** `c997fe2fdaef886201a4b741c18ce878dbecfa8b73add8c75afe3dc6a6ab5d44` +- [static-web-server-v2.32.2-x86_64-unknown-linux-gnu.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-x86_64-unknown-linux-gnu.tar.gz)
+**SHA256SUM:** `88bfbc1b807967a92b51f48516b2f1cd10e43f4d2be0dd0cd8b20f791bb02870` +- [static-web-server-v2.32.2-x86_64-unknown-linux-musl.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-x86_64-unknown-linux-musl.tar.gz)
+**SHA256SUM:** `06716f1e5e488977cdb2f3af37bfcf2e9f2c51efc8e8daaa07a5267b72e3d563` +- [static-web-server-v2.32.2-x86_64-unknown-netbsd.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-x86_64-unknown-netbsd.tar.gz)
+**SHA256SUM:** `94e80dcda88be7e5f787c84f376a5f3824c01af4f8e71b80ab8b97642ecea747` +- [static-web-server-v2.32.2-x86_64-unknown-illumos.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-x86_64-unknown-illumos.tar.gz)
+**SHA256SUM:** `a4ed22683dcb3ca9aee9f538caa16ee136b686def208bae63a9c3218e25fbf8b` ### ARM64 -- [static-web-server-v2.32.1-aarch64-unknown-linux-gnu.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-aarch64-unknown-linux-gnu.tar.gz)
-**SHA256SUM:** `34571e9390fdcdf7b327870e7d3974b5a61a8d80f565c249487f08db1c81bdf0` -- [static-web-server-v2.32.1-aarch64-unknown-linux-musl.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-aarch64-unknown-linux-musl.tar.gz)
-**SHA256SUM:** `faa86f42798a58ff8a35ffe54f1b8b2be0f767b444ecbbf99bbeae10268eaece` -- [static-web-server-v2.32.1-aarch64-apple-darwin.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-aarch64-apple-darwin.tar.gz)
-**SHA256SUM:** `2b167558c428f55bcc177e40d0707d2bfc9fec4211da787e0824483e1326c386` -- [static-web-server-v2.32.1-aarch64-linux-android.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-aarch64-linux-android.tar.gz)
-**SHA256SUM:** `deebfc23d5b88db0a29bf29b4cf66f3c6052d758f5ab7755308ffcc9964aa59d` -- [static-web-server-v2.32.1-aarch64-pc-windows-msvc.zip](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-aarch64-pc-windows-msvc.zip)
-**SHA256SUM:** `edd940eed3ca8f44e81a6db1cbbaa76900392132fc5435e859daa5d3e6dcc2e2` +- [static-web-server-v2.32.2-aarch64-unknown-linux-gnu.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-aarch64-unknown-linux-gnu.tar.gz)
+**SHA256SUM:** `f27b50708f90cfadf7881ec27eca4c1c62de9fadf28d579ebdf511bd86ad96f9` +- [static-web-server-v2.32.2-aarch64-unknown-linux-musl.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-aarch64-unknown-linux-musl.tar.gz)
+**SHA256SUM:** `60d0bef8be23cb7c5d102876fc21a21c06191b43a8412a9e9da1aaa209ecc556` +- [static-web-server-v2.32.2-aarch64-apple-darwin.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-aarch64-apple-darwin.tar.gz)
+**SHA256SUM:** `805478b61561f50072f9921c47f1ff4f860cfc926ae62197fa1c2707c02cc356` +- [static-web-server-v2.32.2-aarch64-linux-android.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-aarch64-linux-android.tar.gz)
+**SHA256SUM:** `c0b869be3ae494f8031aba691be5da69a60761c035652c40a90c6abba62389b0` +- [static-web-server-v2.32.2-aarch64-pc-windows-msvc.zip](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-aarch64-pc-windows-msvc.zip)
+**SHA256SUM:** `7be87e187c1f04ae4f925c08a1e422147bc7a1d000ce1d7cefb68024546ce1b0` ### x86 -- [static-web-server-v2.32.1-i686-pc-windows-msvc.zip](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-i686-pc-windows-msvc.zip)
-**SHA256SUM:** `d9f4da156c8c53469c9007c09723cf45f107379c1f81f832e53d3c720890eeb9` -- [static-web-server-v2.32.1-i686-unknown-freebsd.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-i686-unknown-freebsd.tar.gz)
-**SHA256SUM:** `64e41eb1d9802561aebdd7817a9311ec48020933b31f3971e1aeaaf8784eff1f` -- [static-web-server-v2.32.1-i686-unknown-linux-gnu.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-i686-unknown-linux-gnu.tar.gz)
-**SHA256SUM:** `571ceaf2a20f786ba10ef81198b5bbbe4a9c8b4db2a02e54e6a6e39ab35f3170` -- [static-web-server-v2.32.1-i686-unknown-linux-musl.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-i686-unknown-linux-musl.tar.gz)
-**SHA256SUM:** `cab2684753f5c67ab6917b2eb5239c2308b72cd390fc33021720f8a0b5366229` +- [static-web-server-v2.32.2-i686-pc-windows-msvc.zip](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-i686-pc-windows-msvc.zip)
+**SHA256SUM:** `6d385fd24a1577e79fd39870da7187a314a2813967a8a7920d76627a952a88d1` +- [static-web-server-v2.32.2-i686-unknown-freebsd.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-i686-unknown-freebsd.tar.gz)
+**SHA256SUM:** `fc33922c509c77aed0d2fe4f75a3a9ec41d42c21af22ae5e6cad30af5c54608f` +- [static-web-server-v2.32.2-i686-unknown-linux-gnu.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-i686-unknown-linux-gnu.tar.gz)
+**SHA256SUM:** `cc21fa05b39aba8241a6da491d5f659fd0e46ed3a8ba3a3767bfcf949b77756a` +- [static-web-server-v2.32.2-i686-unknown-linux-musl.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-i686-unknown-linux-musl.tar.gz)
+**SHA256SUM:** `8b8d1a8e629fb6130b58d924da60e7d8054b15da7e6443fff4c1af0c8a4cdeed` ### ARM -- [static-web-server-v2.32.1-arm-unknown-linux-gnueabihf.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-arm-unknown-linux-gnueabihf.tar.gz)
-**SHA256SUM:** `5aaf1b92c565a37666fb474815bd5fd13e529ec3af80a050d79dc48d9cf7dd10` -- [static-web-server-v2.32.1-arm-unknown-linux-musleabihf.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-arm-unknown-linux-musleabihf.tar.gz)
-**SHA256SUM:** `d42fdedd0bf638b0d2a8ac847e67aba06b6d7686ad2eea0517aeee6e028135e5` -- [static-web-server-v2.32.1-armv7-unknown-linux-musleabihf.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-armv7-unknown-linux-musleabihf.tar.gz)
-**SHA256SUM:** `0eabc77293d2beba1e26b847fa7935adcfa7c9a68ef481ea7ba629772a6034d6` +- [static-web-server-v2.32.2-arm-unknown-linux-gnueabihf.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-arm-unknown-linux-gnueabihf.tar.gz)
+**SHA256SUM:** `0ccf4930bfe094b0a08fc89962c1f094e5915335c11fa15f67c7acd6d210d234` +- [static-web-server-v2.32.2-arm-unknown-linux-musleabihf.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-arm-unknown-linux-musleabihf.tar.gz)
+**SHA256SUM:** `130e6211f335efef402562b503e600789826bfd0a2c936fa125a746afcc2c345` +- [static-web-server-v2.32.2-armv7-unknown-linux-musleabihf.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-armv7-unknown-linux-musleabihf.tar.gz)
+**SHA256SUM:** `ca8cdd85a43f85851b889be1982827f6c373e24cd64bf41c2234b0d01d6551a6` ### PowerPC -- [static-web-server-v2.32.1-powerpc64le-unknown-linux-gnu.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-powerpc64le-unknown-linux-gnu.tar.gz)
-**SHA256SUM:** `ad0fb7ef05a1db53177a550dace6200e1d53be881edb61b709b6ebe323a0a76e` +- [static-web-server-v2.32.2-powerpc64le-unknown-linux-gnu.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-powerpc64le-unknown-linux-gnu.tar.gz)
+**SHA256SUM:** `0c992759c149f2d40cad21eb9df6e9e6fd2a815afd2ed33de42f2c06ca6c1d22` ### S390X -- [static-web-server-v2.32.1-s390x-unknown-linux-gnu.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.1/static-web-server-v2.32.1-s390x-unknown-linux-gnu.tar.gz)
-**SHA256SUM:** `a19240d3db07b3a5b5f8f12e73cc2522a4cc1bff69c0cc37dac132ffe46d36ee` +- [static-web-server-v2.32.2-s390x-unknown-linux-gnu.tar.gz](https://github.com/static-web-server/static-web-server/releases/download/v2.32.2/static-web-server-v2.32.2-s390x-unknown-linux-gnu.tar.gz)
+**SHA256SUM:** `bf94aeb75bfc4c995007b4f8821ea700b98b9b7c05cd564fa1702590c20a4752` ## Source files -- [static-web-server-2.32.1.tar.gz](https://github.com/static-web-server/static-web-server/archive/refs/tags/v2.32.1.tar.gz)
-**SHA256SUM:** `771aa43f3bc96334d432e75f31464e1a0d4dcb4aa920c4f58b2339757e929060` -- [static-web-server-2.32.1.zip](https://github.com/static-web-server/static-web-server/archive/refs/tags/v2.32.1.zip)
-**SHA256SUM:** `1d06135ce1846749c3a78ec416493024ecda353b927f684115d047a8b3577de6` +- [static-web-server-2.32.2.tar.gz](https://github.com/static-web-server/static-web-server/archive/refs/tags/v2.32.2.tar.gz)
+**SHA256SUM:** `191a014f2f30fa145fbac727fb930e2a7063f3c27b8e72f33c21a8814969a641` +- [static-web-server-2.32.2.zip](https://github.com/static-web-server/static-web-server/archive/refs/tags/v2.32.2.zip)
+**SHA256SUM:** `49575bf34f583bd284575a0737fc0715671f0c9addf061949f252ec92505f374` diff --git a/docs/content/download-and-install.template.md b/docs/content/download-and-install.template.md index 1d117fa8..7dc851b5 100644 --- a/docs/content/download-and-install.template.md +++ b/docs/content/download-and-install.template.md @@ -30,7 +30,7 @@ curl --proto '=https' --tlsv1.2 -sSfL https://get.static-web-server.net | sh Alternatively, you can install a specific version of SWS to a custom location by setting environment variables. ```sh -export SWS_INSTALL_VERSION="2.31.0" # full list at https://github.com/static-web-server/static-web-server/tags +export SWS_INSTALL_VERSION="2.32.2" # full list at https://github.com/static-web-server/static-web-server/tags export SWS_INSTALL_DIR="~/.local/bin" curl --proto '=https' --tlsv1.2 -sSfL https://get.static-web-server.net | sh ``` diff --git a/scripts/installer.sh b/scripts/installer.sh index 31e7a7b0..d7158bcc 100755 --- a/scripts/installer.sh +++ b/scripts/installer.sh @@ -23,7 +23,7 @@ fi set -u # SWS latest version -version=${SWS_INSTALL_VERSION:-"2.32.1"} +version=${SWS_INSTALL_VERSION:-"2.32.2"} # Default directory where SWS will be installed local_bin=${SWS_INSTALL_DIR:-"/usr/local/bin"} From 5bdfcd4c888e08c10edc0a9ce1954d1799a9ec17 Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Wed, 4 Sep 2024 00:15:55 +0200 Subject: [PATCH 2/8] feat: experimental in-memory files cache with eviction policy support (#328) Via a new advanced configuration entry. The feature also supports expiration policies such as Time To Live (TTL) and Time To Idle (TTI). Admission to a cache is controlled by the Least Frequently Used (LFU) policy and the eviction from a cache is controlled by the Least Recently Used (LRU) policy. Example: ```toml [general] [advanced] [advanced.memory-cache] # Maximum capacity entries of the memory cache-store. Default 256 capacity = 256 # Time to live in seconds of a cached file entry. Default 1h ttl = 3600 # Time to idle in seconds of a cached file entry. Default 5min tti = 300 # Maximum size in bytes for a file entry to be cached. Default 8MB max-file-size = 8192 ``` Note that this feature requires Rust 1.76.0 or newer. This feature is **experimental**. However, when stabilized then a cargo feature will be available as well as a proper documentation page. --- .github/workflows/devel.yml | 2 +- Cargo.lock | 255 +++++++++++++++++++++++++++ Cargo.toml | 6 +- docs/content/building-from-source.md | 4 +- src/cors.rs | 2 +- src/handler.rs | 9 +- src/lib.rs | 1 + src/mem_cache/cache.rs | 255 +++++++++++++++++++++++++++ src/mem_cache/mod.rs | 10 ++ src/mem_cache/stream.rs | 71 ++++++++ src/response.rs | 66 +++++-- src/server.rs | 7 +- src/settings/file.rs | 19 ++ src/settings/mod.rs | 5 +- src/static_files.rs | 34 +++- src/testing.rs | 1 + tests/compression_static.rs | 5 + tests/dir_listing.rs | 8 + tests/static_files.rs | 33 ++++ tests/toml/config.toml | 11 +- 20 files changed, 779 insertions(+), 25 deletions(-) create mode 100644 src/mem_cache/cache.rs create mode 100644 src/mem_cache/mod.rs create mode 100644 src/mem_cache/stream.rs diff --git a/.github/workflows/devel.yml b/.github/workflows/devel.yml index 51f8e8c5..874c14be 100644 --- a/.github/workflows/devel.yml +++ b/.github/workflows/devel.yml @@ -72,7 +72,7 @@ jobs: # We test against the latest and minimum Rust stable version. - build: pinned os: ubuntu-22.04 - rust: 1.74.0 + rust: 1.76.0 # Some of our release builds are generated by a nightly compiler to take # advantage of the latest optimizations/compile time improvements. - build: linux-musl diff --git a/Cargo.lock b/Cargo.lock index c0017a01..fbc011cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -235,6 +235,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytecount" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" + [[package]] name = "byteorder" version = "1.5.0" @@ -247,6 +253,46 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +[[package]] +name = "camino" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "castaway" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.1.10" @@ -331,6 +377,20 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +[[package]] +name = "compact_str" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6050c3a16ddab2e412160b31f2c871015704239bca62f72f6e5f0be631d3f644" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + [[package]] name = "const_fn" version = "0.4.10" @@ -381,6 +441,21 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crypto-common" version = "0.1.6" @@ -391,6 +466,19 @@ dependencies = [ "typenum", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "deranged" version = "0.3.11" @@ -416,6 +504,31 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + [[package]] name = "flate2" version = "1.0.31" @@ -533,6 +646,12 @@ dependencies = [ "url", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "globset" version = "0.4.14" @@ -800,6 +919,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "listenfd" version = "1.0.1" @@ -871,6 +996,21 @@ dependencies = [ "unicase", ] +[[package]] +name = "mini-moka" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c325dfab65f261f386debee8b0969da215b3fa0037e74c8a1234db7ba986d803" +dependencies = [ + "crossbeam-channel", + "crossbeam-utils", + "dashmap", + "skeptic", + "smallvec", + "tagptr", + "triomphe", +] + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -1073,6 +1213,17 @@ version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + [[package]] name = "quote" version = "1.0.36" @@ -1141,6 +1292,19 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustls" version = "0.23.12" @@ -1183,18 +1347,42 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + [[package]] name = "serde" version = "1.0.207" @@ -1321,6 +1509,21 @@ dependencies = [ "tokio", ] +[[package]] +name = "skeptic" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +dependencies = [ + "bytecount", + "cargo_metadata", + "error-chain", + "glob", + "pulldown-cmark", + "tempfile", + "walkdir", +] + [[package]] name = "slab" version = "0.4.9" @@ -1363,6 +1566,7 @@ dependencies = [ "bytes", "chrono", "clap", + "compact_str", "form_urlencoded", "futures-util", "globset", @@ -1374,6 +1578,7 @@ dependencies = [ "listenfd", "maud", "mime_guess", + "mini-moka", "percent-encoding", "pin-project", "prometheus", @@ -1397,6 +1602,12 @@ dependencies = [ "windows-service", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.11.1" @@ -1420,6 +1631,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "tempfile" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -1692,6 +1922,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "triomphe" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369" + [[package]] name = "try-lock" version = "0.2.5" @@ -1816,6 +2052,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1908,6 +2154,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 0529b594..5bc4225b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "static-web-server" version = "2.32.2" edition = "2021" -rust-version = "1.74.0" +rust-version = "1.76.0" authors = ["Jose Quintana "] license = "MIT OR Apache-2.0" description = "A cross-platform, high-performance and asynchronous web server for static files-serving." @@ -67,6 +67,7 @@ bcrypt = { version = "0.15", optional = true } bytes = "1.6" chrono = { version = "0.4", default-features = false, features = ["std", "clock"], optional = true } clap = { version = "4.5", features = ["derive", "env"] } +compact_str = "0.8" form_urlencoded = "1.2" futures-util = { version = "0.3", default-features = false } globset = { version = "0.4", features = ["serde1"] } @@ -78,6 +79,7 @@ lazy_static = "1.5" listenfd = "1.0" maud = { version = "0.26", optional = true } mime_guess = "2.0" +mini-moka = "0.10.3" percent-encoding = "2.3" pin-project = "1.1" regex = "1.10" @@ -86,13 +88,13 @@ serde = { version = "1.0", default-features = false, features = ["derive"] } serde_ignored = "0.1" serde_json = "1.0" serde_repr = "0.1" +shadow-rs = "0.29" tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "macros", "fs", "io-util", "signal"] } tokio-rustls = { version = "0.26", optional = true, default-features = false, features = ["logging", "tls12", "ring"] } tokio-util = { version = "0.7", default-features = false, features = ["io"] } toml = "0.8" tracing = { version = "0.1", default-features = false, features = ["std"] } tracing-subscriber = { version = "0.3", default-features = false, features = ["smallvec", "registry", "parking_lot", "fmt", "ansi", "tracing-log"] } -shadow-rs = "0.29" [target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.tikv-jemallocator] version = "0.6" diff --git a/docs/content/building-from-source.md b/docs/content/building-from-source.md index 25fd058f..c2b8ef3b 100644 --- a/docs/content/building-from-source.md +++ b/docs/content/building-from-source.md @@ -6,7 +6,7 @@ Follow these instructions to either build **`SWS`** project from the source or t If you want to build **SWS** from the source, all you need is a [Rust 2021 Edition](https://blog.rust-lang.org/2021/05/11/edition-2021.html) installed. -So make sure to install Rust [1.74.0](https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html) or newer (or nightly) along with [the toolchain(s)](https://rust-lang.github.io/rustup/concepts/toolchains.html) of your preference. +So make sure to install Rust [1.76.0](https://blog.rust-lang.org/2024/02/08/Rust-1.76.0.html) or newer (or nightly) along with [the toolchain(s)](https://rust-lang.github.io/rustup/concepts/toolchains.html) of your preference. Then clone the repository and use [Cargo](https://doc.rust-lang.org/cargo/) to build the project from the source. @@ -16,7 +16,7 @@ cd static-web-server cargo build --release ``` -Finally, the release binary should be available at `target/release/static-web-server` or under your toolchain directory chosen. +Finally, the release binary should be available at `target/https://blog.rust-lang.org/2024/02/08/Rust-1.76.0.htmlrelease/static-web-server` or under your toolchain directory chosen. !!! info "Don't use the project's `Makefile`" Please don't use the project's `Makefile` since it's only intended for development and some on-demand tasks. diff --git a/src/cors.rs b/src/cors.rs index 23bc8e7c..50aff321 100644 --- a/src/cors.rs +++ b/src/cors.rs @@ -214,7 +214,7 @@ impl Default for Cors { } #[derive(Clone, Debug)] -/// CORS is configurated. +/// CORS configured. pub struct Configured { cors: Cors, allowed_headers: AccessControlAllowHeaders, diff --git a/src/handler.rs b/src/handler.rs index fa1581c4..5096f242 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -30,7 +30,9 @@ use crate::metrics; use crate::{ control_headers, cors, custom_headers, error_page, health, http_ext::MethodExt, - log_addr, maintenance_mode, redirects, rewrites, security_headers, + log_addr, maintenance_mode, + mem_cache::cache::MemCacheOpts, + redirects, rewrites, security_headers, settings::Advanced, static_files::{self, HandleOpts}, virtual_hosts, Error, Result, @@ -44,6 +46,8 @@ pub struct RequestHandlerOpts { // General options /// Root directory of static files. pub root_dir: PathBuf, + /// In-memory cache feature (experimental). + pub memory_cache: Option, /// Compression feature. pub compression: bool, #[cfg(any( @@ -134,6 +138,7 @@ impl Default for RequestHandlerOpts { #[cfg(feature = "directory-listing")] dir_listing_format: DirListFmt::Html, cors: None, + memory_cache: None, security_headers: false, cache_control_headers: true, page404: PathBuf::from("./404.html"), @@ -183,6 +188,7 @@ impl RequestHandler { let ignore_hidden_files = self.opts.ignore_hidden_files; let disable_symlinks = self.opts.disable_symlinks; let index_files: Vec<&str> = self.opts.index_files.iter().map(|s| s.as_str()).collect(); + let memory_cache = self.opts.memory_cache.as_ref(); log_addr::pre_process(&self.opts, req, remote_addr); @@ -251,6 +257,7 @@ impl RequestHandler { let (resp, file_path) = match static_files::handle(&HandleOpts { method: req.method(), headers: req.headers(), + memory_cache, base_path, uri_path: req.uri().path(), uri_query: req.uri().query(), diff --git a/src/lib.rs b/src/lib.rs index 900e0051..5c9a356c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -177,6 +177,7 @@ pub(crate) mod http_ext; pub mod https_redirect; pub(crate) mod log_addr; pub mod maintenance_mode; +pub(crate) mod mem_cache; #[cfg(all(unix, feature = "experimental"))] pub(crate) mod metrics; pub mod redirects; diff --git a/src/mem_cache/cache.rs b/src/mem_cache/cache.rs new file mode 100644 index 00000000..a2e55e9e --- /dev/null +++ b/src/mem_cache/cache.rs @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// This file is part of Static Web Server. +// See https://static-web-server.net/ for more information +// Copyright (C) 2019-present Jose Quintana + +//! It provides in-memory files cache functionality with expiration policy support +//! such as Time to live (TTL) and Time to idle (TTI). +//! +//! Admission to a cache is controlled by the Least Frequently Used (LFU) policy +//! and the eviction from a cache is controlled by the Least Recently Used (LRU) policy. +//! + +use bytes::Bytes; +use compact_str::CompactString; +use headers::{ + AcceptRanges, ContentLength, ContentRange, ContentType, HeaderMap, HeaderMapExt, LastModified, +}; +use hyper::{Body, Response, StatusCode}; +use mini_moka::sync::Cache; +use std::io::{Read, Seek, SeekFrom}; +use std::path::Path; +use std::sync::{Arc, OnceLock}; +use std::time::Duration; +use tokio::sync::Semaphore; + +use crate::conditional_headers::{ConditionalBody, ConditionalHeaders}; +use crate::fs::stream::FileStream; +use crate::handler::RequestHandlerOpts; +use crate::response::{bytes_range, BadRangeError}; +use crate::Result; + +/// Global cache that stores all files in memory. +/// It provides expiration policies like Time to live (TTL) and Time to idle (TTI) support. +pub(crate) static CACHE_STORE: OnceLock>> = OnceLock::new(); + +/// A single cache permit to allow reading a file once. +static CACHE_PERMIT: Semaphore = Semaphore::const_new(1); + +/// It defines the in-memory files cache options. +pub struct MemCacheOpts { + /// The maximum size per file in bytes. + pub max_file_size: u64, +} + +impl MemCacheOpts { + /// Creates a new instance of `MemCacheOpts`. + #[inline] + pub fn new(max_file_size: u64) -> Self { + Self { + max_file_size: 1024 * 1024 * max_file_size, + } + } +} + +/// Make sure to initialize the in-memory cache store. +pub(crate) fn init(handler_opts: &mut RequestHandlerOpts) -> Result { + if let Some(advanced_opts) = handler_opts.advanced_opts.as_ref() { + if let Some(opts) = advanced_opts.memory_cache.as_ref() { + // TODO: define maximum values + + // Default 256 entries + let capacity = opts.capacity.unwrap_or(256); + // Default 1h + let ttl = opts.ttl.unwrap_or(3600); + // Default 5min + let tti = opts.tti.unwrap_or(300); + // Default 8mb + let max_file_size = opts.max_file_size.unwrap_or(8192); + + server_info!( + "in-memory cache (experimental): enabled=true, capacity={capacity}, ttl={ttl}, tti={tti}, max_file_size={max_file_size}" + ); + + let mem_opts = MemCacheOpts::new(max_file_size); + + let cache = Cache::builder() + .max_capacity(capacity) + // Time to live (TTL): 30 minutes + .time_to_live(Duration::from_secs(ttl)) + // Time to idle (TTI): 5 minutes + .time_to_idle(Duration::from_secs(tti)) + .build(); + + if CACHE_STORE.set(cache).is_err() { + bail!("unable to initialize the in-memory cache store") + } + + handler_opts.memory_cache = Some(mem_opts); + + return Ok(()); + } + } + + server_info!("in-memory cache (experimental): enabled=false"); + + Ok(()) +} + +/// Try to get the file in a form of a response from the cache store by a path or +/// acquires a permit to ensure to hold until the file is read first (once). +/// +/// If the file is not found in the cache store then +/// a cache permit is acquired internally (one at a time) +/// to allow the caller to read the file first. +/// Once the file is read on caller's side then the permit is dropped. +pub(crate) async fn get_or_acquire( + file_path: &Path, + headers_opt: &HeaderMap, +) -> Option, StatusCode>> { + let file_path_str = file_path.to_str().or(None)?; + + let store = CACHE_STORE.get().unwrap(); + match store.get::(&file_path_str.into()) { + Some(mem_file) => { + tracing::debug!( + "file `{}` found in the in-memory cache store, returning it directly", + file_path_str + ); + Some(mem_file.response_body(headers_opt)) + } + _ => { + tracing::debug!( + "file `{}` was not found in the in-memory cache store, continuing", + file_path_str + ); + // If a file is not found in the store then continue + // with the normal flow and wait on first file read + if let Err(err) = CACHE_PERMIT.acquire().await { + tracing::error!("error trying to acquire permit on first read: {:?}", err); + return Some(Err(StatusCode::INTERNAL_SERVER_ERROR)); + } + None + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct MemFileTempOpts { + pub(crate) file_path: String, + pub(crate) content_type: ContentType, + pub(crate) last_modified: Option, +} + +impl MemFileTempOpts { + pub(crate) fn new( + file_path: String, + content_type: ContentType, + last_modified: Option, + ) -> Self { + Self { + file_path, + content_type, + last_modified, + } + } +} + +/// In-memory file representation to be store in the cache. +#[derive(Debug)] +pub(crate) struct MemFile { + /// Bytes of the the current file. + data: Bytes, + /// Buffer size for the current file. + buf_size: usize, + /// `Content-Type` header for the current file. + content_type: ContentType, + /// `Last Modified` header for the current file. + last_modified: Option, +} + +impl MemFile { + #[inline] + pub(crate) fn new( + data: Bytes, + buf_size: usize, + content_type: ContentType, + last_modified: Option, + ) -> Self { + Self { + data, + buf_size, + content_type, + last_modified, + } + } + + pub(crate) fn response_body(&self, headers: &HeaderMap) -> Result, StatusCode> { + let conditionals = ConditionalHeaders::new(headers); + let modified = self.last_modified; + + match conditionals.check(modified) { + ConditionalBody::NoBody(resp) => Ok(resp), + ConditionalBody::WithBody(range) => { + let mem_buf = self.data.clone(); + let mut len = mem_buf.len() as u64; + let mut reader = std::io::Cursor::new(mem_buf); + let buf_size = self.buf_size; + + bytes_range(range, len) + .map(|(start, end)| { + match reader.seek(SeekFrom::Start(start)) { + Ok(_) => (), + Err(err) => { + tracing::error!("seek file from start error: {:?}", err); + return Err(StatusCode::INTERNAL_SERVER_ERROR); + } + }; + + let sub_len = end - start; + let reader = reader.take(sub_len); + + let body = Body::wrap_stream(FileStream { reader, buf_size }); + let mut resp = Response::new(body); + + if sub_len != len { + *resp.status_mut() = StatusCode::PARTIAL_CONTENT; + resp.headers_mut().typed_insert( + match ContentRange::bytes(start..end, len) { + Ok(range) => range, + Err(err) => { + tracing::error!("invalid content range error: {:?}", err); + let mut resp = Response::new(Body::empty()); + *resp.status_mut() = StatusCode::RANGE_NOT_SATISFIABLE; + resp.headers_mut() + .typed_insert(ContentRange::unsatisfied_bytes(len)); + return Ok(resp); + } + }, + ); + + len = sub_len; + } + + resp.headers_mut().typed_insert(ContentLength(len)); + resp.headers_mut().typed_insert(self.content_type.clone()); + resp.headers_mut().typed_insert(AcceptRanges::bytes()); + + if let Some(last_modified) = modified { + resp.headers_mut().typed_insert(last_modified); + } + + Ok(resp) + }) + .unwrap_or_else(|BadRangeError| { + // bad byte range + let mut resp = Response::new(Body::empty()); + *resp.status_mut() = StatusCode::RANGE_NOT_SATISFIABLE; + resp.headers_mut() + .typed_insert(ContentRange::unsatisfied_bytes(len)); + Ok(resp) + }) + } + } + } +} diff --git a/src/mem_cache/mod.rs b/src/mem_cache/mod.rs new file mode 100644 index 00000000..9fcffe9a --- /dev/null +++ b/src/mem_cache/mod.rs @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// This file is part of Static Web Server. +// See https://static-web-server.net/ for more information +// Copyright (C) 2019-present Jose Quintana + +//! A module that provides several In-Memory cache facilities. +//! + +pub(crate) mod cache; +pub(crate) mod stream; diff --git a/src/mem_cache/stream.rs b/src/mem_cache/stream.rs new file mode 100644 index 00000000..e7b426ed --- /dev/null +++ b/src/mem_cache/stream.rs @@ -0,0 +1,71 @@ +use bytes::{BufMut, Bytes, BytesMut}; +use futures_util::Stream; +use std::io::Read; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll}; + +use crate::mem_cache::cache::{MemFile, MemFileTempOpts, CACHE_STORE}; +use crate::Result; + +#[derive(Debug)] +pub(crate) struct MemCacheFileStream { + pub(crate) reader: T, + pub(crate) buf_size: usize, + pub(crate) mem_opts: Option, + pub(crate) mem_buf: Option, +} + +impl Stream for MemCacheFileStream { + type Item = Result; + + fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { + let buf_size = self.buf_size; + let mut buf = BytesMut::zeroed(buf_size); + let pinned = Pin::into_inner(self); + + match pinned.reader.read(&mut buf[..]) { + Ok(n) => { + if n == 0 { + Poll::Ready(None) + } else { + buf.truncate(n); + let buf = buf.freeze(); + + // Handle in-memory cache if enabled + if pinned.mem_opts.is_some() && pinned.mem_buf.is_some() { + let buf_data_mut = pinned.mem_buf.as_mut().unwrap(); + buf_data_mut.put(buf.clone()); + + // If file size is reached then proceed cache it + if buf_data_mut.len() == buf_data_mut.capacity() { + let buf_data = pinned.mem_buf.take().unwrap().freeze(); + let mem_file_opts = pinned.mem_opts.as_ref().unwrap(); + + let mem_file = Arc::new(MemFile::new( + buf_data, + buf_size, + mem_file_opts.content_type.to_owned(), + mem_file_opts.last_modified, + )); + + let file_path = mem_file_opts.file_path.as_str(); + tracing::debug!( + "file `{}` is inserted to the in-memory cache store", + file_path + ); + + CACHE_STORE + .get() + .unwrap() + .insert(file_path.into(), mem_file); + } + } + + Poll::Ready(Some(Ok(buf))) + } + } + Err(err) => Poll::Ready(Some(Err(anyhow::Error::from(err)))), + } + } +} diff --git a/src/response.rs b/src/response.rs index fda95e4c..3abc694b 100644 --- a/src/response.rs +++ b/src/response.rs @@ -6,6 +6,7 @@ //! Module to transition files into HTTP responses. //! +use bytes::BytesMut; use headers::{ AcceptRanges, ContentLength, ContentRange, ContentType, HeaderMapExt, LastModified, Range, }; @@ -17,6 +18,10 @@ use std::path::PathBuf; use crate::conditional_headers::{ConditionalBody, ConditionalHeaders}; use crate::fs::stream::{optimal_buf_size, FileStream}; +use crate::mem_cache::{ + cache::{MemCacheOpts, MemFileTempOpts}, + stream::MemCacheFileStream, +}; /// It converts a file object into a corresponding HTTP response or /// returns an error holding an HTTP status code otherwise. @@ -25,6 +30,7 @@ pub(crate) fn response_body( path: &PathBuf, meta: &Metadata, conditionals: ConditionalHeaders, + memory_cache: Option<&MemCacheOpts>, ) -> Result, StatusCode> { let mut len = meta.len(); let modified = meta.modified().ok().map(LastModified::from); @@ -33,6 +39,7 @@ pub(crate) fn response_body( ConditionalBody::NoBody(resp) => Ok(resp), ConditionalBody::WithBody(range) => { let buf_size = optimal_buf_size(meta); + bytes_range(range, len) .map(|(start, end)| { match file.seek(SeekFrom::Start(start)) { @@ -45,9 +52,46 @@ pub(crate) fn response_body( let sub_len = end - start; let reader = BufReader::new(file).take(sub_len); - let stream = FileStream { reader, buf_size }; - let body = Body::wrap_stream(stream); + let mime = mime_guess::from_path(path).first_or_octet_stream(); + let content_type = ContentType::from(mime); + + // Add the file to the in-memory cache only under these conditions: + // - if the feature is enabled and + // - if the file size does not exceed the maximum permitted and + // - if the file is not found in the cache store + // TODO: make this a feature + let body = match memory_cache { + // Cache the file only if does not exceed the max size + Some(mem_cache_opts) if len <= mem_cache_opts.max_file_size => { + match path.to_str() { + Some(path_str) => { + let content_type = content_type.clone(); + let file_path = path_str.to_owned(); + + let mem_buf = Some(BytesMut::with_capacity(len as usize)); + let mem_opts = Some(MemFileTempOpts::new( + file_path, + content_type, + modified, + )); + tracing::debug!( + "preparing `{}` to be inserted in-memory cache store", + path_str, + ); + Body::wrap_stream(MemCacheFileStream { + reader, + buf_size, + mem_opts, + mem_buf, + }) + } + _ => Body::wrap_stream(FileStream { reader, buf_size }), + } + } + _ => Body::wrap_stream(FileStream { reader, buf_size }), + }; + let mut resp = Response::new(body); if sub_len != len { @@ -69,10 +113,8 @@ pub(crate) fn response_body( len = sub_len; } - let mime = mime_guess::from_path(path).first_or_octet_stream(); - resp.headers_mut().typed_insert(ContentLength(len)); - resp.headers_mut().typed_insert(ContentType::from(mime)); + resp.headers_mut().typed_insert(content_type); resp.headers_mut().typed_insert(AcceptRanges::bytes()); if let Some(last_modified) = modified { @@ -81,7 +123,7 @@ pub(crate) fn response_body( Ok(resp) }) - .unwrap_or_else(|BadRange| { + .unwrap_or_else(|BadRangeError| { // bad byte range let mut resp = Response::new(Body::empty()); *resp.status_mut() = StatusCode::RANGE_NOT_SATISFIABLE; @@ -93,11 +135,11 @@ pub(crate) fn response_body( } } -struct BadRange; +pub(crate) struct BadRangeError; /// It handles the `Range` header returning the corresponding start/end-range bytes /// or returns an error for bad ranges otherwise. -fn bytes_range(range: Option, max_len: u64) -> Result<(u64, u64), BadRange> { +pub(crate) fn bytes_range(range: Option, max_len: u64) -> Result<(u64, u64), BadRangeError> { let range = if let Some(range) = range { range } else { @@ -114,7 +156,7 @@ fn bytes_range(range: Option, max_len: u64) -> Result<(u64, u64), BadRang (Bound::Included(a), Bound::Included(b)) => { // `start` can not be greater than `end` if a > b { - return Err(BadRange); + return Err(BadRangeError); } // For the special case where b == the file size (a, if b == max_len { b } else { b + 1 }) @@ -151,11 +193,11 @@ fn bytes_range(range: Option, max_len: u64) -> Result<(u64, u64), BadRang return Ok((start, max_len)); } - Err(BadRange) + Err(BadRangeError) }) .next() - // NOTE: default to `BadRange` in case of wrong `Range` bytes format - .unwrap_or(Err(BadRange)); + // NOTE: default to `BadRangeError` in case of wrong `Range` bytes format + .unwrap_or(Err(BadRangeError)); resp } diff --git a/src/server.rs b/src/server.rs index 7ea53f29..bf7e7f1a 100644 --- a/src/server.rs +++ b/src/server.rs @@ -13,6 +13,7 @@ use std::sync::Arc; use tokio::sync::{watch::Receiver, Mutex}; use crate::handler::{RequestHandler, RequestHandlerOpts}; + #[cfg(all(unix, feature = "experimental"))] use crate::metrics; #[cfg(any(unix, windows))] @@ -44,7 +45,8 @@ use crate::{compression, compression_static}; use crate::basic_auth; use crate::{ - control_headers, cors, health, helpers, log_addr, maintenance_mode, security_headers, Settings, + control_headers, cors, health, helpers, log_addr, maintenance_mode, mem_cache, + security_headers, Settings, }; use crate::{service::RouterService, Context, Result}; @@ -338,6 +340,9 @@ impl Server { // Security Headers option security_headers::init(general.security_headers, &mut handler_opts); + // In-Memory cache option + mem_cache::cache::init(&mut handler_opts)?; + // Create a service router for Hyper let router_service = RouterService::new(RequestHandler { opts: Arc::from(handler_opts), diff --git a/src/settings/file.rs b/src/settings/file.rs index 1f656b4b..3cc417aa 100644 --- a/src/settings/file.rs +++ b/src/settings/file.rs @@ -160,6 +160,20 @@ pub struct VirtualHosts { pub root: Option, } +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "kebab-case")] +/// Represents the in-memory file cache feature. +pub struct MemoryCache { + /// Maximum capacity entries of the memory cache store. + pub capacity: Option, + /// Time to live in seconds of a cached file entry. + pub ttl: Option, + /// Time to idle in seconds of a cached file entry. + pub tti: Option, + /// Maximum size in bytes for a file entry to be cached. + pub max_file_size: Option, +} + /// Advanced server options only available in configuration file mode. #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "kebab-case")] @@ -172,6 +186,8 @@ pub struct Advanced { pub redirects: Option>, /// Name-based virtual hosting pub virtual_hosts: Option>, + /// In-memory cache feature (experimental). + pub memory_cache: Option, } /// General server options available in configuration file mode. @@ -363,6 +379,9 @@ pub struct General { /// Custom maintenance mode HTML file. pub maintenance_mode_file: Option, + /// In-memory files cache feature. + pub memory_cache: Option, + #[cfg(windows)] /// windows service feature. pub windows_service: Option, diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 7666b295..9b598de0 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -25,7 +25,7 @@ pub use cli::Commands; use cli::General; -use self::file::{RedirectsKind, Settings as FileSettings}; +use self::file::{MemoryCache, RedirectsKind, Settings as FileSettings}; #[cfg(any( feature = "compression", @@ -85,6 +85,8 @@ pub struct Advanced { pub redirects: Option>, /// Name-based virtual hosting pub virtual_hosts: Option>, + /// In-memory cache feature (experimental). + pub memory_cache: Option, } /// The full server CLI and File options. @@ -569,6 +571,7 @@ impl Settings { rewrites: rewrites_entries, redirects: redirects_entries, virtual_hosts: vhosts_entries, + memory_cache: advanced.memory_cache, }); } } else if log_init { diff --git a/src/static_files.rs b/src/static_files.rs index a72fc7ac..2a26fffb 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -19,6 +19,7 @@ use crate::conditional_headers::ConditionalHeaders; use crate::fs::meta::{try_metadata, try_metadata_with_html_suffix, FileMetadata}; use crate::fs::path::{sanitize_path, PathExt}; use crate::http_ext::{MethodExt, HTTP_SUPPORTED_METHODS}; +use crate::mem_cache::cache::{self, MemCacheOpts}; use crate::response::response_body; use crate::Result; @@ -44,6 +45,8 @@ const DEFAULT_INDEX_FILES: &[&str; 1] = &["index.html"]; pub struct HandleOpts<'a> { /// Request method. pub method: &'a Method, + /// In-memory files cache feature (experimental). + pub memory_cache: Option<&'a MemCacheOpts>, /// Request headers. pub headers: &'a HeaderMap, /// Request base path. @@ -98,6 +101,24 @@ pub async fn handle<'a>(opts: &HandleOpts<'a>) -> Result(opts: &HandleOpts<'a>) -> Result(opts: &HandleOpts<'a>) -> Result( path: &'a PathBuf, meta: &'a Metadata, path_precompressed: Option, + memory_cache: Option<&'a MemCacheOpts>, ) -> Result, StatusCode> { let conditionals = ConditionalHeaders::new(headers); let file_path = path_precompressed.as_ref().unwrap_or(path); match File::open(file_path) { - Ok(file) => response_body(file, path, meta, conditionals), + Ok(file) => response_body(file, path, meta, conditionals, memory_cache), Err(err) => { let status = match err.kind() { io::ErrorKind::NotFound => { diff --git a/src/testing.rs b/src/testing.rs index b5e4276f..4712d5c6 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -104,6 +104,7 @@ pub mod fixtures { maintenance_mode: general.maintenance_mode, maintenance_mode_status: general.maintenance_mode_status, maintenance_mode_file: general.maintenance_mode_file, + memory_cache: None, advanced_opts: advanced, }; diff --git a/tests/compression_static.rs b/tests/compression_static.rs index f1c9cbc0..6b4f6c17 100644 --- a/tests/compression_static.rs +++ b/tests/compression_static.rs @@ -45,6 +45,7 @@ mod tests { base_path: &public_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -116,6 +117,7 @@ mod tests { base_path: &public_dir(), uri_path: "404.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -184,6 +186,7 @@ mod tests { base_path: &public_dir().join("assets/"), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -250,6 +253,7 @@ mod tests { base_path: &base_path, uri_path: "/", uri_query: None, + memory_cache: None, dir_listing: true, dir_listing_order: 6, dir_listing_format: &DirListFmt::Html, @@ -282,6 +286,7 @@ mod tests { base_path: &public_dir(), uri_path: "main.js", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] diff --git a/tests/dir_listing.rs b/tests/dir_listing.rs index 835bba82..919c70f5 100644 --- a/tests/dir_listing.rs +++ b/tests/dir_listing.rs @@ -43,6 +43,7 @@ mod tests { base_path: &root_dir("docker/public/"), uri_path: "/assets", uri_query: None, + memory_cache: None, dir_listing: true, dir_listing_order: 6, dir_listing_format: &DirListFmt::Html, @@ -76,6 +77,7 @@ mod tests { base_path: &root_dir("docs/"), uri_path: "/content/", uri_query: None, + memory_cache: None, dir_listing: true, dir_listing_order: 6, dir_listing_format: &DirListFmt::Html, @@ -119,6 +121,7 @@ mod tests { base_path: &root_dir("docs/"), uri_path: "/content", uri_query: None, + memory_cache: None, dir_listing: true, dir_listing_order: 6, dir_listing_format: &DirListFmt::Html, @@ -162,6 +165,7 @@ mod tests { base_path: &root_dir("docs/"), uri_path: "/README.md", uri_query: None, + memory_cache: None, dir_listing: true, dir_listing_order: 6, dir_listing_format: &DirListFmt::Html, @@ -195,6 +199,7 @@ mod tests { base_path: &root_dir("tests/fixtures/public/"), uri_path: "/", uri_query: None, + memory_cache: None, dir_listing: true, dir_listing_order: 6, dir_listing_format: &DirListFmt::Html, @@ -249,6 +254,7 @@ mod tests { base_path: &root_dir("tests/fixtures/public/"), uri_path: "/", uri_query: None, + memory_cache: None, dir_listing: true, dir_listing_order: 1, dir_listing_format: &DirListFmt::Json, @@ -321,6 +327,7 @@ mod tests { base_path: &root_dir(&empty_dir), uri_path: "/", uri_query: None, + memory_cache: None, dir_listing: true, dir_listing_order: 1, dir_listing_format: &DirListFmt::Json, @@ -366,6 +373,7 @@ mod tests { base_path: &root_dir("tests/fixtures/public"), uri_path: "/", uri_query: None, + memory_cache: None, dir_listing: true, dir_listing_order: 1, dir_listing_format: &DirListFmt::Html, diff --git a/tests/static_files.rs b/tests/static_files.rs index 62f4d275..dee51ef2 100644 --- a/tests/static_files.rs +++ b/tests/static_files.rs @@ -48,6 +48,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -92,6 +93,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -137,6 +139,7 @@ mod tests { base_path: &root_dir(), uri_path: "xyz.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -169,6 +172,7 @@ mod tests { base_path: &root_dir(), uri_path: "assets", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -203,6 +207,7 @@ mod tests { base_path: &root_dir(), uri_path: "assets", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -236,6 +241,7 @@ mod tests { base_path: &root_dir(), uri_path: "assets", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -274,6 +280,7 @@ mod tests { base_path: &root_dir(), uri_path: uri, uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -327,6 +334,7 @@ mod tests { base_path: &root_dir(), uri_path: "/index%2ehtml", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -362,6 +370,7 @@ mod tests { base_path: &root_dir(), uri_path: "/%2E%2e.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -399,6 +408,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -437,6 +447,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -478,6 +489,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -517,6 +529,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -554,6 +567,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -590,6 +604,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -630,6 +645,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -714,6 +730,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -785,6 +802,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -835,6 +853,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -885,6 +904,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -936,6 +956,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -979,6 +1000,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1032,6 +1054,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1082,6 +1105,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1132,6 +1156,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1185,6 +1210,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1228,6 +1254,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1270,6 +1297,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1327,6 +1355,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1376,6 +1405,7 @@ mod tests { base_path: &root_dir, uri_path: ".dotfile", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1416,6 +1446,7 @@ mod tests { base_path: &root_dir, uri_path: "/", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1458,6 +1489,7 @@ mod tests { base_path: &root_dir, uri_path: "/symlink", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] @@ -1490,6 +1522,7 @@ mod tests { base_path: &root_dir, uri_path: "/symlink/spécial file.txt~", uri_query: None, + memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, #[cfg(feature = "directory-listing")] diff --git a/tests/toml/config.toml b/tests/toml/config.toml index 1db5b7ee..be939ec5 100644 --- a/tests/toml/config.toml +++ b/tests/toml/config.toml @@ -70,7 +70,7 @@ index-files = "index.html, index.htm" #### Maintenance Mode maintenance-mode = false -# maintenance-mode-status = 503 +# maintenance-mode-status = 503 # maintenance-mode-file = "maintenance.html" ### Windows Only @@ -153,3 +153,12 @@ root = "docker" [[advanced.virtual-hosts]] host = "localhost" root = "docker/abc" + +[advanced.memory-cache] +capacity = 100 +# 30min +ttl = 1800 +# 5min +tti = 300 +# 8mb +max-file-size = 8192 From d567b4ec1e2d365a918ca5468c681d78102bb360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Christian=20Gr=C3=BCnhage?= Date: Sun, 8 Sep 2024 21:28:40 +0200 Subject: [PATCH 3/8] feat: support for generating man pages and completions (#475) via a new `static-web-server generate` subcomand. * feat: generate man page and completions * fix: missing Windows imports in binary server entrypoint * refactor: log completions and man pages generation using server_info --------- Co-authored-by: Jose Quintana --- Cargo.lock | 94 +++++++++++++++++++ Cargo.toml | 1 + .../content/features/man-pages-completions.md | 16 ++++ docs/mkdocs.yml | 1 + src/bin/server.rs | 51 +++++++--- src/settings/cli.rs | 23 ++++- src/settings/mod.rs | 2 - 7 files changed, 167 insertions(+), 21 deletions(-) create mode 100644 docs/content/features/man-pages-completions.md diff --git a/Cargo.lock b/Cargo.lock index fbc011cd..fed13ca8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -262,6 +262,19 @@ dependencies = [ "serde", ] +[[package]] +name = "carapace_spec_clap" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c1b382d0ea2f304c9dba34f746284c7b6d231db48eae53b36d1e6eda1aba402" +dependencies = [ + "clap", + "clap_complete", + "indexmap", + "serde", + "serde_yaml", +] + [[package]] name = "cargo-platform" version = "0.1.8" @@ -341,6 +354,21 @@ dependencies = [ "clap_derive", ] +[[package]] +name = "clap_allgen" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b31337b55b534905114db35586730324e5dab9a01af7cf440db39723caeab4" +dependencies = [ + "carapace_spec_clap", + "clap", + "clap_complete", + "clap_complete_fig", + "clap_complete_nushell", + "clap_mangen", + "thiserror", +] + [[package]] name = "clap_builder" version = "4.5.15" @@ -353,6 +381,35 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.5.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "205d5ef6d485fa47606b98b0ddc4ead26eb850aaa86abfb562a94fb3280ecba0" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_complete_fig" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d494102c8ff3951810c72baf96910b980fb065ca5d3101243e6a8dc19747c86b" +dependencies = [ + "clap", + "clap_complete", +] + +[[package]] +name = "clap_complete_nushell" +version = "4.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe32110e006bccf720f8c9af3fee1ba7db290c724eab61544e1d3295be3a40e" +dependencies = [ + "clap", + "clap_complete", +] + [[package]] name = "clap_derive" version = "4.5.13" @@ -371,6 +428,16 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +[[package]] +name = "clap_mangen" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17415fd4dfbea46e3274fcd8d368284519b358654772afb700dc2e8d2b24eeb" +dependencies = [ + "clap", + "roff", +] + [[package]] name = "colorchoice" version = "1.0.2" @@ -836,6 +903,7 @@ checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown", + "serde", ] [[package]] @@ -1286,6 +1354,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "roff" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3" + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1444,6 +1518,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1" version = "0.10.6" @@ -1566,6 +1653,7 @@ dependencies = [ "bytes", "chrono", "clap", + "clap_allgen", "compact_str", "form_urlencoded", "futures-util", @@ -2005,6 +2093,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 5bc4225b..2064f71a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,7 @@ bcrypt = { version = "0.15", optional = true } bytes = "1.6" chrono = { version = "0.4", default-features = false, features = ["std", "clock"], optional = true } clap = { version = "4.5", features = ["derive", "env"] } +clap_allgen = "0.2.0" compact_str = "0.8" form_urlencoded = "1.2" futures-util = { version = "0.3", default-features = false } diff --git a/docs/content/features/man-pages-completions.md b/docs/content/features/man-pages-completions.md new file mode 100644 index 00000000..b4f650ee --- /dev/null +++ b/docs/content/features/man-pages-completions.md @@ -0,0 +1,16 @@ +# Generated CLI documentation +**`SWS`** is capable of generating documentation for its command line interface in the form of man pages and shell completions. + +You can generate completions for these shells and completion engines using `static-web-server generate --completions `: +- bash +- carapace +- elvish +- fig +- fish +- nushell +- powershell +- zsh + +You can generate man pages using `static-web-server generate --man-pages `. + +Finally, if you want both to be generated, you can just use `static-web-server generate ` without specifying `--completions` or `--man-pages`. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 5d4decda..2a769b8c 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -166,6 +166,7 @@ nav: - 'Multiple Index Files': 'features/multiple-index-files.md' - 'Maintenance Mode': 'features/maintenance-mode.md' - 'WebAssembly': 'features/webassembly.md' + - 'Man Pages and Shell Completions': 'features/man-pages-completions.md' - 'Platforms & Architectures': 'platforms-architectures.md' - 'Migrating from v1 to v2': 'migration.md' - 'Changelog v2 (stable)': 'https://github.com/static-web-server/static-web-server/blob/master/CHANGELOG.md' diff --git a/src/bin/server.rs b/src/bin/server.rs index 15e4e732..95bf3866 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -12,7 +12,10 @@ #[global_allocator] static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; -use static_web_server::{Result, Settings}; +use static_web_server::{ + settings::{cli::General, Commands}, + Result, Settings, +}; fn main() -> Result { let opts = Settings::get(true)?; @@ -21,25 +24,45 @@ fn main() -> Result { return static_web_server::settings::cli_output::display_version(); } - #[cfg(windows)] - { - use static_web_server::settings::Commands; - use static_web_server::winservice; - - if let Some(commands) = opts.general.commands { - match commands { - Commands::Install {} => { - return winservice::install_service(&opts.general.config_file); + if let Some(commands) = opts.general.commands { + use static_web_server::server_info; + + match commands { + #[cfg(windows)] + Commands::Install {} => { + return static_web_server::winservice::install_service(&opts.general.config_file); + } + #[cfg(windows)] + Commands::Uninstall {} => { + return static_web_server::winservice::uninstall_service(); + } + Commands::Generate { + completions, + man_pages, + out_dir, + } => { + if completions || !man_pages { + let mut comp_dir = out_dir.clone(); + comp_dir.push("completions"); + clap_allgen::render_shell_completions::(&comp_dir)?; + server_info!("wrote completions to {}", comp_dir.to_string_lossy()); } - Commands::Uninstall {} => { - return winservice::uninstall_service(); + if man_pages || !completions { + let mut man_dir = out_dir.clone(); + man_dir.push("man"); + clap_allgen::render_manpages::(&man_dir)?; + server_info!("wrote man pages to {}", man_dir.to_string_lossy()); } + return Ok(()); } - } else if opts.general.windows_service { - return winservice::run_server_as_service(); } } + #[cfg(windows)] + if opts.general.windows_service { + return static_web_server::winservice::run_server_as_service(); + } + // Run the server by default static_web_server::Server::new(opts)?.run_standalone(None)?; diff --git a/src/settings/cli.rs b/src/settings/cli.rs index 42bf8d2a..12b36106 100644 --- a/src/settings/cli.rs +++ b/src/settings/cli.rs @@ -525,10 +525,9 @@ pub struct General { /// Tell the web server to run in a Windows Service context. Note that the `install` subcommand will enable this option automatically. pub windows_service: bool, - // Windows commands - #[cfg(windows)] + // Subcommands #[command(subcommand)] - /// Subcommands to install or uninstall the SWS Windows Service. + /// Subcommands for additional maintenance tasks, like installing and uninstalling the SWS Windows Service and generation of completions and man pages pub commands: Option, #[arg( @@ -542,17 +541,31 @@ pub struct General { pub version: bool, } -#[cfg(windows)] #[derive(Debug, clap::Subcommand)] -/// Subcommands to install or uninstall the SWS Windows Service. +/// Subcommands for additional maintenance tasks, like installing and uninstalling the SWS Windows Service and generation of completions and man pages pub enum Commands { /// Install a Windows Service for the web server. + #[cfg(windows)] #[command(name = "install")] Install {}, /// Uninstall the current Windows Service. + #[cfg(windows)] #[command(name = "uninstall")] Uninstall {}, + + /// Generate man pages and shell completions + #[command(name = "generate")] + Generate { + /// Generate shell completions + #[arg(long)] + completions: bool, + /// Generate man pages + #[arg(long)] + man_pages: bool, + /// Path to write generated artifacts to + out_dir: PathBuf, + }, } fn value_parser_pathbuf(s: &str) -> Result { diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 9b598de0..8fb9c705 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -20,7 +20,6 @@ pub mod cli; pub mod cli_output; pub mod file; -#[cfg(windows)] pub use cli::Commands; use cli::General; @@ -661,7 +660,6 @@ impl Settings { // Windows-only options and commands #[cfg(windows)] windows_service, - #[cfg(windows)] commands: opts.commands, }, advanced: settings_advanced, From 6bb613867143c24928f473c0dfd9a3ae37ad6f87 Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Sun, 8 Sep 2024 22:19:04 +0200 Subject: [PATCH 4/8] chore: update Alpine (3.18.9) and Debian (12.7) Docker images (#478) --- docker/alpine/Dockerfile | 4 ++-- docker/debian/Dockerfile | 4 ++-- docker/devel/Dockerfile.alpine | 2 +- docker/devel/Dockerfile.debian | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 385260f4..80c801fa 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM alpine:3.18.7 as build +FROM --platform=$BUILDPLATFORM alpine:3.18.9 as build ARG TARGETPLATFORM ARG SERVER_VERSION=0.0.0 @@ -30,7 +30,7 @@ RUN set -ex \ && file /usr/local/bin/static-web-server \ && true -FROM alpine:3.18.7 +FROM alpine:3.18.9 ARG SERVER_VERSION=0.0.0 ENV SERVER_VERSION=${SERVER_VERSION} diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index 626fdf31..1cc92463 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM debian:12.6-slim as build +FROM --platform=$BUILDPLATFORM debian:12.7-slim as build ARG TARGETPLATFORM ARG SERVER_VERSION=0.0.0 @@ -48,7 +48,7 @@ RUN set -ex \ && file /usr/local/bin/static-web-server \ && true -FROM debian:12.6-slim +FROM debian:12.7-slim ARG SERVER_VERSION=0.0.0 ENV SERVER_VERSION=${SERVER_VERSION} diff --git a/docker/devel/Dockerfile.alpine b/docker/devel/Dockerfile.alpine index 6de7480b..b4483c5a 100644 --- a/docker/devel/Dockerfile.alpine +++ b/docker/devel/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM alpine:3.18.7 +FROM alpine:3.18.9 ENV SERVER_VERSION=devel diff --git a/docker/devel/Dockerfile.debian b/docker/devel/Dockerfile.debian index 327e7b39..b7808722 100644 --- a/docker/devel/Dockerfile.debian +++ b/docker/devel/Dockerfile.debian @@ -1,4 +1,4 @@ -FROM debian:12.6-slim +FROM debian:12.7-slim ENV SERVER_VERSION=devel From a3d40b8c2f7cc6961a3cb830d6d75bc513eddfd6 Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Tue, 10 Sep 2024 15:28:54 +0200 Subject: [PATCH 5/8] fix: issues when building SWS without default features (#480) * fix: issues when building without default features * fix: windows http1_cancel_recv build issues --- .github/workflows/devel.yml | 31 ++++++++++++++++++++++++++++ docs/content/building-from-source.md | 9 ++++++-- src/headers_ext/mod.rs | 2 ++ src/http_ext.rs | 1 + src/lib.rs | 7 ------- src/server.rs | 30 ++++++++++++++++++--------- src/static_files.rs | 5 ----- tests/compression.rs | 7 +++++++ tests/compression_static.rs | 5 ----- tests/handler.rs | 14 +++++++++++++ tests/static_files.rs | 2 -- 11 files changed, 82 insertions(+), 31 deletions(-) diff --git a/.github/workflows/devel.yml b/.github/workflows/devel.yml index 874c14be..d4992940 100644 --- a/.github/workflows/devel.yml +++ b/.github/workflows/devel.yml @@ -263,6 +263,37 @@ jobs: ;; esac + - name: Turn off default features + shell: bash + run: | + echo "CARGO_FEATURES=--no-default-features" >> $GITHUB_ENV + + - name: Run tests without default features + shell: bash + run: | + ${{ env.CARGO_BIN }} test --verbose ${{ env.CARGO_FEATURES }} ${{ env.TARGET_FLAGS }} ${{ env.SKIP_TESTS }} + + - name: Run build without default features + shell: bash + run: | + ${{ env.CARGO_BIN }} build --bin static-web-server -vv ${{ env.CARGO_FEATURES }} ${{ env.TARGET_FLAGS }} + + - name: Run executable without default features + shell: bash + run: | + case "${{ matrix.build }}" in + *-arm*|*bsd*|*illumos*|*ppc64*|*s390x*) + echo "arm,bsd,illumos,ppc64,s390x are unable to execute on CI for now!" + ;; + *) + if [[ "${{ matrix.os }}" == "windows-2022" ]]; then + target/${{ matrix.target }}/debug/static-web-server.exe -h + else + target/${{ matrix.target }}/debug/static-web-server -h + fi + ;; + esac + checks: name: checks runs-on: ubuntu-22.04 diff --git a/docs/content/building-from-source.md b/docs/content/building-from-source.md index c2b8ef3b..39710ddd 100644 --- a/docs/content/building-from-source.md +++ b/docs/content/building-from-source.md @@ -55,10 +55,10 @@ For example, if you want to run or build SWS without the default features like ` # run cargo run --no-default-features -- -h -# or build +# build cargo build --release --no-default-features -# or including all features (example) +# or build including all features (example) RUSTFLAGS="--cfg tokio_unstable" \ cargo build -vv --release --features all ``` @@ -87,8 +87,13 @@ Built binaries can be found under the corresponding toolchain directory inside ` ```sh # run tests for default features cargo test + +# run all tests without default features +cargo test --tests --no-default-features + # or run tests for all features including experimental ones RUSTFLAGS="--cfg tokio_unstable" cargo test --features all + # or run specific tests cargo test --test rewrites ``` diff --git a/src/headers_ext/mod.rs b/src/headers_ext/mod.rs index 3999c5af..0ce8e896 100644 --- a/src/headers_ext/mod.rs +++ b/src/headers_ext/mod.rs @@ -7,6 +7,8 @@ //! header. //! +#![allow(unused)] + mod accept_encoding; mod content_coding; mod quality_value; diff --git a/src/http_ext.rs b/src/http_ext.rs index fb1b6bb8..a6814148 100644 --- a/src/http_ext.rs +++ b/src/http_ext.rs @@ -15,6 +15,7 @@ pub trait MethodExt { /// If method is allowed. fn is_allowed(&self) -> bool; /// If method is `GET`. + #[allow(unused)] fn is_get(&self) -> bool; /// If method is `HEAD`. fn is_head(&self) -> bool; diff --git a/src/lib.rs b/src/lib.rs index 5c9a356c..a169e67e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -162,13 +162,6 @@ pub mod error_page; pub mod fallback_page; pub(crate) mod fs; pub mod handler; -#[cfg(any( - feature = "compression", - feature = "compression-gzip", - feature = "compression-brotli", - feature = "compression-zstd", - feature = "compression-deflate" -))] pub(crate) mod headers_ext; pub(crate) mod health; pub(crate) mod http_ext; diff --git a/src/server.rs b/src/server.rs index bf7e7f1a..43b5aa85 100644 --- a/src/server.rs +++ b/src/server.rs @@ -350,7 +350,8 @@ impl Server { #[cfg(windows)] let (sender, receiver) = tokio::sync::watch::channel(()); - // ctrl+c listening + + // Windows ctrl+c listening #[cfg(windows)] let ctrlc_task = tokio::spawn(async move { if !general.windows_service { @@ -603,18 +604,16 @@ impl Server { http1_cancel_recv, )); - #[cfg(windows)] - let http1_cancel_recv = Arc::new(Mutex::new(_cancel_recv)); - #[cfg(windows)] - let http1_ctrlc_recv = Arc::new(Mutex::new(Some(receiver))); - #[cfg(windows)] let http1_server = http1_server.with_graceful_shutdown(async move { - if general.windows_service { - signals::wait_for_ctrl_c(http1_cancel_recv, grace_period).await; + let http1_cancel_recv = if general.windows_service { + // http1_cancel_recv + Arc::new(Mutex::new(_cancel_recv)) } else { - signals::wait_for_ctrl_c(http1_ctrlc_recv, grace_period).await; - } + // http1_ctrlc_recv + Arc::new(Mutex::new(Some(receiver))) + }; + signals::wait_for_ctrl_c(http1_cancel_recv, grace_period).await; }); server_info!( @@ -625,8 +624,19 @@ impl Server { server_info!("press ctrl+c to shut down the server"); + #[cfg(unix)] http1_server.await?; + #[cfg(windows)] + let http1_server_task = tokio::spawn(async move { + if let Err(err) = http1_server.await { + tracing::error!("http1 server failed to start up: {:?}", err); + std::process::exit(1) + } + }); + #[cfg(windows)] + tokio::try_join!(ctrlc_task, http1_server_task)?; + #[cfg(windows)] _cancel_fn(); diff --git a/src/static_files.rs b/src/static_files.rs index 2a26fffb..5ace8112 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -27,7 +27,6 @@ use crate::Result; feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] @@ -278,7 +277,6 @@ fn get_composed_file_metadata<'a>( feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] @@ -326,7 +324,6 @@ fn get_composed_file_metadata<'a>( feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] @@ -356,7 +353,6 @@ fn get_composed_file_metadata<'a>( feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] @@ -381,7 +377,6 @@ fn get_composed_file_metadata<'a>( feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] diff --git a/tests/compression.rs b/tests/compression.rs index 8c8e7e46..2ca82293 100644 --- a/tests/compression.rs +++ b/tests/compression.rs @@ -3,6 +3,13 @@ #![deny(rust_2018_idioms)] #![deny(dead_code)] +#[cfg(any( + feature = "compression", + feature = "compression-gzip", + feature = "compression-brotli", + feature = "compression-zstd", + feature = "compression-deflate" +))] #[cfg(test)] pub mod tests { use headers::HeaderValue; diff --git a/tests/compression_static.rs b/tests/compression_static.rs index 6b4f6c17..c3951b89 100644 --- a/tests/compression_static.rs +++ b/tests/compression_static.rs @@ -7,7 +7,6 @@ feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] @@ -57,7 +56,6 @@ mod tests { feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] @@ -129,7 +127,6 @@ mod tests { feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] @@ -198,7 +195,6 @@ mod tests { feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] @@ -298,7 +294,6 @@ mod tests { feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] diff --git a/tests/handler.rs b/tests/handler.rs index d53c6585..a98b2407 100644 --- a/tests/handler.rs +++ b/tests/handler.rs @@ -30,6 +30,13 @@ pub mod tests { res.headers().get("content-type"), Some(&HeaderValue::from_static("text/html")) ); + #[cfg(any( + feature = "compression", + feature = "compression-deflate", + feature = "compression-gzip", + feature = "compression-brotli", + feature = "compression-zstd" + ))] assert_eq!( res.headers().get("vary"), Some(&HeaderValue::from_static("accept-encoding")) @@ -62,6 +69,13 @@ pub mod tests { res.headers().get("content-type"), Some(&HeaderValue::from_static("text/html")) ); + #[cfg(any( + feature = "compression", + feature = "compression-deflate", + feature = "compression-gzip", + feature = "compression-brotli", + feature = "compression-zstd" + ))] assert_eq!( res.headers().get("vary"), Some(&HeaderValue::from_static("accept-encoding")) diff --git a/tests/static_files.rs b/tests/static_files.rs index dee51ef2..6f6decf6 100644 --- a/tests/static_files.rs +++ b/tests/static_files.rs @@ -15,7 +15,6 @@ mod tests { feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] @@ -698,7 +697,6 @@ mod tests { feature = "compression", feature = "compression-deflate", feature = "compression-gzip", - feature = "compression-deflate", feature = "compression-brotli", feature = "compression-zstd" ))] From e25b5867bc0adc15020069481243c01f62ca47e3 Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:38:57 +0200 Subject: [PATCH 6/8] chore: update dependencies 08.09.2024 (#479) --- Cargo.lock | 208 ++++++++++++++++++++++++++++------------------------- Cargo.toml | 4 +- 2 files changed, 114 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fed13ca8..31e47101 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aho-corasick" @@ -92,7 +92,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -102,14 +102,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "async-compression" @@ -135,17 +135,17 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets", ] [[package]] @@ -255,24 +255,24 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] [[package]] name = "carapace_spec_clap" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1b382d0ea2f304c9dba34f746284c7b6d231db48eae53b36d1e6eda1aba402" +checksum = "09a6810b1aada7fb10830104d1d5dd8019fbdefd5e51bae3961cc5b58f458023" dependencies = [ "clap", "clap_complete", "indexmap", "serde", - "serde_yaml", + "serde_yaml_ng", ] [[package]] @@ -308,12 +308,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.10" +version = "1.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" +checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -346,9 +347,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.15" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -371,9 +372,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", @@ -466,18 +467,18 @@ checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" [[package]] name = "const_format" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" dependencies = [ "proc-macro2", "quote", @@ -492,9 +493,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -578,7 +579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -592,15 +593,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "flate2" -version = "1.0.31" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", "miniz_oxide", @@ -696,9 +697,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "git2" @@ -721,9 +722,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", @@ -897,9 +898,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", @@ -959,9 +960,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libgit2-sys" @@ -977,9 +978,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -1081,11 +1082,11 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -1097,7 +1098,7 @@ dependencies = [ "hermit-abi", "libc", "wasi", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1136,18 +1137,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" [[package]] name = "overload" @@ -1294,18 +1295,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags", ] @@ -1351,7 +1352,7 @@ dependencies = [ "libc", "spin", "untrusted", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1368,22 +1369,22 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "log", "once_cell", @@ -1412,9 +1413,9 @@ checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -1459,18 +1460,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.207" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.207" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -1488,9 +1489,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.124" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -1519,10 +1520,10 @@ dependencies = [ ] [[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" +name = "serde_yaml_ng" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +checksum = "7b4db627b98b36d4203a7b458cf3573730f2bb591b28871d916dfa9efabfd41f" dependencies = [ "indexmap", "itoa", @@ -1564,6 +1565,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -1633,7 +1640,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1710,9 +1717,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.74" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -1727,15 +1734,15 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] name = "tempfile" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", "once_cell", "rustix", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -1838,9 +1845,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -1850,7 +1857,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1878,9 +1885,9 @@ dependencies = [ [[package]] name = "tokio-metrics-collector" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767da47381602cc481653456823b3ebb600e83d5dd4e0293da9b5566c6c00f0" +checksum = "db29b219a9b30347d896588baf5c85184b137aed52c37a80cab5ba68ee3a7c7e" dependencies = [ "lazy_static", "parking_lot", @@ -1902,9 +1909,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -1913,9 +1920,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -2050,9 +2057,9 @@ dependencies = [ [[package]] name = "tzdb_data" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1889fdffac09d65c1d95c42d5202e9b21ad8c758f426e9fe09088817ea998d6" +checksum = "654c1ec546942ce0594e8d220e6b8e3899e0a0a8fe70ddd54d32a376dfefe3f8" dependencies = [ "tz-rs", ] @@ -2074,9 +2081,9 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" @@ -2089,9 +2096,9 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "unsafe-libyaml" @@ -2254,7 +2261,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -2280,7 +2287,7 @@ checksum = "d24d6bcc7f734a4091ecf8d7a64c5f7d7066f45585c1861eba06449909609c8a" dependencies = [ "bitflags", "widestring", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2292,6 +2299,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.52.6" diff --git a/Cargo.toml b/Cargo.toml index 2064f71a..5a5a95e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,7 +64,7 @@ aho-corasick = "1.1" anyhow = "1.0" async-compression = { version = "0.4", default-features = false, optional = true, features = ["brotli", "deflate", "gzip", "zstd", "tokio"] } bcrypt = { version = "0.15", optional = true } -bytes = "1.6" +bytes = "1.7" chrono = { version = "0.4", default-features = false, features = ["std", "clock"], optional = true } clap = { version = "4.5", features = ["derive", "env"] } clap_allgen = "0.2.0" @@ -110,7 +110,7 @@ prometheus = { version = "0.13", optional = true } windows-service = "0.7" [dev-dependencies] -bytes = "1.6" +bytes = "1.7" serde_json = "1.0" [build-dependencies] From ec85abdf3213e9995786974b44dd8f2628ecf7eb Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Sun, 15 Sep 2024 21:42:23 +0200 Subject: [PATCH 7/8] feat: add in-memory files cache to the `experimental` Cargo feature (#482) --- Cargo.toml | 8 ++++---- src/handler.rs | 11 ++++++++--- src/lib.rs | 1 + src/response.rs | 18 +++++++++++++----- src/server.rs | 7 +++++-- src/settings/file.rs | 3 +++ src/settings/mod.rs | 7 ++++++- src/static_files.rs | 30 +++++++++++++++++++++++------- src/testing.rs | 1 + tests/compression_static.rs | 5 +++++ tests/dir_listing.rs | 8 ++++++++ tests/static_files.rs | 33 +++++++++++++++++++++++++++++++++ 12 files changed, 110 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5a5a95e6..73b288d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,9 +55,9 @@ directory-listing = ["chrono", "maud"] basic-auth = ["bcrypt"] # Fallback Page fallback-page = [] -# Experimental features +# Experimental features (requires: `RUSTFLAGS="--cfg tokio_unstable"`) # --experimental-metrics -experimental = ["tokio-metrics-collector", "prometheus"] +experimental = ["tokio-metrics-collector", "prometheus", "compact_str", "mini-moka"] [dependencies] aho-corasick = "1.1" @@ -68,7 +68,7 @@ bytes = "1.7" chrono = { version = "0.4", default-features = false, features = ["std", "clock"], optional = true } clap = { version = "4.5", features = ["derive", "env"] } clap_allgen = "0.2.0" -compact_str = "0.8" +compact_str = { version = "0.8.0", optional = true } form_urlencoded = "1.2" futures-util = { version = "0.3", default-features = false } globset = { version = "0.4", features = ["serde1"] } @@ -80,7 +80,7 @@ lazy_static = "1.5" listenfd = "1.0" maud = { version = "0.26", optional = true } mime_guess = "2.0" -mini-moka = "0.10.3" +mini-moka = { version = "0.10.3", optional = true } percent-encoding = "2.3" pin-project = "1.1" regex = "1.10" diff --git a/src/handler.rs b/src/handler.rs index 5096f242..b3f19aa0 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -27,12 +27,13 @@ use crate::fallback_page; #[cfg(all(unix, feature = "experimental"))] use crate::metrics; +#[cfg(feature = "experimental")] +use crate::mem_cache::cache::MemCacheOpts; + use crate::{ control_headers, cors, custom_headers, error_page, health, http_ext::MethodExt, - log_addr, maintenance_mode, - mem_cache::cache::MemCacheOpts, - redirects, rewrites, security_headers, + log_addr, maintenance_mode, redirects, rewrites, security_headers, settings::Advanced, static_files::{self, HandleOpts}, virtual_hosts, Error, Result, @@ -46,6 +47,7 @@ pub struct RequestHandlerOpts { // General options /// Root directory of static files. pub root_dir: PathBuf, + #[cfg(feature = "experimental")] /// In-memory cache feature (experimental). pub memory_cache: Option, /// Compression feature. @@ -138,6 +140,7 @@ impl Default for RequestHandlerOpts { #[cfg(feature = "directory-listing")] dir_listing_format: DirListFmt::Html, cors: None, + #[cfg(feature = "experimental")] memory_cache: None, security_headers: false, cache_control_headers: true, @@ -188,6 +191,7 @@ impl RequestHandler { let ignore_hidden_files = self.opts.ignore_hidden_files; let disable_symlinks = self.opts.disable_symlinks; let index_files: Vec<&str> = self.opts.index_files.iter().map(|s| s.as_str()).collect(); + #[cfg(feature = "experimental")] let memory_cache = self.opts.memory_cache.as_ref(); log_addr::pre_process(&self.opts, req, remote_addr); @@ -257,6 +261,7 @@ impl RequestHandler { let (resp, file_path) = match static_files::handle(&HandleOpts { method: req.method(), headers: req.headers(), + #[cfg(feature = "experimental")] memory_cache, base_path, uri_path: req.uri().path(), diff --git a/src/lib.rs b/src/lib.rs index a169e67e..85874f82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -170,6 +170,7 @@ pub(crate) mod http_ext; pub mod https_redirect; pub(crate) mod log_addr; pub mod maintenance_mode; +#[cfg(feature = "experimental")] pub(crate) mod mem_cache; #[cfg(all(unix, feature = "experimental"))] pub(crate) mod metrics; diff --git a/src/response.rs b/src/response.rs index 3abc694b..e9bfe97c 100644 --- a/src/response.rs +++ b/src/response.rs @@ -6,7 +6,6 @@ //! Module to transition files into HTTP responses. //! -use bytes::BytesMut; use headers::{ AcceptRanges, ContentLength, ContentRange, ContentType, HeaderMapExt, LastModified, Range, }; @@ -18,9 +17,14 @@ use std::path::PathBuf; use crate::conditional_headers::{ConditionalBody, ConditionalHeaders}; use crate::fs::stream::{optimal_buf_size, FileStream}; -use crate::mem_cache::{ - cache::{MemCacheOpts, MemFileTempOpts}, - stream::MemCacheFileStream, + +#[cfg(feature = "experimental")] +use { + crate::mem_cache::{ + cache::{MemCacheOpts, MemFileTempOpts}, + stream::MemCacheFileStream, + }, + bytes::BytesMut, }; /// It converts a file object into a corresponding HTTP response or @@ -30,7 +34,7 @@ pub(crate) fn response_body( path: &PathBuf, meta: &Metadata, conditionals: ConditionalHeaders, - memory_cache: Option<&MemCacheOpts>, + #[cfg(feature = "experimental")] memory_cache: Option<&MemCacheOpts>, ) -> Result, StatusCode> { let mut len = meta.len(); let modified = meta.modified().ok().map(LastModified::from); @@ -61,6 +65,7 @@ pub(crate) fn response_body( // - if the file size does not exceed the maximum permitted and // - if the file is not found in the cache store // TODO: make this a feature + #[cfg(feature = "experimental")] let body = match memory_cache { // Cache the file only if does not exceed the max size Some(mem_cache_opts) if len <= mem_cache_opts.max_file_size => { @@ -92,6 +97,9 @@ pub(crate) fn response_body( _ => Body::wrap_stream(FileStream { reader, buf_size }), }; + #[cfg(not(feature = "experimental"))] + let body = Body::wrap_stream(FileStream { reader, buf_size }); + let mut resp = Response::new(body); if sub_len != len { diff --git a/src/server.rs b/src/server.rs index 43b5aa85..8df52d3b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -44,9 +44,11 @@ use crate::{compression, compression_static}; #[cfg(feature = "basic-auth")] use crate::basic_auth; +#[cfg(feature = "experimental")] +use crate::mem_cache; + use crate::{ - control_headers, cors, health, helpers, log_addr, maintenance_mode, mem_cache, - security_headers, Settings, + control_headers, cors, health, helpers, log_addr, maintenance_mode, security_headers, Settings, }; use crate::{service::RouterService, Context, Result}; @@ -341,6 +343,7 @@ impl Server { security_headers::init(general.security_headers, &mut handler_opts); // In-Memory cache option + #[cfg(feature = "experimental")] mem_cache::cache::init(&mut handler_opts)?; // Create a service router for Hyper diff --git a/src/settings/file.rs b/src/settings/file.rs index 3cc417aa..cdd45994 100644 --- a/src/settings/file.rs +++ b/src/settings/file.rs @@ -160,6 +160,7 @@ pub struct VirtualHosts { pub root: Option, } +#[cfg(feature = "experimental")] #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "kebab-case")] /// Represents the in-memory file cache feature. @@ -186,6 +187,7 @@ pub struct Advanced { pub redirects: Option>, /// Name-based virtual hosting pub virtual_hosts: Option>, + #[cfg(feature = "experimental")] /// In-memory cache feature (experimental). pub memory_cache: Option, } @@ -379,6 +381,7 @@ pub struct General { /// Custom maintenance mode HTML file. pub maintenance_mode_file: Option, + #[cfg(feature = "experimental")] /// In-memory files cache feature. pub memory_cache: Option, diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 8fb9c705..5cd58b54 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -24,7 +24,10 @@ pub use cli::Commands; use cli::General; -use self::file::{MemoryCache, RedirectsKind, Settings as FileSettings}; +#[cfg(feature = "experimental")] +use self::file::MemoryCache; + +use self::file::{RedirectsKind, Settings as FileSettings}; #[cfg(any( feature = "compression", @@ -84,6 +87,7 @@ pub struct Advanced { pub redirects: Option>, /// Name-based virtual hosting pub virtual_hosts: Option>, + #[cfg(feature = "experimental")] /// In-memory cache feature (experimental). pub memory_cache: Option, } @@ -570,6 +574,7 @@ impl Settings { rewrites: rewrites_entries, redirects: redirects_entries, virtual_hosts: vhosts_entries, + #[cfg(feature = "experimental")] memory_cache: advanced.memory_cache, }); } diff --git a/src/static_files.rs b/src/static_files.rs index 5ace8112..d29a5ff0 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -19,10 +19,12 @@ use crate::conditional_headers::ConditionalHeaders; use crate::fs::meta::{try_metadata, try_metadata_with_html_suffix, FileMetadata}; use crate::fs::path::{sanitize_path, PathExt}; use crate::http_ext::{MethodExt, HTTP_SUPPORTED_METHODS}; -use crate::mem_cache::cache::{self, MemCacheOpts}; use crate::response::response_body; use crate::Result; +#[cfg(feature = "experimental")] +use crate::mem_cache::{cache, cache::MemCacheOpts}; + #[cfg(any( feature = "compression", feature = "compression-deflate", @@ -45,6 +47,7 @@ pub struct HandleOpts<'a> { /// Request method. pub method: &'a Method, /// In-memory files cache feature (experimental). + #[cfg(feature = "experimental")] pub memory_cache: Option<&'a MemCacheOpts>, /// Request headers. pub headers: &'a HeaderMap, @@ -101,8 +104,8 @@ pub async fn handle<'a>(opts: &HandleOpts<'a>) -> Result(opts: &HandleOpts<'a>) -> Result(opts: &HandleOpts<'a>) -> Result( path: &'a PathBuf, meta: &'a Metadata, path_precompressed: Option, - memory_cache: Option<&'a MemCacheOpts>, + #[cfg(feature = "experimental")] memory_cache: Option<&'a MemCacheOpts>, ) -> Result, StatusCode> { let conditionals = ConditionalHeaders::new(headers); let file_path = path_precompressed.as_ref().unwrap_or(path); match File::open(file_path) { - Ok(file) => response_body(file, path, meta, conditionals, memory_cache), + Ok(file) => { + #[cfg(feature = "experimental")] + let resp = response_body(file, path, meta, conditionals, memory_cache); + + #[cfg(not(feature = "experimental"))] + let resp = response_body(file, path, meta, conditionals); + + resp + } Err(err) => { let status = match err.kind() { io::ErrorKind::NotFound => { diff --git a/src/testing.rs b/src/testing.rs index 4712d5c6..bac712a7 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -104,6 +104,7 @@ pub mod fixtures { maintenance_mode: general.maintenance_mode, maintenance_mode_status: general.maintenance_mode_status, maintenance_mode_file: general.maintenance_mode_file, + #[cfg(feature = "experimental")] memory_cache: None, advanced_opts: advanced, }; diff --git a/tests/compression_static.rs b/tests/compression_static.rs index c3951b89..63492961 100644 --- a/tests/compression_static.rs +++ b/tests/compression_static.rs @@ -44,6 +44,7 @@ mod tests { base_path: &public_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -115,6 +116,7 @@ mod tests { base_path: &public_dir(), uri_path: "404.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -183,6 +185,7 @@ mod tests { base_path: &public_dir().join("assets/"), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -249,6 +252,7 @@ mod tests { base_path: &base_path, uri_path: "/", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, dir_listing: true, dir_listing_order: 6, @@ -282,6 +286,7 @@ mod tests { base_path: &public_dir(), uri_path: "main.js", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, diff --git a/tests/dir_listing.rs b/tests/dir_listing.rs index 919c70f5..5e0f1258 100644 --- a/tests/dir_listing.rs +++ b/tests/dir_listing.rs @@ -43,6 +43,7 @@ mod tests { base_path: &root_dir("docker/public/"), uri_path: "/assets", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, dir_listing: true, dir_listing_order: 6, @@ -77,6 +78,7 @@ mod tests { base_path: &root_dir("docs/"), uri_path: "/content/", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, dir_listing: true, dir_listing_order: 6, @@ -121,6 +123,7 @@ mod tests { base_path: &root_dir("docs/"), uri_path: "/content", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, dir_listing: true, dir_listing_order: 6, @@ -165,6 +168,7 @@ mod tests { base_path: &root_dir("docs/"), uri_path: "/README.md", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, dir_listing: true, dir_listing_order: 6, @@ -199,6 +203,7 @@ mod tests { base_path: &root_dir("tests/fixtures/public/"), uri_path: "/", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, dir_listing: true, dir_listing_order: 6, @@ -254,6 +259,7 @@ mod tests { base_path: &root_dir("tests/fixtures/public/"), uri_path: "/", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, dir_listing: true, dir_listing_order: 1, @@ -327,6 +333,7 @@ mod tests { base_path: &root_dir(&empty_dir), uri_path: "/", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, dir_listing: true, dir_listing_order: 1, @@ -373,6 +380,7 @@ mod tests { base_path: &root_dir("tests/fixtures/public"), uri_path: "/", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, dir_listing: true, dir_listing_order: 1, diff --git a/tests/static_files.rs b/tests/static_files.rs index 6f6decf6..74f4d9ad 100644 --- a/tests/static_files.rs +++ b/tests/static_files.rs @@ -47,6 +47,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -92,6 +93,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -138,6 +140,7 @@ mod tests { base_path: &root_dir(), uri_path: "xyz.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -171,6 +174,7 @@ mod tests { base_path: &root_dir(), uri_path: "assets", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -206,6 +210,7 @@ mod tests { base_path: &root_dir(), uri_path: "assets", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -240,6 +245,7 @@ mod tests { base_path: &root_dir(), uri_path: "assets", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -279,6 +285,7 @@ mod tests { base_path: &root_dir(), uri_path: uri, uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -333,6 +340,7 @@ mod tests { base_path: &root_dir(), uri_path: "/index%2ehtml", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -369,6 +377,7 @@ mod tests { base_path: &root_dir(), uri_path: "/%2E%2e.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -407,6 +416,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -446,6 +456,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -488,6 +499,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -528,6 +540,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -566,6 +579,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -603,6 +617,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -644,6 +659,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -728,6 +744,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -800,6 +817,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -851,6 +869,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -902,6 +921,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -954,6 +974,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -998,6 +1019,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1052,6 +1074,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1103,6 +1126,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1154,6 +1178,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1208,6 +1233,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1252,6 +1278,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1295,6 +1322,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1353,6 +1381,7 @@ mod tests { base_path: &root_dir(), uri_path: "index.html", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1403,6 +1432,7 @@ mod tests { base_path: &root_dir, uri_path: ".dotfile", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1444,6 +1474,7 @@ mod tests { base_path: &root_dir, uri_path: "/", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1487,6 +1518,7 @@ mod tests { base_path: &root_dir, uri_path: "/symlink", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, @@ -1520,6 +1552,7 @@ mod tests { base_path: &root_dir, uri_path: "/symlink/spécial file.txt~", uri_query: None, + #[cfg(feature = "experimental")] memory_cache: None, #[cfg(feature = "directory-listing")] dir_listing: false, From e6a348758610cee643462011f0d71009d5951032 Mon Sep 17 00:00:00 2001 From: Jose Quintana Date: Tue, 17 Sep 2024 23:24:19 +0200 Subject: [PATCH 8/8] v2.33.0 --- CHANGELOG.md | 21 ++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- .../configuration/command-line-arguments.md | 32 +++++++++++-------- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ca6b102..85bbe60e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 _**Note:** See changelog for v1 under the [1.x](https://github.com/static-web-server/static-web-server/blob/1.x/CHANGELOG.md) branch._ +## v2.33.0 - 2024-09-17 + +This new `v2.33.0` release brings several security and bug fixes. New features like experimental in-memory files cache with eviction policy support, new subcomand to generate man pages and shell completions as well as other improvements. + +Note that experimental features are subject to change in future releases. Feel free to give it a try and let us know your feedback. + +__Fixes__ + +- [e25b586](https://github.com/static-web-server/static-web-server/commit/e25b586) Bugfix/security dependency updates including tokio, rustls, serde, toml, once_cell, flate2, clap and other crates. PR [#479](https://github.com/static-web-server/static-web-server/pull/479). +- [a3d40b8](https://github.com/static-web-server/static-web-server/commit/a3d40b8) Crate: Issues when building SWS without default features. PR [#480](https://github.com/static-web-server/static-web-server/pull/480). +- [6bb6138](https://github.com/static-web-server/static-web-server/commit/6bb6138) Docker: Update Alpine (`3.18.9`) and Debian (`12.7`) Docker images. PR [#478](https://github.com/static-web-server/static-web-server/pull/478). + +__Features__ + +- [5bdfcd4](https://github.com/static-web-server/static-web-server/commit/5bdfcd4) Advanced: Experimental in-memory files cache with eviction policy support via a new advanced config option. See PR [#328](https://github.com/static-web-server/static-web-server/pull/328) description for usage and details. +- [ec85abd](https://github.com/static-web-server/static-web-server/commit/ec85abd) Crate: Add in-memory files cache to the `experimental` Cargo feature. See PR [#482](https://github.com/static-web-server/static-web-server/pull/482) description for more details. + - **MSRV update**: Note that due to this change, the SWS's *Minimum Supported Rust Version* is now `1.76.0` when building from source or using it as a library. See [docs](https://static-web-server.net/building-from-source/). +- [d567b4e](https://github.com/static-web-server/static-web-server/commit/d567b4e) CLI: Support for generating man pages and shell completions via new `generate` subcomand. PR [#475](https://github.com/static-web-server/static-web-server/pull/475) by [@jcgruenhage](https://github.com/jcgruenhage). See [docs](https://static-web-server.net/features/man-pages-**completions**/). + +For more details see the [v2.33.0 milestone](https://github.com/static-web-server/static-web-server/milestone/23?closed=1) and the full changelog [v2.32.2...v2.33.0](https://github.com/static-web-server/static-web-server/compare/v2.32.2...v2.33.0). + ## v2.32.2 - 2024-08-13 This new `v2.32.2` release brings several security and bug fixes as well as other improvements. diff --git a/Cargo.lock b/Cargo.lock index 31e47101..e82c71c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1651,7 +1651,7 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "static-web-server" -version = "2.32.2" +version = "2.33.0" dependencies = [ "aho-corasick", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 73b288d1..c4fe691b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "static-web-server" -version = "2.32.2" +version = "2.33.0" edition = "2021" rust-version = "1.76.0" authors = ["Jose Quintana "] diff --git a/docs/content/configuration/command-line-arguments.md b/docs/content/configuration/command-line-arguments.md index 1ab76d82..dffd5b5d 100644 --- a/docs/content/configuration/command-line-arguments.md +++ b/docs/content/configuration/command-line-arguments.md @@ -12,7 +12,11 @@ $ static-web-server -h A cross-platform, high-performance and asynchronous web server for static files-serving. -Usage: static-web-server [OPTIONS] +Usage: static-web-server [OPTIONS] [COMMAND] + +Commands: + generate Generate man pages and shell completions + help Print this message or the help of the given subcommand(s) Options: -a, --host @@ -41,13 +45,13 @@ Options: Specify an optional CORS list of allowed headers separated by commas. Default "origin, content-type". It requires `--cors-allow-origins` to be used along with [env: SERVER_CORS_ALLOW_HEADERS=] [default: "origin, content-type, authorization"] --cors-expose-headers Specify an optional CORS list of exposed headers separated by commas. Default "origin, content-type". It requires `--cors-expose-origins` to be used along with [env: SERVER_CORS_EXPOSE_HEADERS=] [default: "origin, content-type"] - -t, --http2[=] + -t, --http2 [] Enable HTTP/2 with TLS support [env: SERVER_HTTP2_TLS=] [default: false] [possible values: true, false] --http2-tls-cert Specify the file path to read the certificate [env: SERVER_HTTP2_TLS_CERT=] --http2-tls-key Specify the file path to read the private key [env: SERVER_HTTP2_TLS_KEY=] - --https-redirect[=] + --https-redirect [] Redirect all requests with scheme "http" to "https" for the current server instance. It depends on "http2" to be enabled [env: SERVER_HTTPS_REDIRECT=] [default: false] [possible values: true, false] --https-redirect-host Canonical host name or IP of the HTTPS (HTTPS/2) server. It depends on "https_redirect" to be enabled [env: SERVER_HTTPS_REDIRECT_HOST=] [default: localhost] @@ -57,21 +61,21 @@ Options: List of host names or IPs allowed to redirect from. HTTP requests must contain the HTTP 'Host' header and match against this list. It depends on "https_redirect" to be enabled [env: SERVER_HTTPS_REDIRECT_FROM_HOSTS=] [default: localhost] --index-files List of files that will be used as an index for requests ending with the slash character (‘/’). Files are checked in the specified order [env: SERVER_INDEX_FILES=] [default: index.html] - -x, --compression[=] + -x, --compression [] Gzip, Deflate, Brotli or Zstd compression on demand determined by the Accept-Encoding header and applied to text-based web file types only [env: SERVER_COMPRESSION=] [default: true] [possible values: true, false] --compression-level Compression level to apply for Gzip, Deflate, Brotli or Zstd compression [env: SERVER_COMPRESSION_LEVEL=] [default: default] [possible values: fastest, best, default] - --compression-static[=] + --compression-static [] Look up the pre-compressed file variant (`.gz`, `.br` or `.zst`) on disk of a requested file and serves it directly if available. The compression type is determined by the `Accept-Encoding` header [env: SERVER_COMPRESSION_STATIC=] [default: false] [possible values: true, false] - -z, --directory-listing[=] + -z, --directory-listing [] Enable directory listing for all requests ending with the slash character (‘/’) [env: SERVER_DIRECTORY_LISTING=] [default: false] [possible values: true, false] --directory-listing-order Specify a default code number to order directory listing entries per `Name`, `Last modified` or `Size` attributes (columns). Code numbers supported: 0 (Name asc), 1 (Name desc), 2 (Last modified asc), 3 (Last modified desc), 4 (Size asc), 5 (Size desc). Default 6 (unordered) [env: SERVER_DIRECTORY_LISTING_ORDER=] [default: 6] --directory-listing-format Specify a content format for directory listing entries. Formats supported: "html" or "json". Default "html" [env: SERVER_DIRECTORY_LISTING_FORMAT=] [default: html] [possible values: html, json] - --security-headers[=] + --security-headers [] Enable security headers by default when HTTP/2 feature is activated. Headers included: "Strict-Transport-Security: max-age=63072000; includeSubDomains; preload" (2 years max-age), "X-Frame-Options: DENY" and "Content-Security-Policy: frame-ancestors 'self'" [env: SERVER_SECURITY_HEADERS=] [default: false] [possible values: true, false] - -e, --cache-control-headers[=] + -e, --cache-control-headers [] Enable cache control headers for incoming requests based on a set of file types. The file type list can be found on `src/control_headers.rs` file [env: SERVER_CACHE_CONTROL_HEADERS=] [default: true] [possible values: true, false] --basic-auth It provides The "Basic" HTTP Authentication scheme using credentials as "user-id:password" pairs. Password must be encoded using the "BCrypt" password-hashing function [env: SERVER_BASIC_AUTH=] [default: ] @@ -79,17 +83,17 @@ Options: Defines a grace period in seconds after a `SIGTERM` signal is caught which will delay the server before to shut it down gracefully. The maximum value is 255 seconds [env: SERVER_GRACE_PERIOD=] [default: 0] -w, --config-file Server TOML configuration file path [env: SERVER_CONFIG_FILE=] [default: ./config.toml] - --log-remote-address[=] + --log-remote-address [] Log incoming requests information along with its remote address if available using the `info` log level [env: SERVER_LOG_REMOTE_ADDRESS=] [default: false] [possible values: true, false] - --redirect-trailing-slash[=] + --redirect-trailing-slash [] Check for a trailing slash in the requested directory URI and redirect permanently (308) to the same path with a trailing slash suffix if it is missing [env: SERVER_REDIRECT_TRAILING_SLASH=] [default: true] [possible values: true, false] - --ignore-hidden-files[=] + --ignore-hidden-files [] Ignore hidden files/directories (dotfiles), preventing them to be served and being included in auto HTML index pages (directory listing) [env: SERVER_IGNORE_HIDDEN_FILES=] [default: false] [possible values: true, false] - --disable-symlinks[=] + --disable-symlinks [] Prevent following files or directories if any path name component is a symbolic link [env: SERVER_DISABLE_SYMLINKS=] [default: false] [possible values: true, false] - --health[=] + --health [] Add a /health endpoint that doesn't generate any log entry and returns a 200 status code. This is especially useful with Kubernetes liveness and readiness probes [env: SERVER_HEALTH=] [default: false] [possible values: true, false] - --maintenance-mode[=] + --maintenance-mode [] Enable the server's maintenance mode functionality [env: SERVER_MAINTENANCE_MODE=] [default: false] [possible values: true, false] --maintenance-mode-status Provide a custom HTTP status code when entering into maintenance mode. Default 503 [env: SERVER_MAINTENANCE_MODE_STATUS=] [default: 503]