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}