sark_core/http/response/direct/
headers.rs1use 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}