Skip to main content

sark_core/http/response/direct/
headers.rs

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