Skip to main content

sark_core/http/response/direct/
headers.rs

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