1 | use super::{DecoderError, NeedMore}; |
2 | use crate::ext::Protocol; |
3 | |
4 | use bytes::Bytes; |
5 | use http::header::{HeaderName, HeaderValue}; |
6 | use http::{Method, StatusCode}; |
7 | use std::fmt; |
8 | |
9 | /// HTTP/2 Header |
10 | #[derive (Debug, Clone, Eq, PartialEq)] |
11 | pub enum Header<T = HeaderName> { |
12 | Field { name: T, value: HeaderValue }, |
13 | // TODO: Change these types to `http::uri` types. |
14 | Authority(BytesStr), |
15 | Method(Method), |
16 | Scheme(BytesStr), |
17 | Path(BytesStr), |
18 | Protocol(Protocol), |
19 | Status(StatusCode), |
20 | } |
21 | |
22 | /// The header field name |
23 | #[derive (Debug, Clone, Eq, PartialEq, Hash)] |
24 | pub enum Name<'a> { |
25 | Field(&'a HeaderName), |
26 | Authority, |
27 | Method, |
28 | Scheme, |
29 | Path, |
30 | Protocol, |
31 | Status, |
32 | } |
33 | |
34 | #[doc (hidden)] |
35 | #[derive (Clone, Eq, PartialEq, Default)] |
36 | pub struct BytesStr(Bytes); |
37 | |
38 | pub fn len(name: &HeaderName, value: &HeaderValue) -> usize { |
39 | let n: &str = name.as_ref(); |
40 | 32 + n.len() + value.len() |
41 | } |
42 | |
43 | impl Header<Option<HeaderName>> { |
44 | pub fn reify(self) -> Result<Header, HeaderValue> { |
45 | use self::Header::*; |
46 | |
47 | Ok(match self { |
48 | Field { |
49 | name: Some(n: HeaderName), |
50 | value: HeaderValue, |
51 | } => Field { name: n, value }, |
52 | Field { name: None, value: HeaderValue } => return Err(value), |
53 | Authority(v: BytesStr) => Authority(v), |
54 | Method(v: Method) => Method(v), |
55 | Scheme(v: BytesStr) => Scheme(v), |
56 | Path(v: BytesStr) => Path(v), |
57 | Protocol(v: Protocol) => Protocol(v), |
58 | Status(v: StatusCode) => Status(v), |
59 | }) |
60 | } |
61 | } |
62 | |
63 | impl Header { |
64 | pub fn new(name: Bytes, value: Bytes) -> Result<Header, DecoderError> { |
65 | if name.is_empty() { |
66 | return Err(DecoderError::NeedMore(NeedMore::UnexpectedEndOfStream)); |
67 | } |
68 | if name[0] == b':' { |
69 | match &name[1..] { |
70 | b"authority" => { |
71 | let value = BytesStr::try_from(value)?; |
72 | Ok(Header::Authority(value)) |
73 | } |
74 | b"method" => { |
75 | let method = Method::from_bytes(&value)?; |
76 | Ok(Header::Method(method)) |
77 | } |
78 | b"scheme" => { |
79 | let value = BytesStr::try_from(value)?; |
80 | Ok(Header::Scheme(value)) |
81 | } |
82 | b"path" => { |
83 | let value = BytesStr::try_from(value)?; |
84 | Ok(Header::Path(value)) |
85 | } |
86 | b"protocol" => { |
87 | let value = Protocol::try_from(value)?; |
88 | Ok(Header::Protocol(value)) |
89 | } |
90 | b"status" => { |
91 | let status = StatusCode::from_bytes(&value)?; |
92 | Ok(Header::Status(status)) |
93 | } |
94 | _ => Err(DecoderError::InvalidPseudoheader), |
95 | } |
96 | } else { |
97 | // HTTP/2 requires lower case header names |
98 | let name = HeaderName::from_lowercase(&name)?; |
99 | let value = HeaderValue::from_bytes(&value)?; |
100 | |
101 | Ok(Header::Field { name, value }) |
102 | } |
103 | } |
104 | |
105 | pub fn len(&self) -> usize { |
106 | match *self { |
107 | Header::Field { |
108 | ref name, |
109 | ref value, |
110 | } => len(name, value), |
111 | Header::Authority(ref v) => 32 + 10 + v.len(), |
112 | Header::Method(ref v) => 32 + 7 + v.as_ref().len(), |
113 | Header::Scheme(ref v) => 32 + 7 + v.len(), |
114 | Header::Path(ref v) => 32 + 5 + v.len(), |
115 | Header::Protocol(ref v) => 32 + 9 + v.as_str().len(), |
116 | Header::Status(_) => 32 + 7 + 3, |
117 | } |
118 | } |
119 | |
120 | /// Returns the header name |
121 | pub fn name(&self) -> Name { |
122 | match *self { |
123 | Header::Field { ref name, .. } => Name::Field(name), |
124 | Header::Authority(..) => Name::Authority, |
125 | Header::Method(..) => Name::Method, |
126 | Header::Scheme(..) => Name::Scheme, |
127 | Header::Path(..) => Name::Path, |
128 | Header::Protocol(..) => Name::Protocol, |
129 | Header::Status(..) => Name::Status, |
130 | } |
131 | } |
132 | |
133 | pub fn value_slice(&self) -> &[u8] { |
134 | match *self { |
135 | Header::Field { ref value, .. } => value.as_ref(), |
136 | Header::Authority(ref v) => v.as_ref(), |
137 | Header::Method(ref v) => v.as_ref().as_ref(), |
138 | Header::Scheme(ref v) => v.as_ref(), |
139 | Header::Path(ref v) => v.as_ref(), |
140 | Header::Protocol(ref v) => v.as_ref(), |
141 | Header::Status(ref v) => v.as_str().as_ref(), |
142 | } |
143 | } |
144 | |
145 | pub fn value_eq(&self, other: &Header) -> bool { |
146 | match *self { |
147 | Header::Field { ref value, .. } => { |
148 | let a = value; |
149 | match *other { |
150 | Header::Field { ref value, .. } => a == value, |
151 | _ => false, |
152 | } |
153 | } |
154 | Header::Authority(ref a) => match *other { |
155 | Header::Authority(ref b) => a == b, |
156 | _ => false, |
157 | }, |
158 | Header::Method(ref a) => match *other { |
159 | Header::Method(ref b) => a == b, |
160 | _ => false, |
161 | }, |
162 | Header::Scheme(ref a) => match *other { |
163 | Header::Scheme(ref b) => a == b, |
164 | _ => false, |
165 | }, |
166 | Header::Path(ref a) => match *other { |
167 | Header::Path(ref b) => a == b, |
168 | _ => false, |
169 | }, |
170 | Header::Protocol(ref a) => match *other { |
171 | Header::Protocol(ref b) => a == b, |
172 | _ => false, |
173 | }, |
174 | Header::Status(ref a) => match *other { |
175 | Header::Status(ref b) => a == b, |
176 | _ => false, |
177 | }, |
178 | } |
179 | } |
180 | |
181 | pub fn is_sensitive(&self) -> bool { |
182 | match *self { |
183 | Header::Field { ref value, .. } => value.is_sensitive(), |
184 | // TODO: Technically these other header values can be sensitive too. |
185 | _ => false, |
186 | } |
187 | } |
188 | |
189 | pub fn skip_value_index(&self) -> bool { |
190 | use http::header; |
191 | |
192 | match *self { |
193 | Header::Field { ref name, .. } => matches!( |
194 | *name, |
195 | header::AGE |
196 | | header::AUTHORIZATION |
197 | | header::CONTENT_LENGTH |
198 | | header::ETAG |
199 | | header::IF_MODIFIED_SINCE |
200 | | header::IF_NONE_MATCH |
201 | | header::LOCATION |
202 | | header::COOKIE |
203 | | header::SET_COOKIE |
204 | ), |
205 | Header::Path(..) => true, |
206 | _ => false, |
207 | } |
208 | } |
209 | } |
210 | |
211 | // Mostly for tests |
212 | impl From<Header> for Header<Option<HeaderName>> { |
213 | fn from(src: Header) -> Self { |
214 | match src { |
215 | Header::Field { name: HeaderName, value: HeaderValue } => Header::Field { |
216 | name: Some(name), |
217 | value, |
218 | }, |
219 | Header::Authority(v: BytesStr) => Header::Authority(v), |
220 | Header::Method(v: Method) => Header::Method(v), |
221 | Header::Scheme(v: BytesStr) => Header::Scheme(v), |
222 | Header::Path(v: BytesStr) => Header::Path(v), |
223 | Header::Protocol(v: Protocol) => Header::Protocol(v), |
224 | Header::Status(v: StatusCode) => Header::Status(v), |
225 | } |
226 | } |
227 | } |
228 | |
229 | impl<'a> Name<'a> { |
230 | pub fn into_entry(self, value: Bytes) -> Result<Header, DecoderError> { |
231 | match self { |
232 | Name::Field(name) => Ok(Header::Field { |
233 | name: name.clone(), |
234 | value: HeaderValue::from_bytes(&value)?, |
235 | }), |
236 | Name::Authority => Ok(Header::Authority(BytesStr::try_from(value)?)), |
237 | Name::Method => Ok(Header::Method(Method::from_bytes(&value)?)), |
238 | Name::Scheme => Ok(Header::Scheme(BytesStr::try_from(value)?)), |
239 | Name::Path => Ok(Header::Path(BytesStr::try_from(value)?)), |
240 | Name::Protocol => Ok(Header::Protocol(Protocol::try_from(value)?)), |
241 | Name::Status => { |
242 | match StatusCode::from_bytes(&value) { |
243 | Ok(status) => Ok(Header::Status(status)), |
244 | // TODO: better error handling |
245 | Err(_) => Err(DecoderError::InvalidStatusCode), |
246 | } |
247 | } |
248 | } |
249 | } |
250 | |
251 | pub fn as_slice(&self) -> &[u8] { |
252 | match *self { |
253 | Name::Field(ref name) => name.as_ref(), |
254 | Name::Authority => b":authority" , |
255 | Name::Method => b":method" , |
256 | Name::Scheme => b":scheme" , |
257 | Name::Path => b":path" , |
258 | Name::Protocol => b":protocol" , |
259 | Name::Status => b":status" , |
260 | } |
261 | } |
262 | } |
263 | |
264 | // ===== impl BytesStr ===== |
265 | |
266 | impl BytesStr { |
267 | pub(crate) const fn from_static(value: &'static str) -> Self { |
268 | BytesStr(Bytes::from_static(value.as_bytes())) |
269 | } |
270 | |
271 | pub(crate) fn from(value: &str) -> Self { |
272 | BytesStr(Bytes::copy_from_slice(data:value.as_bytes())) |
273 | } |
274 | |
275 | #[doc (hidden)] |
276 | pub fn try_from(bytes: Bytes) -> Result<Self, std::str::Utf8Error> { |
277 | std::str::from_utf8(bytes.as_ref())?; |
278 | Ok(BytesStr(bytes)) |
279 | } |
280 | |
281 | pub(crate) fn as_str(&self) -> &str { |
282 | // Safety: check valid utf-8 in constructor |
283 | unsafe { std::str::from_utf8_unchecked(self.0.as_ref()) } |
284 | } |
285 | |
286 | pub(crate) fn into_inner(self) -> Bytes { |
287 | self.0 |
288 | } |
289 | } |
290 | |
291 | impl std::ops::Deref for BytesStr { |
292 | type Target = str; |
293 | fn deref(&self) -> &str { |
294 | self.as_str() |
295 | } |
296 | } |
297 | |
298 | impl AsRef<[u8]> for BytesStr { |
299 | fn as_ref(&self) -> &[u8] { |
300 | self.0.as_ref() |
301 | } |
302 | } |
303 | |
304 | impl fmt::Debug for BytesStr { |
305 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
306 | self.0.fmt(f) |
307 | } |
308 | } |
309 | |