added function header and made use_cookie use it

This commit is contained in:
Maccesch 2024-07-28 17:41:16 +01:00
parent c64fb046f8
commit 4ec66ecbc8
7 changed files with 138 additions and 74 deletions

View file

@ -3,6 +3,12 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 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). 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 ## [0.11.0] - 2024-07-27
### New Functions 🚀 ### 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 the DOM controlled by a value from storage. This leads to hydration errors which can be fixed by setting this new
option to `true`. option to `true`.
- `cookie::SameSite` is now re-exported - `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 - New book chapter about codecs
- The macro `use_derive_signal!` is now exported (thanks to @mscofield0). - 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`. - The new `UseWebSocketOptions::on_message` takes a `&T`.
- `UseWebSocketOptions::on_error` now takes a `UseWebSocketError` instead of a `web_sys::Event`. - `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. - `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). (note the `n`) (thanks to @mondeja).
### Fixes 🍕 ### Fixes 🍕

View file

@ -99,6 +99,7 @@
# Utilities # Utilities
- [header](utilities/header.md)
- [is_err](utilities/is_err.md) - [is_err](utilities/is_err.md)
- [is_none](utilities/is_none.md) - [is_none](utilities/is_none.md)
- [is_ok](utilities/is_ok.md) - [is_ok](utilities/is_ok.md)

View file

@ -0,0 +1,3 @@
# header
<!-- cmdrun python3 ../extract_doc_comment.py utils/header -->

View file

@ -1,6 +1,7 @@
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
use crate::core::now; use crate::core::now;
use crate::utils::get_header;
use codee::{CodecError, Decoder, Encoder}; use codee::{CodecError, Decoder, Encoder};
use cookie::time::{Duration, OffsetDateTime}; use cookie::time::{Duration, OffsetDateTime};
pub use cookie::SameSite; pub use cookie::SameSite;
@ -496,78 +497,7 @@ impl<T, E, D> Default for UseCookieOptions<T, E, D> {
path: None, path: None,
same_site: None, same_site: None,
ssr_cookies_header_getter: Rc::new(move || { ssr_cookies_header_getter: Rc::new(move || {
#[cfg(feature = "ssr")] get_header!(COOKIE, use_cookie, ssr_cookies_header_getter)
{
#[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::<actix_web::HttpRequest>()
.map(|req| req.headers().clone());
}
#[cfg(feature = "axum")]
{
headers = use_context::<http1::request::Parts>().map(|parts| parts.headers);
}
#[cfg(feature = "spin")]
{
headers = use_context::<leptos_spin::RequestParts>()
.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
}), }),
ssr_set_cookie: Rc::new(|cookie: &Cookie| { ssr_set_cookie: Rc::new(|cookie: &Cookie| {
#[cfg(feature = "ssr")] #[cfg(feature = "ssr")]

76
src/utils/header.rs Normal file
View file

@ -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<N>(name: N) -> Option<String>
where
N: Into<HeaderName>,
{
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::<actix_web::HttpRequest>().map(|req| req.headers().clone());
}
#[cfg(feature = "axum")]
{
headers = use_context::<http1::request::Parts>().map(|parts| parts.headers);
}
#[cfg(feature = "spin")]
{
headers = use_context::<leptos_spin::RequestParts>().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())
})
}
}

36
src/utils/header_macro.rs Normal file
View file

@ -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;

View file

@ -1,4 +1,10 @@
mod filters; mod filters;
#[cfg(all(
feature = "ssr",
any(feature = "axum", feature = "actix", feature = "spin")
))]
mod header;
mod header_macro;
mod is; mod is;
mod js; mod js;
mod js_value_from_to_string; mod js_value_from_to_string;
@ -7,6 +13,12 @@ mod signal_filtered;
mod use_derive_signal; mod use_derive_signal;
pub use filters::*; 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 use is::*;
pub(crate) use js_value_from_to_string::*; pub(crate) use js_value_from_to_string::*;
pub use pausable::*; pub use pausable::*;