Skip to main content

trillium_http/headers/
known_header_name.rs

1use super::{HeaderName, HeaderNameInner};
2use std::{
3    fmt::{self, Debug, Display, Formatter},
4    hash::Hash,
5    str::FromStr,
6};
7
8impl Display for KnownHeaderName {
9    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
10        f.write_str(self.as_ref())
11    }
12}
13
14impl From<KnownHeaderName> for HeaderName<'_> {
15    fn from(khn: KnownHeaderName) -> Self {
16        Self(HeaderNameInner::KnownHeader(khn))
17    }
18}
19
20impl PartialEq<HeaderName<'_>> for KnownHeaderName {
21    fn eq(&self, other: &HeaderName) -> bool {
22        matches!(&other.0, HeaderNameInner::KnownHeader(k) if self == k)
23    }
24}
25
26impl AsRef<str> for KnownHeaderName {
27    fn as_ref(&self) -> &str {
28        self.as_str()
29    }
30}
31
32macro_rules! known_headers {
33    (
34        $(
35            ($capitalized:literal, $variant:tt)
36        ),+
37    ) => {
38
39        /// A short nonehaustive enum of headers that trillium can
40        /// represent as a u8. Use a `KnownHeaderName` variant instead
41        /// of a &'static str anywhere possible, as it allows trillium
42        /// to skip parsing the header entirely.
43        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
44        #[non_exhaustive]
45        #[repr(u8)]
46        pub enum KnownHeaderName {
47            $(
48                #[doc = concat!("The [", $capitalized, "](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/", $capitalized, ") header.")]
49                $variant,
50            )+
51        }
52
53        impl KnownHeaderName {
54            /// Retrieve a static string representation of this header name
55            pub fn as_str(&self) -> &'static str {
56                match self {
57                    $( Self::$variant => $capitalized, )+
58                }
59            }
60        }
61
62        impl FromStr for KnownHeaderName {
63            type Err = ();
64            fn from_str(s: &str) -> Result<Self, Self::Err> {
65                if !s.is_ascii() { return Err(()); }
66                let len = s.len();
67
68                $( if len == $capitalized.len() && s.eq_ignore_ascii_case($capitalized) { return Ok(Self::$variant); } )+
69                Err(())
70            }
71        }
72
73        #[cfg(test)]
74        mod known_header_name_tests {
75            use super::*;
76
77            #[test]
78            fn roundtrip_all_variants() {
79                $(
80                    let parsed: KnownHeaderName = $capitalized.parse()
81                        .unwrap_or_else(|_| panic!("failed to parse {:?}", $capitalized));
82                    assert_eq!(
83                        parsed,
84                        KnownHeaderName::$variant,
85                        "parse({:?}) returned wrong variant",
86                        $capitalized,
87                    );
88                    assert_eq!(
89                        parsed.as_str(),
90                        $capitalized,
91                        "as_str() mismatch for {:?}",
92                        stringify!($variant),
93                    );
94                )+
95            }
96
97            #[test]
98            fn case_insensitive_roundtrip() {
99                $(
100                    let lower: KnownHeaderName = $capitalized.to_lowercase().parse()
101                        .unwrap_or_else(|_| panic!("failed to parse lowercase {:?}", $capitalized));
102                    assert_eq!(lower, KnownHeaderName::$variant);
103
104                    let upper: KnownHeaderName = $capitalized.to_uppercase().parse()
105                        .unwrap_or_else(|_| panic!("failed to parse uppercase {:?}", $capitalized));
106                    assert_eq!(upper, KnownHeaderName::$variant);
107                )+
108            }
109
110            #[test]
111            fn unknown_headers_return_err() {
112                assert!("X-Unknown-Custom-Header".parse::<KnownHeaderName>().is_err());
113                assert!("".parse::<KnownHeaderName>().is_err());
114                assert!("Hostt".parse::<KnownHeaderName>().is_err());
115                assert!("Hos".parse::<KnownHeaderName>().is_err());
116            }
117        }
118    }
119}
120
121// generated with
122//
123// console.log($$('main > article > div > dl > dt > a > code').map(code => {
124// let lowered = code.innerText.toLowerCase();
125// let enum_ = lowered.replace(/(?:-|^)([a-z])/g, (_, p1) => p1.toUpperCase());
126// return`("${code.innerText}", ${enum_}, "${lowered}")`
127// }).join(",\n"))
128//
129// on https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
130//
131//
132// per https://httpwg.org/specs/rfc9110.html#rfc.section.5.3,
133//
134// The order in which field lines with differing field names are received in a section is not
135// significant. However, it is good practice to send header fields that contain additional control
136// data first, such as Host on requests and Date on responses, so that implementations can decide
137// when not to handle a message as early as possible.
138known_headers! {
139    ("Host", Host),
140    ("Date", Date),
141
142    ("Accept", Accept),
143    ("Accept-CH", AcceptCh),
144    ("Accept-CH-Lifetime", AcceptChLifetime),
145    ("Accept-Charset", AcceptCharset),
146    ("Accept-Encoding", AcceptEncoding),
147    ("Accept-Language", AcceptLanguage),
148    ("Accept-Push-Policy", AcceptPushPolicy),
149    ("Accept-Ranges", AcceptRanges),
150    ("Accept-Signature", AcceptSignature),
151    ("Access-Control-Allow-Credentials", AccessControlAllowCredentials),
152    ("Access-Control-Allow-Headers", AccessControlAllowHeaders),
153    ("Access-Control-Allow-Methods", AccessControlAllowMethods),
154    ("Access-Control-Allow-Origin", AccessControlAllowOrigin),
155    ("Access-Control-Expose-Headers", AccessControlExposeHeaders),
156    ("Access-Control-Max-Age", AccessControlMaxAge),
157    ("Access-Control-Request-Headers", AccessControlRequestHeaders),
158    ("Access-Control-Request-Method", AccessControlRequestMethod),
159    ("Age", Age),
160    ("Allow", Allow),
161    ("Alt-Svc", AltSvc),
162    ("Alt-Used", AltUsed),
163    ("Authorization", Authorization),
164    ("Cache-Control", CacheControl),
165    ("Clear-Site-Data", ClearSiteData),
166    ("Connection", Connection),
167    ("Content-DPR", ContentDpr),
168    ("Content-Digest", ContentDigest),
169    ("Content-Disposition", ContentDisposition),
170    ("Content-Encoding", ContentEncoding),
171    ("Content-Language", ContentLanguage),
172    ("Content-Length", ContentLength),
173    ("Content-Location", ContentLocation),
174    ("Content-Range", ContentRange),
175    ("Content-Security-Policy", ContentSecurityPolicy),
176    ("Content-Security-Policy-Report-Only", ContentSecurityPolicyReportOnly),
177    ("Content-Type", ContentType),
178    ("Cookie", Cookie),
179    ("Cookie2", Cookie2),
180    ("Cross-Origin-Embedder-Policy", CrossOriginEmbedderPolicy),
181    ("Cross-Origin-Opener-Policy", CrossOriginOpenerPolicy),
182    ("Cross-Origin-Resource-Policy", CrossOriginResourcePolicy),
183    ("DNT", Dnt),
184    ("DPR", Dpr),
185    ("DPoP", Dpop),
186    ("Deprecation", Deprecation),
187    ("Device-Memory", DeviceMemory),
188    ("Digest", Digest),
189    ("Downlink", Downlink),
190    ("ECT", Ect),
191    ("ETag", Etag),
192    ("Early-Data", EarlyData),
193    ("Expect", Expect),
194    ("Expect-CT", ExpectCt),
195    ("Expires", Expires),
196    ("Feature-Policy", FeaturePolicy),
197    ("Forwarded", Forwarded),
198    ("From", From),
199    ("If-Match", IfMatch),
200    ("If-Modified-Since", IfModifiedSince),
201    ("If-None-Match", IfNoneMatch),
202    ("If-Range", IfRange),
203    ("If-Unmodified-Since", IfUnmodifiedSince),
204    ("Keep-Alive", KeepAlive),
205    ("Large-Allocation", LargeAllocation),
206    ("Last-Event-ID", LastEventId),
207    ("Last-Modified", LastModified),
208    ("Link", Link),
209    ("Location", Location),
210    ("Max-Forwards", MaxForwards),
211    ("NEL", Nel),
212    ("Origin", Origin),
213    ("Origin-Isolation", OriginIsolation),
214    ("Permissions-Policy", PermissionsPolicy),
215    ("Ping-From", PingFrom),
216    ("Ping-To", PingTo),
217    ("Pragma", Pragma),
218    ("Priority", Priority),
219    ("Proxy-Authenticate", ProxyAuthenticate),
220    ("Proxy-Authorization", ProxyAuthorization),
221    ("Proxy-Connection", ProxyConnection),
222    ("Proxy-Status", ProxyStatus),
223    ("Public-Key-Pins", PublicKeyPins),
224    ("Public-Key-Pins-Report-Only", PublicKeyPinsReportOnly),
225    ("Purpose", Purpose),
226    ("Push-Policy", PushPolicy),
227    ("RTT", Rtt),
228    ("Range", Range),
229    ("RateLimit-Reset", RatelimitReset),
230    ("Ratelimit-Limit", RatelimitLimit),
231    ("Ratelimit-Remaining", RatelimitRemaining),
232    ("Referer", Referer),
233    ("Referrer-Policy", ReferrerPolicy),
234    ("Refresh-Cache", RefreshCache),
235    ("Report-To", ReportTo),
236    ("Repr-Digest", ReprDigest),
237    ("Retry-After", RetryAfter),
238    ("Save-Data", SaveData),
239    ("Sec-CH-UA", SecChUa),
240    ("Sec-CH-UA-Mobile", SecChUAMobile),
241    ("Sec-CH-UA-Platform", SecChUAPlatform),
242    ("Sec-Fetch-Dest", SecFetchDest),
243    ("Sec-Fetch-Mode", SecFetchMode),
244    ("Sec-Fetch-Site", SecFetchSite),
245    ("Sec-Fetch-User", SecFetchUser),
246    ("Sec-GPC", SecGpc),
247    ("Sec-WebSocket-Accept", SecWebsocketAccept),
248    ("Sec-WebSocket-Extensions", SecWebsocketExtensions),
249    ("Sec-WebSocket-Key", SecWebsocketKey),
250    ("Sec-WebSocket-Protocol", SecWebsocketProtocol),
251    ("Sec-WebSocket-Version", SecWebsocketVersion),
252    ("Server", Server),
253    ("Server-Timing", ServerTiming),
254    ("Service-Worker-Allowed", ServiceWorkerAllowed),
255    ("Set-Cookie", SetCookie),
256    ("Set-Cookie2", SetCookie2),
257    ("Signature", Signature),
258    ("Signed-Headers", SignedHeaders),
259    ("SourceMap", Sourcemap),
260    ("Strict-Transport-Security", StrictTransportSecurity),
261    ("TE", Te),
262    ("Timing-Allow-Origin", TimingAllowOrigin),
263    ("Traceparent", Traceparent),
264    ("Tracestate", Tracestate),
265    ("Trailer", Trailer),
266    ("Transfer-Encoding", TransferEncoding),
267    ("Upgrade", Upgrade),
268    ("Upgrade-Insecure-Requests", UpgradeInsecureRequests),
269    ("User-Agent", UserAgent),
270    ("Vary", Vary),
271    ("Via", Via),
272    ("Viewport-Width", ViewportWidth),
273    ("WWW-Authenticate", WwwAuthenticate),
274    ("Want-Content-Digest", WantContentDigest),
275    ("Want-Digest", WantDigest),
276    ("Want-Repr-Digest", WantReprDigest),
277    ("Warning", Warning),
278    ("Width", Width),
279    ("X-B3-Traceid", Xb3Traceid),
280    ("X-Cache", Xcache),
281    ("X-Content-Type-Options", XcontentTypeOptions),
282    ("X-Correlation-ID", XcorrelationId),
283    ("X-DNS-Prefetch-Control", XdnsPrefetchControl),
284    ("X-Download-Options", XdownloadOptions),
285    ("X-Firefox-Spdy", XfirefoxSpdy),
286    ("X-Forwarded-By", XforwardedBy),
287    ("X-Forwarded-For", XforwardedFor),
288    ("X-Forwarded-Host", XforwardedHost),
289    ("X-Forwarded-Proto", XforwardedProto),
290    ("X-Forwarded-SSL", XforwardedSsl),
291    ("X-Frame-Options", XframeOptions),
292    ("X-Permitted-Cross-Domain-Policies", XpermittedCrossDomainPolicies),
293    ("X-Pingback", Xpingback),
294    ("X-Powered-By", XpoweredBy),
295    ("X-Real-IP", XrealIp),
296    ("X-Request-Id", XrequestId),
297    ("X-Requested-With", XrequestedWith),
298    ("X-Robots-Tag", XrobotsTag),
299    ("X-Runtime", Xruntime),
300    ("X-Served-By", XservedBy),
301    ("X-UA-Compatible", XuaCompatible),
302    ("X-XSS-Protection", XxssProtection)
303}