1use super::{DecoderError, NeedMore};
2use crate::ext::Protocol;
3
4use bytes::Bytes;
5use http::header::{HeaderName, HeaderValue};
6use http::{Method, StatusCode};
7use std::fmt;
8
9/// HTTP/2 Header
10#[derive(Debug, Clone, Eq, PartialEq)]
11pub 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)]
24pub 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)]
36pub struct BytesStr(Bytes);
37
38pub fn len(name: &HeaderName, value: &HeaderValue) -> usize {
39 let n: &str = name.as_ref();
40 32 + n.len() + value.len()
41}
42
43impl 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
63impl 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
212impl 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
229impl<'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
266impl 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
291impl std::ops::Deref for BytesStr {
292 type Target = str;
293 fn deref(&self) -> &str {
294 self.as_str()
295 }
296}
297
298impl AsRef<[u8]> for BytesStr {
299 fn as_ref(&self) -> &[u8] {
300 self.0.as_ref()
301 }
302}
303
304impl fmt::Debug for BytesStr {
305 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306 self.0.fmt(f)
307 }
308}
309