turbopack_dev_server/source/
headers.rs1use std::{collections::BTreeMap, hash::Hash, mem::replace, ops::DerefMut};
2
3use serde::{Deserialize, Serialize};
4use turbo_tasks::{NonLocalValue, TaskInput, trace::TraceRawVcs};
5
6#[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#[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 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 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}