Coverage Report

Created: 2024-12-17 06:15

/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
}