actix_quick_extract/headers/
mod.rs

1//! A collection of types that make extracting headers from requests easier
2//!
3//! # Note
4//!
5//! Headers are assumed to be valid strings. If they are not valid strings, then the request will fail
6//! If you want to handle invalid strings you will need to access the headers directly
7//!
8//! The data is cloned out of the request. if you are wanting to prevent this. You will need to access the headers directly
9mod authorization;
10mod host;
11mod origin;
12mod origin_or_host;
13mod user_agent;
14use actix_web::FromRequest;
15#[doc(inline)]
16pub use authorization::RawAuthorization;
17use derive_more::Into;
18#[doc(inline)]
19pub use host::Host;
20#[doc(inline)]
21pub use origin::Origin;
22#[doc(inline)]
23pub use origin_or_host::OriginOrHost;
24#[doc(inline)]
25pub use user_agent::UserAgent;
26
27use crate::ExtractError;
28
29/// Will accept no value. But will deny if the header is not valid. Such as if it is not valid UTF-8
30///
31/// It wraps the value in an Option
32///
33/// None means the header was not present
34///
35/// ```no_run
36/// use actix_quick_extract::headers::{AcceptNoneDenyBad, Origin};
37/// use actix_web::get;
38///
39/// #[get("/")]
40/// pub async fn index(origin: AcceptNoneDenyBad<Origin>) -> String {
41///     format!("Your Origin Header is: {:?}", origin.0)
42/// }
43/// ```
44#[derive(Debug, Clone, PartialEq, Eq, Hash, Into)]
45#[repr(transparent)]
46pub struct AcceptNoneDenyBad<T: HeaderType>(pub Option<T>);
47
48/// A type that can be extracted from a request header
49pub trait HeaderType {
50    fn from_request(req: &actix_web::HttpRequest) -> Result<Self, crate::ExtractError>
51    where
52        Self: Sized;
53}
54
55impl<T: HeaderType> FromRequest for AcceptNoneDenyBad<T> {
56    type Error = ExtractError;
57    type Future = futures_util::future::Ready<Result<Self, crate::ExtractError>>;
58
59    fn from_request(req: &actix_web::HttpRequest, _: &mut actix_web::dev::Payload) -> Self::Future {
60        let result = <T>::from_request(req).map(|v| AcceptNoneDenyBad(Some(v)));
61        let result = if let Err(ExtractError::MissingHeader(_)) = &result {
62            Ok(AcceptNoneDenyBad(None))
63        } else {
64            result
65        };
66        futures_util::future::ready(result)
67    }
68}
69
70macro_rules! simple_header {
71    ($for_type:ty, $header:ident, $header_name:literal) => {
72        impl crate::headers::HeaderType for $for_type {
73            #[inline]
74            fn from_request(req: &actix_web::HttpRequest) -> Result<Self, crate::ExtractError> {
75                let header_value = if let Some(value) = req.headers().get($header) {
76                    value
77                        .to_str()
78                        .map(|value| value.to_owned())
79                        .map_err(|v| crate::ExtractError::ToStrError($header_name, v))?
80                } else {
81                    log::debug!(concat!("No `", $header_name, "` Header Found"));
82                    return Err(crate::ExtractError::MissingHeader($header_name));
83                };
84
85                Ok(<$for_type>::from(header_value))
86            }
87        }
88        crate::ready_impl_from_request!($for_type as Header);
89    };
90}
91
92pub(crate) use simple_header;