Skip to main content

turbopack_dev_server/source/
headers.rs

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