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