Skip to main content

rama_http_types/header/
name.rs

1use bytes::{Bytes, BytesMut};
2use rama_core::bytes::ByteStr;
3
4use std::borrow::Cow;
5use std::convert::TryFrom;
6use std::error::Error;
7use std::fmt;
8use std::hash::{Hash, Hasher};
9use std::mem::MaybeUninit;
10use std::str::FromStr;
11
12/// Represents an HTTP header field name
13///
14/// Header field names identify the header. Header sets may include multiple
15/// headers with the same name. The HTTP specification defines a number of
16/// standard headers, but HTTP messages may include non-standard header names as
17/// well as long as they adhere to the specification.
18///
19/// `HeaderName` is used as the [`HeaderMap`] key. Constants are available for
20/// all standard header names in the [`header`] module.
21///
22/// Standard header constants can be used for equality checks. They cannot be
23/// used as const patterns on stable Rust because `HeaderName` implements
24/// semantic, case-insensitive `PartialEq` manually. If Rust stabilizes the
25/// structural matching support needed for this representation, these constants
26/// can become pattern-matchable again.
27///
28/// # Representation
29///
30/// `HeaderName` represents standard header names using an `enum`, as such they
31/// will not require an allocation for storage. Header names preserve their
32/// original casing while equality, ordering and hashing continue to use HTTP's
33/// case-insensitive header-name semantics.
34///
35/// [`HeaderMap`]: struct.HeaderMap.html
36/// [`header`]: index.html
37#[derive(Clone)]
38pub struct HeaderName {
39    inner: Repr<Custom>,
40}
41
42/// Display adapter for a [`HeaderName`] in its preserved spelling.
43#[derive(Debug, Clone, Copy)]
44pub struct OriginalHeaderName<'a>(&'a HeaderName);
45
46/// Display adapter for a [`HeaderName`] in lowercase wire spelling.
47#[derive(Debug, Clone, Copy)]
48pub struct LowercaseHeaderName<'a>(&'a HeaderName);
49
50// Almost a full `HeaderName`
51#[derive(Debug)]
52pub struct HdrName<'a> {
53    inner: Repr<MaybeLower<'a>>,
54}
55
56impl Hash for HdrName<'_> {
57    #[inline]
58    fn hash<H: Hasher>(&self, hasher: &mut H) {
59        match self.inner {
60            Repr::Standard(v) => v.header.hash(hasher),
61            Repr::Custom(ref v) => v.hash(hasher),
62        }
63    }
64}
65
66#[derive(Debug, Clone)]
67enum Repr<T> {
68    Standard(StandardName),
69    Custom(T),
70}
71
72// Used to hijack the Hash impl
73#[derive(Debug, Clone, Eq, PartialEq)]
74struct Custom(ByteStr);
75
76#[derive(Debug, Clone)]
77// Invariant: If lower then buf is valid UTF-8.
78struct MaybeLower<'a> {
79    buf: &'a [u8],
80    lower: bool,
81}
82
83#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
84struct CaseMask(u64);
85
86impl CaseMask {
87    const LOWER: Self = Self(0);
88
89    #[inline]
90    const fn is_upper(self, index: usize) -> bool {
91        (self.0 & (1 << index)) != 0
92    }
93
94    const fn from_original(lower: &[u8], original: &[u8]) -> Self {
95        let mut mask = 0u64;
96        let mut i = 0;
97        while i < lower.len() && i < 64 {
98            if original[i] != lower[i] {
99                mask |= 1 << i;
100            }
101            i += 1;
102        }
103        Self(mask)
104    }
105}
106
107/// A possible error when converting a `HeaderName` from another type.
108pub struct InvalidHeaderName {
109    _priv: (),
110}
111
112macro_rules! standard_headers {
113    (
114        $(
115            $(#[$docs:meta])*
116            ($konst:ident, $upcase:ident, $name_bytes:literal);
117        )+
118    ) => {
119        #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
120        pub enum StandardHeader {
121            $(
122                $konst,
123            )+
124        }
125
126        $(
127            $(#[$docs])*
128            pub const $upcase: HeaderName = HeaderName {
129                inner: Repr::Standard(StandardName {
130                    header: StandardHeader::$konst,
131                    case: CaseMask::LOWER,
132                }),
133            };
134        )+
135
136        impl StandardHeader {
137            const fn as_bytes(&self) -> &'static [u8] {
138                match *self {
139                    $(
140                    StandardHeader::$konst => $name_bytes,
141                    )+
142                }
143            }
144
145            #[inline]
146            fn as_str(&self) -> &'static str {
147                // Safety: test_parse_standard_headers ensures these &[u8]s are &str-safe.
148                unsafe { std::str::from_utf8_unchecked(self.as_bytes()) }
149            }
150
151            const fn from_bytes(name_bytes: &[u8]) -> Option<StandardHeader> {
152                match name_bytes {
153                    $(
154                        $name_bytes => Some(StandardHeader::$konst),
155                    )+
156                    _ => None,
157                }
158            }
159
160            const fn from_bytes_ignore_case(name_bytes: &[u8]) -> Option<StandardHeader> {
161                $(
162                    if eq_ignore_ascii_case_const($name_bytes, name_bytes) {
163                        return Some(StandardHeader::$konst);
164                    }
165                )+
166                None
167            }
168        }
169
170        #[cfg(test)]
171        const TEST_HEADERS: &'static [(StandardHeader, &'static [u8])] = &[
172            $(
173            (StandardHeader::$konst, $name_bytes),
174            )+
175        ];
176
177        #[test]
178        fn test_parse_standard_headers() {
179            for &(std, name_bytes) in TEST_HEADERS {
180                // Test lower case
181                assert_eq!(HeaderName::from_bytes(name_bytes).unwrap(), HeaderName::from(std));
182
183                // Test upper case
184                let upper = std::str::from_utf8(name_bytes).expect("byte string constants are all utf-8").to_uppercase();
185                assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(), HeaderName::from(std));
186            }
187        }
188
189        #[test]
190        fn test_standard_headers_into_bytes() {
191            for &(std, name_bytes) in TEST_HEADERS {
192                let name = std::str::from_utf8(name_bytes).unwrap();
193                let std = HeaderName::from(std);
194                // Test lower case
195                let bytes: Bytes =
196                    HeaderName::from_bytes(name_bytes).unwrap().inner.into();
197                assert_eq!(bytes, name);
198                assert_eq!(HeaderName::from_bytes(name_bytes).unwrap(), std);
199
200                // Test upper case
201                let upper = name.to_uppercase();
202                let bytes: Bytes =
203                    HeaderName::from_bytes(upper.as_bytes()).unwrap().inner.into();
204                assert_eq!(bytes, name_bytes);
205                assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(),
206                           std);
207            }
208
209        }
210    }
211}
212
213// Generate constants for all standard HTTP headers. This includes a static hash
214// code for the "fast hash" path. The hash code for static headers *do not* have
215// to match the text representation of those headers. This is because header
216// strings are always converted to the static values (when they match) before
217// being hashed. This means that it is impossible to compare the static hash
218// code of CONTENT_LENGTH with "content-length".
219standard_headers! {
220    /// Advertises which content types the client is able to understand.
221    ///
222    /// The Accept request HTTP header advertises which content types, expressed
223    /// as MIME types, the client is able to understand. Using content
224    /// negotiation, the server then selects one of the proposals, uses it and
225    /// informs the client of its choice with the Content-Type response header.
226    /// Browsers set adequate values for this header depending of the context
227    /// where the request is done: when fetching a CSS stylesheet a different
228    /// value is set for the request than when fetching an image, video or a
229    /// script.
230    (Accept, ACCEPT, b"accept");
231
232    /// Advertises which character set the client is able to understand.
233    ///
234    /// The Accept-Charset request HTTP header advertises which character set
235    /// the client is able to understand. Using content negotiation, the server
236    /// then selects one of the proposals, uses it and informs the client of its
237    /// choice within the Content-Type response header. Browsers usually don't
238    /// set this header as the default value for each content type is usually
239    /// correct and transmitting it would allow easier fingerprinting.
240    ///
241    /// If the server cannot serve any matching character set, it can
242    /// theoretically send back a 406 (Not Acceptable) error code. But, for a
243    /// better user experience, this is rarely done and the more common way is
244    /// to ignore the Accept-Charset header in this case.
245    (AcceptCharset, ACCEPT_CHARSET, b"accept-charset");
246
247    /// Advertises which content encoding the client is able to understand.
248    ///
249    /// The Accept-Encoding request HTTP header advertises which content
250    /// encoding, usually a compression algorithm, the client is able to
251    /// understand. Using content negotiation, the server selects one of the
252    /// proposals, uses it and informs the client of its choice with the
253    /// Content-Encoding response header.
254    ///
255    /// Even if both the client and the server supports the same compression
256    /// algorithms, the server may choose not to compress the body of a
257    /// response, if the identity value is also acceptable. Two common cases
258    /// lead to this:
259    ///
260    /// * The data to be sent is already compressed and a second compression
261    /// won't lead to smaller data to be transmitted. This may the case with
262    /// some image formats;
263    ///
264    /// * The server is overloaded and cannot afford the computational overhead
265    /// induced by the compression requirement. Typically, Microsoft recommends
266    /// not to compress if a server use more than 80 % of its computational
267    /// power.
268    ///
269    /// As long as the identity value, meaning no compression, is not explicitly
270    /// forbidden, by an identity;q=0 or a *;q=0 without another explicitly set
271    /// value for identity, the server must never send back a 406 Not Acceptable
272    /// error.
273    (AcceptEncoding, ACCEPT_ENCODING, b"accept-encoding");
274
275    /// Advertises which languages the client is able to understand.
276    ///
277    /// The Accept-Language request HTTP header advertises which languages the
278    /// client is able to understand, and which locale variant is preferred.
279    /// Using content negotiation, the server then selects one of the proposals,
280    /// uses it and informs the client of its choice with the Content-Language
281    /// response header. Browsers set adequate values for this header according
282    /// their user interface language and even if a user can change it, this
283    /// happens rarely (and is frown upon as it leads to fingerprinting).
284    ///
285    /// This header is a hint to be used when the server has no way of
286    /// determining the language via another way, like a specific URL, that is
287    /// controlled by an explicit user decision. It is recommended that the
288    /// server never overrides an explicit decision. The content of the
289    /// Accept-Language is often out of the control of the user (like when
290    /// traveling and using an Internet Cafe in a different country); the user
291    /// may also want to visit a page in another language than the locale of
292    /// their user interface.
293    ///
294    /// If the server cannot serve any matching language, it can theoretically
295    /// send back a 406 (Not Acceptable) error code. But, for a better user
296    /// experience, this is rarely done and more common way is to ignore the
297    /// Accept-Language header in this case.
298    (AcceptLanguage, ACCEPT_LANGUAGE, b"accept-language");
299
300    /// Marker used by the server to advertise partial request support.
301    ///
302    /// The Accept-Ranges response HTTP header is a marker used by the server to
303    /// advertise its support of partial requests. The value of this field
304    /// indicates the unit that can be used to define a range.
305    ///
306    /// In presence of an Accept-Ranges header, the browser may try to resume an
307    /// interrupted download, rather than to start it from the start again.
308    (AcceptRanges, ACCEPT_RANGES, b"accept-ranges");
309
310    /// Preflight response indicating if the response to the request can be
311    /// exposed to the page.
312    ///
313    /// The Access-Control-Allow-Credentials response header indicates whether
314    /// or not the response to the request can be exposed to the page. It can be
315    /// exposed when the true value is returned; it can't in other cases.
316    ///
317    /// Credentials are cookies, authorization headers or TLS client
318    /// certificates.
319    ///
320    /// When used as part of a response to a preflight request, this indicates
321    /// whether or not the actual request can be made using credentials. Note
322    /// that simple GET requests are not preflighted, and so if a request is
323    /// made for a resource with credentials, if this header is not returned
324    /// with the resource, the response is ignored by the browser and not
325    /// returned to web content.
326    ///
327    /// The Access-Control-Allow-Credentials header works in conjunction with
328    /// the XMLHttpRequest.withCredentials property or with the credentials
329    /// option in the Request() constructor of the Fetch API. Credentials must
330    /// be set on both sides (the Access-Control-Allow-Credentials header and in
331    /// the XHR or Fetch request) in order for the CORS request with credentials
332    /// to succeed.
333    (AccessControlAllowCredentials, ACCESS_CONTROL_ALLOW_CREDENTIALS, b"access-control-allow-credentials");
334
335    /// Preflight response indicating permitted HTTP headers.
336    ///
337    /// The Access-Control-Allow-Headers response header is used in response to
338    /// a preflight request to indicate which HTTP headers will be available via
339    /// Access-Control-Expose-Headers when making the actual request.
340    ///
341    /// The simple headers, Accept, Accept-Language, Content-Language,
342    /// Content-Type (but only with a MIME type of its parsed value (ignoring
343    /// parameters) of either application/x-www-form-urlencoded,
344    /// multipart/form-data, or text/plain), are always available and don't need
345    /// to be listed by this header.
346    ///
347    /// This header is required if the request has an
348    /// Access-Control-Request-Headers header.
349    (AccessControlAllowHeaders, ACCESS_CONTROL_ALLOW_HEADERS, b"access-control-allow-headers");
350
351    /// Preflight header response indicating permitted access methods.
352    ///
353    /// The Access-Control-Allow-Methods response header specifies the method or
354    /// methods allowed when accessing the resource in response to a preflight
355    /// request.
356    (AccessControlAllowMethods, ACCESS_CONTROL_ALLOW_METHODS, b"access-control-allow-methods");
357
358    /// Indicates whether the response can be shared with resources with the
359    /// given origin.
360    (AccessControlAllowOrigin, ACCESS_CONTROL_ALLOW_ORIGIN, b"access-control-allow-origin");
361
362    /// Indicates which headers can be exposed as part of the response by
363    /// listing their names.
364    (AccessControlExposeHeaders, ACCESS_CONTROL_EXPOSE_HEADERS, b"access-control-expose-headers");
365
366    /// Indicates how long the results of a preflight request can be cached.
367    (AccessControlMaxAge, ACCESS_CONTROL_MAX_AGE, b"access-control-max-age");
368
369    /// Informs the server which HTTP headers will be used when an actual
370    /// request is made.
371    (AccessControlRequestHeaders, ACCESS_CONTROL_REQUEST_HEADERS, b"access-control-request-headers");
372
373    /// Informs the server know which HTTP method will be used when the actual
374    /// request is made.
375    (AccessControlRequestMethod, ACCESS_CONTROL_REQUEST_METHOD, b"access-control-request-method");
376
377    /// Indicates the time in seconds the object has been in a proxy cache.
378    ///
379    /// The Age header is usually close to zero. If it is Age: 0, it was
380    /// probably just fetched from the origin server; otherwise It is usually
381    /// calculated as a difference between the proxy's current date and the Date
382    /// general header included in the HTTP response.
383    (Age, AGE, b"age");
384
385    /// Lists the set of methods support by a resource.
386    ///
387    /// This header must be sent if the server responds with a 405 Method Not
388    /// Allowed status code to indicate which request methods can be used. An
389    /// empty Allow header indicates that the resource allows no request
390    /// methods, which might occur temporarily for a given resource, for
391    /// example.
392    (Allow, ALLOW, b"allow");
393
394    /// Advertises the availability of alternate services to clients.
395    (AltSvc, ALT_SVC, b"alt-svc");
396
397    /// Contains the credentials to authenticate a user agent with a server.
398    ///
399    /// Usually this header is included after the server has responded with a
400    /// 401 Unauthorized status and the WWW-Authenticate header.
401    (Authorization, AUTHORIZATION, b"authorization");
402
403    /// Specifies directives for caching mechanisms in both requests and
404    /// responses.
405    ///
406    /// Caching directives are unidirectional, meaning that a given directive in
407    /// a request is not implying that the same directive is to be given in the
408    /// response.
409    (CacheControl, CACHE_CONTROL, b"cache-control");
410
411    /// Indicates how caches have handled a response and its corresponding request.
412    ///
413    /// See [RFC 9211](https://www.rfc-editor.org/rfc/rfc9211.html).
414    (CacheStatus, CACHE_STATUS, b"cache-status");
415
416    /// Specifies directives that allow origin servers to control the behavior of CDN caches
417    /// interposed between them and clients separately from other caches that might handle the
418    /// response.
419    ///
420    /// See [RFC 9213](https://www.rfc-editor.org/rfc/rfc9213.html).
421    (CdnCacheControl, CDN_CACHE_CONTROL, b"cdn-cache-control");
422
423    /// Controls whether or not the network connection stays open after the
424    /// current transaction finishes.
425    ///
426    /// If the value sent is keep-alive, the connection is persistent and not
427    /// closed, allowing for subsequent requests to the same server to be done.
428    ///
429    /// Except for the standard hop-by-hop headers (Keep-Alive,
430    /// Transfer-Encoding, TE, Connection, Trailer, Upgrade, Proxy-Authorization
431    /// and Proxy-Authenticate), any hop-by-hop headers used by the message must
432    /// be listed in the Connection header, so that the first proxy knows he has
433    /// to consume them and not to forward them further. Standard hop-by-hop
434    /// headers can be listed too (it is often the case of Keep-Alive, but this
435    /// is not mandatory.
436    (Connection, CONNECTION, b"connection");
437
438    /// Indicates if the content is expected to be displayed inline.
439    ///
440    /// In a regular HTTP response, the Content-Disposition response header is a
441    /// header indicating if the content is expected to be displayed inline in
442    /// the browser, that is, as a Web page or as part of a Web page, or as an
443    /// attachment, that is downloaded and saved locally.
444    ///
445    /// In a multipart/form-data body, the HTTP Content-Disposition general
446    /// header is a header that can be used on the subpart of a multipart body
447    /// to give information about the field it applies to. The subpart is
448    /// delimited by the boundary defined in the Content-Type header. Used on
449    /// the body itself, Content-Disposition has no effect.
450    ///
451    /// The Content-Disposition header is defined in the larger context of MIME
452    /// messages for e-mail, but only a subset of the possible parameters apply
453    /// to HTTP forms and POST requests. Only the value form-data, as well as
454    /// the optional directive name and filename, can be used in the HTTP
455    /// context.
456    (ContentDisposition, CONTENT_DISPOSITION, b"content-disposition");
457
458    /// Used to compress the media-type.
459    ///
460    /// When present, its value indicates what additional content encoding has
461    /// been applied to the entity-body. It lets the client know, how to decode
462    /// in order to obtain the media-type referenced by the Content-Type header.
463    ///
464    /// It is recommended to compress data as much as possible and therefore to
465    /// use this field, but some types of resources, like jpeg images, are
466    /// already compressed.  Sometimes using additional compression doesn't
467    /// reduce payload size and can even make the payload longer.
468    (ContentEncoding, CONTENT_ENCODING, b"content-encoding");
469
470    /// Used to describe the languages intended for the audience.
471    ///
472    /// This header allows a user to differentiate according to the users' own
473    /// preferred language. For example, if "Content-Language: de-DE" is set, it
474    /// says that the document is intended for German language speakers
475    /// (however, it doesn't indicate the document is written in German. For
476    /// example, it might be written in English as part of a language course for
477    /// German speakers).
478    ///
479    /// If no Content-Language is specified, the default is that the content is
480    /// intended for all language audiences. Multiple language tags are also
481    /// possible, as well as applying the Content-Language header to various
482    /// media types and not only to textual documents.
483    (ContentLanguage, CONTENT_LANGUAGE, b"content-language");
484
485    /// Indicates the size of the entity-body.
486    ///
487    /// The header value must be a decimal indicating the number of octets sent
488    /// to the recipient.
489    (ContentLength, CONTENT_LENGTH, b"content-length");
490
491    /// Indicates an alternate location for the returned data.
492    ///
493    /// The principal use case is to indicate the URL of the resource
494    /// transmitted as the result of content negotiation.
495    ///
496    /// Location and Content-Location are different: Location indicates the
497    /// target of a redirection (or the URL of a newly created document), while
498    /// Content-Location indicates the direct URL to use to access the resource,
499    /// without the need of further content negotiation. Location is a header
500    /// associated with the response, while Content-Location is associated with
501    /// the entity returned.
502    (ContentLocation, CONTENT_LOCATION, b"content-location");
503
504    /// Indicates where in a full body message a partial message belongs.
505    (ContentRange, CONTENT_RANGE, b"content-range");
506
507    /// Allows controlling resources the user agent is allowed to load for a
508    /// given page.
509    ///
510    /// With a few exceptions, policies mostly involve specifying server origins
511    /// and script endpoints. This helps guard against cross-site scripting
512    /// attacks (XSS).
513    (ContentSecurityPolicy, CONTENT_SECURITY_POLICY, b"content-security-policy");
514
515    /// Allows experimenting with policies by monitoring their effects.
516    ///
517    /// The HTTP Content-Security-Policy-Report-Only response header allows web
518    /// developers to experiment with policies by monitoring (but not enforcing)
519    /// their effects. These violation reports consist of JSON documents sent
520    /// via an HTTP POST request to the specified URI.
521    (ContentSecurityPolicyReportOnly, CONTENT_SECURITY_POLICY_REPORT_ONLY, b"content-security-policy-report-only");
522
523    /// Used to indicate the media type of the resource.
524    ///
525    /// In responses, a Content-Type header tells the client what the content
526    /// type of the returned content actually is. Browsers will do MIME sniffing
527    /// in some cases and will not necessarily follow the value of this header;
528    /// to prevent this behavior, the header X-Content-Type-Options can be set
529    /// to nosniff.
530    ///
531    /// In requests, (such as POST or PUT), the client tells the server what
532    /// type of data is actually sent.
533    (ContentType, CONTENT_TYPE, b"content-type");
534
535    /// Contains stored HTTP cookies previously sent by the server with the
536    /// Set-Cookie header.
537    ///
538    /// The Cookie header might be omitted entirely, if the privacy setting of
539    /// the browser are set to block them, for example.
540    (Cookie, COOKIE, b"cookie");
541
542    /// Indicates the client's tracking preference.
543    ///
544    /// This header lets users indicate whether they would prefer privacy rather
545    /// than personalized content.
546    (Dnt, DNT, b"dnt");
547
548    /// Contains the date and time at which the message was originated.
549    (Date, DATE, b"date");
550
551    /// Identifier for a specific version of a resource.
552    ///
553    /// This header allows caches to be more efficient, and saves bandwidth, as
554    /// a web server does not need to send a full response if the content has
555    /// not changed. On the other side, if the content has changed, etags are
556    /// useful to help prevent simultaneous updates of a resource from
557    /// overwriting each other ("mid-air collisions").
558    ///
559    /// If the resource at a given URL changes, a new Etag value must be
560    /// generated. Etags are therefore similar to fingerprints and might also be
561    /// used for tracking purposes by some servers. A comparison of them allows
562    /// to quickly determine whether two representations of a resource are the
563    /// same, but they might also be set to persist indefinitely by a tracking
564    /// server.
565    (Etag, ETAG, b"etag");
566
567    /// Indicates expectations that need to be fulfilled by the server in order
568    /// to properly handle the request.
569    ///
570    /// The only expectation defined in the specification is Expect:
571    /// 100-continue, to which the server shall respond with:
572    ///
573    /// * 100 if the information contained in the header is sufficient to cause
574    /// an immediate success,
575    ///
576    /// * 417 (Expectation Failed) if it cannot meet the expectation; or any
577    /// other 4xx status otherwise.
578    ///
579    /// For example, the server may reject a request if its Content-Length is
580    /// too large.
581    ///
582    /// No common browsers send the Expect header, but some other clients such
583    /// as cURL do so by default.
584    (Expect, EXPECT, b"expect");
585
586    /// Contains the date/time after which the response is considered stale.
587    ///
588    /// Invalid dates, like the value 0, represent a date in the past and mean
589    /// that the resource is already expired.
590    ///
591    /// If there is a Cache-Control header with the "max-age" or "s-max-age"
592    /// directive in the response, the Expires header is ignored.
593    (Expires, EXPIRES, b"expires");
594
595    /// Contains information from the client-facing side of proxy servers that
596    /// is altered or lost when a proxy is involved in the path of the request.
597    ///
598    /// The alternative and de-facto standard versions of this header are the
599    /// X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Proto headers.
600    ///
601    /// This header is used for debugging, statistics, and generating
602    /// location-dependent content and by design it exposes privacy sensitive
603    /// information, such as the IP address of the client. Therefore the user's
604    /// privacy must be kept in mind when deploying this header.
605    (Forwarded, FORWARDED, b"forwarded");
606
607    /// Contains an Internet email address for a human user who controls the
608    /// requesting user agent.
609    ///
610    /// If you are running a robotic user agent (e.g. a crawler), the From
611    /// header should be sent, so you can be contacted if problems occur on
612    /// servers, such as if the robot is sending excessive, unwanted, or invalid
613    /// requests.
614    (From, FROM, b"from");
615
616    /// Specifies the domain name of the server and (optionally) the TCP port
617    /// number on which the server is listening.
618    ///
619    /// If no port is given, the default port for the service requested (e.g.,
620    /// "80" for an HTTP URL) is implied.
621    ///
622    /// A Host header field must be sent in all HTTP/1.1 request messages. A 400
623    /// (Bad Request) status code will be sent to any HTTP/1.1 request message
624    /// that lacks a Host header field or contains more than one.
625    (Host, HOST, b"host");
626
627    /// Makes a request conditional based on the E-Tag.
628    ///
629    /// For GET and HEAD methods, the server will send back the requested
630    /// resource only if it matches one of the listed ETags. For PUT and other
631    /// non-safe methods, it will only upload the resource in this case.
632    ///
633    /// The comparison with the stored ETag uses the strong comparison
634    /// algorithm, meaning two files are considered identical byte to byte only.
635    /// This is weakened when the  W/ prefix is used in front of the ETag.
636    ///
637    /// There are two common use cases:
638    ///
639    /// * For GET and HEAD methods, used in combination with an Range header, it
640    /// can guarantee that the new ranges requested comes from the same resource
641    /// than the previous one. If it doesn't match, then a 416 (Range Not
642    /// Satisfiable) response is returned.
643    ///
644    /// * For other methods, and in particular for PUT, If-Match can be used to
645    /// prevent the lost update problem. It can check if the modification of a
646    /// resource that the user wants to upload will not override another change
647    /// that has been done since the original resource was fetched. If the
648    /// request cannot be fulfilled, the 412 (Precondition Failed) response is
649    /// returned.
650    (IfMatch, IF_MATCH, b"if-match");
651
652    /// Makes a request conditional based on the modification date.
653    ///
654    /// The If-Modified-Since request HTTP header makes the request conditional:
655    /// the server will send back the requested resource, with a 200 status,
656    /// only if it has been last modified after the given date. If the request
657    /// has not been modified since, the response will be a 304 without any
658    /// body; the Last-Modified header will contain the date of last
659    /// modification. Unlike If-Unmodified-Since, If-Modified-Since can only be
660    /// used with a GET or HEAD.
661    ///
662    /// When used in combination with If-None-Match, it is ignored, unless the
663    /// server doesn't support If-None-Match.
664    ///
665    /// The most common use case is to update a cached entity that has no
666    /// associated ETag.
667    (IfModifiedSince, IF_MODIFIED_SINCE, b"if-modified-since");
668
669    /// Makes a request conditional based on the E-Tag.
670    ///
671    /// The If-None-Match HTTP request header makes the request conditional. For
672    /// GET and HEAD methods, the server will send back the requested resource,
673    /// with a 200 status, only if it doesn't have an ETag matching the given
674    /// ones. For other methods, the request will be processed only if the
675    /// eventually existing resource's ETag doesn't match any of the values
676    /// listed.
677    ///
678    /// When the condition fails for GET and HEAD methods, then the server must
679    /// return HTTP status code 304 (Not Modified). For methods that apply
680    /// server-side changes, the status code 412 (Precondition Failed) is used.
681    /// Note that the server generating a 304 response MUST generate any of the
682    /// following header fields that would have been sent in a 200 (OK) response
683    /// to the same request: Cache-Control, Content-Location, Date, ETag,
684    /// Expires, and Vary.
685    ///
686    /// The comparison with the stored ETag uses the weak comparison algorithm,
687    /// meaning two files are considered identical not only if they are
688    /// identical byte to byte, but if the content is equivalent. For example,
689    /// two pages that would differ only by the date of generation in the footer
690    /// would be considered as identical.
691    ///
692    /// When used in combination with If-Modified-Since, it has precedence (if
693    /// the server supports it).
694    ///
695    /// There are two common use cases:
696    ///
697    /// * For `GET` and `HEAD` methods, to update a cached entity that has an associated ETag.
698    /// * For other methods, and in particular for `PUT`, `If-None-Match` used with
699    /// the `*` value can be used to save a file not known to exist,
700    /// guaranteeing that another upload didn't happen before, losing the data
701    /// of the previous put; this problems is the variation of the lost update
702    /// problem.
703    (IfNoneMatch, IF_NONE_MATCH, b"if-none-match");
704
705    /// Makes a request conditional based on range.
706    ///
707    /// The If-Range HTTP request header makes a range request conditional: if
708    /// the condition is fulfilled, the range request will be issued and the
709    /// server sends back a 206 Partial Content answer with the appropriate
710    /// body. If the condition is not fulfilled, the full resource is sent back,
711    /// with a 200 OK status.
712    ///
713    /// This header can be used either with a Last-Modified validator, or with
714    /// an ETag, but not with both.
715    ///
716    /// The most common use case is to resume a download, to guarantee that the
717    /// stored resource has not been modified since the last fragment has been
718    /// received.
719    (IfRange, IF_RANGE, b"if-range");
720
721    /// Makes the request conditional based on the last modification date.
722    ///
723    /// The If-Unmodified-Since request HTTP header makes the request
724    /// conditional: the server will send back the requested resource, or accept
725    /// it in the case of a POST or another non-safe method, only if it has not
726    /// been last modified after the given date. If the request has been
727    /// modified after the given date, the response will be a 412 (Precondition
728    /// Failed) error.
729    ///
730    /// There are two common use cases:
731    ///
732    /// * In conjunction non-safe methods, like POST, it can be used to
733    /// implement an optimistic concurrency control, like done by some wikis:
734    /// editions are rejected if the stored document has been modified since the
735    /// original has been retrieved.
736    ///
737    /// * In conjunction with a range request with a If-Range header, it can be
738    /// used to ensure that the new fragment requested comes from an unmodified
739    /// document.
740    (IfUnmodifiedSince, IF_UNMODIFIED_SINCE, b"if-unmodified-since");
741
742    /// The Last-Modified header contains the date and time when the origin believes
743    /// the resource was last modified.
744    ///
745    /// The value is a valid Date/Time string defined in [RFC9910](https://datatracker.ietf.org/doc/html/rfc9110#section-5.6.7)
746    (LastModified, LAST_MODIFIED, b"last-modified");
747
748    /// Allows the server to point an interested client to another resource
749    /// containing metadata about the requested resource.
750    (Link, LINK, b"link");
751
752    /// Indicates the URL to redirect a page to.
753    ///
754    /// The Location response header indicates the URL to redirect a page to. It
755    /// only provides a meaning when served with a 3xx status response.
756    ///
757    /// The HTTP method used to make the new request to fetch the page pointed
758    /// to by Location depends of the original method and of the kind of
759    /// redirection:
760    ///
761    /// * If 303 (See Also) responses always lead to the use of a GET method,
762    /// 307 (Temporary Redirect) and 308 (Permanent Redirect) don't change the
763    /// method used in the original request;
764    ///
765    /// * 301 (Permanent Redirect) and 302 (Found) doesn't change the method
766    /// most of the time, though older user-agents may (so you basically don't
767    /// know).
768    ///
769    /// All responses with one of these status codes send a Location header.
770    ///
771    /// Beside redirect response, messages with 201 (Created) status also
772    /// include the Location header. It indicates the URL to the newly created
773    /// resource.
774    ///
775    /// Location and Content-Location are different: Location indicates the
776    /// target of a redirection (or the URL of a newly created resource), while
777    /// Content-Location indicates the direct URL to use to access the resource
778    /// when content negotiation happened, without the need of further content
779    /// negotiation. Location is a header associated with the response, while
780    /// Content-Location is associated with the entity returned.
781    (Location, LOCATION, b"location");
782
783    /// Indicates the max number of intermediaries the request should be sent
784    /// through.
785    (MaxForwards, MAX_FORWARDS, b"max-forwards");
786
787    /// Indicates where a fetch originates from.
788    ///
789    /// It doesn't include any path information, but only the server name. It is
790    /// sent with CORS requests, as well as with POST requests. It is similar to
791    /// the Referer header, but, unlike this header, it doesn't disclose the
792    /// whole path.
793    (Origin, ORIGIN, b"origin");
794
795    /// HTTP/1.0 header usually used for backwards compatibility.
796    ///
797    /// The Pragma HTTP/1.0 general header is an implementation-specific header
798    /// that may have various effects along the request-response chain. It is
799    /// used for backwards compatibility with HTTP/1.0 caches where the
800    /// Cache-Control HTTP/1.1 header is not yet present.
801    (Pragma, PRAGMA, b"pragma");
802
803    /// Defines the authentication method that should be used to gain access to
804    /// a proxy.
805    ///
806    /// Unlike `www-authenticate`, the `proxy-authenticate` header field applies
807    /// only to the next outbound client on the response chain. This is because
808    /// only the client that chose a given proxy is likely to have the
809    /// credentials necessary for authentication. However, when multiple proxies
810    /// are used within the same administrative domain, such as office and
811    /// regional caching proxies within a large corporate network, it is common
812    /// for credentials to be generated by the user agent and passed through the
813    /// hierarchy until consumed. Hence, in such a configuration, it will appear
814    /// as if Proxy-Authenticate is being forwarded because each proxy will send
815    /// the same challenge set.
816    ///
817    /// The `proxy-authenticate` header is sent along with a `407 Proxy
818    /// Authentication Required`.
819    (ProxyAuthenticate, PROXY_AUTHENTICATE, b"proxy-authenticate");
820
821    /// Contains the credentials to authenticate a user agent to a proxy server.
822    ///
823    /// This header is usually included after the server has responded with a
824    /// 407 Proxy Authentication Required status and the Proxy-Authenticate
825    /// header.
826    (ProxyAuthorization, PROXY_AUTHORIZATION, b"proxy-authorization");
827
828    /// Associates a specific cryptographic public key with a certain server.
829    ///
830    /// This decreases the risk of MITM attacks with forged certificates. If one
831    /// or several keys are pinned and none of them are used by the server, the
832    /// browser will not accept the response as legitimate, and will not display
833    /// it.
834    (PublicKeyPins, PUBLIC_KEY_PINS, b"public-key-pins");
835
836    /// Sends reports of pinning violation to the report-uri specified in the
837    /// header.
838    ///
839    /// Unlike `Public-Key-Pins`, this header still allows browsers to connect
840    /// to the server if the pinning is violated.
841    (PublicKeyPinsReportOnly, PUBLIC_KEY_PINS_REPORT_ONLY, b"public-key-pins-report-only");
842
843    /// Indicates the part of a document that the server should return.
844    ///
845    /// Several parts can be requested with one Range header at once, and the
846    /// server may send back these ranges in a multipart document. If the server
847    /// sends back ranges, it uses the 206 Partial Content for the response. If
848    /// the ranges are invalid, the server returns the 416 Range Not Satisfiable
849    /// error. The server can also ignore the Range header and return the whole
850    /// document with a 200 status code.
851    (Range, RANGE, b"range");
852
853    /// Contains the address of the previous web page from which a link to the
854    /// currently requested page was followed.
855    ///
856    /// The Referer header allows servers to identify where people are visiting
857    /// them from and may use that data for analytics, logging, or optimized
858    /// caching, for example.
859    (Referer, REFERER, b"referer");
860
861    /// Governs which referrer information should be included with requests
862    /// made.
863    (ReferrerPolicy, REFERRER_POLICY, b"referrer-policy");
864
865    /// Informs the web browser that the current page or frame should be
866    /// refreshed.
867    (Refresh, REFRESH, b"refresh");
868
869    /// The Retry-After response HTTP header indicates how long the user agent
870    /// should wait before making a follow-up request. There are two main cases
871    /// this header is used:
872    ///
873    /// * When sent with a 503 (Service Unavailable) response, it indicates how
874    /// long the service is expected to be unavailable.
875    ///
876    /// * When sent with a redirect response, such as 301 (Moved Permanently),
877    /// it indicates the minimum time that the user agent is asked to wait
878    /// before issuing the redirected request.
879    (RetryAfter, RETRY_AFTER, b"retry-after");
880
881    /// The |Sec-WebSocket-Accept| header field is used in the WebSocket
882    /// opening handshake. It is sent from the server to the client to
883    /// confirm that the server is willing to initiate the WebSocket
884    /// connection.
885    (SecWebSocketAccept, SEC_WEBSOCKET_ACCEPT, b"sec-websocket-accept");
886
887    /// The |Sec-WebSocket-Extensions| header field is used in the WebSocket
888    /// opening handshake. It is initially sent from the client to the
889    /// server, and then subsequently sent from the server to the client, to
890    /// agree on a set of protocol-level extensions to use for the duration
891    /// of the connection.
892    (SecWebSocketExtensions, SEC_WEBSOCKET_EXTENSIONS, b"sec-websocket-extensions");
893
894    /// The |Sec-WebSocket-Key| header field is used in the WebSocket opening
895    /// handshake. It is sent from the client to the server to provide part
896    /// of the information used by the server to prove that it received a
897    /// valid WebSocket opening handshake. This helps ensure that the server
898    /// does not accept connections from non-WebSocket clients (e.g., HTTP
899    /// clients) that are being abused to send data to unsuspecting WebSocket
900    /// servers.
901    (SecWebSocketKey, SEC_WEBSOCKET_KEY, b"sec-websocket-key");
902
903    /// The |Sec-WebSocket-Protocol| header field is used in the WebSocket
904    /// opening handshake. It is sent from the client to the server and back
905    /// from the server to the client to confirm the subprotocol of the
906    /// connection.  This enables scripts to both select a subprotocol and be
907    /// sure that the server agreed to serve that subprotocol.
908    (SecWebSocketProtocol, SEC_WEBSOCKET_PROTOCOL, b"sec-websocket-protocol");
909
910    /// The |Sec-WebSocket-Version| header field is used in the WebSocket
911    /// opening handshake.  It is sent from the client to the server to
912    /// indicate the protocol version of the connection.  This enables
913    /// servers to correctly interpret the opening handshake and subsequent
914    /// data being sent from the data, and close the connection if the server
915    /// cannot interpret that data in a safe manner.
916    (SecWebSocketVersion, SEC_WEBSOCKET_VERSION, b"sec-websocket-version");
917
918    /// Contains information about the software used by the origin server to
919    /// handle the request.
920    ///
921    /// Overly long and detailed Server values should be avoided as they
922    /// potentially reveal internal implementation details that might make it
923    /// (slightly) easier for attackers to find and exploit known security
924    /// holes.
925    (Server, SERVER, b"server");
926
927    /// Used to send cookies from the server to the user agent.
928    (SetCookie, SET_COOKIE, b"set-cookie");
929
930    /// Tells the client to communicate with HTTPS instead of using HTTP.
931    (StrictTransportSecurity, STRICT_TRANSPORT_SECURITY, b"strict-transport-security");
932
933    /// Informs the server of transfer encodings willing to be accepted as part
934    /// of the response.
935    ///
936    /// See also the Transfer-Encoding response header for more details on
937    /// transfer encodings. Note that chunked is always acceptable for HTTP/1.1
938    /// recipients and you that don't have to specify "chunked" using the TE
939    /// header. However, it is useful for setting if the client is accepting
940    /// trailer fields in a chunked transfer coding using the "trailers" value.
941    (Te, TE, b"te");
942
943    /// Allows the sender to include additional fields at the end of chunked
944    /// messages.
945    (Trailer, TRAILER, b"trailer");
946
947    /// Specifies the form of encoding used to safely transfer the entity to the
948    /// client.
949    ///
950    /// `transfer-encoding` is a hop-by-hop header, that is applying to a
951    /// message between two nodes, not to a resource itself. Each segment of a
952    /// multi-node connection can use different `transfer-encoding` values. If
953    /// you want to compress data over the whole connection, use the end-to-end
954    /// header `content-encoding` header instead.
955    ///
956    /// When present on a response to a `HEAD` request that has no body, it
957    /// indicates the value that would have applied to the corresponding `GET`
958    /// message.
959    (TransferEncoding, TRANSFER_ENCODING, b"transfer-encoding");
960
961    /// Contains a string that allows identifying the requesting client's
962    /// software.
963    (UserAgent, USER_AGENT, b"user-agent");
964
965    /// Used as part of the exchange to upgrade the protocol.
966    (Upgrade, UPGRADE, b"upgrade");
967
968    /// Sends a signal to the server expressing the client’s preference for an
969    /// encrypted and authenticated response.
970    (UpgradeInsecureRequests, UPGRADE_INSECURE_REQUESTS, b"upgrade-insecure-requests");
971
972    /// Determines how to match future requests with cached responses.
973    ///
974    /// The `vary` HTTP response header determines how to match future request
975    /// headers to decide whether a cached response can be used rather than
976    /// requesting a fresh one from the origin server. It is used by the server
977    /// to indicate which headers it used when selecting a representation of a
978    /// resource in a content negotiation algorithm.
979    ///
980    /// The `vary` header should be set on a 304 Not Modified response exactly
981    /// like it would have been set on an equivalent 200 OK response.
982    (Vary, VARY, b"vary");
983
984    /// Added by proxies to track routing.
985    ///
986    /// The `via` general header is added by proxies, both forward and reverse
987    /// proxies, and can appear in the request headers and the response headers.
988    /// It is used for tracking message forwards, avoiding request loops, and
989    /// identifying the protocol capabilities of senders along the
990    /// request/response chain.
991    (Via, VIA, b"via");
992
993    /// General HTTP header contains information about possible problems with
994    /// the status of the message.
995    ///
996    /// More than one `warning` header may appear in a response. Warning header
997    /// fields can in general be applied to any message, however some warn-codes
998    /// are specific to caches and can only be applied to response messages.
999    (Warning, WARNING, b"warning");
1000
1001    /// Defines the authentication method that should be used to gain access to
1002    /// a resource.
1003    (WwwAuthenticate, WWW_AUTHENTICATE, b"www-authenticate");
1004
1005    /// Marker used by the server to indicate that the MIME types advertised in
1006    /// the `content-type` headers should not be changed and be followed.
1007    ///
1008    /// This allows to opt-out of MIME type sniffing, or, in other words, it is
1009    /// a way to say that the webmasters knew what they were doing.
1010    ///
1011    /// This header was introduced by Microsoft in IE 8 as a way for webmasters
1012    /// to block content sniffing that was happening and could transform
1013    /// non-executable MIME types into executable MIME types. Since then, other
1014    /// browsers have introduced it, even if their MIME sniffing algorithms were
1015    /// less aggressive.
1016    ///
1017    /// Site security testers usually expect this header to be set.
1018    (XContentTypeOptions, X_CONTENT_TYPE_OPTIONS, b"x-content-type-options");
1019
1020    /// Controls DNS prefetching.
1021    ///
1022    /// The `x-dns-prefetch-control` HTTP response header controls DNS
1023    /// prefetching, a feature by which browsers proactively perform domain name
1024    /// resolution on both links that the user may choose to follow as well as
1025    /// URLs for items referenced by the document, including images, CSS,
1026    /// JavaScript, and so forth.
1027    ///
1028    /// This prefetching is performed in the background, so that the DNS is
1029    /// likely to have been resolved by the time the referenced items are
1030    /// needed. This reduces latency when the user clicks a link.
1031    (XDnsPrefetchControl, X_DNS_PREFETCH_CONTROL, b"x-dns-prefetch-control");
1032
1033    /// Indicates whether or not a browser should be allowed to render a page in
1034    /// a frame.
1035    ///
1036    /// Sites can use this to avoid clickjacking attacks, by ensuring that their
1037    /// content is not embedded into other sites.
1038    ///
1039    /// The added security is only provided if the user accessing the document
1040    /// is using a browser supporting `x-frame-options`.
1041    (XFrameOptions, X_FRAME_OPTIONS, b"x-frame-options");
1042
1043    /// Stop pages from loading when an XSS attack is detected.
1044    ///
1045    /// The HTTP X-XSS-Protection response header is a feature of Internet
1046    /// Explorer, Chrome and Safari that stops pages from loading when they
1047    /// detect reflected cross-site scripting (XSS) attacks. Although these
1048    /// protections are largely unnecessary in modern browsers when sites
1049    /// implement a strong Content-Security-Policy that disables the use of
1050    /// inline JavaScript ('unsafe-inline'), they can still provide protections
1051    /// for users of older web browsers that don't yet support CSP.
1052    (XXssProtection, X_XSS_PROTECTION, b"x-xss-protection");
1053
1054    // Conventional / non-IANA-registered header names (de-facto standards,
1055    // vendor headers, drafts) — first-class standard headers all the same.
1056
1057    /// `X-Forwarded-Host` — de-facto proxy host forwarding header.
1058    (XForwardedHost, X_FORWARDED_HOST, b"x-forwarded-host");
1059
1060    /// `X-Forwarded-For` — de-facto client-IP forwarding header.
1061    (XForwardedFor, X_FORWARDED_FOR, b"x-forwarded-for");
1062
1063    /// `X-Forwarded-Proto` — de-facto proxy scheme forwarding header.
1064    (XForwardedProto, X_FORWARDED_PROTO, b"x-forwarded-proto");
1065
1066    /// `X-Robots-Tag` — robots indexing directives.
1067    (XRobotsTag, X_ROBOTS_TAG, b"x-robots-tag");
1068
1069    /// `X-Clacks-Overhead` — GNU Terry Pratchett.
1070    (XClacksOverhead, X_CLACKS_OVERHEAD, b"x-clacks-overhead");
1071
1072    /// `Sec-GPC` — Global Privacy Control.
1073    (SecGpc, SEC_GPC, b"sec-gpc");
1074
1075    /// `Sec-Fetch-Site` — Fetch Metadata request header.
1076    (SecFetchSite, SEC_FETCH_SITE, b"sec-fetch-site");
1077
1078    /// `Permissions-Policy`.
1079    (PermissionsPolicy, PERMISSIONS_POLICY, b"permissions-policy");
1080
1081    /// `Cross-Origin-Embedder-Policy`.
1082    (CrossOriginEmbedderPolicy, CROSS_ORIGIN_EMBEDDER_POLICY, b"cross-origin-embedder-policy");
1083
1084    /// `Cross-Origin-Embedder-Policy-Report-Only`.
1085    (CrossOriginEmbedderPolicyReportOnly, CROSS_ORIGIN_EMBEDDER_POLICY_REPORT_ONLY, b"cross-origin-embedder-policy-report-only");
1086
1087    /// `Cross-Origin-Opener-Policy`.
1088    (CrossOriginOpenerPolicy, CROSS_ORIGIN_OPENER_POLICY, b"cross-origin-opener-policy");
1089
1090    /// `Cross-Origin-Opener-Policy-Report-Only`.
1091    (CrossOriginOpenerPolicyReportOnly, CROSS_ORIGIN_OPENER_POLICY_REPORT_ONLY, b"cross-origin-opener-policy-report-only");
1092
1093    /// `Cross-Origin-Resource-Policy`.
1094    (CrossOriginResourcePolicy, CROSS_ORIGIN_RESOURCE_POLICY, b"cross-origin-resource-policy");
1095
1096    /// `Keep-Alive` — HTTP/1.1 connection keep-alive parameters.
1097    (KeepAlive, KEEP_ALIVE, b"keep-alive");
1098
1099    /// `Proxy-Connection` — legacy hop-by-hop connection header.
1100    (ProxyConnection, PROXY_CONNECTION, b"proxy-connection");
1101
1102    /// `Last-Event-ID` — Server-Sent Events resumption id.
1103    (LastEventId, LAST_EVENT_ID, b"last-event-id");
1104
1105    /// `CF-Connecting-IP` — Cloudflare client IP.
1106    (CfConnectingIp, CF_CONNECTING_IP, b"cf-connecting-ip");
1107
1108    /// `True-Client-IP` — client-IP forwarding header.
1109    (TrueClientIp, TRUE_CLIENT_IP, b"true-client-ip");
1110
1111    /// `Client-IP` — client-IP forwarding header.
1112    (ClientIp, CLIENT_IP, b"client-ip");
1113
1114    /// `X-Client-IP` — client-IP forwarding header.
1115    (XClientIp, X_CLIENT_IP, b"x-client-ip");
1116
1117    /// `X-Real-IP` — client-IP forwarding header.
1118    (XRealIp, X_REAL_IP, b"x-real-ip");
1119
1120    /// `Access-Control-Allow-Private-Network` — Private Network Access (CORS).
1121    (AccessControlAllowPrivateNetwork, ACCESS_CONTROL_ALLOW_PRIVATE_NETWORK, b"access-control-allow-private-network");
1122
1123    /// `Access-Control-Request-Private-Network` — Private Network Access (CORS).
1124    (AccessControlRequestPrivateNetwork, ACCESS_CONTROL_REQUEST_PRIVATE_NETWORK, b"access-control-request-private-network");
1125
1126    /// `Sec-CH-Save-Data` — client hint.
1127    (SecChSaveData, SEC_CH_SAVE_DATA, b"sec-ch-save-data");
1128
1129    /// `Sec-CH-ECT` — effective connection type client hint.
1130    (SecChEct, SEC_CH_ECT, b"sec-ch-ect");
1131
1132    /// `Sec-CH-RTT` — round-trip-time client hint.
1133    (SecChRtt, SEC_CH_RTT, b"sec-ch-rtt");
1134
1135    /// `Sec-CH-Downlink` — downlink-speed client hint.
1136    (SecChDownlink, SEC_CH_DOWNLINK, b"sec-ch-downlink");
1137
1138    /// `Accept-CH` — client-hint negotiation (server-advertised).
1139    (AcceptCh, ACCEPT_CH, b"accept-ch");
1140
1141    /// `Critical-CH` — critical client-hint negotiation.
1142    (CriticalCh, CRITICAL_CH, b"critical-ch");
1143}
1144
1145#[derive(Debug, Clone, Copy)]
1146struct StandardName {
1147    header: StandardHeader,
1148    case: CaseMask,
1149}
1150
1151impl StandardName {
1152    #[inline]
1153    const fn new(header: StandardHeader, lower: &[u8], original: &[u8]) -> Self {
1154        Self {
1155            header,
1156            case: CaseMask::from_original(lower, original),
1157        }
1158    }
1159
1160    #[inline]
1161    fn as_str(&self) -> &'static str {
1162        self.header.as_str()
1163    }
1164
1165    fn as_original_str(&self) -> Cow<'static, str> {
1166        if self.case == CaseMask::LOWER {
1167            return Cow::Borrowed(self.as_str());
1168        }
1169
1170        let mut value = String::with_capacity(self.as_str().len());
1171        for (i, b) in self.as_str().bytes().enumerate() {
1172            let b = if self.case.is_upper(i) {
1173                b.to_ascii_uppercase()
1174            } else {
1175                b
1176            };
1177            value.push(char::from(b));
1178        }
1179        Cow::Owned(value)
1180    }
1181
1182    fn fmt_original(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1183        for (i, b) in self.as_str().bytes().enumerate() {
1184            let b = if self.case.is_upper(i) {
1185                b.to_ascii_uppercase()
1186            } else {
1187                b
1188            };
1189            f.write_str(unsafe { std::str::from_utf8_unchecked(std::slice::from_ref(&b)) })?;
1190        }
1191        Ok(())
1192    }
1193
1194    fn write_original<B: bytes::BufMut>(&self, dst: &mut B) {
1195        for (i, b) in self.as_str().bytes().enumerate() {
1196            let b = if self.case.is_upper(i) {
1197                b.to_ascii_uppercase()
1198            } else {
1199                b
1200            };
1201            dst.put_u8(b);
1202        }
1203    }
1204}
1205
1206/// Valid header name characters
1207///
1208/// ```not_rust
1209///       field-name     = token
1210///       separators     = "(" | ")" | "<" | ">" | "@"
1211///                      | "," | ";" | ":" | "\" | <">
1212///                      | "/" | "[" | "]" | "?" | "="
1213///                      | "{" | "}" | SP | HT
1214///       token          = 1*tchar
1215///       tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
1216///                      / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
1217///                      / DIGIT / ALPHA
1218///                      ; any VCHAR, except delimiters
1219/// ```
1220// HEADER_CHARS maps every byte that is 128 or larger to 0 so everything that is
1221// mapped by HEADER_CHARS, maps to a valid single-byte UTF-8 codepoint.
1222#[rustfmt::skip]
1223const HEADER_CHARS: [u8; 256] = [
1224    //  0      1      2      3      4      5      6      7      8      9
1225        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //   x
1226        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  1x
1227        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  2x
1228        0,     0,     0,  b'!',     0,  b'#',  b'$',  b'%',  b'&', b'\'', //  3x
1229        0,     0,  b'*',  b'+',     0,  b'-',  b'.',     0,  b'0',  b'1', //  4x
1230     b'2',  b'3',  b'4',  b'5',  b'6',  b'7',  b'8',  b'9',     0,     0, //  5x
1231        0,     0,     0,     0,     0,  b'a',  b'b',  b'c',  b'd',  b'e', //  6x
1232     b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm',  b'n',  b'o', //  7x
1233     b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w',  b'x',  b'y', //  8x
1234     b'z',     0,     0,     0,  b'^',  b'_',  b'`',  b'a',  b'b',  b'c', //  9x
1235     b'd',  b'e',  b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm', // 10x
1236     b'n',  b'o',  b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w', // 11x
1237     b'x',  b'y',  b'z',     0,  b'|',     0,  b'~',     0,     0,     0, // 12x
1238        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 13x
1239        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 14x
1240        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 15x
1241        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 16x
1242        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 17x
1243        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 18x
1244        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 19x
1245        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 20x
1246        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 21x
1247        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 22x
1248        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 23x
1249        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 24x
1250        0,     0,     0,     0,     0,     0                              // 25x
1251];
1252
1253/// Valid header name characters for HTTP/2.0 and HTTP/3.0
1254// HEADER_CHARS_H2 maps every byte that is 128 or larger to 0 so everything that is
1255// mapped by HEADER_CHARS_H2, maps to a valid single-byte UTF-8 codepoint.
1256#[rustfmt::skip]
1257const HEADER_CHARS_H2: [u8; 256] = [
1258    //  0      1      2      3      4      5      6      7      8      9
1259        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //   x
1260        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  1x
1261        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  2x
1262        0,     0,     0,  b'!',  b'"',  b'#',  b'$',  b'%',  b'&', b'\'', //  3x
1263        0,     0,  b'*',  b'+',     0,  b'-',  b'.',     0,  b'0',  b'1', //  4x
1264     b'2',  b'3',  b'4',  b'5',  b'6',  b'7',  b'8',  b'9',     0,     0, //  5x
1265        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  6x
1266        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  7x
1267        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  8x
1268        0,     0,     0,     0,  b'^',  b'_',  b'`',  b'a',  b'b',  b'c', //  9x
1269     b'd',  b'e',  b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm', // 10x
1270     b'n',  b'o',  b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w', // 11x
1271     b'x',  b'y',  b'z',     0,  b'|',     0,  b'~',     0,     0,     0, // 12x
1272        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 13x
1273        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 14x
1274        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 15x
1275        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 16x
1276        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 17x
1277        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 18x
1278        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 19x
1279        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 20x
1280        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 21x
1281        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 22x
1282        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 23x
1283        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 24x
1284        0,     0,     0,     0,     0,     0                              // 25x
1285];
1286
1287fn parse_hdr<'a>(
1288    data: &'a [u8],
1289    b: &'a mut [MaybeUninit<u8>; SCRATCH_BUF_SIZE],
1290    table: &[u8; 256],
1291) -> Result<HdrName<'a>, InvalidHeaderName> {
1292    match data.len() {
1293        0 => Err(InvalidHeaderName::new()),
1294        len @ 1..=SCRATCH_BUF_SIZE => {
1295            // Read from data into the buffer - transforming using `table` as we go
1296            data.iter()
1297                .zip(b.iter_mut())
1298                .for_each(|(index, out)| *out = MaybeUninit::new(table[*index as usize]));
1299            // Safety: len bytes of b were just initialized.
1300            let name: &'a [u8] = unsafe { slice_assume_init(&b[0..len]) };
1301            match StandardHeader::from_bytes(name) {
1302                Some(sh) => Ok(StandardName::new(sh, name, data).into()),
1303                None => {
1304                    if name.contains(&0) {
1305                        Err(InvalidHeaderName::new())
1306                    } else {
1307                        Ok(HdrName::custom(data, data == name))
1308                    }
1309                }
1310            }
1311        }
1312        SCRATCH_BUF_OVERFLOW..=super::MAX_HEADER_NAME_LEN => Ok(HdrName::custom(data, false)),
1313        _ => Err(InvalidHeaderName::new()),
1314    }
1315}
1316
1317impl<'a> From<StandardHeader> for HdrName<'a> {
1318    fn from(hdr: StandardHeader) -> HdrName<'a> {
1319        HdrName {
1320            inner: Repr::Standard(StandardName {
1321                header: hdr,
1322                case: CaseMask::LOWER,
1323            }),
1324        }
1325    }
1326}
1327
1328impl<'a> From<StandardName> for HdrName<'a> {
1329    fn from(name: StandardName) -> HdrName<'a> {
1330        HdrName {
1331            inner: Repr::Standard(name),
1332        }
1333    }
1334}
1335
1336impl HeaderName {
1337    /// Converts a slice of bytes to an HTTP header name.
1338    ///
1339    /// This function preserves the original header-name spelling while using
1340    /// HTTP's case-insensitive semantics for equality and hashing.
1341    pub fn from_bytes(src: &[u8]) -> Result<HeaderName, InvalidHeaderName> {
1342        let mut buf = uninit_u8_array();
1343        // Precondition: HEADER_CHARS is a valid table for parse_hdr().
1344        match parse_hdr(src, &mut buf, &HEADER_CHARS)?.inner {
1345            Repr::Standard(std) => Ok(std.into()),
1346            Repr::Custom(MaybeLower { buf, lower: true }) => {
1347                let buf = Bytes::copy_from_slice(buf);
1348                // Safety: the invariant on MaybeLower ensures buf is valid UTF-8.
1349                let val = unsafe { ByteStr::from_utf8_unchecked(buf) };
1350                Ok(Custom(val).into())
1351            }
1352            Repr::Custom(MaybeLower { buf, lower: false }) => {
1353                use bytes::BufMut;
1354                let mut dst = BytesMut::with_capacity(buf.len());
1355
1356                for b in buf.iter() {
1357                    // HEADER_CHARS maps all bytes to valid single-byte UTF-8
1358                    if HEADER_CHARS[*b as usize] == 0 {
1359                        return Err(InvalidHeaderName::new());
1360                    }
1361
1362                    dst.put_u8(*b);
1363                }
1364
1365                // Safety: the loop above maps all bytes in buf to valid single byte
1366                // UTF-8 before copying them into dst. This means that dst (and hence
1367                // dst.freeze()) is valid UTF-8.
1368                let val = unsafe { ByteStr::from_utf8_unchecked(dst.freeze()) };
1369
1370                Ok(Custom(val).into())
1371            }
1372        }
1373    }
1374
1375    /// Converts a slice of bytes to an HTTP header name.
1376    ///
1377    /// This function expects the input to only contain lowercase characters.
1378    /// This is useful when decoding HTTP/2.0 or HTTP/3.0 headers. Both
1379    /// require that all headers be represented in lower case.
1380    ///
1381    /// # Examples
1382    ///
1383    /// ```
1384    /// # use rama_http_types::header::*;
1385    ///
1386    /// // Parsing a lower case header
1387    /// let hdr = HeaderName::from_lowercase(b"content-length").unwrap();
1388    /// assert_eq!(CONTENT_LENGTH, hdr);
1389    ///
1390    /// // Parsing a header that contains uppercase characters
1391    /// assert!(HeaderName::from_lowercase(b"Content-Length").is_err());
1392    /// ```
1393    pub fn from_lowercase(src: &[u8]) -> Result<HeaderName, InvalidHeaderName> {
1394        let mut buf = uninit_u8_array();
1395        // Precondition: HEADER_CHARS_H2 is a valid table for parse_hdr()
1396        match parse_hdr(src, &mut buf, &HEADER_CHARS_H2)?.inner {
1397            Repr::Standard(std) => Ok(std.into()),
1398            Repr::Custom(MaybeLower { buf, lower: true }) => {
1399                let buf = Bytes::copy_from_slice(buf);
1400                // Safety: the invariant on MaybeLower ensures buf is valid UTF-8.
1401                let val = unsafe { ByteStr::from_utf8_unchecked(buf) };
1402                Ok(Custom(val).into())
1403            }
1404            Repr::Custom(MaybeLower { buf, lower: false }) => {
1405                for &b in buf.iter() {
1406                    // HEADER_CHARS_H2 maps all bytes that are not valid single-byte
1407                    // UTF-8 to 0 so this check returns an error for invalid UTF-8.
1408                    if HEADER_CHARS_H2[b as usize] == 0 {
1409                        return Err(InvalidHeaderName::new());
1410                    }
1411                }
1412
1413                let buf = Bytes::copy_from_slice(buf);
1414                // Safety: the loop above checks that each byte of buf (either
1415                // version) is valid UTF-8.
1416                let val = unsafe { ByteStr::from_utf8_unchecked(buf) };
1417                Ok(Custom(val).into())
1418            }
1419        }
1420    }
1421
1422    /// Converts a static string to a HTTP header name.
1423    ///
1424    /// This function preserves the original header-name spelling while using
1425    /// HTTP's case-insensitive semantics for equality and hashing.
1426    ///
1427    /// # Panics
1428    ///
1429    /// This function panics when the static string is a invalid header.
1430    ///
1431    /// # Examples
1432    ///
1433    /// ```
1434    /// # use rama_http_types::header::*;
1435    /// // Parsing a standard header
1436    /// let hdr = HeaderName::from_static("Content-Length");
1437    /// assert_eq!(CONTENT_LENGTH, hdr);
1438    ///
1439    /// // Parsing a custom header
1440    /// let CUSTOM_HEADER: &'static str = "custom-header";
1441    ///
1442    /// let a = HeaderName::from_bytes(b"Custom-Header").unwrap();
1443    /// let b = HeaderName::from_static(CUSTOM_HEADER);
1444    /// assert_eq!(a, b);
1445    /// ```
1446    ///
1447    /// ```should_panic
1448    /// # use rama_http_types::header::*;
1449    /// #
1450    /// // Parsing a header that contains invalid symbols:
1451    /// HeaderName::from_static("content{}{}length"); // This line panics!
1452    /// ```
1453    pub const fn from_static(src: &'static str) -> HeaderName {
1454        let name_bytes = src.as_bytes();
1455        if let Some(standard) = StandardHeader::from_bytes_ignore_case(name_bytes) {
1456            let lower = standard.as_bytes();
1457            return HeaderName {
1458                inner: Repr::Standard(StandardName::new(standard, lower, name_bytes)),
1459            };
1460        }
1461
1462        if name_bytes.is_empty() || name_bytes.len() > super::MAX_HEADER_NAME_LEN || {
1463            let mut i = 0;
1464            loop {
1465                if i >= name_bytes.len() {
1466                    break false;
1467                } else if HEADER_CHARS[name_bytes[i] as usize] == 0 {
1468                    break true;
1469                }
1470                i += 1;
1471            }
1472        } {
1473            // Invalid header name
1474            panic!("HeaderName::from_static with invalid bytes")
1475        }
1476
1477        HeaderName {
1478            inner: Repr::Custom(Custom(ByteStr::from_static(src))),
1479        }
1480    }
1481
1482    /// Returns a `str` representation of the header.
1483    ///
1484    /// Standard headers are returned in their normalized lowercase spelling.
1485    /// Custom headers are returned in their original spelling.
1486    #[inline]
1487    pub fn as_str(&self) -> &str {
1488        match self.inner {
1489            Repr::Standard(v) => v.as_str(),
1490            Repr::Custom(ref v) => &v.0,
1491        }
1492    }
1493
1494    /// Returns the preserved spelling of the header name.
1495    ///
1496    /// Standard headers with mixed or uppercase spelling may need to rebuild
1497    /// their original casing from the compact case mask, so this returns
1498    /// [`Cow`]. For display-only use, prefer [`Self::display_original`].
1499    #[inline]
1500    pub fn as_original_str(&self) -> Cow<'_, str> {
1501        match self.inner {
1502            Repr::Standard(v) => v.as_original_str(),
1503            Repr::Custom(ref v) => Cow::Borrowed(&v.0),
1504        }
1505    }
1506
1507    /// Returns the lowercase spelling of the header name.
1508    ///
1509    /// This borrows for standard headers and already-lowercase custom headers.
1510    /// Custom headers with uppercase ASCII letters are lowercased into an owned
1511    /// string. For display-only use, prefer [`Self::display_lowercase`].
1512    #[inline]
1513    pub fn as_lower_str(&self) -> Cow<'_, str> {
1514        match self.inner {
1515            Repr::Standard(v) => Cow::Borrowed(v.as_str()),
1516            Repr::Custom(ref v) => {
1517                if v.0.as_bytes().iter().any(u8::is_ascii_uppercase) {
1518                    Cow::Owned(lowercase_ascii(v.0.as_bytes()))
1519                } else {
1520                    Cow::Borrowed(&v.0)
1521                }
1522            }
1523        }
1524    }
1525
1526    /// Returns a display adapter that writes the preserved header spelling.
1527    #[inline]
1528    pub fn display_original(&self) -> OriginalHeaderName<'_> {
1529        OriginalHeaderName(self)
1530    }
1531
1532    /// Returns a display adapter that writes the lowercase header spelling.
1533    ///
1534    /// This is useful for HTTP/2 and HTTP/3 diagnostics or formatting. It does
1535    /// not allocate.
1536    #[inline]
1537    pub fn display_lowercase(&self) -> LowercaseHeaderName<'_> {
1538        LowercaseHeaderName(self)
1539    }
1540
1541    /// Returns the standard header represented by this name, if this is a
1542    /// standard header.
1543    #[inline]
1544    pub fn standard(&self) -> Option<StandardHeader> {
1545        match self.inner {
1546            Repr::Standard(v) => Some(v.header),
1547            Repr::Custom(_) => None,
1548        }
1549    }
1550
1551    /// Write the original header spelling represented by this name.
1552    ///
1553    /// For HTTP/2 and HTTP/3 use [`Self::write_lowercase`] instead.
1554    pub fn write_original<B: bytes::BufMut>(&self, dst: &mut B) {
1555        match self.inner {
1556            Repr::Standard(v) => v.write_original(dst),
1557            Repr::Custom(ref v) => dst.put_slice(v.0.as_bytes()),
1558        }
1559    }
1560
1561    /// Write the lowercase wire representation required by HTTP/2 and HTTP/3.
1562    pub fn write_lowercase<B: bytes::BufMut>(&self, dst: &mut B) {
1563        match self.inner {
1564            Repr::Standard(v) => dst.put_slice(v.as_str().as_bytes()),
1565            Repr::Custom(ref v) => {
1566                for &b in v.0.as_bytes() {
1567                    dst.put_u8(HEADER_CHARS[b as usize]);
1568                }
1569            }
1570        }
1571    }
1572
1573    pub(super) fn into_bytes(self) -> Bytes {
1574        self.inner.into()
1575    }
1576
1577    #[inline]
1578    fn eq_str(&self, other: &str) -> bool {
1579        eq_ignore_ascii_case(self.as_ref(), other.as_bytes())
1580    }
1581}
1582
1583impl FromStr for HeaderName {
1584    type Err = InvalidHeaderName;
1585
1586    fn from_str(s: &str) -> Result<HeaderName, InvalidHeaderName> {
1587        HeaderName::from_bytes(s.as_bytes()).map_err(|_| InvalidHeaderName { _priv: () })
1588    }
1589}
1590
1591impl AsRef<str> for HeaderName {
1592    fn as_ref(&self) -> &str {
1593        self.as_str()
1594    }
1595}
1596
1597impl AsRef<[u8]> for HeaderName {
1598    fn as_ref(&self) -> &[u8] {
1599        self.as_str().as_bytes()
1600    }
1601}
1602
1603impl fmt::Debug for HeaderName {
1604    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1605        fmt::Debug::fmt(&format_args!("{self}"), fmt)
1606    }
1607}
1608
1609impl fmt::Display for HeaderName {
1610    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1611        self.display_original().fmt(fmt)
1612    }
1613}
1614
1615impl fmt::Display for OriginalHeaderName<'_> {
1616    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1617        match self.0.inner {
1618            Repr::Standard(v) => v.fmt_original(fmt),
1619            Repr::Custom(ref v) => fmt.write_str(&v.0),
1620        }
1621    }
1622}
1623
1624impl fmt::Display for LowercaseHeaderName<'_> {
1625    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1626        match self.0.inner {
1627            Repr::Standard(v) => fmt.write_str(v.as_str()),
1628            Repr::Custom(ref v) => fmt_lowercase_ascii(fmt, v.0.as_bytes()),
1629        }
1630    }
1631}
1632
1633impl serde::Serialize for HeaderName {
1634    #[inline]
1635    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1636    where
1637        S: serde::Serializer,
1638    {
1639        serializer.serialize_str(&self.to_string())
1640    }
1641}
1642
1643impl<'de> serde::Deserialize<'de> for HeaderName {
1644    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1645    where
1646        D: serde::Deserializer<'de>,
1647    {
1648        let s = <std::borrow::Cow<'de, str>>::deserialize(deserializer)?;
1649        Self::from_bytes(s.as_bytes()).map_err(serde::de::Error::custom)
1650    }
1651}
1652
1653impl InvalidHeaderName {
1654    pub(super) fn new() -> InvalidHeaderName {
1655        InvalidHeaderName { _priv: () }
1656    }
1657}
1658
1659impl From<&HeaderName> for HeaderName {
1660    fn from(src: &HeaderName) -> HeaderName {
1661        src.clone()
1662    }
1663}
1664
1665#[doc(hidden)]
1666impl<T> From<Repr<T>> for Bytes
1667where
1668    T: Into<Bytes>,
1669{
1670    fn from(repr: Repr<T>) -> Bytes {
1671        match repr {
1672            Repr::Standard(header) => Bytes::from_static(header.as_str().as_bytes()),
1673            Repr::Custom(header) => header.into(),
1674        }
1675    }
1676}
1677
1678impl From<Custom> for Bytes {
1679    #[inline]
1680    fn from(Custom(inner): Custom) -> Bytes {
1681        Bytes::from(inner)
1682    }
1683}
1684
1685impl PartialEq for HeaderName {
1686    #[inline]
1687    fn eq(&self, other: &Self) -> bool {
1688        match (&self.inner, &other.inner) {
1689            (Repr::Standard(a), Repr::Standard(b)) => a.header == b.header,
1690            (Repr::Custom(a), Repr::Custom(b)) => {
1691                eq_ignore_ascii_case(a.0.as_bytes(), b.0.as_bytes())
1692            }
1693            _ => false,
1694        }
1695    }
1696}
1697
1698impl Eq for HeaderName {}
1699
1700impl Hash for HeaderName {
1701    #[inline]
1702    fn hash<H: Hasher>(&self, hasher: &mut H) {
1703        match self.inner {
1704            Repr::Standard(v) => v.header.hash(hasher),
1705            Repr::Custom(ref v) => v.hash(hasher),
1706        }
1707    }
1708}
1709
1710impl TryFrom<&str> for HeaderName {
1711    type Error = InvalidHeaderName;
1712    #[inline]
1713    fn try_from(s: &str) -> Result<Self, Self::Error> {
1714        Self::from_bytes(s.as_bytes())
1715    }
1716}
1717
1718impl TryFrom<&String> for HeaderName {
1719    type Error = InvalidHeaderName;
1720    #[inline]
1721    fn try_from(s: &String) -> Result<Self, Self::Error> {
1722        Self::from_bytes(s.as_bytes())
1723    }
1724}
1725
1726impl TryFrom<&[u8]> for HeaderName {
1727    type Error = InvalidHeaderName;
1728    #[inline]
1729    fn try_from(s: &[u8]) -> Result<Self, Self::Error> {
1730        Self::from_bytes(s)
1731    }
1732}
1733
1734impl TryFrom<String> for HeaderName {
1735    type Error = InvalidHeaderName;
1736
1737    #[inline]
1738    fn try_from(s: String) -> Result<Self, Self::Error> {
1739        Self::from_bytes(s.as_bytes())
1740    }
1741}
1742
1743impl TryFrom<Vec<u8>> for HeaderName {
1744    type Error = InvalidHeaderName;
1745
1746    #[inline]
1747    fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
1748        Self::from_bytes(&vec)
1749    }
1750}
1751
1752#[doc(hidden)]
1753impl From<StandardHeader> for HeaderName {
1754    fn from(src: StandardHeader) -> HeaderName {
1755        HeaderName {
1756            inner: Repr::Standard(StandardName {
1757                header: src,
1758                case: CaseMask::LOWER,
1759            }),
1760        }
1761    }
1762}
1763
1764impl From<StandardName> for HeaderName {
1765    fn from(src: StandardName) -> HeaderName {
1766        HeaderName {
1767            inner: Repr::Standard(src),
1768        }
1769    }
1770}
1771
1772#[doc(hidden)]
1773impl From<Custom> for HeaderName {
1774    fn from(src: Custom) -> HeaderName {
1775        HeaderName {
1776            inner: Repr::Custom(src),
1777        }
1778    }
1779}
1780
1781impl PartialEq<&HeaderName> for HeaderName {
1782    #[inline]
1783    fn eq(&self, other: &&HeaderName) -> bool {
1784        *self == **other
1785    }
1786}
1787
1788impl PartialEq<HeaderName> for &HeaderName {
1789    #[inline]
1790    fn eq(&self, other: &HeaderName) -> bool {
1791        *other == *self
1792    }
1793}
1794
1795impl PartialEq<str> for HeaderName {
1796    /// Performs a case-insensitive comparison of the string against the header
1797    /// name
1798    ///
1799    /// # Examples
1800    ///
1801    /// ```
1802    /// use rama_http_types::header::CONTENT_LENGTH;
1803    ///
1804    /// assert_eq!(CONTENT_LENGTH, "content-length");
1805    /// assert_eq!(CONTENT_LENGTH, "Content-Length");
1806    /// assert_ne!(CONTENT_LENGTH, "content length");
1807    /// ```
1808    #[inline]
1809    fn eq(&self, other: &str) -> bool {
1810        self.eq_str(other)
1811    }
1812}
1813
1814impl PartialEq<str> for &HeaderName {
1815    /// Performs a case-insensitive comparison of the string against the header
1816    /// name
1817    #[inline]
1818    fn eq(&self, other: &str) -> bool {
1819        (*self).eq_str(other)
1820    }
1821}
1822
1823impl PartialEq<HeaderName> for str {
1824    /// Performs a case-insensitive comparison of the string against the header
1825    /// name
1826    ///
1827    /// # Examples
1828    ///
1829    /// ```
1830    /// use rama_http_types::header::CONTENT_LENGTH;
1831    ///
1832    /// assert_eq!(CONTENT_LENGTH, "content-length");
1833    /// assert_eq!(CONTENT_LENGTH, "Content-Length");
1834    /// assert_ne!(CONTENT_LENGTH, "content length");
1835    /// ```
1836    #[inline]
1837    fn eq(&self, other: &HeaderName) -> bool {
1838        other.eq_str(self)
1839    }
1840}
1841
1842impl PartialEq<&HeaderName> for str {
1843    /// Performs a case-insensitive comparison of the string against the header
1844    /// name
1845    #[inline]
1846    fn eq(&self, other: &&HeaderName) -> bool {
1847        (*other).eq_str(self)
1848    }
1849}
1850
1851impl PartialEq<&str> for HeaderName {
1852    /// Performs a case-insensitive comparison of the string against the header
1853    /// name
1854    #[inline]
1855    fn eq(&self, other: &&str) -> bool {
1856        self.eq_str(other)
1857    }
1858}
1859
1860impl PartialEq<HeaderName> for &str {
1861    /// Performs a case-insensitive comparison of the string against the header
1862    /// name
1863    #[inline]
1864    fn eq(&self, other: &HeaderName) -> bool {
1865        other.eq_str(self)
1866    }
1867}
1868
1869impl PartialEq<String> for HeaderName {
1870    /// Performs a case-insensitive comparison of the string against the header
1871    /// name
1872    #[inline]
1873    fn eq(&self, other: &String) -> bool {
1874        self.eq_str(other)
1875    }
1876}
1877
1878impl PartialEq<String> for &HeaderName {
1879    /// Performs a case-insensitive comparison of the string against the header
1880    /// name
1881    #[inline]
1882    fn eq(&self, other: &String) -> bool {
1883        (*self).eq_str(other)
1884    }
1885}
1886
1887impl PartialEq<HeaderName> for String {
1888    /// Performs a case-insensitive comparison of the string against the header
1889    /// name
1890    #[inline]
1891    fn eq(&self, other: &HeaderName) -> bool {
1892        other.eq_str(self)
1893    }
1894}
1895
1896impl PartialEq<&HeaderName> for String {
1897    /// Performs a case-insensitive comparison of the string against the header
1898    /// name
1899    #[inline]
1900    fn eq(&self, other: &&HeaderName) -> bool {
1901        (*other).eq_str(self)
1902    }
1903}
1904
1905impl PartialEq<&String> for HeaderName {
1906    /// Performs a case-insensitive comparison of the string against the header
1907    /// name
1908    #[inline]
1909    fn eq(&self, other: &&String) -> bool {
1910        self.eq_str(other)
1911    }
1912}
1913
1914impl PartialEq<HeaderName> for &String {
1915    /// Performs a case-insensitive comparison of the string against the header
1916    /// name
1917    #[inline]
1918    fn eq(&self, other: &HeaderName) -> bool {
1919        other.eq_str(self)
1920    }
1921}
1922
1923impl fmt::Debug for InvalidHeaderName {
1924    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1925        f.debug_struct("InvalidHeaderName")
1926            // skip _priv noise
1927            .finish()
1928    }
1929}
1930
1931impl fmt::Display for InvalidHeaderName {
1932    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1933        f.write_str("invalid HTTP header name")
1934    }
1935}
1936
1937impl Error for InvalidHeaderName {}
1938
1939// ===== HdrName =====
1940
1941impl<'a> HdrName<'a> {
1942    // Precondition: if lower then buf is valid UTF-8
1943    fn custom(buf: &'a [u8], lower: bool) -> HdrName<'a> {
1944        HdrName {
1945            // Invariant (on MaybeLower): follows from the precondition
1946            inner: Repr::Custom(MaybeLower { buf, lower }),
1947        }
1948    }
1949
1950    pub fn from_bytes<F, U>(hdr: &[u8], f: F) -> Result<U, InvalidHeaderName>
1951    where
1952        F: FnOnce(HdrName<'_>) -> U,
1953    {
1954        let mut buf = uninit_u8_array();
1955        // Precondition: HEADER_CHARS is a valid table for parse_hdr().
1956        let hdr = parse_hdr(hdr, &mut buf, &HEADER_CHARS)?;
1957        Ok(f(hdr))
1958    }
1959
1960    pub fn from_static<F, U>(hdr: &'static str, f: F) -> U
1961    where
1962        F: FnOnce(HdrName<'_>) -> U,
1963    {
1964        let mut buf = uninit_u8_array();
1965        let hdr =
1966            // Precondition: HEADER_CHARS is a valid table for parse_hdr().
1967            parse_hdr(hdr.as_bytes(), &mut buf, &HEADER_CHARS).expect("static str is invalid name");
1968        f(hdr)
1969    }
1970}
1971
1972#[doc(hidden)]
1973impl<'a> From<HdrName<'a>> for HeaderName {
1974    fn from(src: HdrName<'a>) -> HeaderName {
1975        match src.inner {
1976            Repr::Standard(s) => HeaderName {
1977                inner: Repr::Standard(s),
1978            },
1979            Repr::Custom(maybe_lower) => {
1980                if maybe_lower.lower {
1981                    let buf = Bytes::copy_from_slice(maybe_lower.buf);
1982                    // Safety: the invariant on MaybeLower ensures buf is valid UTF-8.
1983                    let byte_str = unsafe { ByteStr::from_utf8_unchecked(buf) };
1984
1985                    HeaderName {
1986                        inner: Repr::Custom(Custom(byte_str)),
1987                    }
1988                } else {
1989                    use bytes::BufMut;
1990                    let mut dst = BytesMut::with_capacity(maybe_lower.buf.len());
1991
1992                    for b in maybe_lower.buf.iter() {
1993                        // HEADER_CHARS maps each byte to a valid single-byte UTF-8
1994                        // codepoint.
1995                        dst.put_u8(*b);
1996                    }
1997
1998                    // Safety: the loop above maps each byte of maybe_lower.buf to a
1999                    // valid single-byte UTF-8 codepoint before copying it into dst.
2000                    // dst (and hence dst.freeze()) is thus valid UTF-8.
2001                    let buf = unsafe { ByteStr::from_utf8_unchecked(dst.freeze()) };
2002
2003                    HeaderName {
2004                        inner: Repr::Custom(Custom(buf)),
2005                    }
2006                }
2007            }
2008        }
2009    }
2010}
2011
2012#[doc(hidden)]
2013impl<'a> PartialEq<HdrName<'a>> for HeaderName {
2014    #[inline]
2015    fn eq(&self, other: &HdrName<'a>) -> bool {
2016        match self.inner {
2017            Repr::Standard(a) => match other.inner {
2018                Repr::Standard(b) => a.header == b.header,
2019                _ => false,
2020            },
2021            Repr::Custom(Custom(ref a)) => match other.inner {
2022                Repr::Custom(ref b) => eq_ignore_ascii_case(a.as_bytes(), b.buf),
2023                _ => false,
2024            },
2025        }
2026    }
2027}
2028
2029// ===== Custom =====
2030
2031impl Hash for Custom {
2032    #[inline]
2033    fn hash<H: Hasher>(&self, hasher: &mut H) {
2034        for &b in self.0.as_bytes() {
2035            hasher.write(&[HEADER_CHARS[b as usize]]);
2036        }
2037    }
2038}
2039
2040// ===== MaybeLower =====
2041
2042impl<'a> Hash for MaybeLower<'a> {
2043    #[inline]
2044    fn hash<H: Hasher>(&self, hasher: &mut H) {
2045        if self.lower {
2046            hasher.write(self.buf);
2047        } else {
2048            for &b in self.buf {
2049                hasher.write(&[HEADER_CHARS[b as usize]]);
2050            }
2051        }
2052    }
2053}
2054
2055#[inline]
2056fn eq_ignore_ascii_case(lower: &[u8], s: &[u8]) -> bool {
2057    if lower.len() != s.len() {
2058        return false;
2059    }
2060
2061    lower
2062        .iter()
2063        .zip(s)
2064        .all(|(a, b)| HEADER_CHARS[*a as usize] == HEADER_CHARS[*b as usize])
2065}
2066
2067fn lowercase_ascii(bytes: &[u8]) -> String {
2068    let mut value = String::with_capacity(bytes.len());
2069    for &b in bytes {
2070        value.push(char::from(HEADER_CHARS[b as usize]));
2071    }
2072    value
2073}
2074
2075fn fmt_lowercase_ascii(fmt: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result {
2076    for &b in bytes {
2077        let b = HEADER_CHARS[b as usize];
2078        // Safety: header names are restricted to ASCII token bytes.
2079        fmt.write_str(unsafe { std::str::from_utf8_unchecked(std::slice::from_ref(&b)) })?;
2080    }
2081    Ok(())
2082}
2083
2084const fn eq_ignore_ascii_case_const(lower: &[u8], s: &[u8]) -> bool {
2085    if lower.len() != s.len() {
2086        return false;
2087    }
2088
2089    let mut i = 0;
2090    while i < lower.len() {
2091        if HEADER_CHARS[lower[i] as usize] != HEADER_CHARS[s[i] as usize] {
2092            return false;
2093        }
2094        i += 1;
2095    }
2096
2097    true
2098}
2099
2100// Utility functions for MaybeUninit<>. These are drawn from unstable API's on
2101// MaybeUninit<> itself.
2102const SCRATCH_BUF_SIZE: usize = 64;
2103const SCRATCH_BUF_OVERFLOW: usize = SCRATCH_BUF_SIZE + 1;
2104
2105fn uninit_u8_array() -> [MaybeUninit<u8>; SCRATCH_BUF_SIZE] {
2106    let arr = MaybeUninit::<[MaybeUninit<u8>; SCRATCH_BUF_SIZE]>::uninit();
2107    // Safety: assume_init() is claiming that an array of MaybeUninit<>
2108    // has been initialized, but MaybeUninit<>'s do not require initialization.
2109    unsafe { arr.assume_init() }
2110}
2111
2112// Assuming all the elements are initialized, get a slice of them.
2113//
2114// Safety: All elements of `slice` must be initialized to prevent
2115// undefined behavior.
2116unsafe fn slice_assume_init<T>(slice: &[MaybeUninit<T>]) -> &[T] {
2117    &*(slice as *const [MaybeUninit<T>] as *const [T])
2118}
2119
2120#[cfg(test)]
2121mod tests {
2122    use self::StandardHeader::Vary;
2123    use super::*;
2124
2125    #[test]
2126    fn test_bounds() {
2127        fn check_bounds<T: Sync + Send>() {}
2128        check_bounds::<HeaderName>();
2129    }
2130
2131    #[test]
2132    fn test_parse_invalid_headers() {
2133        for i in 0..128 {
2134            let hdr = vec![1u8; i];
2135            assert!(
2136                HeaderName::from_bytes(&hdr).is_err(),
2137                "{} invalid header chars did not fail",
2138                i
2139            );
2140        }
2141    }
2142
2143    const ONE_TOO_LONG: &[u8] = &[b'a'; super::super::MAX_HEADER_NAME_LEN + 1];
2144
2145    #[test]
2146    fn test_invalid_name_lengths() {
2147        assert!(
2148            HeaderName::from_bytes(&[]).is_err(),
2149            "zero-length header name is an error",
2150        );
2151
2152        let long = &ONE_TOO_LONG[0..super::super::MAX_HEADER_NAME_LEN];
2153
2154        let long_str = std::str::from_utf8(long).unwrap();
2155        assert_eq!(HeaderName::from_static(long_str), long_str); // shouldn't panic!
2156
2157        assert!(
2158            HeaderName::from_bytes(long).is_ok(),
2159            "max header name length is ok",
2160        );
2161        assert!(
2162            HeaderName::from_bytes(ONE_TOO_LONG).is_err(),
2163            "longer than max header name length is an error",
2164        );
2165    }
2166
2167    #[test]
2168    #[should_panic]
2169    fn test_static_invalid_name_lengths() {
2170        // Safety: ONE_TOO_LONG contains only the UTF-8 safe, single-byte codepoint b'a'.
2171        let _ = HeaderName::from_static(unsafe { std::str::from_utf8_unchecked(ONE_TOO_LONG) });
2172    }
2173
2174    #[test]
2175    fn test_from_hdr_name() {
2176        use self::StandardHeader::Vary;
2177
2178        let name = HeaderName::from(HdrName {
2179            inner: Repr::Standard(StandardName {
2180                header: Vary,
2181                case: CaseMask::LOWER,
2182            }),
2183        });
2184
2185        assert_eq!(name.standard(), Some(Vary));
2186        assert_eq!(name.to_string(), "vary");
2187
2188        let name = HeaderName::from(HdrName {
2189            inner: Repr::Custom(MaybeLower {
2190                buf: b"hello-world",
2191                lower: true,
2192            }),
2193        });
2194
2195        assert_eq!(name.as_str(), "hello-world");
2196
2197        let name = HeaderName::from(HdrName {
2198            inner: Repr::Custom(MaybeLower {
2199                buf: b"Hello-World",
2200                lower: false,
2201            }),
2202        });
2203
2204        assert_eq!(name.as_str(), "Hello-World");
2205        assert_eq!(name, "hello-world");
2206    }
2207
2208    #[test]
2209    fn test_eq_hdr_name() {
2210        use self::StandardHeader::Vary;
2211
2212        let a = HeaderName {
2213            inner: Repr::Standard(StandardName {
2214                header: Vary,
2215                case: CaseMask::LOWER,
2216            }),
2217        };
2218        let b = HdrName {
2219            inner: Repr::Standard(StandardName {
2220                header: Vary,
2221                case: CaseMask::LOWER,
2222            }),
2223        };
2224
2225        assert_eq!(a, b);
2226
2227        let a = HeaderName {
2228            inner: Repr::Custom(Custom(ByteStr::from_static("vaary"))),
2229        };
2230        assert_ne!(a, b);
2231
2232        let b = HdrName {
2233            inner: Repr::Custom(MaybeLower {
2234                buf: b"vaary",
2235                lower: true,
2236            }),
2237        };
2238
2239        assert_eq!(a, b);
2240
2241        let b = HdrName {
2242            inner: Repr::Custom(MaybeLower {
2243                buf: b"vaary",
2244                lower: false,
2245            }),
2246        };
2247
2248        assert_eq!(a, b);
2249
2250        let b = HdrName {
2251            inner: Repr::Custom(MaybeLower {
2252                buf: b"VAARY",
2253                lower: false,
2254            }),
2255        };
2256
2257        assert_eq!(a, b);
2258
2259        let a = HeaderName {
2260            inner: Repr::Standard(StandardName {
2261                header: Vary,
2262                case: CaseMask::LOWER,
2263            }),
2264        };
2265        assert_ne!(a, b);
2266    }
2267
2268    #[test]
2269    fn test_from_static_std() {
2270        let a = HeaderName {
2271            inner: Repr::Standard(StandardName {
2272                header: Vary,
2273                case: CaseMask::LOWER,
2274            }),
2275        };
2276
2277        let b = HeaderName::from_static("vary");
2278        assert_eq!(a, b);
2279
2280        let b = HeaderName::from_static("vaary");
2281        assert_ne!(a, b);
2282    }
2283
2284    #[test]
2285    fn test_from_static_std_uppercase() {
2286        let name = HeaderName::from_static("Vary");
2287        assert_eq!(name.standard(), Some(Vary));
2288        assert_eq!(name.to_string(), "Vary");
2289    }
2290
2291    #[test]
2292    fn test_original_and_lowercase_views() {
2293        let standard = HeaderName::from_static("Content-Length");
2294        assert_eq!(standard.as_str(), "content-length");
2295        assert!(matches!(standard.as_original_str(), Cow::Owned(_)));
2296        assert!(matches!(standard.as_lower_str(), Cow::Borrowed(_)));
2297        assert_eq!(standard.as_original_str(), "Content-Length");
2298        assert_eq!(standard.as_lower_str(), "content-length");
2299        assert_eq!(standard.display_original().to_string(), "Content-Length");
2300        assert_eq!(standard.display_lowercase().to_string(), "content-length");
2301
2302        let lower_standard = HeaderName::from_static("content-length");
2303        assert!(matches!(lower_standard.as_original_str(), Cow::Borrowed(_)));
2304        assert!(matches!(lower_standard.as_lower_str(), Cow::Borrowed(_)));
2305
2306        let custom = HeaderName::from_static("X-CuStOm");
2307        assert_eq!(custom.as_str(), "X-CuStOm");
2308        assert!(matches!(custom.as_original_str(), Cow::Borrowed(_)));
2309        assert!(matches!(custom.as_lower_str(), Cow::Owned(_)));
2310        assert_eq!(custom.as_original_str(), "X-CuStOm");
2311        assert_eq!(custom.as_lower_str(), "x-custom");
2312        assert_eq!(custom.display_original().to_string(), "X-CuStOm");
2313        assert_eq!(custom.display_lowercase().to_string(), "x-custom");
2314
2315        let lower_custom = HeaderName::from_static("x-custom");
2316        assert!(matches!(lower_custom.as_original_str(), Cow::Borrowed(_)));
2317        assert!(matches!(lower_custom.as_lower_str(), Cow::Borrowed(_)));
2318    }
2319
2320    #[test]
2321    fn test_string_comparisons() {
2322        let name = HeaderName::from_static("X-Rama-Custom-Header-Marker");
2323        let marker = String::from("x-rama-custom-header-marker");
2324
2325        assert_eq!(name, "x-rama-custom-header-marker");
2326        assert_eq!(name, "X-RAMA-CUSTOM-HEADER-MARKER");
2327        assert_eq!("x-rama-custom-header-marker", name);
2328        assert_eq!("X-RAMA-CUSTOM-HEADER-MARKER", name);
2329
2330        assert_eq!(&name, "x-rama-custom-header-marker");
2331        assert_eq!(&name, &marker);
2332        assert_eq!(marker, &name);
2333
2334        let entries = [(&name, ())];
2335        assert!(
2336            entries
2337                .iter()
2338                .find(|(name, _)| *name == "x-rama-custom-header-marker")
2339                .is_some()
2340        );
2341    }
2342
2343    #[test]
2344    #[should_panic]
2345    fn test_from_static_std_symbol() {
2346        HeaderName::from_static("vary{}");
2347    }
2348
2349    // MaybeLower { lower: true }
2350    #[test]
2351    fn test_from_static_custom_short() {
2352        let a = HeaderName {
2353            inner: Repr::Custom(Custom(ByteStr::from_static("customheader"))),
2354        };
2355        let b = HeaderName::from_static("customheader");
2356        assert_eq!(a, b);
2357    }
2358
2359    #[test]
2360    fn test_from_static_custom_short_uppercase() {
2361        let name = HeaderName::from_static("CustomHeader");
2362        assert_eq!(name.as_str(), "CustomHeader");
2363        assert_eq!(name, "customheader");
2364    }
2365
2366    #[test]
2367    #[should_panic]
2368    fn test_from_static_custom_short_symbol() {
2369        HeaderName::from_static("Custom{Header");
2370    }
2371
2372    // MaybeLower { lower: false }
2373    #[test]
2374    fn test_from_static_custom_long() {
2375        let a = HeaderName {
2376            inner: Repr::Custom(Custom(ByteStr::from_static(
2377                "longer-than-63--thisheaderislongerthansixtythreecharactersandthushandleddifferent",
2378            ))),
2379        };
2380        let b = HeaderName::from_static(
2381            "longer-than-63--thisheaderislongerthansixtythreecharactersandthushandleddifferent",
2382        );
2383        assert_eq!(a, b);
2384    }
2385
2386    #[test]
2387    fn test_from_static_custom_long_uppercase() {
2388        let name = HeaderName::from_static(
2389            "Longer-Than-63--ThisHeaderIsLongerThanSixtyThreeCharactersAndThusHandledDifferent",
2390        );
2391        assert_eq!(
2392            name.as_str(),
2393            "Longer-Than-63--ThisHeaderIsLongerThanSixtyThreeCharactersAndThusHandledDifferent"
2394        );
2395        assert_eq!(
2396            name,
2397            "longer-than-63--thisheaderislongerthansixtythreecharactersandthushandleddifferent"
2398        );
2399    }
2400
2401    #[test]
2402    #[should_panic]
2403    fn test_from_static_custom_long_symbol() {
2404        HeaderName::from_static(
2405            "longer-than-63--thisheader{}{}{}{}islongerthansixtythreecharactersandthushandleddifferent",
2406        );
2407    }
2408
2409    #[test]
2410    fn test_from_static_custom_single_char() {
2411        let a = HeaderName {
2412            inner: Repr::Custom(Custom(ByteStr::from_static("a"))),
2413        };
2414        let b = HeaderName::from_static("a");
2415        assert_eq!(a, b);
2416    }
2417
2418    #[test]
2419    #[should_panic]
2420    fn test_from_static_empty() {
2421        HeaderName::from_static("");
2422    }
2423
2424    #[test]
2425    fn test_all_tokens() {
2426        HeaderName::from_static("!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyz");
2427    }
2428
2429    #[test]
2430    fn test_from_lowercase() {
2431        HeaderName::from_lowercase(&[0; 10]).unwrap_err();
2432        HeaderName::from_lowercase(&[b'A'; 10]).unwrap_err();
2433        HeaderName::from_lowercase(&[0x1; 10]).unwrap_err();
2434        HeaderName::from_lowercase(&[0xFF; 10]).unwrap_err();
2435        //HeaderName::from_lowercase(&[0; 100]).unwrap_err();
2436        HeaderName::from_lowercase(&[b'A'; 100]).unwrap_err();
2437        HeaderName::from_lowercase(&[0x1; 100]).unwrap_err();
2438        HeaderName::from_lowercase(&[0xFF; 100]).unwrap_err();
2439    }
2440}