1use crate::{get_body, parse_header, split_lines};
2use alloc::string::ToString;
3
4pub struct HttpResponseParser<'a>(&'a [u8]);
5
6impl<'a> HttpResponseParser<'a> {
7 pub fn from_buffer(buffer: &'a [u8]) -> Self {
8 HttpResponseParser(buffer)
9 }
10
11 pub fn split_lines(&self) -> impl Iterator<Item = &'a [u8]> + Clone + 'a {
12 split_lines(self.0)
13 }
14
15 pub fn get_status_code(&self) -> Option<u16> {
16 let mut lines = self.split_lines();
17
18 let status_line = lines.next()?;
19
20 let mut parts = status_line.splitn(3, |&b| b == b' ');
21
22 parts.next()?; let status_code_str = parts.next()?;
24
25 let status_code_str = core::str::from_utf8(status_code_str).ok()?;
26 let status_code = status_code_str.parse::<u16>().ok()?;
27
28 Some(status_code)
29 }
30
31 pub fn get_headers(&self) -> impl Iterator<Item = (&'a str, &'a str)> + 'a {
32 let mut lines = self.split_lines();
33
34 lines.next();
36
37 lines
38 .take_while(|line| !line.is_empty())
39 .filter_map(parse_header)
40 }
41
42 pub fn get_body(&self) -> Option<&'a [u8]> {
43 get_body(self.0)
44 }
45}
46
47pub struct HttpResponseBuilder<'a> {
48 buffer: &'a mut [u8],
49 position: usize,
50}
51
52impl<'a> HttpResponseBuilder<'a> {
53 pub const LINE_ENDING: &'static [u8] = b"\r\n";
54
55 pub fn from_buffer(buffer: &'a mut [u8]) -> Self {
56 buffer.fill(0);
57
58 HttpResponseBuilder {
59 buffer,
60 position: 0,
61 }
62 }
63
64 pub fn add_line(&mut self, buffer: &[u8]) -> Option<()> {
65 let total_length = buffer.len() + Self::LINE_ENDING.len();
66
67 let destination_buffer = self
68 .buffer
69 .get_mut(self.position..self.position + total_length)?;
70
71 destination_buffer[..buffer.len()].copy_from_slice(buffer);
72 destination_buffer[buffer.len()..buffer.len() + Self::LINE_ENDING.len()]
73 .copy_from_slice(Self::LINE_ENDING);
74
75 self.position += total_length;
76
77 Some(())
78 }
79
80 pub fn add_line_iterator<'b, I>(&mut self, iter: I) -> Option<()>
81 where
82 I: Iterator<Item = &'b [u8]>,
83 {
84 let mut position = self.position; for part in iter {
88 let part_length = part.len();
89
90 let destination_buffer = self.buffer.get_mut(position..position + part_length)?;
91
92 destination_buffer.copy_from_slice(part);
93 position += part_length;
94 }
95
96 let destination_buffer = self
97 .buffer
98 .get_mut(position..position + Self::LINE_ENDING.len())?;
99 destination_buffer.copy_from_slice(Self::LINE_ENDING);
100 position += Self::LINE_ENDING.len();
101
102 self.position = position;
103
104 Some(())
105 }
106
107 pub fn add_status_code(&mut self, status_code: u16) -> Option<()> {
108 let status_line = &["HTTP/1.1 ", &status_code.to_string(), " \r\n"].concat();
109 self.add_line(status_line.as_bytes())
110 }
111
112 pub fn add_header(&mut self, name: &str, value: &[u8]) -> Option<()> {
113 let header_line = &[name.as_bytes(), b": ", value].concat();
114 self.add_line(header_line)
115 }
116
117 pub fn add_body(&mut self, body: &[u8]) -> Option<()> {
118 let destination_buffer = self
119 .buffer
120 .get_mut(self.position..self.position + body.len())?;
121
122 destination_buffer.copy_from_slice(body);
123 self.position += body.len();
124
125 Some(())
126 }
127
128 pub fn add_chunk(&mut self, chunk: &[u8]) -> Option<()> {
129 self.add_line(chunk.len().to_string().as_bytes())?;
130 self.add_line(chunk)?;
131 Some(())
132 }
133
134 pub fn get_position(&self) -> usize {
135 self.position
136 }
137}