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