tower_sombrero/headers/
mod.rs

1macro_rules! header {
2    ($value:literal) => {{
3        static GENERATED_HEADER_VALUE: ::http::HeaderValue =
4            ::http::HeaderValue::from_static($value);
5        GENERATED_HEADER_VALUE.clone()
6    }};
7}
8
9/// You should probably be using a [`http::header`] constant here.
10macro_rules! header_name {
11    ($value:literal) => {{
12        static GENERATED_HEADER_NAME: ::http::HeaderName = ::http::HeaderName::from_static($value);
13        GENERATED_HEADER_NAME.clone()
14    }};
15}
16
17mod csp;
18mod sts;
19
20pub use csp::{ContentSecurityPolicy, CspHashAlgorithm, CspSchemeSource, CspSource};
21use http::{
22    header::{
23        REFERRER_POLICY, X_CONTENT_TYPE_OPTIONS, X_DNS_PREFETCH_CONTROL, X_FRAME_OPTIONS,
24        X_XSS_PROTECTION,
25    },
26    HeaderName, HeaderValue,
27};
28pub use sts::StrictTransportSecurity;
29
30pub trait Header {
31    fn name(&self) -> HeaderName;
32    fn value(&self) -> HeaderValue;
33}
34
35#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
36pub enum CrossOriginEmbedderPolicy {
37    #[default]
38    RequireCorp,
39    Credentialless,
40    UnsafeNone,
41}
42
43impl Header for CrossOriginEmbedderPolicy {
44    fn name(&self) -> HeaderName {
45        header_name!("cross-origin-embedder-policy")
46    }
47
48    fn value(&self) -> HeaderValue {
49        match self {
50            Self::RequireCorp => header!("require-corp"),
51            Self::Credentialless => header!("credentialless"),
52            Self::UnsafeNone => header!("unsafe-none"),
53        }
54    }
55}
56
57#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
58pub enum CrossOriginOpenerPolicy {
59    #[default]
60    SameOrigin,
61    SameOriginAllowPopups,
62    UnsafeNone,
63}
64
65impl Header for CrossOriginOpenerPolicy {
66    fn name(&self) -> HeaderName {
67        header_name!("cross-origin-opener-policy")
68    }
69
70    fn value(&self) -> HeaderValue {
71        match self {
72            Self::SameOrigin => header!("same-origin"),
73            Self::SameOriginAllowPopups => header!("same-origin-allow-popups"),
74            Self::UnsafeNone => header!("unsafe-none"),
75        }
76    }
77}
78
79#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
80pub enum CrossOriginResourcePolicy {
81    #[default]
82    SameOrigin,
83    SameSite,
84    CrossOrigin,
85}
86
87impl Header for CrossOriginResourcePolicy {
88    fn name(&self) -> HeaderName {
89        header_name!("cross-origin-resource-policy")
90    }
91
92    fn value(&self) -> HeaderValue {
93        match self {
94            Self::SameOrigin => header!("same-origin"),
95            Self::SameSite => header!("same-site"),
96            Self::CrossOrigin => header!("cross-origin"),
97        }
98    }
99}
100
101#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
102pub struct OriginAgentCluster;
103
104impl Header for OriginAgentCluster {
105    fn name(&self) -> HeaderName {
106        header_name!("origin-agent-cluster")
107    }
108
109    fn value(&self) -> HeaderValue {
110        header!("?1")
111    }
112}
113
114#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
115pub enum ReferrerPolicy {
116    #[default]
117    /// The Referer header will be omitted: sent requests do not include any referrer information.
118    NoReferrer,
119    /// Send the origin, path, and querystring in Referer when the protocol security level stays the same or improves (HTTP→HTTP, HTTP→HTTPS, HTTPS→HTTPS). Don't send the Referer header for requests to less secure destinations (HTTPS→HTTP, HTTPS→file).
120    NoReferrerWhenDowngrade,
121    /// Send only the origin in the Referer header. For example, a document at `https://example.com/page.html` will send the referee `https://example.com/`.
122    Origin,
123    /// When performing a same-origin request to the same protocol level (HTTP→HTTP, HTTPS→HTTPS), send the origin, path, and query string. Send only the origin for cross origin requests and requests to less secure destinations (HTTPS→HTTP).
124    OriginWhenCrossOrigin,
125    /// Send the origin, path, and query string for same-origin requests. Don't send the Referer header for cross-origin requests.
126    SameOrigin,
127    /// Send only the origin when the protocol security level stays the same (HTTPS→HTTPS). Don't send the Referer header to less secure destinations (HTTPS→HTTP)
128    StrictOrigin,
129    /// Send the origin, path, and querystring when performing a same-origin request. For cross-origin requests send the origin (only) when the protocol security level stays same (HTTPS→HTTPS). Don't send the Referer header to less secure destinations (HTTPS→HTTP).
130    StrictOriginWhenCrossOrigin,
131    /// Send the origin, path, and query string when performing any request, regardless of security.
132    UnsafeUrl,
133}
134
135impl Header for ReferrerPolicy {
136    fn name(&self) -> HeaderName {
137        REFERRER_POLICY
138    }
139
140    fn value(&self) -> HeaderValue {
141        match self {
142            Self::NoReferrer => header!("no-referrer"),
143            Self::NoReferrerWhenDowngrade => header!("no-referrer-when-downgrade"),
144            Self::Origin => header!("origin"),
145            Self::OriginWhenCrossOrigin => header!("origin-when-cross-origin"),
146            Self::SameOrigin => header!("same-origin"),
147            Self::StrictOrigin => header!("strict-origin"),
148            Self::StrictOriginWhenCrossOrigin => header!("strict-origin-when-cross-origin"),
149
150            Self::UnsafeUrl => header!("unsafe-url"),
151        }
152    }
153}
154
155#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
156pub struct XContentTypeOptions;
157
158impl Header for XContentTypeOptions {
159    fn name(&self) -> HeaderName {
160        X_CONTENT_TYPE_OPTIONS
161    }
162
163    fn value(&self) -> HeaderValue {
164        header!("nosniff")
165    }
166}
167
168#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
169pub enum XDnsPrefetchControl {
170    On,
171    #[default]
172    Off,
173}
174
175impl Header for XDnsPrefetchControl {
176    fn name(&self) -> HeaderName {
177        X_DNS_PREFETCH_CONTROL
178    }
179
180    fn value(&self) -> HeaderValue {
181        match self {
182            Self::Off => header!("off"),
183            Self::On => header!("on"),
184        }
185    }
186}
187
188#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
189pub struct XDownloadOptions;
190
191impl Header for XDownloadOptions {
192    fn name(&self) -> HeaderName {
193        header_name!("x-download-options")
194    }
195
196    fn value(&self) -> HeaderValue {
197        header!("noopen")
198    }
199}
200
201#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
202pub enum XFrameOptions {
203    Deny,
204    #[default]
205    Sameorigin,
206}
207
208impl Header for XFrameOptions {
209    fn name(&self) -> HeaderName {
210        X_FRAME_OPTIONS
211    }
212
213    fn value(&self) -> HeaderValue {
214        match self {
215            Self::Deny => header!("DENY"),
216            Self::Sameorigin => header!("SAMEORIGIN"),
217        }
218    }
219}
220
221#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
222pub enum XPermittedCrossDomainPolicies {
223    #[default]
224    None,
225    MasterOnly,
226    ByContentType,
227    All,
228}
229
230impl Header for XPermittedCrossDomainPolicies {
231    fn name(&self) -> HeaderName {
232        header_name!("x-permitted-cross-domain-policies")
233    }
234
235    fn value(&self) -> HeaderValue {
236        match self {
237            Self::None => header!("none"),
238            Self::MasterOnly => header!("master-only"),
239            Self::ByContentType => header!("by-content-type"),
240            Self::All => header!("all"),
241        }
242    }
243}
244
245#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
246pub enum XXssProtection {
247    #[default]
248    False,
249    TrueBlock,
250    True,
251}
252
253impl Header for XXssProtection {
254    fn name(&self) -> HeaderName {
255        X_XSS_PROTECTION
256    }
257
258    fn value(&self) -> HeaderValue {
259        match self {
260            Self::TrueBlock => header!("1; mode=block"),
261            Self::True => header!("1"),
262            Self::False => header!("0"),
263        }
264    }
265}