turbopack_dev_server/source/
headers.rs

1use std::{collections::BTreeMap, hash::Hash, mem::replace, ops::DerefMut};
2
3use bincode::{Decode, Encode};
4use turbo_tasks::{NonLocalValue, TaskInput, trace::TraceRawVcs};
5
6/// A parsed query string from a http request
7#[derive(
8    Clone,
9    Debug,
10    PartialEq,
11    Eq,
12    Default,
13    Hash,
14    TraceRawVcs,
15    NonLocalValue,
16    TaskInput,
17    Encode,
18    Decode,
19)]
20pub struct Headers(BTreeMap<String, HeaderValue>);
21
22/// The value of an http header. HTTP headers might contain non-utf-8 bytes. An
23/// header might also occur multiple times.
24#[derive(
25    Clone, Debug, PartialEq, Eq, Hash, TraceRawVcs, NonLocalValue, TaskInput, Encode, Decode,
26)]
27pub enum HeaderValue {
28    SingleString(String),
29    SingleBytes(Vec<u8>),
30    MultiStrings(Vec<String>),
31    MultiBytes(Vec<Vec<u8>>),
32}
33
34impl std::ops::Deref for Headers {
35    type Target = BTreeMap<String, HeaderValue>;
36    fn deref(&self) -> &Self::Target {
37        &self.0
38    }
39}
40
41impl DerefMut for Headers {
42    fn deref_mut(&mut self) -> &mut Self::Target {
43        &mut self.0
44    }
45}
46
47impl HeaderValue {
48    /// Extends the current value with another occurrence of that header which
49    /// is a string
50    pub fn extend_with_string(&mut self, new: String) {
51        *self = match replace(self, HeaderValue::SingleBytes(Vec::new())) {
52            HeaderValue::SingleString(s) => HeaderValue::MultiStrings(vec![s, new]),
53            HeaderValue::SingleBytes(b) => HeaderValue::MultiBytes(vec![b, new.into()]),
54            HeaderValue::MultiStrings(mut v) => {
55                v.push(new);
56                HeaderValue::MultiStrings(v)
57            }
58            HeaderValue::MultiBytes(mut v) => {
59                v.push(new.into());
60                HeaderValue::MultiBytes(v)
61            }
62        }
63    }
64    /// Extends the current value with another occurrence of that header which
65    /// is a non-utf-8 valid byte sequence
66    pub fn extend_with_bytes(&mut self, new: Vec<u8>) {
67        *self = match replace(self, HeaderValue::SingleBytes(Vec::new())) {
68            HeaderValue::SingleString(s) => HeaderValue::MultiBytes(vec![s.into(), new]),
69            HeaderValue::SingleBytes(b) => HeaderValue::MultiBytes(vec![b, new]),
70            HeaderValue::MultiStrings(v) => {
71                let mut v: Vec<Vec<u8>> = v.into_iter().map(|s| s.into()).collect();
72                v.push(new);
73                HeaderValue::MultiBytes(v)
74            }
75            HeaderValue::MultiBytes(mut v) => {
76                v.push(new);
77                HeaderValue::MultiBytes(v)
78            }
79        }
80    }
81
82    pub fn contains(&self, string_value: &str) -> bool {
83        match self {
84            HeaderValue::SingleString(s) => s.contains(string_value),
85            HeaderValue::MultiStrings(s) => s.iter().any(|s| s.contains(string_value)),
86            _ => false,
87        }
88    }
89}