From 4ec66ecbc85bbb14b485f9c7aa8955cfe720c7cc Mon Sep 17 00:00:00 2001 From: Maccesch Date: Sun, 28 Jul 2024 17:41:16 +0100 Subject: [PATCH] added function header and made use_cookie use it --- CHANGELOG.md | 10 +++- docs/book/src/SUMMARY.md | 1 + docs/book/src/utilities/header.md | 3 ++ src/use_cookie.rs | 74 +----------------------------- src/utils/header.rs | 76 +++++++++++++++++++++++++++++++ src/utils/header_macro.rs | 36 +++++++++++++++ src/utils/mod.rs | 12 +++++ 7 files changed, 138 insertions(+), 74 deletions(-) create mode 100644 docs/book/src/utilities/header.md create mode 100644 src/utils/header.rs create mode 100644 src/utils/header_macro.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index c2d7794..6516447 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### New Functions 🚀 + +- `header` – Standard implementations for reading a header on the server. + ## [0.11.0] - 2024-07-27 ### New Functions 🚀 @@ -31,7 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 the DOM controlled by a value from storage. This leads to hydration errors which can be fixed by setting this new option to `true`. - `cookie::SameSite` is now re-exported -- Changing the signal returned by `use_cookie` now tries and changes the headers during SSR. +- Changing the signal returned by `use_cookie` now tries and changes the headers during SSR. - New book chapter about codecs - The macro `use_derive_signal!` is now exported (thanks to @mscofield0). @@ -66,7 +72,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The new `UseWebSocketOptions::on_message` takes a `&T`. - `UseWebSocketOptions::on_error` now takes a `UseWebSocketError` instead of a `web_sys::Event`. - `use_storage` now always saves the default value to storage if the key doesn't exist yet. -- Renamed `BreakpointsSematic` to `BreakpointsSemantic` and `breakpoints_sematic` to `breakpoints_semantic` +- Renamed `BreakpointsSematic` to `BreakpointsSemantic` and `breakpoints_sematic` to `breakpoints_semantic` (note the `n`) (thanks to @mondeja). ### Fixes 🍕 diff --git a/docs/book/src/SUMMARY.md b/docs/book/src/SUMMARY.md index 502a1a6..c70b480 100644 --- a/docs/book/src/SUMMARY.md +++ b/docs/book/src/SUMMARY.md @@ -99,6 +99,7 @@ # Utilities +- [header](utilities/header.md) - [is_err](utilities/is_err.md) - [is_none](utilities/is_none.md) - [is_ok](utilities/is_ok.md) diff --git a/docs/book/src/utilities/header.md b/docs/book/src/utilities/header.md new file mode 100644 index 0000000..2bd2d1f --- /dev/null +++ b/docs/book/src/utilities/header.md @@ -0,0 +1,3 @@ +# header + + diff --git a/src/use_cookie.rs b/src/use_cookie.rs index b7773a8..2e6c894 100644 --- a/src/use_cookie.rs +++ b/src/use_cookie.rs @@ -1,6 +1,7 @@ #![allow(clippy::too_many_arguments)] use crate::core::now; +use crate::utils::get_header; use codee::{CodecError, Decoder, Encoder}; use cookie::time::{Duration, OffsetDateTime}; pub use cookie::SameSite; @@ -496,78 +497,7 @@ impl Default for UseCookieOptions { path: None, same_site: None, ssr_cookies_header_getter: Rc::new(move || { - #[cfg(feature = "ssr")] - { - #[cfg(all(feature = "actix", feature = "axum"))] - compile_error!("You can only enable one of features \"actix\" and \"axum\" at the same time"); - - #[cfg(all(feature = "actix", feature = "spin"))] - compile_error!("You can only enable one of features \"actix\" and \"spin\" at the same time"); - - #[cfg(all(feature = "axum", feature = "spin"))] - compile_error!("You can only enable one of features \"axum\" and \"spin\" at the same time"); - - #[cfg(feature = "actix")] - const COOKIE: http0_2::HeaderName = http0_2::header::COOKIE; - #[cfg(any(feature = "axum", feature = "spin"))] - const COOKIE: http1::HeaderName = http1::header::COOKIE; - - #[cfg(feature = "actix")] - type HeaderValue = http0_2::HeaderValue; - #[cfg(feature = "axum")] - type HeaderValue = http1::HeaderValue; - - #[cfg(any(feature = "axum", feature = "actix", feature = "spin"))] - let headers; - #[cfg(feature = "actix")] - { - headers = use_context::() - .map(|req| req.headers().clone()); - } - #[cfg(feature = "axum")] - { - headers = use_context::().map(|parts| parts.headers); - } - #[cfg(feature = "spin")] - { - headers = use_context::() - .map(|parts| parts.headers().clone()); - } - - #[cfg(all( - not(feature = "axum"), - not(feature = "actix"), - not(feature = "spin") - ))] - { - leptos::logging::warn!("If you're using use_cookie without the feature `axum`, `actix` or `spin` enabled, you should provide the option `ssr_cookies_header_getter`"); - None - } - - #[cfg(any(feature = "axum", feature = "actix"))] - { - headers.map(|headers| { - headers - .get(COOKIE) - .cloned() - .unwrap_or_else(|| HeaderValue::from_static("")) - .to_str() - .unwrap_or_default() - .to_owned() - }) - } - #[cfg(feature = "spin")] - { - headers.and_then(|headers| { - headers - .iter() - .find(|(key, _)| **key == COOKIE) - .and_then(|(_, value)| String::from_utf8(value.to_vec()).ok()) - }) - } - } - #[cfg(not(feature = "ssr"))] - None + get_header!(COOKIE, use_cookie, ssr_cookies_header_getter) }), ssr_set_cookie: Rc::new(|cookie: &Cookie| { #[cfg(feature = "ssr")] diff --git a/src/utils/header.rs b/src/utils/header.rs new file mode 100644 index 0000000..0e9d6cd --- /dev/null +++ b/src/utils/header.rs @@ -0,0 +1,76 @@ +#[cfg(feature = "actix")] +use http0_2::HeaderName; +#[cfg(any(feature = "axum", feature = "spin"))] +use http1::HeaderName; +use leptos::*; + +/// Get the value of the header with the given name. +/// +/// This function is only meant to be used on the server. +/// So it is only defined when the feature `"ssr"` is enabled together with one of the +/// features `"axum"`, `"actix"` or `"spin"`. +/// +/// ## Example +/// +/// ```ignore +/// # use leptos_use::utils::header; +/// # +/// let content_len = header(http::header::CONTENT_LENGTH); +/// ``` +pub fn header(name: N) -> Option +where + N: Into, +{ + let name = name.into(); + + #[cfg(all(feature = "actix", feature = "axum"))] + compile_error!("You can only enable one of features \"actix\" and \"axum\" at the same time"); + + #[cfg(all(feature = "actix", feature = "spin"))] + compile_error!("You can only enable one of features \"actix\" and \"spin\" at the same time"); + + #[cfg(all(feature = "axum", feature = "spin"))] + compile_error!("You can only enable one of features \"axum\" and \"spin\" at the same time"); + + #[cfg(feature = "actix")] + type HeaderValue = http0_2::HeaderValue; + #[cfg(feature = "axum")] + type HeaderValue = http1::HeaderValue; + + #[cfg(any(feature = "axum", feature = "actix", feature = "spin"))] + let headers; + #[cfg(feature = "actix")] + { + headers = use_context::().map(|req| req.headers().clone()); + } + #[cfg(feature = "axum")] + { + headers = use_context::().map(|parts| parts.headers); + } + #[cfg(feature = "spin")] + { + headers = use_context::().map(|parts| parts.headers().clone()); + } + + #[cfg(any(feature = "axum", feature = "actix"))] + { + headers.map(|headers| { + headers + .get(name) + .cloned() + .unwrap_or_else(|| HeaderValue::from_static("")) + .to_str() + .unwrap_or_default() + .to_owned() + }) + } + #[cfg(feature = "spin")] + { + headers.and_then(|headers| { + headers + .iter() + .find(|(key, _)| **key == name) + .and_then(|(_, value)| String::from_utf8(value.to_vec()).ok()) + }) + } +} diff --git a/src/utils/header_macro.rs b/src/utils/header_macro.rs new file mode 100644 index 0000000..2cb0b52 --- /dev/null +++ b/src/utils/header_macro.rs @@ -0,0 +1,36 @@ +macro_rules! get_header { + ( + $header_name:ident, + $function_name:ident, + $option_name:ident + $(,)? + ) => { + if cfg!(feature = "ssr") { + #[cfg(all( + not(feature = "axum"), + not(feature = "actix"), + not(feature = "spin") + ))] + { + leptos::logging::warn!( + "If you're using `{}` with SSR but without any of the features `axum`, `actix` or `spin` enabled, you have to provide the option `{}`", + stringify!($function_name), + stringify!($option_name) + ); + return None; + } + + #[cfg(feature = "actix")] + const $header_name: http0_2::HeaderName = http0_2::header::$header_name; + #[cfg(any(feature = "axum", feature = "spin"))] + const $header_name: http1::HeaderName = http1::header::$header_name; + + #[cfg(any(feature = "axum", feature = "actix", feature = "spin"))] + crate::utils::header($header_name) + } else { + None + } + }; +} + +pub(crate) use get_header; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 906f4e1..32d43b0 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,4 +1,10 @@ mod filters; +#[cfg(all( + feature = "ssr", + any(feature = "axum", feature = "actix", feature = "spin") +))] +mod header; +mod header_macro; mod is; mod js; mod js_value_from_to_string; @@ -7,6 +13,12 @@ mod signal_filtered; mod use_derive_signal; pub use filters::*; +#[cfg(all( + feature = "ssr", + any(feature = "axum", feature = "actix", feature = "spin") +))] +pub use header::*; +pub(crate) use header_macro::*; pub use is::*; pub(crate) use js_value_from_to_string::*; pub use pausable::*;