1#![allow(clippy::len_without_is_empty)]
2
3use ntex_bytes::{ByteString, Bytes};
4use ntex_http::{HeaderName, HeaderValue, Method, StatusCode};
5
6use super::{DecoderError, NeedMore};
7
8#[derive(Debug, Clone, Eq, PartialEq)]
10pub enum Header<T = HeaderName> {
11 Field { name: T, value: HeaderValue },
12 Authority(ByteString),
14 Method(Method),
15 Scheme(ByteString),
16 Path(ByteString),
17 Protocol(ByteString),
18 Status(StatusCode),
19}
20
21#[derive(Debug, Clone, Eq, PartialEq, Hash)]
23pub enum Name<'a> {
24 Field(&'a HeaderName),
25 Authority,
26 Method,
27 Scheme,
28 Path,
29 Protocol,
30 Status,
31}
32
33pub fn len(name: &HeaderName, value: &HeaderValue) -> usize {
34 let n: &str = name.as_ref();
35 32 + n.len() + value.len()
36}
37
38impl Header<Option<HeaderName>> {
39 pub fn reify(self) -> Result<Header, HeaderValue> {
40 use self::Header::*;
41
42 Ok(match self {
43 Field {
44 name: Some(n),
45 value,
46 } => Field { name: n, value },
47 Field { name: None, value } => return Err(value),
48 Authority(v) => Authority(v),
49 Method(v) => Method(v),
50 Scheme(v) => Scheme(v),
51 Path(v) => Path(v),
52 Protocol(v) => Protocol(v),
53 Status(v) => Status(v),
54 })
55 }
56}
57
58impl Header {
59 pub fn new(name: Bytes, value: Bytes) -> Result<Header, DecoderError> {
60 if name.is_empty() {
61 return Err(DecoderError::NeedMore(NeedMore::UnexpectedEndOfStream));
62 }
63 if name[0] == b':' {
64 match &name[1..] {
65 b"authority" => {
66 let value = ByteString::try_from(value)?;
67 Ok(Header::Authority(value))
68 }
69 b"method" => {
70 let method = Method::from_bytes(&value)?;
71 Ok(Header::Method(method))
72 }
73 b"scheme" => {
74 let value = ByteString::try_from(value)?;
75 Ok(Header::Scheme(value))
76 }
77 b"path" => {
78 let value = ByteString::try_from(value)?;
79 Ok(Header::Path(value))
80 }
81 b"protocol" => {
82 let value = ByteString::try_from(value)?;
83 Ok(Header::Protocol(value))
84 }
85 b"status" => {
86 let status = StatusCode::from_bytes(&value)?;
87 Ok(Header::Status(status))
88 }
89 _ => Err(DecoderError::InvalidPseudoheader),
90 }
91 } else {
92 let name = HeaderName::from_lowercase(&name)?;
94 let value = HeaderValue::from_bytes(&value)?;
95
96 Ok(Header::Field { name, value })
97 }
98 }
99
100 pub fn len(&self) -> usize {
101 match *self {
102 Header::Field {
103 ref name,
104 ref value,
105 } => len(name, value),
106 Header::Authority(ref v) => 32 + 10 + v.len(),
107 Header::Method(ref v) => 32 + 7 + v.as_ref().len(),
108 Header::Scheme(ref v) => 32 + 7 + v.len(),
109 Header::Path(ref v) => 32 + 5 + v.len(),
110 Header::Protocol(ref v) => 32 + 9 + v.len(),
111 Header::Status(_) => 32 + 7 + 3,
112 }
113 }
114
115 pub fn name(&self) -> Name<'_> {
117 match *self {
118 Header::Field { ref name, .. } => Name::Field(name),
119 Header::Authority(..) => Name::Authority,
120 Header::Method(..) => Name::Method,
121 Header::Scheme(..) => Name::Scheme,
122 Header::Path(..) => Name::Path,
123 Header::Protocol(..) => Name::Protocol,
124 Header::Status(..) => Name::Status,
125 }
126 }
127
128 pub fn value_slice(&self) -> &[u8] {
129 match *self {
130 Header::Field { ref value, .. } => value.as_ref(),
131 Header::Authority(ref v) => v.as_bytes(),
132 Header::Method(ref v) => v.as_ref().as_ref(),
133 Header::Scheme(ref v) => v.as_bytes(),
134 Header::Path(ref v) => v.as_bytes(),
135 Header::Protocol(ref v) => v.as_bytes(),
136 Header::Status(ref v) => v.as_str().as_ref(),
137 }
138 }
139
140 pub fn value_eq(&self, other: &Header) -> bool {
141 match *self {
142 Header::Field { ref value, .. } => {
143 let a = value;
144 match *other {
145 Header::Field { ref value, .. } => a == value,
146 _ => false,
147 }
148 }
149 Header::Authority(ref a) => match *other {
150 Header::Authority(ref b) => a == b,
151 _ => false,
152 },
153 Header::Method(ref a) => match *other {
154 Header::Method(ref b) => a == b,
155 _ => false,
156 },
157 Header::Scheme(ref a) => match *other {
158 Header::Scheme(ref b) => a == b,
159 _ => false,
160 },
161 Header::Path(ref a) => match *other {
162 Header::Path(ref b) => a == b,
163 _ => false,
164 },
165 Header::Protocol(ref a) => match *other {
166 Header::Protocol(ref b) => a == b,
167 _ => false,
168 },
169 Header::Status(ref a) => match *other {
170 Header::Status(ref b) => a == b,
171 _ => false,
172 },
173 }
174 }
175
176 pub fn is_sensitive(&self) -> bool {
177 match *self {
178 Header::Field { ref value, .. } => value.is_sensitive(),
179 _ => false,
181 }
182 }
183
184 pub fn skip_value_index(&self) -> bool {
185 use ntex_http::header;
186
187 match *self {
188 Header::Field { ref name, .. } => matches!(
189 *name,
190 header::AGE
191 | header::AUTHORIZATION
192 | header::CONTENT_LENGTH
193 | header::ETAG
194 | header::IF_MODIFIED_SINCE
195 | header::IF_NONE_MATCH
196 | header::LOCATION
197 | header::COOKIE
198 | header::SET_COOKIE
199 ),
200 Header::Path(..) => true,
201 _ => false,
202 }
203 }
204}
205
206impl From<Header> for Header<Option<HeaderName>> {
208 fn from(src: Header) -> Self {
209 match src {
210 Header::Field { name, value } => Header::Field {
211 name: Some(name),
212 value,
213 },
214 Header::Authority(v) => Header::Authority(v),
215 Header::Method(v) => Header::Method(v),
216 Header::Scheme(v) => Header::Scheme(v),
217 Header::Path(v) => Header::Path(v),
218 Header::Protocol(v) => Header::Protocol(v),
219 Header::Status(v) => Header::Status(v),
220 }
221 }
222}
223
224impl Name<'_> {
225 pub fn into_entry(self, value: Bytes) -> Result<Header, DecoderError> {
226 match self {
227 Name::Field(name) => Ok(Header::Field {
228 name: name.clone(),
229 value: HeaderValue::from_bytes(&value)?,
230 }),
231 Name::Authority => Ok(Header::Authority(ByteString::try_from(value)?)),
232 Name::Method => Ok(Header::Method(Method::from_bytes(&value)?)),
233 Name::Scheme => Ok(Header::Scheme(ByteString::try_from(value)?)),
234 Name::Path => Ok(Header::Path(ByteString::try_from(value)?)),
235 Name::Protocol => Ok(Header::Protocol(ByteString::try_from(value)?)),
236 Name::Status => {
237 match StatusCode::from_bytes(&value) {
238 Ok(status) => Ok(Header::Status(status)),
239 Err(_) => Err(DecoderError::InvalidStatusCode),
241 }
242 }
243 }
244 }
245
246 pub fn as_slice(&self) -> &[u8] {
247 match *self {
248 Name::Field(ref name) => name.as_ref(),
249 Name::Authority => b":authority",
250 Name::Method => b":method",
251 Name::Scheme => b":scheme",
252 Name::Path => b":path",
253 Name::Protocol => b":protocol",
254 Name::Status => b":status",
255 }
256 }
257}