Skip to main content

trillium_http/
headers.rs

1//! Header types
2pub(crate) mod compression_error;
3pub(crate) mod date;
4mod entry;
5mod entry_name;
6mod field_section;
7mod header_name;
8pub(crate) mod header_observer;
9mod header_value;
10mod header_values;
11#[cfg(feature = "unstable")]
12pub mod hpack;
13#[cfg(not(feature = "unstable"))]
14pub(crate) mod hpack;
15pub(crate) mod huffman;
16mod integer_prefix;
17mod known_header_name;
18pub(in crate::headers) mod recent_pairs;
19mod static_hit;
20mod unknown_header_name;
21
22#[cfg(feature = "unstable")]
23pub mod qpack;
24
25#[cfg(not(feature = "unstable"))]
26pub(crate) mod qpack;
27
28use crate::headers::entry::{OccupiedEntryInner, VacantEntryInner};
29pub use entry::{Entry, OccupiedEntry, VacantEntry};
30use hashbrown::{
31    HashMap,
32    hash_map::{self, Entry as HashbrownEntry},
33};
34pub use header_name::HeaderName;
35use header_name::HeaderNameInner;
36pub use header_value::HeaderValue;
37pub use header_values::HeaderValues;
38pub use known_header_name::KnownHeaderName;
39use std::{
40    collections::{
41        BTreeMap,
42        btree_map::{self, Entry as BTreeEntry},
43    },
44    fmt::{self, Debug, Display, Formatter},
45};
46use unknown_header_name::UnknownHeaderName;
47
48/// Trillium's header map type
49#[derive(Debug, Clone, PartialEq, Eq, Default)]
50#[must_use]
51pub struct Headers {
52    pub(crate) known: BTreeMap<KnownHeaderName, HeaderValues>,
53    pub(crate) unknown: HashMap<UnknownHeaderName<'static>, HeaderValues>,
54}
55
56/// Default Server header
57pub const SERVER_HEADER: HeaderValue =
58    HeaderValue::const_new(concat!("trillium-http/", env!("CARGO_PKG_VERSION")));
59
60#[cfg(feature = "serde")]
61impl serde::Serialize for Headers {
62    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
63    where
64        S: serde::Serializer,
65    {
66        use serde::ser::SerializeMap;
67        let mut map = serializer.serialize_map(Some(self.len()))?;
68        for (key, values) in self {
69            map.serialize_entry(&key, values)?;
70        }
71        map.end()
72    }
73}
74
75impl Display for Headers {
76    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
77        // Sorted+allocated so test snapshots are deterministic.
78        // HTTP/1.x has no stable-order requirement, so wire emission iterates directly.
79        let mut data = self.iter().collect::<Vec<_>>();
80        data.sort_by(|(a, _), (b, _)| a.cmp(b));
81        for (n, v) in data {
82            for v in v {
83                f.write_fmt(format_args!("{n}: {v}\r\n"))?;
84            }
85        }
86        Ok(())
87    }
88}
89
90impl Headers {
91    #[doc(hidden)]
92    pub fn extend_parse(&mut self, bytes: &[u8]) -> Result<usize, crate::Error> {
93        use memchr::memmem::Finder;
94
95        let mut new_header_count = 0;
96        let mut last_line = 0;
97        for newline in Finder::new(b"\r\n").find_iter(bytes) {
98            if newline == last_line {
99                continue;
100            }
101
102            let line = &bytes[last_line..newline];
103
104            // Validate each field line as it's parsed, appending the valid ones as we go. On the
105            // first violation we return `Err` with `self` still holding everything before it, so
106            // the request parser can synthesize a response from the partial parse
107            // rather than closing blind. A line with no colon — e.g. an obs-fold
108            // continuation — has no name and is rejected (obs-fold is forbidden in requests).
109            let colon = memchr::memchr(b':', line).ok_or(crate::Error::InvalidHeaderName)?;
110            let name = HeaderName::parse(&line[..colon])?;
111            if !name.is_valid() {
112                return Err(crate::Error::InvalidHeaderName);
113            }
114
115            let mut value_start = colon + 1;
116            while line
117                .get(value_start)
118                .is_some_and(|b| matches!(b, b'\t' | b' '))
119            {
120                value_start += 1;
121            }
122            let value_bytes = line[value_start..].trim_ascii_end();
123            // A field value carries no C0 control except HTAB; obs-text (`0x80..=0xFF`) is allowed.
124            if !value_bytes.iter().all(|&b| b >= 0x20 || b == b'\t') {
125                return Err(crate::Error::InvalidHeaderValue(name.to_owned()));
126            }
127
128            self.append(name.to_owned(), HeaderValue::parse(value_bytes));
129            new_header_count += 1;
130            last_line = newline + 2;
131        }
132        Ok(new_header_count)
133    }
134
135    #[doc(hidden)]
136    pub fn parse(bytes: &[u8]) -> Result<Self, crate::Error> {
137        let mut headers = Headers::new();
138        headers.extend_parse(bytes)?;
139        Ok(headers)
140    }
141}
142
143impl Headers {
144    /// Construct a new headers with a default capacity
145    pub fn new() -> Self {
146        Self::default()
147    }
148
149    /// Return an iterator over borrowed header names and header
150    /// values. First yields the known headers and then the unknown
151    /// headers, if any.
152    pub fn iter(&self) -> Iter<'_> {
153        self.into()
154    }
155
156    /// Are there zero headers?
157    pub fn is_empty(&self) -> bool {
158        self.known.is_empty() && self.unknown.is_empty()
159    }
160
161    /// How many unique [`HeaderName`] have been added to these [`Headers`]?
162    /// Note that each header name may have more than one [`HeaderValue`].
163    pub fn len(&self) -> usize {
164        self.known.len() + self.unknown.len()
165    }
166
167    /// add the header value or header values into this header map. If
168    /// there is already a header with the same name, the new values
169    /// will be added to the existing ones. To replace any existing
170    /// values, use [`Headers::insert`]
171    ///
172    /// Identical to [`headers.entry(name).append(values)`][Entry::append]
173    pub fn append(
174        &mut self,
175        name: impl Into<HeaderName<'static>>,
176        values: impl Into<HeaderValues>,
177    ) -> &mut HeaderValues {
178        self.entry(name).append(values)
179    }
180
181    /// A slightly more efficient way to combine two [`Headers`] than
182    /// using [`Extend`]
183    pub fn append_all(&mut self, other: Headers) {
184        for (name, value) in other.known {
185            match self.known.entry(name) {
186                BTreeEntry::Occupied(mut entry) => {
187                    entry.get_mut().extend(value);
188                }
189                BTreeEntry::Vacant(entry) => {
190                    entry.insert(value);
191                }
192            }
193        }
194
195        for (name, value) in other.unknown {
196            match self.unknown.entry(name) {
197                HashbrownEntry::Occupied(mut entry) => {
198                    entry.get_mut().extend(value);
199                }
200                HashbrownEntry::Vacant(entry) => {
201                    entry.insert(value);
202                }
203            }
204        }
205    }
206
207    /// Combine two [`Headers`], replacing any existing header values
208    pub fn insert_all(&mut self, other: Headers) {
209        for (name, value) in other.known {
210            self.known.insert(name, value);
211        }
212
213        for (name, value) in other.unknown {
214            self.unknown.insert(name, value);
215        }
216    }
217
218    /// Add a header value or header values into this header map. If a
219    /// header already exists with the same name, it will be
220    /// replaced. To combine, see [`Headers::append`]
221    pub fn insert(
222        &mut self,
223        name: impl Into<HeaderName<'static>>,
224        values: impl Into<HeaderValues>,
225    ) -> &mut Self {
226        self.entry(name).insert(values);
227        self
228    }
229
230    /// Add a header value or header values into this header map if
231    /// and only if there is not already a header with the same name.
232    ///
233    /// Identical to [`headers.entry(name).or_insert(default)`][Entry::or_insert]
234    pub fn try_insert(
235        &mut self,
236        name: impl Into<HeaderName<'static>>,
237        values: impl Into<HeaderValues>,
238    ) -> &mut Self {
239        self.entry(name).or_insert(values);
240        self
241    }
242
243    /// if a key does not exist already, execute the provided function and insert a value
244    ///
245    /// Identical to
246    /// [`headers.entry(name).or_insert_with(values)`][Entry::or_insert_with]
247    pub fn try_insert_with<V>(
248        &mut self,
249        name: impl Into<HeaderName<'static>>,
250        values: impl FnOnce() -> V,
251    ) -> &mut HeaderValues
252    where
253        V: Into<HeaderValues>,
254    {
255        self.entry(name).or_insert_with(values)
256    }
257
258    /// Return a view into the entry for this header name, whether or not it is populated.
259    ///
260    /// See also [`Entry`]
261    pub fn entry(&mut self, name: impl Into<HeaderName<'static>>) -> Entry<'_> {
262        match name.into().0 {
263            HeaderNameInner::KnownHeader(known) => match self.known.entry(known) {
264                BTreeEntry::Vacant(vacant) => {
265                    Entry::Vacant(VacantEntry(VacantEntryInner::Known(vacant)))
266                }
267                BTreeEntry::Occupied(occupied) => {
268                    Entry::Occupied(OccupiedEntry(OccupiedEntryInner::Known(occupied)))
269                }
270            },
271
272            HeaderNameInner::UnknownHeader(unknown) => match self.unknown.entry(unknown) {
273                HashbrownEntry::Occupied(occupied) => {
274                    Entry::Occupied(OccupiedEntry(OccupiedEntryInner::Unknown(occupied)))
275                }
276
277                HashbrownEntry::Vacant(vacant) => {
278                    Entry::Vacant(VacantEntry(VacantEntryInner::Unknown(vacant)))
279                }
280            },
281        }
282    }
283
284    /// Retrieves a &str header value if there is at least one header
285    /// in the map with this name. If there are several headers with
286    /// the same name, this follows the behavior defined at
287    /// [`HeaderValues::one`]. Returns None if there is no header with
288    /// the provided header name.
289    pub fn get_str<'a>(&self, name: impl Into<HeaderName<'a>>) -> Option<&str> {
290        self.get_values(name).and_then(HeaderValues::as_str)
291    }
292
293    /// The body length declared by a single, well-formed `Content-Length` header
294    ///
295    /// Returns `None` when the header is absent, empty, present more than once, contains any
296    /// non-digit octet, or overflows `u64`. Prefer this over parsing `Content-Length`.
297    pub fn content_length(&self) -> Option<u64> {
298        self.get_values(KnownHeaderName::ContentLength)
299            .and_then(crate::util::parse_content_length)
300    }
301
302    /// Retrieves a singular header value from this header map. If there are several headers with
303    /// the same name, this follows the behavior defined at [`HeaderValues::one`]. Returns None if
304    /// there is no header with the provided header name
305    pub fn get<'a>(&self, name: impl Into<HeaderName<'a>>) -> Option<&HeaderValue> {
306        self.get_values(name).and_then(HeaderValues::one)
307    }
308
309    /// Takes all headers with the provided header name out of this header map and returns
310    /// them. Returns None if the header did not have an entry in this map.
311    pub fn remove<'a>(&mut self, name: impl Into<HeaderName<'a>>) -> Option<HeaderValues> {
312        match name.into().0 {
313            HeaderNameInner::KnownHeader(known) => self.known.remove(&known),
314            HeaderNameInner::UnknownHeader(unknown) => self.unknown.remove(&&unknown),
315        }
316    }
317
318    /// Retrieves a reference to all header values with the provided
319    /// header name. If you expect there to be only one value, use
320    /// [`Headers::get`].
321    pub fn get_values<'a>(&self, name: impl Into<HeaderName<'a>>) -> Option<&HeaderValues> {
322        match name.into().0 {
323            HeaderNameInner::KnownHeader(known) => self.known.get(&known),
324            HeaderNameInner::UnknownHeader(unknown) => self.unknown.get(&&unknown),
325        }
326    }
327
328    /// Predicate function to check whether this header map contains
329    /// the provided header name. If you are using this to
330    /// conditionally insert a value, consider using
331    /// [`Headers::try_insert`] instead.
332    pub fn has_header<'a>(&self, name: impl Into<HeaderName<'a>>) -> bool {
333        match name.into().0 {
334            HeaderNameInner::KnownHeader(known) => self.known.contains_key(&known),
335            HeaderNameInner::UnknownHeader(unknown) => self.unknown.contains_key(&unknown),
336        }
337    }
338
339    /// Convenience function to check whether the value contained in
340    /// this header map for the provided name is
341    /// ascii-case-insensitively equal to the provided comparison
342    /// &str. Returns false if there is no value for the name
343    pub fn eq_ignore_ascii_case<'a>(
344        &'a self,
345        name: impl Into<HeaderName<'a>>,
346        needle: &str,
347    ) -> bool {
348        self.get_str(name)
349            .is_some_and(|v| v.eq_ignore_ascii_case(needle))
350    }
351
352    /// Chainable method to insert a header
353    pub fn with_inserted_header(
354        mut self,
355        name: impl Into<HeaderName<'static>>,
356        values: impl Into<HeaderValues>,
357    ) -> Self {
358        self.insert(name, values);
359        self
360    }
361
362    /// Chainable method to append a header
363    pub fn with_appended_header(
364        mut self,
365        name: impl Into<HeaderName<'static>>,
366        values: impl Into<HeaderValues>,
367    ) -> Self {
368        self.append(name, values);
369        self
370    }
371
372    /// Chainable method to remove a header
373    pub fn without_header<'a>(mut self, name: impl Into<HeaderName<'a>>) -> Self {
374        self.remove(name);
375        self
376    }
377
378    /// Chainable method to remove multiple headers by name
379    pub fn without_headers<'a, I, H>(mut self, names: I) -> Self
380    where
381        I: IntoIterator<Item = H>,
382        H: Into<HeaderName<'a>>,
383    {
384        self.remove_all(names);
385        self
386    }
387
388    /// remove multiple headers by name
389    pub fn remove_all<'a, I, H>(&mut self, names: I)
390    where
391        I: IntoIterator<Item = H>,
392        H: Into<HeaderName<'a>>,
393    {
394        for name in names {
395            self.remove(name);
396        }
397    }
398}
399
400impl<HN, HV> Extend<(HN, HV)> for Headers
401where
402    HN: Into<HeaderName<'static>>,
403    HV: Into<HeaderValues>,
404{
405    fn extend<T: IntoIterator<Item = (HN, HV)>>(&mut self, iter: T) {
406        for (name, values) in iter {
407            self.append(name, values);
408        }
409    }
410}
411
412impl<HN, HV> FromIterator<(HN, HV)> for Headers
413where
414    HN: Into<HeaderName<'static>>,
415    HV: Into<HeaderValues>,
416{
417    fn from_iter<T: IntoIterator<Item = (HN, HV)>>(iter: T) -> Self {
418        let iter = iter.into_iter();
419        let mut headers = Self::new();
420        for (name, values) in iter {
421            headers.append(name, values);
422        }
423
424        headers
425    }
426}
427
428impl<'a> IntoIterator for &'a Headers {
429    type IntoIter = Iter<'a>;
430    type Item = (HeaderName<'a>, &'a HeaderValues);
431
432    fn into_iter(self) -> Self::IntoIter {
433        self.into()
434    }
435}
436
437/// An owned iterator for Headers
438#[derive(Debug)]
439pub struct IntoIter {
440    known: btree_map::IntoIter<KnownHeaderName, HeaderValues>,
441    unknown: hash_map::IntoIter<UnknownHeaderName<'static>, HeaderValues>,
442}
443
444impl Iterator for IntoIter {
445    type Item = (HeaderName<'static>, HeaderValues);
446
447    fn next(&mut self) -> Option<Self::Item> {
448        let IntoIter { known, unknown } = self;
449        known
450            .next()
451            .map(|(k, v)| (HeaderName::from(k), v))
452            .or_else(|| unknown.next().map(|(k, v)| (HeaderName::from(k), v)))
453    }
454}
455
456impl From<Headers> for IntoIter {
457    fn from(value: Headers) -> Self {
458        Self {
459            known: value.known.into_iter(),
460            unknown: value.unknown.into_iter(),
461        }
462    }
463}
464
465/// A borrowed iterator for Headers
466#[derive(Debug)]
467pub struct Iter<'a> {
468    known: btree_map::Iter<'a, KnownHeaderName, HeaderValues>,
469    unknown: hash_map::Iter<'a, UnknownHeaderName<'static>, HeaderValues>,
470}
471
472impl<'a> From<&'a Headers> for Iter<'a> {
473    fn from(value: &'a Headers) -> Self {
474        Iter {
475            known: value.known.iter(),
476            unknown: value.unknown.iter(),
477        }
478    }
479}
480
481impl<'a> Iterator for Iter<'a> {
482    type Item = (HeaderName<'a>, &'a HeaderValues);
483
484    fn next(&mut self) -> Option<Self::Item> {
485        let Iter { known, unknown } = self;
486        known
487            .next()
488            .map(|(k, v)| (HeaderName::from(*k), v))
489            .or_else(|| unknown.next().map(|(k, v)| (HeaderName::from(&**k), v)))
490    }
491}
492
493impl IntoIterator for Headers {
494    type IntoIter = IntoIter;
495    type Item = (HeaderName<'static>, HeaderValues);
496
497    fn into_iter(self) -> Self::IntoIter {
498        self.into()
499    }
500}