turbopack_dev_server/source/
headers.rs

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