Skip to main content

sark_core/http/response/direct/
headers.rs

1use o3::buffer::{Owned, Shared};
2
3use super::value::{HeaderItemInner, HeaderValueInner, InlineHeaderValue};
4use crate::http::request::LocalFrameBytesRef;
5
6const INLINE_HEADERS: usize = 4;
7pub(in crate::http::response) const INLINE_HOT_TEXT_PARTS: usize = 10;
8
9pub struct HeadersInner<'req> {
10    entries: [HeaderItemInner<'req>; INLINE_HEADERS],
11    len: u8,
12    wire_len: usize,
13}
14
15pub type Headers = HeadersInner<'static>;
16
17impl<'req> Clone for HeadersInner<'req> {
18    fn clone(&self) -> Self {
19        let len = usize::from(self.len);
20        let entries = std::array::from_fn(|idx| {
21            if idx < len {
22                self.entries[idx].clone()
23            } else {
24                HeaderItemInner::placeholder()
25            }
26        });
27        Self {
28            entries,
29            len: self.len,
30            wire_len: self.wire_len,
31        }
32    }
33}
34
35impl<'req> std::fmt::Debug for HeadersInner<'req> {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        f.debug_struct("Headers")
38            .field("len", &self.len)
39            .field("wire_len", &self.wire_len)
40            .finish()
41    }
42}
43
44impl<'req> Default for HeadersInner<'req> {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl<'req> HeadersInner<'req> {
51    pub fn new() -> Self {
52        Self {
53            entries: std::array::from_fn(|_| HeaderItemInner::placeholder()),
54            len: 0,
55            wire_len: 0,
56        }
57    }
58
59    pub fn from_items<const N: usize>(items: [HeaderItemInner<'req>; N]) -> Self {
60        const {
61            assert!(N <= INLINE_HEADERS, "direct header overflow");
62        }
63        let mut iter = IntoIterator::into_iter(items);
64        let mut wire_len = 0usize;
65        let entries = std::array::from_fn(|i| {
66            if i < N {
67                let item = iter.next().expect("from_fn within N must yield Some");
68                wire_len += item.wire_len();
69                item
70            } else {
71                HeaderItemInner::placeholder()
72            }
73        });
74        Self {
75            entries,
76            len: N as u8,
77            wire_len,
78        }
79    }
80
81    pub fn is_empty(&self) -> bool {
82        self.len == 0
83    }
84
85    pub fn len(&self) -> usize {
86        usize::from(self.len)
87    }
88
89    pub fn wire_len(&self) -> usize {
90        self.wire_len
91    }
92
93    pub fn has_content_encoding(&self) -> bool {
94        self.entries[..usize::from(self.len)]
95            .iter()
96            .any(|e| e.name.as_str().eq_ignore_ascii_case("content-encoding"))
97    }
98
99    pub fn push_static(&mut self, name: &'static str, value: HeaderStaticValueToken) -> &mut Self {
100        self.push_value(name, HeaderValueInner::Static(value.as_bytes()))
101    }
102
103    pub fn push_shared(&mut self, name: &'static str, value: Shared) -> &mut Self {
104        self.push_value(name, HeaderValueInner::Shared(value))
105    }
106
107    pub fn push_inline(&mut self, name: &'static str, value: InlineHeaderValue) -> &mut Self {
108        self.push_value(name, HeaderValueInner::Inline(value))
109    }
110
111    pub fn push_local(&mut self, name: &'static str, value: LocalFrameBytesRef<'req>) -> &mut Self {
112        self.push_value(name, HeaderValueInner::Local(value))
113    }
114
115    pub fn write_into(&self, out: &mut Owned) {
116        for idx in 0..usize::from(self.len) {
117            let header = &self.entries[idx];
118            out.extend_from_slice(header.name_bytes());
119            out.extend_from_slice(b": ");
120            out.extend_from_slice(header.value_bytes());
121            out.extend_from_slice(b"\r\n");
122        }
123    }
124
125    pub fn write(&self, out: &mut [u8]) -> usize {
126        let mut off = 0usize;
127        for idx in 0..usize::from(self.len) {
128            let header = &self.entries[idx];
129            let name = header.name_bytes();
130            let value = header.value_bytes();
131            let name_end = off + name.len();
132            out[off..name_end].copy_from_slice(name);
133            off = name_end;
134            out[off..off + 2].copy_from_slice(b": ");
135            off += 2;
136            let value_end = off + value.len();
137            out[off..value_end].copy_from_slice(value);
138            off = value_end;
139            out[off..off + 2].copy_from_slice(b"\r\n");
140            off += 2;
141        }
142        off
143    }
144
145    fn push_value(&mut self, name: &'static str, value: HeaderValueInner<'req>) -> &mut Self {
146        assert!(
147            usize::from(self.len) < INLINE_HEADERS,
148            "direct header overflow: max {}",
149            INLINE_HEADERS
150        );
151        self.wire_len += name.len() + 2 + value.len() + 2;
152        self.entries[usize::from(self.len)] = HeaderItemInner {
153            name: HeaderNameToken::new(name),
154            value,
155        };
156        self.len += 1;
157        self
158    }
159}
160
161#[derive(Clone, Copy, Debug, PartialEq, Eq)]
162pub struct HeaderNameToken(&'static str);
163
164impl HeaderNameToken {
165    pub fn new(name: &'static str) -> Self {
166        HeaderAssert::name(name);
167        Self(name)
168    }
169
170    pub(crate) const fn empty_placeholder() -> Self {
171        Self("")
172    }
173
174    pub fn as_str(self) -> &'static str {
175        self.0
176    }
177
178    pub fn as_bytes(self) -> &'static [u8] {
179        self.0.as_bytes()
180    }
181}
182
183#[derive(Clone, Copy, Debug, PartialEq, Eq)]
184pub struct HeaderStaticValueToken(&'static str);
185
186impl HeaderStaticValueToken {
187    pub fn new(value: &'static str) -> Self {
188        HeaderAssert::value(value);
189        Self(value)
190    }
191
192    pub fn as_str(self) -> &'static str {
193        self.0
194    }
195
196    pub fn as_bytes(self) -> &'static [u8] {
197        self.0.as_bytes()
198    }
199}
200
201pub(super) struct HeaderAssert;
202
203impl HeaderAssert {
204    pub(super) fn name(name: &str) {
205        assert!(!name.is_empty(), "direct header name must not be empty");
206        assert!(
207            !name
208                .as_bytes()
209                .iter()
210                .any(|b| *b == b':' || *b == b'\r' || *b == b'\n'),
211            "direct header name must not contain separators"
212        );
213        assert!(
214            !matches!(
215                name,
216                "date" | "server" | "content-length" | "connection" | "transfer-encoding"
217            ),
218            "direct header must not override managed headers: {name}"
219        );
220    }
221
222    pub(super) fn value(value: &str) {
223        Self::value_bytes(value.as_bytes());
224    }
225
226    pub(super) fn value_bytes(value: &[u8]) {
227        assert!(
228            !value.iter().any(|b| *b == b'\r' || *b == b'\n'),
229            "direct header value must not contain CR/LF"
230        );
231    }
232}