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