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