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