http_sig/
header.rs

1use std::cmp::Ordering;
2use std::str::FromStr;
3
4use http::header::{HeaderName, InvalidHeaderName};
5
6/// Pseudo-headers are used to incorporate additional information into a HTTP
7/// signature for which there is no corresponding HTTP header.
8///
9/// They are described as "special headers" in the draft specification:
10/// https://tools.ietf.org/id/draft-cavage-http-signatures-12.html#canonicalization
11#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
12#[non_exhaustive]
13pub enum PseudoHeader {
14    /// The `(request-target)` pseudo-header is constructed by joining the lower-cased
15    /// request method (`get`, `post`, etc.) and the request path (`/some/page?foo=1`)
16    /// with a single space character.
17    ///
18    /// For example:
19    /// `get /index.html`
20    RequestTarget,
21    /// Passed as part of the auth header
22    Created,
23    /// Passed as part of the auth header
24    Expires,
25}
26
27impl PseudoHeader {
28    /// Returns the string representation of the pseudo-header.
29    pub fn as_str(&self) -> &str {
30        match self {
31            PseudoHeader::RequestTarget => "(request-target)",
32            PseudoHeader::Created => "(created)",
33            PseudoHeader::Expires => "(expires)",
34        }
35    }
36}
37
38impl FromStr for PseudoHeader {
39    type Err = ();
40    fn from_str(s: &str) -> Result<PseudoHeader, Self::Err> {
41        match s {
42            "(request-target)" => Ok(PseudoHeader::RequestTarget),
43            "(created)" => Ok(PseudoHeader::Created),
44            "(expires)" => Ok(PseudoHeader::Expires),
45            _ => Err(()),
46        }
47    }
48}
49
50/// A header which can be incorporated into a HTTP signature.
51///
52/// Headers can either be normal HTTP headers or special "pseudo-headers"
53/// used for including additional information into a signature.
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub enum Header {
56    /// This header is one of the special "pseudo-headers"
57    Pseudo(PseudoHeader),
58    /// This header is a normal HTTP heaeder.
59    Normal(HeaderName),
60}
61
62impl Header {
63    /// Returns the string representation of the header, as it will appear
64    /// in the HTTP signature.
65    pub fn as_str(&self) -> &str {
66        match self {
67            Header::Pseudo(h) => h.as_str(),
68            Header::Normal(h) => h.as_str(),
69        }
70    }
71}
72
73impl FromStr for Header {
74    type Err = InvalidHeaderName;
75    fn from_str(s: &str) -> Result<Header, Self::Err> {
76        PseudoHeader::from_str(s)
77            .map(Into::into)
78            .or_else(|_| HeaderName::from_str(s).map(Into::into))
79    }
80}
81
82impl Ord for Header {
83    fn cmp(&self, other: &Header) -> Ordering {
84        self.as_str().cmp(other.as_str())
85    }
86}
87
88impl PartialOrd for Header {
89    fn partial_cmp(&self, other: &Header) -> Option<Ordering> {
90        Some(self.cmp(other))
91    }
92}
93
94impl From<HeaderName> for Header {
95    fn from(other: HeaderName) -> Self {
96        Header::Normal(other)
97    }
98}
99
100impl From<PseudoHeader> for Header {
101    fn from(other: PseudoHeader) -> Self {
102        Header::Pseudo(other)
103    }
104}