1use encodify::{Fold, base64};
19
20mod parse;
21
22pub(crate) use parse::{AuthenticatedHeader, ChainedHeaderIterator, HeaderIterator, HeaderParser};
23
24impl<'x, T> Header<'x, T> {
25 pub fn new(name: &'x [u8], value: &'x [u8], header: T) -> Self {
27 Header {
28 name,
29 value,
30 header,
31 }
32 }
33}
34
35pub(crate) trait HeaderStream<'x> {
36 fn next_header(&mut self) -> Option<(&'x [u8], &'x [u8])>;
37 fn body(&mut self) -> &'x [u8];
38}
39
40pub(crate) const MAX_HEADER_LINE_LEN: usize = 76;
41const MEMCHR_MIN_LEN: usize = 16;
42const BASE64_GROUP_LEN: usize = 4;
43const BASE64_FOLD: Fold<'static> =
44 Fold::new(MAX_HEADER_LINE_LEN - 1, b"\r\n\t", 0).with_granularity(BASE64_GROUP_LEN);
45
46pub struct HeaderFolder<'x, W: Writer> {
53 writer: &'x mut W,
54 bytes_left: usize,
55}
56
57impl<'x, W: Writer> HeaderFolder<'x, W> {
58 pub fn new(writer: &'x mut W) -> Self {
60 HeaderFolder {
61 writer,
62 bytes_left: MAX_HEADER_LINE_LEN,
63 }
64 }
65
66 #[inline(always)]
67 fn write_chunk(&mut self, chunk: &[u8]) {
68 if chunk == b"\r\n" {
69 self.writer.write(chunk);
70 self.bytes_left = MAX_HEADER_LINE_LEN;
71 } else if chunk.len() < self.bytes_left {
72 self.writer.write(chunk);
73 self.bytes_left -= chunk.len();
74 } else if chunk.len() >= MAX_HEADER_LINE_LEN {
75 let mut add_new_line = self.bytes_left != MAX_HEADER_LINE_LEN;
76 let mut last_piece_len = MAX_HEADER_LINE_LEN;
77 for chunk in chunk.chunks(MAX_HEADER_LINE_LEN) {
78 if add_new_line {
79 self.writer.write(b"\r\n\t");
80 }
81 add_new_line = true;
82 self.writer.write(chunk);
83 last_piece_len = chunk.len();
84 }
85 self.bytes_left = MAX_HEADER_LINE_LEN - last_piece_len;
86 } else {
87 self.writer.write(b"\r\n\t");
88 self.writer.write(chunk);
89 self.bytes_left = MAX_HEADER_LINE_LEN - chunk.len();
90 }
91 }
92}
93
94#[inline(always)]
95fn find_semicolon(buf: &[u8]) -> Option<usize> {
96 if buf.len() >= MEMCHR_MIN_LEN {
97 memchr::memchr(b';', buf)
98 } else {
99 buf.iter().position(|ch| *ch == b';')
100 }
101}
102
103impl<'x, W: Writer> Writer for HeaderFolder<'x, W> {
104 fn write(&mut self, buf: &[u8]) {
105 let mut rest = buf;
106 while !rest.is_empty() {
107 let (chunk, tail) = match find_semicolon(rest) {
108 Some(pos) => rest.split_at(pos + 1),
109 None => (rest, Default::default()),
110 };
111 self.write_chunk(chunk);
112 rest = tail;
113 }
114 }
115
116 fn write_base64(&mut self, bytes: &[u8]) {
117 let mut column = MAX_HEADER_LINE_LEN.saturating_sub(self.bytes_left);
118 base64::STANDARD.encode_folded(bytes, &mut column, BASE64_FOLD, |piece| {
119 self.writer.write(piece)
120 });
121 self.bytes_left = MAX_HEADER_LINE_LEN.saturating_sub(column);
122 }
123}
124
125#[derive(Debug, Clone, PartialEq, Eq)]
133pub struct Header<'x, T> {
134 pub name: &'x [u8],
136 pub value: &'x [u8],
139 pub header: T,
141}
142
143pub(crate) const HEADER_CAPACITY: usize = 512;
144
145pub trait HeaderWriter: Sized {
147 fn write_header(&self, writer: &mut impl Writer);
150 fn to_header(&self) -> String {
153 let mut buf = Vec::with_capacity(HEADER_CAPACITY);
154 self.write_header(&mut buf);
155 String::from_utf8(buf)
156 .unwrap_or_else(|err| String::from_utf8_lossy(err.as_bytes()).into_owned())
157 }
158}
159
160pub trait Writable {
165 fn write(self, writer: &mut impl Writer);
167}
168
169impl Writable for &[u8] {
170 fn write(self, writer: &mut impl Writer) {
171 writer.write(self);
172 }
173}
174
175pub trait Writer {
177 fn write(&mut self, buf: &[u8]);
179
180 fn write_len(&mut self, buf: &[u8], len: &mut usize) {
182 self.write(buf);
183 *len += buf.len();
184 }
185
186 fn write_base64(&mut self, bytes: &[u8]) {
189 base64::STANDARD.encode_chunks(bytes, |chunk| self.write(chunk));
190 }
191}
192
193impl Writer for Vec<u8> {
194 fn write(&mut self, buf: &[u8]) {
195 self.extend(buf);
196 }
197}
198
199impl Writer for &mut Vec<u8> {
200 fn write(&mut self, buf: &[u8]) {
201 self.extend(buf);
202 }
203}
204
205const MAX_U64_DIGITS: usize = 20;
206
207pub(crate) struct IntegerBuffer([u8; MAX_U64_DIGITS]);
208
209impl IntegerBuffer {
210 pub(crate) const fn new() -> Self {
211 IntegerBuffer([0; MAX_U64_DIGITS])
212 }
213
214 pub(crate) fn digits(&mut self, value: u64) -> &[u8] {
215 let mut value = value;
216 let mut pos = MAX_U64_DIGITS;
217 loop {
218 pos -= 1;
219 if let Some(digit) = self.0.get_mut(pos) {
220 *digit = b'0' + (value % 10) as u8;
221 }
222 value /= 10;
223 if value == 0 || pos == 0 {
224 break;
225 }
226 }
227 self.0.get(pos..).unwrap_or_default()
228 }
229
230 pub(crate) fn text(&mut self, value: u64) -> &str {
231 std::str::from_utf8(self.digits(value)).unwrap_or_default()
232 }
233}
234
235pub(crate) fn write_integer(writer: &mut impl Writer, value: u64) {
236 let mut buffer = IntegerBuffer::new();
237 writer.write(buffer.digits(value));
238}
239
240#[cfg(test)]
241mod tests;