cloud_sdk/transport/header/
response.rs1use core::fmt;
2
3use super::{
4 HeaderError, HeaderSensitivity, MAX_RESPONSE_HEADER_BYTES, MAX_RESPONSE_HEADERS,
5 encoded_line_len, validate_name, validate_response_value,
6};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9struct HeaderRange {
10 name_start: u16,
11 name_len: u8,
12 value_start: u16,
13 value_len: u16,
14 sensitivity: HeaderSensitivity,
15}
16
17const EMPTY_RANGE: HeaderRange = HeaderRange {
18 name_start: 0,
19 name_len: 0,
20 value_start: 0,
21 value_len: 0,
22 sensitivity: HeaderSensitivity::Public,
23};
24
25#[derive(Clone, Copy)]
39pub struct ResponseHeader<'a> {
40 name: &'a str,
41 value: &'a [u8],
42 sensitivity: HeaderSensitivity,
43}
44
45impl<'a> ResponseHeader<'a> {
46 #[must_use]
48 pub const fn name(self) -> &'a str {
49 self.name
50 }
51
52 #[must_use]
54 pub const fn value(self) -> &'a [u8] {
55 self.value
56 }
57
58 #[must_use]
60 pub const fn sensitivity(self) -> HeaderSensitivity {
61 self.sensitivity
62 }
63}
64
65impl fmt::Debug for ResponseHeader<'_> {
66 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
67 formatter
68 .debug_struct("ResponseHeader")
69 .field("name", &self.name)
70 .field("value", &"[redacted]")
71 .field("sensitivity", &self.sensitivity)
72 .finish()
73 }
74}
75
76#[derive(Clone, Copy)]
88pub struct ResponseHeaders {
89 bytes: [u8; MAX_RESPONSE_HEADER_BYTES],
90 ranges: [HeaderRange; MAX_RESPONSE_HEADERS],
91 bytes_len: usize,
92 count: usize,
93 encoded_len: usize,
94}
95
96impl ResponseHeaders {
97 #[must_use]
99 pub const fn new() -> Self {
100 Self {
101 bytes: [0; MAX_RESPONSE_HEADER_BYTES],
102 ranges: [EMPTY_RANGE; MAX_RESPONSE_HEADERS],
103 bytes_len: 0,
104 count: 0,
105 encoded_len: 0,
106 }
107 }
108
109 pub fn try_push(
111 &mut self,
112 name: &str,
113 value: &[u8],
114 sensitivity: HeaderSensitivity,
115 ) -> Result<(), HeaderError> {
116 validate_name(name)?;
117 validate_response_value(value)?;
118 if self.count >= MAX_RESPONSE_HEADERS {
119 return Err(HeaderError::TooManyHeaders);
120 }
121 if self
122 .iter()
123 .any(|header| header.name.eq_ignore_ascii_case(name))
124 {
125 return Err(HeaderError::DuplicateName);
126 }
127 let line_len = encoded_line_len(name.len(), value.len())?;
128 let encoded_len = self
129 .encoded_len
130 .checked_add(line_len)
131 .ok_or(HeaderError::AggregateTooLarge)?;
132 if encoded_len > MAX_RESPONSE_HEADER_BYTES {
133 return Err(HeaderError::AggregateTooLarge);
134 }
135 let stored_len = name
136 .len()
137 .checked_add(value.len())
138 .ok_or(HeaderError::AggregateTooLarge)?;
139 let end = self
140 .bytes_len
141 .checked_add(stored_len)
142 .ok_or(HeaderError::AggregateTooLarge)?;
143 let name_start =
144 u16::try_from(self.bytes_len).map_err(|_| HeaderError::AggregateTooLarge)?;
145 let value_start = self
146 .bytes_len
147 .checked_add(name.len())
148 .and_then(|offset| u16::try_from(offset).ok())
149 .ok_or(HeaderError::AggregateTooLarge)?;
150 let range = HeaderRange {
151 name_start,
152 name_len: u8::try_from(name.len()).map_err(|_| HeaderError::NameTooLong)?,
153 value_start,
154 value_len: u16::try_from(value.len()).map_err(|_| HeaderError::ValueTooLong)?,
155 sensitivity,
156 };
157 let next_count = self
158 .count
159 .checked_add(1)
160 .ok_or(HeaderError::TooManyHeaders)?;
161 let slot = self
162 .ranges
163 .get_mut(self.count)
164 .ok_or(HeaderError::TooManyHeaders)?;
165 let region = self
166 .bytes
167 .get_mut(self.bytes_len..end)
168 .ok_or(HeaderError::AggregateTooLarge)?;
169 let (name_out, value_out) = region.split_at_mut(name.len());
170 name_out.copy_from_slice(name.as_bytes());
171 value_out.copy_from_slice(value);
172 *slot = range;
173 self.bytes_len = end;
174 self.encoded_len = encoded_len;
175 self.count = next_count;
176 Ok(())
177 }
178
179 #[must_use]
181 pub const fn len(&self) -> usize {
182 self.count
183 }
184
185 #[must_use]
187 pub const fn is_empty(&self) -> bool {
188 self.count == 0
189 }
190
191 #[must_use]
193 pub const fn encoded_len(&self) -> usize {
194 self.encoded_len
195 }
196
197 pub fn iter(&self) -> impl Iterator<Item = ResponseHeader<'_>> {
199 self.ranges
200 .get(..self.count)
201 .unwrap_or_default()
202 .iter()
203 .filter_map(|range| self.view(*range))
204 }
205
206 #[must_use]
208 pub fn get(&self, name: &str) -> Option<ResponseHeader<'_>> {
209 self.iter()
210 .find(|header| header.name.eq_ignore_ascii_case(name))
211 }
212
213 fn view(&self, range: HeaderRange) -> Option<ResponseHeader<'_>> {
214 let name_start = usize::from(range.name_start);
215 let name_end = name_start.checked_add(usize::from(range.name_len))?;
216 let value_start = usize::from(range.value_start);
217 let value_end = value_start.checked_add(usize::from(range.value_len))?;
218 let name = self
219 .bytes
220 .get(name_start..name_end)
221 .and_then(|bytes| core::str::from_utf8(bytes).ok())?;
222 let value = self.bytes.get(value_start..value_end)?;
223 Some(ResponseHeader {
224 name,
225 value,
226 sensitivity: range.sensitivity,
227 })
228 }
229}
230
231impl Default for ResponseHeaders {
232 fn default() -> Self {
233 Self::new()
234 }
235}
236
237impl fmt::Debug for ResponseHeaders {
238 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
239 formatter
240 .debug_struct("ResponseHeaders")
241 .field("count", &self.count)
242 .field("encoded_len", &self.encoded_len)
243 .field("values", &"[redacted]")
244 .finish()
245 }
246}