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