Add sync constructors to CookieJar, SignedCookieJar, and PrivateCookieJar (#1264)

* Add sync constructors to `CookieJar`, `SignedCookieJar`, and `PrivateCookieJar`

* Move to constructor

* use `RequestParts::extract`
This commit is contained in:
David Pedersen 2022-08-16 15:42:01 +02:00 committed by GitHub
parent fb32fcc07c
commit 01630cfef6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 18 deletions

View file

@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning].
- **added:** Support chaining handlers with `HandlerCallWithExtractors::or` ([#1170])
- **change:** axum-extra's MSRV is now 1.60 ([#1239])
- **added:** Add Protocol Buffer extractor and response ([#1239])
- **added:** Add sync constructors to `CookieJar`, `PrivateCookieJar`, and
`SignedCookieJar` so they're easier to use in custom middleware
[#1086]: https://github.com/tokio-rs/axum/pull/1086
[#1119]: https://github.com/tokio-rs/axum/pull/1119

View file

@ -82,7 +82,7 @@ pub use cookie::Key;
/// .route("/me", get(me));
/// # let app: Router<axum::body::Body> = app;
/// ```
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct CookieJar {
jar: cookie::CookieJar,
}
@ -95,18 +95,12 @@ where
type Rejection = Infallible;
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
let mut jar = cookie::CookieJar::new();
for cookie in cookies_from_request(req) {
jar.add_original(cookie);
}
Ok(Self { jar })
Ok(Self::from_headers(req.headers()))
}
}
fn cookies_from_request<B>(
req: &mut RequestParts<B>,
) -> impl Iterator<Item = Cookie<'static>> + '_ {
req.headers()
fn cookies_from_request(headers: &HeaderMap) -> impl Iterator<Item = Cookie<'static>> + '_ {
headers
.get_all(COOKIE)
.into_iter()
.filter_map(|value| value.to_str().ok())
@ -115,6 +109,31 @@ fn cookies_from_request<B>(
}
impl CookieJar {
/// Create a new `CookieJar` from a map of request headers.
///
/// The cookies in `headers` will be added to the jar.
///
/// This is inteded to be used in middleware and other places where it might be difficult to
/// run extractors. Normally you should create `CookieJar`s through [`FromRequest`].
pub fn from_headers(headers: &HeaderMap) -> Self {
let mut jar = cookie::CookieJar::new();
for cookie in cookies_from_request(headers) {
jar.add_original(cookie);
}
Self { jar }
}
/// Create a new empty `CookieJar`.
///
/// This is inteded to be used in middleware and other places where it might be difficult to
/// run extractors. Normally you should create `CookieJar`s through [`FromRequest`].
///
/// If you need a jar that contains the headers from a request use `impl From<&HeaderMap> for
/// CookieJar`.
pub fn new() -> Self {
Self::default()
}
/// Get a cookie from the jar.
///
/// # Example

View file

@ -6,6 +6,7 @@ use axum::{
Extension,
};
use cookie::PrivateJar;
use http::HeaderMap;
use std::{convert::Infallible, fmt, marker::PhantomData};
/// Extractor that grabs private cookies from the request and manages the jar.
@ -82,21 +83,53 @@ where
type Rejection = <axum::Extension<K> as FromRequest<B>>::Rejection;
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
let key = Extension::<K>::from_request(req).await?.0.into();
let key = req.extract::<Extension<K>>().await?.0.into();
let PrivateCookieJar {
jar,
key,
_marker: _,
} = PrivateCookieJar::from_headers(req.headers(), key);
Ok(PrivateCookieJar {
jar,
key,
_marker: PhantomData,
})
}
}
impl PrivateCookieJar {
/// Create a new `PrivateCookieJar` from a map of request headers.
///
/// The valid cookies in `headers` will be added to the jar.
///
/// This is inteded to be used in middleware and other where places it might be difficult to
/// run extractors. Normally you should create `PrivateCookieJar`s through [`FromRequest`].
pub fn from_headers(headers: &HeaderMap, key: Key) -> Self {
let mut jar = cookie::CookieJar::new();
let mut private_jar = jar.private_mut(&key);
for cookie in cookies_from_request(req) {
for cookie in cookies_from_request(headers) {
if let Some(cookie) = private_jar.decrypt(cookie) {
private_jar.add_original(cookie);
}
}
Ok(Self {
Self {
jar,
key,
_marker: PhantomData,
})
}
}
/// Create a new empty `PrivateCookieJarIter`.
///
/// This is inteded to be used in middleware and other places where it might be difficult to
/// run extractors. Normally you should create `PrivateCookieJar`s through [`FromRequest`].
pub fn new(key: Key) -> Self {
Self {
jar: Default::default(),
key,
_marker: PhantomData,
}
}
}

View file

@ -7,6 +7,7 @@ use axum::{
};
use cookie::SignedJar;
use cookie::{Cookie, Key};
use http::HeaderMap;
use std::{convert::Infallible, fmt, marker::PhantomData};
/// Extractor that grabs signed cookies from the request and manages the jar.
@ -100,21 +101,53 @@ where
type Rejection = <axum::Extension<K> as FromRequest<B>>::Rejection;
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
let key = Extension::<K>::from_request(req).await?.0.into();
let key = req.extract::<Extension<K>>().await?.0.into();
let SignedCookieJar {
jar,
key,
_marker: _,
} = SignedCookieJar::from_headers(req.headers(), key);
Ok(SignedCookieJar {
jar,
key,
_marker: PhantomData,
})
}
}
impl SignedCookieJar {
/// Create a new `SignedCookieJar` from a map of request headers.
///
/// The valid cookies in `headers` will be added to the jar.
///
/// This is inteded to be used in middleware and other places where it might be difficult to
/// run extractors. Normally you should create `SignedCookieJar`s through [`FromRequest`].
pub fn from_headers(headers: &HeaderMap, key: Key) -> Self {
let mut jar = cookie::CookieJar::new();
let mut signed_jar = jar.signed_mut(&key);
for cookie in cookies_from_request(req) {
for cookie in cookies_from_request(headers) {
if let Some(cookie) = signed_jar.verify(cookie) {
signed_jar.add_original(cookie);
}
}
Ok(Self {
Self {
jar,
key,
_marker: PhantomData,
})
}
}
/// Create a new empty `SignedCookieJar`.
///
/// This is inteded to be used in middleware and other places where it might be difficult to
/// run extractors. Normally you should create `SignedCookieJar`s through [`FromRequest`].
pub fn new(key: Key) -> Self {
Self {
jar: Default::default(),
key,
_marker: PhantomData,
}
}
}