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