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