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