Skip to content

Commit

Permalink
Implement cookie prefixes via 'PrefixedJar'.
Browse files Browse the repository at this point in the history
Closes #214.
  • Loading branch information
SergioBenitez committed Oct 7, 2023
1 parent c105b67 commit d68d011
Show file tree
Hide file tree
Showing 5 changed files with 460 additions and 6 deletions.
83 changes: 82 additions & 1 deletion src/jar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::collections::HashSet;
#[cfg(any(feature = "signed", feature = "private"))] use crate::secure::Key;

use crate::delta::DeltaCookie;
use crate::prefix::{Prefix, PrefixedJar};
use crate::Cookie;

/// A collection of cookies that tracks its modifications.
Expand Down Expand Up @@ -486,7 +487,7 @@ impl CookieJar {
/// # Example
///
/// ```rust
/// use cookie::{Cookie, CookieJar, Key};
/// use cookie::{CookieJar, Key};
///
/// // Generate a secure key.
/// let key = Key::generate();
Expand All @@ -503,6 +504,86 @@ impl CookieJar {
pub fn signed_mut<'a>(&'a mut self, key: &Key) -> SignedJar<&'a mut Self> {
SignedJar::new(self, key)
}

/// Returns a read-only `PrefixedJar` with `self` as its parent jar that
/// prefixes the name of cookies with `prefix`. Any retrievals from the
/// child jar will be made from the parent jar.
///
/// **Note:** Cookie prefixes are specified in an [HTTP draft]! Their
/// meaning and definition are subject to change.
///
/// # Example
///
/// ```rust
/// use cookie::CookieJar;
/// use cookie::prefix::{Host, Secure};
///
/// // Add a `Host` prefixed cookie.
/// let mut jar = CookieJar::new();
/// jar.prefixed_mut(Host).add(("h0st", "value"));
/// jar.prefixed_mut(Secure).add(("secur3", "value"));
///
/// // The cookie's name is prefixed in the parent jar.
/// assert!(matches!(jar.get("h0st"), None));
/// assert!(matches!(jar.get("__Host-h0st"), Some(_)));
/// assert!(matches!(jar.get("secur3"), None));
/// assert!(matches!(jar.get("__Secure-secur3"), Some(_)));
///
/// // The prefixed jar automatically removes the prefix.
/// assert_eq!(jar.prefixed(Host).get("h0st").unwrap().name(), "h0st");
/// assert_eq!(jar.prefixed(Host).get("h0st").unwrap().value(), "value");
/// assert_eq!(jar.prefixed(Secure).get("secur3").unwrap().name(), "secur3");
/// assert_eq!(jar.prefixed(Secure).get("secur3").unwrap().value(), "value");
///
/// // Only the correct prefixed jar retrieves the cookie.
/// assert!(matches!(jar.prefixed(Host).get("secur3"), None));
/// assert!(matches!(jar.prefixed(Secure).get("h0st"), None));
/// ```
#[inline(always)]
pub fn prefixed<'a, P: Prefix>(&'a self, prefix: P) -> PrefixedJar<P, &'a Self> {
let _ = prefix;
PrefixedJar::new(self)
}

/// Returns a read/write `PrefixedJar` with `self` as its parent jar that
/// prefixes the name of cookies with `prefix` and makes the cookie conform
/// to the prefix's requirements. This means that added cookies:
///
/// 1. Have the [`Prefix::PREFIX`] prepended to their name.
/// 2. Modify the cookie via [`Prefix::conform()`] so that it conforms to
/// the prefix's requirements.
///
/// Any modifications to the child jar will be reflected on the parent jar,
/// and any retrievals from the child jar will be made from the parent jar.
///
/// **Note:** Cookie prefixes are specified in an [HTTP draft]! Their
/// meaning and definition are subject to change.
///
/// # Example
///
/// ```rust
/// use cookie::CookieJar;
/// use cookie::prefix::{Host, Secure};
///
/// // Add some prefixed cookies.
/// let mut jar = CookieJar::new();
/// jar.prefixed_mut(Host).add(("one", "1"));
/// jar.prefixed_mut(Secure).add((2.to_string(), "2"));
/// jar.prefixed_mut(Host).add((format!("{:0b}", 3), "0b11"));
///
/// // Fetch cookies with either `prefixed()` or `prefixed_mut()`.
/// assert_eq!(jar.prefixed(Host).get("one").unwrap().value(), "1");
/// assert_eq!(jar.prefixed(Secure).get("2").unwrap().value(), "2");
/// assert_eq!(jar.prefixed_mut(Host).get("11").unwrap().value(), "0b11");
///
/// // Remove cookies.
/// jar.prefixed_mut(Host).remove("one");
/// assert!(jar.prefixed(Host).get("one").is_none());
/// ```
pub fn prefixed_mut<'a, P: Prefix>(&'a mut self, prefix: P) -> PrefixedJar<P, &'a mut Self> {
let _ = prefix;
PrefixedJar::new(self)
}
}

use std::collections::hash_set::Iter as HashSetIter;
Expand Down
10 changes: 8 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,15 @@ mod builder;
mod parse;
mod jar;
mod delta;
mod draft;
mod same_site;
mod expiration;

/// Implementation of [HTTP RFC6265 draft] cookie prefixes.
///
/// [HTTP RFC6265 draft]:
/// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#name-cookie-name-prefixes
pub mod prefix;

#[cfg(any(feature = "private", feature = "signed"))] #[macro_use] mod secure;
#[cfg(any(feature = "private", feature = "signed"))] pub use secure::*;

Expand All @@ -97,7 +103,7 @@ use crate::parse::parse_cookie;
pub use crate::parse::ParseError;
pub use crate::builder::CookieBuilder;
pub use crate::jar::{CookieJar, Delta, Iter};
pub use crate::draft::*;
pub use crate::same_site::*;
pub use crate::expiration::*;

#[derive(Debug, Clone)]
Expand Down
Loading

0 comments on commit d68d011

Please sign in to comment.