trillium_http/headers/
unknown_header_name.rs

1use super::{HeaderName, HeaderNameInner::UnknownHeader};
2use hashbrown::Equivalent;
3use smartcow::SmartCow;
4use std::{
5    fmt::{self, Debug, Display, Formatter},
6    hash::{Hash, Hasher},
7    ops::Deref,
8};
9
10#[derive(Clone)]
11pub(super) struct UnknownHeaderName<'a>(SmartCow<'a>);
12
13impl PartialEq for UnknownHeaderName<'_> {
14    fn eq(&self, other: &Self) -> bool {
15        self.0.eq_ignore_ascii_case(&other.0)
16    }
17}
18
19impl Eq for UnknownHeaderName<'_> {}
20
21impl Hash for UnknownHeaderName<'_> {
22    fn hash<H: Hasher>(&self, state: &mut H) {
23        for c in self.0.as_bytes() {
24            c.to_ascii_lowercase().hash(state);
25        }
26    }
27}
28
29impl Debug for UnknownHeaderName<'_> {
30    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
31        Debug::fmt(&self.0, f)
32    }
33}
34
35impl Display for UnknownHeaderName<'_> {
36    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
37        Display::fmt(&self.0, f)
38    }
39}
40
41impl<'a> From<UnknownHeaderName<'a>> for HeaderName<'a> {
42    fn from(value: UnknownHeaderName<'a>) -> Self {
43        HeaderName(UnknownHeader(value))
44    }
45}
46
47fn is_tchar(c: char) -> bool {
48    matches!(
49        c,
50        'a'..='z'
51        | 'A'..='Z'
52        | '0'..='9'
53        | '!'
54        | '#'
55        | '$'
56        | '%'
57        | '&'
58        | '\''
59        | '*'
60        | '+'
61        | '-'
62        | '.'
63        | '^'
64        | '_'
65        | '`'
66        | '|'
67        | '~'
68    )
69}
70
71impl UnknownHeaderName<'_> {
72    pub(crate) fn is_valid(&self) -> bool {
73        // token per https://www.rfc-editor.org/rfc/rfc9110#section-5.1
74        // tchar per https://www.rfc-editor.org/rfc/rfc9110#section-5.6.2
75        !self.is_empty() && self.0.chars().all(is_tchar)
76    }
77
78    pub(crate) fn into_owned(self) -> UnknownHeaderName<'static> {
79        UnknownHeaderName(self.0.into_owned())
80    }
81}
82
83impl From<String> for UnknownHeaderName<'static> {
84    fn from(value: String) -> Self {
85        Self(value.into())
86    }
87}
88
89impl<'a> From<&'a str> for UnknownHeaderName<'a> {
90    fn from(value: &'a str) -> Self {
91        Self(value.into())
92    }
93}
94
95impl<'a> From<SmartCow<'a>> for UnknownHeaderName<'a> {
96    fn from(value: SmartCow<'a>) -> Self {
97        Self(value)
98    }
99}
100
101impl<'a> From<UnknownHeaderName<'a>> for SmartCow<'a> {
102    fn from(value: UnknownHeaderName<'a>) -> Self {
103        value.0
104    }
105}
106
107impl Deref for UnknownHeaderName<'_> {
108    type Target = str;
109
110    fn deref(&self) -> &Self::Target {
111        &self.0
112    }
113}
114
115impl Equivalent<UnknownHeaderName<'_>> for &UnknownHeaderName<'_> {
116    fn equivalent(&self, key: &UnknownHeaderName<'_>) -> bool {
117        key.eq_ignore_ascii_case(self)
118    }
119}