h2/hpack/
header.rs

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),
50                value,
51            } => Field { name: n, value },
52            Field { name: None, value } => return Err(value),
53            Authority(v) => Authority(v),
54            Method(v) => Method(v),
55            Scheme(v) => Scheme(v),
56            Path(v) => Path(v),
57            Protocol(v) => Protocol(v),
58            Status(v) => 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, value } => Header::Field {
216                name: Some(name),
217                value,
218            },
219            Header::Authority(v) => Header::Authority(v),
220            Header::Method(v) => Header::Method(v),
221            Header::Scheme(v) => Header::Scheme(v),
222            Header::Path(v) => Header::Path(v),
223            Header::Protocol(v) => Header::Protocol(v),
224            Header::Status(v) => 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(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}