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