| 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 | fn as_str(&self) -> &'static str { |
| 89 | match *self { |
| 90 | // Safety: test_parse_standard_headers ensures these &[u8]s are &str-safe. |
| 91 | $( |
| 92 | StandardHeader::$konst => unsafe { std::str::from_utf8_unchecked( $name_bytes ) }, |
| 93 | )+ |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | const fn from_bytes(name_bytes: &[u8]) -> Option<StandardHeader> { |
| 98 | match name_bytes { |
| 99 | $( |
| 100 | $name_bytes => Some(StandardHeader::$konst), |
| 101 | )+ |
| 102 | _ => None, |
| 103 | } |
| 104 | } |
| 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 | fn parse_hdr<'a>( |
| 1074 | data: &'a [u8], |
| 1075 | b: &'a mut [MaybeUninit<u8>; SCRATCH_BUF_SIZE], |
| 1076 | table: &[u8; 256], |
| 1077 | ) -> Result<HdrName<'a>, InvalidHeaderName> { |
| 1078 | match data.len() { |
| 1079 | 0 => Err(InvalidHeaderName::new()), |
| 1080 | len @ 1..=SCRATCH_BUF_SIZE => { |
| 1081 | // Read from data into the buffer - transforming using `table` as we go |
| 1082 | data.iter() |
| 1083 | .zip(b.iter_mut()) |
| 1084 | .for_each(|(index, out)| *out = MaybeUninit::new(table[*index as usize])); |
| 1085 | // Safety: len bytes of b were just initialized. |
| 1086 | let name: &'a [u8] = unsafe { slice_assume_init(&b[0..len]) }; |
| 1087 | match StandardHeader::from_bytes(name) { |
| 1088 | Some(sh) => Ok(sh.into()), |
| 1089 | None => { |
| 1090 | if name.contains(&0) { |
| 1091 | Err(InvalidHeaderName::new()) |
| 1092 | } else { |
| 1093 | Ok(HdrName::custom(name, true)) |
| 1094 | } |
| 1095 | } |
| 1096 | } |
| 1097 | } |
| 1098 | SCRATCH_BUF_OVERFLOW..=super::MAX_HEADER_NAME_LEN => Ok(HdrName::custom(data, false)), |
| 1099 | _ => Err(InvalidHeaderName::new()), |
| 1100 | } |
| 1101 | } |
| 1102 | |
| 1103 | impl<'a> From<StandardHeader> for HdrName<'a> { |
| 1104 | fn from(hdr: StandardHeader) -> HdrName<'a> { |
| 1105 | HdrName { |
| 1106 | inner: Repr::Standard(hdr), |
| 1107 | } |
| 1108 | } |
| 1109 | } |
| 1110 | |
| 1111 | impl HeaderName { |
| 1112 | /// Converts a slice of bytes to an HTTP header name. |
| 1113 | /// |
| 1114 | /// This function normalizes the input. |
| 1115 | pub fn from_bytes(src: &[u8]) -> Result<HeaderName, InvalidHeaderName> { |
| 1116 | let mut buf = uninit_u8_array(); |
| 1117 | // Precondition: HEADER_CHARS is a valid table for parse_hdr(). |
| 1118 | match parse_hdr(src, &mut buf, &HEADER_CHARS)?.inner { |
| 1119 | Repr::Standard(std) => Ok(std.into()), |
| 1120 | Repr::Custom(MaybeLower { buf, lower: true }) => { |
| 1121 | let buf = Bytes::copy_from_slice(buf); |
| 1122 | // Safety: the invariant on MaybeLower ensures buf is valid UTF-8. |
| 1123 | let val = unsafe { ByteStr::from_utf8_unchecked(buf) }; |
| 1124 | Ok(Custom(val).into()) |
| 1125 | } |
| 1126 | Repr::Custom(MaybeLower { buf, lower: false }) => { |
| 1127 | use bytes::BufMut; |
| 1128 | let mut dst = BytesMut::with_capacity(buf.len()); |
| 1129 | |
| 1130 | for b in buf.iter() { |
| 1131 | // HEADER_CHARS maps all bytes to valid single-byte UTF-8 |
| 1132 | let b = HEADER_CHARS[*b as usize]; |
| 1133 | |
| 1134 | if b == 0 { |
| 1135 | return Err(InvalidHeaderName::new()); |
| 1136 | } |
| 1137 | |
| 1138 | 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 | let val = unsafe { ByteStr::from_utf8_unchecked(dst.freeze()) }; |
| 1145 | |
| 1146 | Ok(Custom(val).into()) |
| 1147 | } |
| 1148 | } |
| 1149 | } |
| 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 | pub fn from_lowercase(src: &[u8]) -> Result<HeaderName, InvalidHeaderName> { |
| 1170 | let mut buf = uninit_u8_array(); |
| 1171 | // Precondition: HEADER_CHARS_H2 is a valid table for parse_hdr() |
| 1172 | match parse_hdr(src, &mut buf, &HEADER_CHARS_H2)?.inner { |
| 1173 | Repr::Standard(std) => Ok(std.into()), |
| 1174 | Repr::Custom(MaybeLower { buf, lower: true }) => { |
| 1175 | let buf = Bytes::copy_from_slice(buf); |
| 1176 | // Safety: the invariant on MaybeLower ensures buf is valid UTF-8. |
| 1177 | let val = unsafe { ByteStr::from_utf8_unchecked(buf) }; |
| 1178 | Ok(Custom(val).into()) |
| 1179 | } |
| 1180 | Repr::Custom(MaybeLower { buf, lower: false }) => { |
| 1181 | 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 | if HEADER_CHARS_H2[b as usize] == 0 { |
| 1185 | return Err(InvalidHeaderName::new()); |
| 1186 | } |
| 1187 | } |
| 1188 | |
| 1189 | let buf = Bytes::copy_from_slice(buf); |
| 1190 | // Safety: the loop above checks that each byte of buf (either |
| 1191 | // version) is valid UTF-8. |
| 1192 | let val = unsafe { ByteStr::from_utf8_unchecked(buf) }; |
| 1193 | Ok(Custom(val).into()) |
| 1194 | } |
| 1195 | } |
| 1196 | } |
| 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 | pub const fn from_static(src: &'static str) -> HeaderName { |
| 1257 | let name_bytes = src.as_bytes(); |
| 1258 | if let Some(standard) = StandardHeader::from_bytes(name_bytes) { |
| 1259 | return HeaderName { |
| 1260 | inner: Repr::Standard(standard), |
| 1261 | }; |
| 1262 | } |
| 1263 | |
| 1264 | if name_bytes.is_empty() || name_bytes.len() > super::MAX_HEADER_NAME_LEN || { |
| 1265 | let mut i = 0; |
| 1266 | loop { |
| 1267 | if i >= name_bytes.len() { |
| 1268 | break false; |
| 1269 | } else if HEADER_CHARS_H2[name_bytes[i] as usize] == 0 { |
| 1270 | break true; |
| 1271 | } |
| 1272 | i += 1; |
| 1273 | } |
| 1274 | } { |
| 1275 | // TODO: When msrv is bumped to larger than 1.57, this should be |
| 1276 | // replaced with `panic!` macro. |
| 1277 | // https://blog.rust-lang.org/2021/12/02/Rust-1.57.0.html#panic-in-const-contexts |
| 1278 | // |
| 1279 | // See the panics section of this method's document for details. |
| 1280 | #[allow (clippy::no_effect, clippy::out_of_bounds_indexing)] |
| 1281 | ([] as [u8; 0])[0]; // Invalid header name |
| 1282 | } |
| 1283 | |
| 1284 | HeaderName { |
| 1285 | inner: Repr::Custom(Custom(ByteStr::from_static(src))), |
| 1286 | } |
| 1287 | } |
| 1288 | |
| 1289 | /// Returns a `str` representation of the header. |
| 1290 | /// |
| 1291 | /// The returned string will always be lower case. |
| 1292 | #[inline ] |
| 1293 | pub fn as_str(&self) -> &str { |
| 1294 | match self.inner { |
| 1295 | Repr::Standard(v) => v.as_str(), |
| 1296 | Repr::Custom(ref v) => &v.0, |
| 1297 | } |
| 1298 | } |
| 1299 | |
| 1300 | pub(super) fn into_bytes(self) -> Bytes { |
| 1301 | self.inner.into() |
| 1302 | } |
| 1303 | } |
| 1304 | |
| 1305 | impl FromStr for HeaderName { |
| 1306 | type Err = InvalidHeaderName; |
| 1307 | |
| 1308 | fn from_str(s: &str) -> Result<HeaderName, InvalidHeaderName> { |
| 1309 | HeaderName::from_bytes(s.as_bytes()).map_err(|_| InvalidHeaderName { _priv: () }) |
| 1310 | } |
| 1311 | } |
| 1312 | |
| 1313 | impl AsRef<str> for HeaderName { |
| 1314 | fn as_ref(&self) -> &str { |
| 1315 | self.as_str() |
| 1316 | } |
| 1317 | } |
| 1318 | |
| 1319 | impl AsRef<[u8]> for HeaderName { |
| 1320 | fn as_ref(&self) -> &[u8] { |
| 1321 | self.as_str().as_bytes() |
| 1322 | } |
| 1323 | } |
| 1324 | |
| 1325 | impl Borrow<str> for HeaderName { |
| 1326 | fn borrow(&self) -> &str { |
| 1327 | self.as_str() |
| 1328 | } |
| 1329 | } |
| 1330 | |
| 1331 | impl fmt::Debug for HeaderName { |
| 1332 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1333 | fmt::Debug::fmt(self.as_str(), f:fmt) |
| 1334 | } |
| 1335 | } |
| 1336 | |
| 1337 | impl fmt::Display for HeaderName { |
| 1338 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1339 | fmt::Display::fmt(self.as_str(), f:fmt) |
| 1340 | } |
| 1341 | } |
| 1342 | |
| 1343 | impl InvalidHeaderName { |
| 1344 | pub(super) fn new() -> InvalidHeaderName { |
| 1345 | InvalidHeaderName { _priv: () } |
| 1346 | } |
| 1347 | } |
| 1348 | |
| 1349 | impl<'a> From<&'a HeaderName> for HeaderName { |
| 1350 | fn from(src: &'a HeaderName) -> HeaderName { |
| 1351 | src.clone() |
| 1352 | } |
| 1353 | } |
| 1354 | |
| 1355 | #[doc (hidden)] |
| 1356 | impl<T> From<Repr<T>> for Bytes |
| 1357 | where |
| 1358 | T: Into<Bytes>, |
| 1359 | { |
| 1360 | fn from(repr: Repr<T>) -> Bytes { |
| 1361 | match repr { |
| 1362 | Repr::Standard(header: StandardHeader) => Bytes::from_static(header.as_str().as_bytes()), |
| 1363 | Repr::Custom(header: T) => header.into(), |
| 1364 | } |
| 1365 | } |
| 1366 | } |
| 1367 | |
| 1368 | impl From<Custom> for Bytes { |
| 1369 | #[inline ] |
| 1370 | fn from(Custom(inner: ByteStr): Custom) -> Bytes { |
| 1371 | Bytes::from(inner) |
| 1372 | } |
| 1373 | } |
| 1374 | |
| 1375 | impl<'a> TryFrom<&'a str> for HeaderName { |
| 1376 | type Error = InvalidHeaderName; |
| 1377 | #[inline ] |
| 1378 | fn try_from(s: &'a str) -> Result<Self, Self::Error> { |
| 1379 | Self::from_bytes(src:s.as_bytes()) |
| 1380 | } |
| 1381 | } |
| 1382 | |
| 1383 | impl<'a> TryFrom<&'a String> for HeaderName { |
| 1384 | type Error = InvalidHeaderName; |
| 1385 | #[inline ] |
| 1386 | fn try_from(s: &'a String) -> Result<Self, Self::Error> { |
| 1387 | Self::from_bytes(src:s.as_bytes()) |
| 1388 | } |
| 1389 | } |
| 1390 | |
| 1391 | impl<'a> TryFrom<&'a [u8]> for HeaderName { |
| 1392 | type Error = InvalidHeaderName; |
| 1393 | #[inline ] |
| 1394 | fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> { |
| 1395 | Self::from_bytes(src:s) |
| 1396 | } |
| 1397 | } |
| 1398 | |
| 1399 | impl TryFrom<String> for HeaderName { |
| 1400 | type Error = InvalidHeaderName; |
| 1401 | |
| 1402 | #[inline ] |
| 1403 | fn try_from(s: String) -> Result<Self, Self::Error> { |
| 1404 | Self::from_bytes(src:s.as_bytes()) |
| 1405 | } |
| 1406 | } |
| 1407 | |
| 1408 | impl TryFrom<Vec<u8>> for HeaderName { |
| 1409 | type Error = InvalidHeaderName; |
| 1410 | |
| 1411 | #[inline ] |
| 1412 | fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> { |
| 1413 | Self::from_bytes(&vec) |
| 1414 | } |
| 1415 | } |
| 1416 | |
| 1417 | #[doc (hidden)] |
| 1418 | impl From<StandardHeader> for HeaderName { |
| 1419 | fn from(src: StandardHeader) -> HeaderName { |
| 1420 | HeaderName { |
| 1421 | inner: Repr::Standard(src), |
| 1422 | } |
| 1423 | } |
| 1424 | } |
| 1425 | |
| 1426 | #[doc (hidden)] |
| 1427 | impl From<Custom> for HeaderName { |
| 1428 | fn from(src: Custom) -> HeaderName { |
| 1429 | HeaderName { |
| 1430 | inner: Repr::Custom(src), |
| 1431 | } |
| 1432 | } |
| 1433 | } |
| 1434 | |
| 1435 | impl<'a> PartialEq<&'a HeaderName> for HeaderName { |
| 1436 | #[inline ] |
| 1437 | fn eq(&self, other: &&'a HeaderName) -> bool { |
| 1438 | *self == **other |
| 1439 | } |
| 1440 | } |
| 1441 | |
| 1442 | impl<'a> PartialEq<HeaderName> for &'a HeaderName { |
| 1443 | #[inline ] |
| 1444 | fn eq(&self, other: &HeaderName) -> bool { |
| 1445 | *other == *self |
| 1446 | } |
| 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 | fn eq(&self, other: &str) -> bool { |
| 1464 | eq_ignore_ascii_case(self.as_ref(), s:other.as_bytes()) |
| 1465 | } |
| 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 | fn eq(&self, other: &HeaderName) -> bool { |
| 1483 | *other == *self |
| 1484 | } |
| 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 | fn eq(&self, other: &&'a str) -> bool { |
| 1492 | *self == **other |
| 1493 | } |
| 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 | fn eq(&self, other: &HeaderName) -> bool { |
| 1501 | *other == *self |
| 1502 | } |
| 1503 | } |
| 1504 | |
| 1505 | impl fmt::Debug for InvalidHeaderName { |
| 1506 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 1507 | fDebugStruct<'_, '_>.debug_struct(name:"InvalidHeaderName" ) |
| 1508 | // skip _priv noise |
| 1509 | .finish() |
| 1510 | } |
| 1511 | } |
| 1512 | |
| 1513 | impl fmt::Display for InvalidHeaderName { |
| 1514 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1515 | f.write_str(data:"invalid HTTP header name" ) |
| 1516 | } |
| 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 | fn custom(buf: &'a [u8], lower: bool) -> HdrName<'a> { |
| 1526 | HdrName { |
| 1527 | // Invariant (on MaybeLower): follows from the precondition |
| 1528 | inner: Repr::Custom(MaybeLower { buf, lower }), |
| 1529 | } |
| 1530 | } |
| 1531 | |
| 1532 | pub fn from_bytes<F, U>(hdr: &[u8], f: F) -> Result<U, InvalidHeaderName> |
| 1533 | where |
| 1534 | F: FnOnce(HdrName<'_>) -> U, |
| 1535 | { |
| 1536 | let mut buf = uninit_u8_array(); |
| 1537 | // Precondition: HEADER_CHARS is a valid table for parse_hdr(). |
| 1538 | let hdr = parse_hdr(hdr, &mut buf, &HEADER_CHARS)?; |
| 1539 | Ok(f(hdr)) |
| 1540 | } |
| 1541 | |
| 1542 | pub fn from_static<F, U>(hdr: &'static str, f: F) -> U |
| 1543 | where |
| 1544 | F: FnOnce(HdrName<'_>) -> U, |
| 1545 | { |
| 1546 | let mut buf = uninit_u8_array(); |
| 1547 | let hdr = |
| 1548 | // Precondition: HEADER_CHARS is a valid table for parse_hdr(). |
| 1549 | parse_hdr(hdr.as_bytes(), &mut buf, &HEADER_CHARS).expect("static str is invalid name" ); |
| 1550 | f(hdr) |
| 1551 | } |
| 1552 | } |
| 1553 | |
| 1554 | #[doc (hidden)] |
| 1555 | impl<'a> From<HdrName<'a>> for HeaderName { |
| 1556 | fn from(src: HdrName<'a>) -> HeaderName { |
| 1557 | match src.inner { |
| 1558 | Repr::Standard(s) => HeaderName { |
| 1559 | inner: Repr::Standard(s), |
| 1560 | }, |
| 1561 | Repr::Custom(maybe_lower) => { |
| 1562 | if maybe_lower.lower { |
| 1563 | let buf = Bytes::copy_from_slice(maybe_lower.buf); |
| 1564 | // Safety: the invariant on MaybeLower ensures buf is valid UTF-8. |
| 1565 | let byte_str = unsafe { ByteStr::from_utf8_unchecked(buf) }; |
| 1566 | |
| 1567 | HeaderName { |
| 1568 | inner: Repr::Custom(Custom(byte_str)), |
| 1569 | } |
| 1570 | } else { |
| 1571 | use bytes::BufMut; |
| 1572 | let mut dst = BytesMut::with_capacity(maybe_lower.buf.len()); |
| 1573 | |
| 1574 | for b in maybe_lower.buf.iter() { |
| 1575 | // HEADER_CHARS maps each byte to a valid single-byte UTF-8 |
| 1576 | // codepoint. |
| 1577 | dst.put_u8(HEADER_CHARS[*b as usize]); |
| 1578 | } |
| 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 | let buf = unsafe { ByteStr::from_utf8_unchecked(dst.freeze()) }; |
| 1584 | |
| 1585 | HeaderName { |
| 1586 | inner: Repr::Custom(Custom(buf)), |
| 1587 | } |
| 1588 | } |
| 1589 | } |
| 1590 | } |
| 1591 | } |
| 1592 | } |
| 1593 | |
| 1594 | #[doc (hidden)] |
| 1595 | impl<'a> PartialEq<HdrName<'a>> for HeaderName { |
| 1596 | #[inline ] |
| 1597 | fn eq(&self, other: &HdrName<'a>) -> bool { |
| 1598 | match self.inner { |
| 1599 | Repr::Standard(a: StandardHeader) => match other.inner { |
| 1600 | Repr::Standard(b: StandardHeader) => a == b, |
| 1601 | _ => false, |
| 1602 | }, |
| 1603 | Repr::Custom(Custom(ref a: &ByteStr)) => match other.inner { |
| 1604 | Repr::Custom(ref b: &MaybeLower<'a>) => { |
| 1605 | if b.lower { |
| 1606 | a.as_bytes() == b.buf |
| 1607 | } else { |
| 1608 | eq_ignore_ascii_case(lower:a.as_bytes(), s:b.buf) |
| 1609 | } |
| 1610 | } |
| 1611 | _ => false, |
| 1612 | }, |
| 1613 | } |
| 1614 | } |
| 1615 | } |
| 1616 | |
| 1617 | // ===== Custom ===== |
| 1618 | |
| 1619 | impl Hash for Custom { |
| 1620 | #[inline ] |
| 1621 | fn hash<H: Hasher>(&self, hasher: &mut H) { |
| 1622 | hasher.write(self.0.as_bytes()) |
| 1623 | } |
| 1624 | } |
| 1625 | |
| 1626 | // ===== MaybeLower ===== |
| 1627 | |
| 1628 | impl<'a> Hash for MaybeLower<'a> { |
| 1629 | #[inline ] |
| 1630 | fn hash<H: Hasher>(&self, hasher: &mut H) { |
| 1631 | if self.lower { |
| 1632 | hasher.write(self.buf); |
| 1633 | } else { |
| 1634 | for &b: u8 in self.buf { |
| 1635 | hasher.write(&[HEADER_CHARS[b as usize]]); |
| 1636 | } |
| 1637 | } |
| 1638 | } |
| 1639 | } |
| 1640 | |
| 1641 | // Assumes that the left hand side is already lower case |
| 1642 | #[inline ] |
| 1643 | fn eq_ignore_ascii_case(lower: &[u8], s: &[u8]) -> bool { |
| 1644 | if lower.len() != s.len() { |
| 1645 | return false; |
| 1646 | } |
| 1647 | |
| 1648 | lowerimpl Iterator |
| 1649 | .iter() |
| 1650 | .zip(s) |
| 1651 | .all(|(a: &u8, b: &u8)| *a == HEADER_CHARS[*b as usize]) |
| 1652 | } |
| 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 | fn uninit_u8_array() -> [MaybeUninit<u8>; SCRATCH_BUF_SIZE] { |
| 1660 | let arr: MaybeUninit<[MaybeUninit<…>; 64]> = MaybeUninit::<[MaybeUninit<u8>; SCRATCH_BUF_SIZE]>::uninit(); |
| 1661 | // Safety: assume_init() is claiming that an array of MaybeUninit<> |
| 1662 | // has been initialized, but MaybeUninit<>'s do not require initialization. |
| 1663 | unsafe { arr.assume_init() } |
| 1664 | } |
| 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 | unsafe fn slice_assume_init<T>(slice: &[MaybeUninit<T>]) -> &[T] { |
| 1671 | &*(slice as *const [MaybeUninit<T>] as *const [T]) |
| 1672 | } |
| 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 | } |
| 1923 | |