Skip to main content

sark_core/http/response/direct/
headers.rs

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