diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ad089d..38f8cde 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,10 +31,14 @@ jobs: run: cargo fmt --check - name: Clippy run: cargo clippy --features prost,serde,docs,math --tests -- -D warnings - - name: Run tests - run: cargo test --all-features + - name: Run tests (general) + run: cargo test --features math,docs,ssr,prost,serde + - name: Run tests (axum) + run: cargo test --features math,docs,ssr,prost,serde,axum --doc use_cookie::use_cookie + - name: Run tests (actix) + run: cargo test --features math,docs,ssr,prost,serde,actix --doc use_cookie::use_cookie -#### mdbook + #### mdbook - name: Install mdbook I uses: taiki-e/install-action@v2 with: @@ -59,7 +63,7 @@ jobs: - name: Deploy book to github pages id: deployment uses: actions/deploy-pages@v2 -##### mdbook end + ##### mdbook end - name: Publish crate leptos-use uses: katyo/publish-crates@v2 @@ -76,38 +80,3 @@ jobs: -F RELEASE.md -t "Version $RELEASE_VERSION" ${GITHUB_REF#refs/*/} - -# coverage: -# name: Coverage -# runs-on: ubuntu-latest -# -# steps: -# - name: Checkout sources -# uses: actions/checkout@v2 -# -# - name: Install rust -# uses: actions-rs/toolchain@v1 -# with: -# toolchain: stable -# profile: minimal -# override: true -# -# - name: Cache -# uses: Swatinem/rust-cache@v1 -# -# - name: Install cargo-tarpaulin -# uses: actions-rs/cargo@v1 -# with: -# command: install -# args: cargo-tarpaulin -# -# - name: Run cargo tarpaulin -# uses: actions-rs/cargo@v1 -# with: -# command: tarpaulin -# args: --output-dir coverage --out Lcov -# -# - name: Publish to Coveralls -# uses: coverallsapp/github-action@master -# with: -# github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f5500fb..d43d0b4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,5 +24,9 @@ jobs: run: cargo fmt --check - name: Clippy run: cargo clippy --features prost,serde,docs,math --tests -- -D warnings - - name: Run tests - run: cargo test --all-features + - name: Run tests (general) + run: cargo test --features math,docs,ssr,prost,serde + - name: Run tests (axum) + run: cargo test --features math,docs,ssr,prost,serde,axum --doc use_cookie::use_cookie + - name: Run tests (actix) + run: cargo test --features math,docs,ssr,prost,serde,actix --doc use_cookie::use_cookie diff --git a/src/use_cookie.rs b/src/use_cookie.rs index 1cec388..438a8c4 100644 --- a/src/use_cookie.rs +++ b/src/use_cookie.rs @@ -1,4 +1,6 @@ use cookie::Cookie; +use default_struct_builder::DefaultBuilder; +use std::rc::Rc; /// Get a cookie by name, for both SSR and CSR /// @@ -39,39 +41,43 @@ use cookie::Cookie; /// /// > If you're using `axum` you have to enable the `"axum"` feature in your Cargo.toml. /// > In case it's `actix-web` enable the feature `"actix"`. +/// +/// ### Bring your own header +/// +/// In case you're neither using Axum nor Actix, or the default implementation is not to your liking, +/// you can provide your own way of reading the cookie header value. +/// +/// ``` +/// # use leptos::*; +/// # use leptos_use::{use_cookie_with_options, UseCookieOptions}; +/// # +/// # #[component] +/// # fn Demo() -> impl IntoView { +/// use_cookie_with_options("auth", UseCookieOptions::default().ssr_cookies_header_getter(|| { +/// #[cfg(feature = "ssr")] +/// { +/// "Somehow get the value of the cookie header as a string".to_owned() +/// } +/// })); +/// # view! {} +/// # } +/// ``` pub fn use_cookie(cookie_name: &str) -> Option> { + use_cookie_with_options(cookie_name, UseCookieOptions::default()) +} + +/// Version of [`use_cookie`] that takes [`UseCookieOptions`]. +pub fn use_cookie_with_options( + cookie_name: &str, + options: UseCookieOptions, +) -> Option> { let cookies; + #[cfg(feature = "ssr")] { - use leptos::expect_context; - - #[cfg(feature = "actix")] - const COOKIE: http0_2::HeaderName = http0_2::header::COOKIE; - #[cfg(feature = "axum")] - const COOKIE: http1::HeaderName = http1::header::COOKIE; - - #[cfg(feature = "actix")] - type HeaderValue = http0_2::HeaderValue; - #[cfg(feature = "axum")] - type HeaderValue = http1::HeaderValue; - - let headers; - #[cfg(feature = "actix")] - { - headers = expect_context::().headers().clone(); - } - #[cfg(feature = "axum")] - { - headers = expect_context::().headers; - } - cookies = headers - .get(COOKIE) - .cloned() - .unwrap_or_else(|| HeaderValue::from_static("")) - .to_str() - .unwrap_or_default() - .to_owned(); + cookies = (options.ssr_cookies_header_getter)(); } + #[cfg(not(feature = "ssr"))] { use wasm_bindgen::JsCast; @@ -86,3 +92,65 @@ pub fn use_cookie(cookie_name: &str) -> Option> { .find(|cookie| cookie.name() == cookie_name) .map(|cookie| cookie.into_owned()) } + +/// Options for [`use_cookie_with_options`]. +#[derive(Clone, DefaultBuilder)] +pub struct UseCookieOptions { + /// Getter function to return the string value of the cookie header. + /// When you use one of the features "axum" or "actix" there's a valid default implementation provided. + ssr_cookies_header_getter: Rc String>, +} + +impl Default for UseCookieOptions { + #[allow(dead_code)] + fn default() -> Self { + Self { + ssr_cookies_header_getter: Rc::new(move || { + #[cfg(feature = "ssr")] + { + #[cfg(any(feature = "axum", feature = "actix"))] + use leptos::expect_context; + + #[cfg(all(feature = "actix", feature = "axum"))] + compile_error!("You cannot enable only one of features \"actix\" and \"axum\" at the same time"); + + #[cfg(feature = "actix")] + const COOKIE: http0_2::HeaderName = http0_2::header::COOKIE; + #[cfg(feature = "axum")] + 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"))] + let headers; + #[cfg(feature = "actix")] + { + headers = expect_context::().headers().clone(); + } + #[cfg(feature = "axum")] + { + headers = expect_context::().headers; + } + + #[cfg(all(not(feature = "axum"), not(feature = "actix")))] + { + leptos::logging::warn!("If you're using use_cookie without the feature `axum` or `actix` enabled, you should provide the option `ssr_cookies_header_getter`"); + "".to_owned() + } + + #[cfg(any(feature = "axum", feature = "actix"))] + headers + .get(COOKIE) + .cloned() + .unwrap_or_else(|| HeaderValue::from_static("")) + .to_str() + .unwrap_or_default() + .to_owned() + } + }), + } + } +}