biscotti/lib.rs
1//! A crate to handle HTTP cookies in a Rust server.
2//!
3//! # Overview
4//!
5//! You can use `biscotti` to handle cookies in your server.
6//!
7//! It has support for:
8//!
9//! - Handling cookies attached to incoming requests, via [`RequestCookies`]
10//! - Building cookies for outgoing responses, via [`ResponseCookies`]
11//! - Encrypting, signing or encoding cookies, via [`Processor`]
12//!
13//! In particular:
14//!
15//! - It can handle multiple request cookies with the same name
16//! - It lets you add multiple cookies with the same name but different paths or domains
17//! - Cookies are percent-encoded/decoded by default (but you can opt out)
18//! - It has built-in support for rotating signing/encryption keys over time
19//!
20//! # Non-goals
21//!
22//! `biscotti` is not designed to handle cookies on the client side.
23//! It doesn't provide any logic to parse the `Set-Cookie` headers returned in a server response.
24//!
25//! # Quickstart
26//!
27//! ## Incoming cookies
28//!
29//! ```rust
30//! use biscotti::{Processor, ProcessorConfig, RequestCookies};
31//!
32//! // Start by creating a `Processor` instance from a `Config`.
33//! // It determines if (and which) cookies should be decrypted, verified or percent-decoded.
34//! let processor: Processor = ProcessorConfig::default().into();
35//! // You can then use `RequestCookies::parse_header` to parse the `Cookie` header
36//! // you received from the client.
37//! let cookies = RequestCookies::parse_header(
38//! "name=first%20value; name2=val; name=another%20value",
39//! &processor
40//! ).unwrap();
41//!
42//! // You can now access the cookies!
43//!
44//! // You can access the first cookie with a given name...
45//! assert_eq!(cookies.get("name").unwrap().value(), "first value");
46//! // ...or opt to retrieve all values associated with that cookie name.
47//! assert_eq!(cookies.get_all("name").unwrap().len(), 2);
48//!
49//! assert_eq!(cookies.get("name2").unwrap().value(), "val");
50//! assert_eq!(cookies.get_all("name2").unwrap().len(), 1);
51//! ```
52//!
53//! ## Outgoing cookies
54//!
55//! ```rust
56//! use std::collections::HashSet;
57//! use biscotti::{Processor, ProcessorConfig, ResponseCookies, RemovalCookie, ResponseCookie};
58//! use biscotti::SameSite;
59//!
60//! // Start by creating a `ResponseCookies` instance to hold the cookies you want to send.
61//! let mut cookies = ResponseCookies::new();
62//!
63//! // You can add cookies to the `ResponseCookies` instance via the `insert` method.
64//! cookies.insert(ResponseCookie::new("name", "a value"));
65//! cookies.insert(ResponseCookie::new("name", "a value").set_path("/"));
66//! // If you want to remove a cookie from the client's machine, you can use a `RemovalCookie`.
67//! cookies.insert(RemovalCookie::new("another name"));
68//!
69//! // You then convert obtain the respective `Set-Cookie` header values.
70//! // A processor is required: it determines if (and which) cookies should be encrypted,
71//! // signed or percent-encoded.
72//! let processor: Processor = ProcessorConfig::default().into();
73//! let header_values: HashSet<_> = cookies.header_values(&processor).collect();
74//! assert_eq!(header_values, HashSet::from([
75//! "name=a%20value".to_string(),
76//! // Both `name` cookies are kept since they have different path attributes.
77//! "name=a%20value; Path=/".to_string(),
78//! // A removal cookie is a cookie with an empty value and an expiry in the past.
79//! "another%20name=; Expires=Thu, 01 Jan 1970 00:00:00 GMT".to_string(),
80//! ]));
81//! ```
82//!
83//! ## Credits
84//!
85//! `biscotti` is heavily inspired by the [`cookie` crate](https://crates.io/crates/cookie) [Copyright (c) 2017 Sergio Benitez,
86//! Copyright (c) 2014 Alex Crichton].
87//! `biscotti` started as a `cookie` fork and it includes non-negligible portions of its
88//! code.
89//!
90//! [`Processor`]: crate::Processor
91//! [`RequestCookies`]: crate::RequestCookies
92//! [`ResponseCookies`]: crate::ResponseCookies
93
94pub mod config;
95mod crypto;
96mod encoding;
97mod expiration;
98mod processor;
99mod removal;
100mod request_cookie;
101mod request_cookies;
102mod response_cookie;
103mod response_cookie_id;
104mod response_cookies;
105mod same_site;
106
107pub mod request;
108pub mod response;
109
110pub use crate::expiration::*;
111pub use crate::same_site::*;
112pub use config::inner::ProcessorConfig;
113pub use crypto::Key;
114pub use jiff as time;
115pub use processor::Processor;
116pub use removal::RemovalCookie;
117pub use request_cookie::RequestCookie;
118pub use request_cookies::RequestCookies;
119pub use response_cookie::ResponseCookie;
120pub use response_cookie_id::ResponseCookieId;
121pub use response_cookies::ResponseCookies;
122
123/// Errors that can occur when using `biscotti`.
124pub mod errors {
125 pub use crate::crypto::{KeyError, ShortKeyError};
126 pub use crate::processor::{CryptoError, DecodingError, ProcessIncomingError};
127 pub use crate::request_cookies::{EmptyNameError, MissingPairError, ParseError};
128}