1use super::error::Http1BuildError;
4use super::fields::Http1FieldRef;
5use super::fields::{is_token, validate_field_ref};
6use super::head::{Http1RequestHead, Http1ResponseHead, Http1Version};
7use super::head::{valid_reason, valid_request_target};
8
9pub struct Http1RequestHeadBuilder<'output, 'input, 'fields> {
11 buffer: &'output mut [u8],
12 method: &'input [u8],
13 target: &'input [u8],
14 version: Http1Version,
15 fields: &'fields [Http1FieldRef<'input>],
16}
17
18impl<'output, 'input, 'fields> Http1RequestHeadBuilder<'output, 'input, 'fields> {
19 pub const fn new(
21 buffer: &'output mut [u8],
22 method: &'input [u8],
23 target: &'input [u8],
24 version: Http1Version,
25 fields: &'fields [Http1FieldRef<'input>],
26 ) -> Self {
27 Self {
28 buffer,
29 method,
30 target,
31 version,
32 fields,
33 }
34 }
35
36 pub fn build(self) -> Result<Http1RequestHead<'output>, Http1BuildError> {
38 if self.method.is_empty()
39 || !self.method.iter().copied().all(is_token)
40 || !valid_request_target(self.target)
41 || !self.fields.iter().copied().all(validate_field_ref)
42 {
43 return Err(Http1BuildError::InvalidValue);
44 }
45 let start_line_len = checked_sum(&[
46 self.method.len(),
47 1,
48 self.target.len(),
49 1,
50 self.version.as_bytes().len(),
51 2,
52 ])?;
53 let fields_len = encoded_fields_len(self.fields)?;
54 let required = checked_sum(&[start_line_len, fields_len, 2])?;
55 if self.buffer.len() < required {
56 return Err(Http1BuildError::BufferTooShort {
57 required,
58 available: self.buffer.len(),
59 });
60 }
61
62 let method_end = self.method.len();
63 let target_end = method_end + 1 + self.target.len();
64 let fields_start = start_line_len;
65 let mut offset = 0;
66 write_part(self.buffer, &mut offset, self.method);
67 write_part(self.buffer, &mut offset, b" ");
68 write_part(self.buffer, &mut offset, self.target);
69 write_part(self.buffer, &mut offset, b" ");
70 write_part(self.buffer, &mut offset, self.version.as_bytes());
71 write_part(self.buffer, &mut offset, b"\r\n");
72 write_fields(self.buffer, &mut offset, self.fields);
73 write_part(self.buffer, &mut offset, b"\r\n");
74 Ok(Http1RequestHead::from_validated(
75 &self.buffer[..required],
76 method_end,
77 target_end,
78 fields_start,
79 self.version,
80 ))
81 }
82}
83
84pub struct Http1ResponseHeadBuilder<'output, 'input, 'fields> {
86 buffer: &'output mut [u8],
87 version: Http1Version,
88 status: u16,
89 reason: &'input [u8],
90 fields: &'fields [Http1FieldRef<'input>],
91}
92
93impl<'output, 'input, 'fields> Http1ResponseHeadBuilder<'output, 'input, 'fields> {
94 pub const fn new(
96 buffer: &'output mut [u8],
97 version: Http1Version,
98 status: u16,
99 reason: &'input [u8],
100 fields: &'fields [Http1FieldRef<'input>],
101 ) -> Self {
102 Self {
103 buffer,
104 version,
105 status,
106 reason,
107 fields,
108 }
109 }
110
111 pub fn build(self) -> Result<Http1ResponseHead<'output>, Http1BuildError> {
113 if self.status > 999
114 || !valid_reason(self.reason)
115 || !self.fields.iter().copied().all(validate_field_ref)
116 {
117 return Err(Http1BuildError::InvalidValue);
118 }
119 let start_line_len =
120 checked_sum(&[self.version.as_bytes().len(), 1, 3, 1, self.reason.len(), 2])?;
121 let fields_len = encoded_fields_len(self.fields)?;
122 let required = checked_sum(&[start_line_len, fields_len, 2])?;
123 if self.buffer.len() < required {
124 return Err(Http1BuildError::BufferTooShort {
125 required,
126 available: self.buffer.len(),
127 });
128 }
129
130 let reason_start = self.version.as_bytes().len() + 1 + 3 + 1;
131 let fields_start = start_line_len;
132 let status = [
133 b'0' + ((self.status / 100) as u8),
134 b'0' + (((self.status / 10) % 10) as u8),
135 b'0' + ((self.status % 10) as u8),
136 ];
137 let mut offset = 0;
138 write_part(self.buffer, &mut offset, self.version.as_bytes());
139 write_part(self.buffer, &mut offset, b" ");
140 write_part(self.buffer, &mut offset, &status);
141 write_part(self.buffer, &mut offset, b" ");
142 write_part(self.buffer, &mut offset, self.reason);
143 write_part(self.buffer, &mut offset, b"\r\n");
144 write_fields(self.buffer, &mut offset, self.fields);
145 write_part(self.buffer, &mut offset, b"\r\n");
146 Ok(Http1ResponseHead::from_validated(
147 &self.buffer[..required],
148 self.status,
149 reason_start,
150 fields_start,
151 self.version,
152 ))
153 }
154}
155
156fn encoded_fields_len(fields: &[Http1FieldRef<'_>]) -> Result<usize, Http1BuildError> {
157 let mut length = 0usize;
158 for field in fields {
159 length = length
160 .checked_add(field.name().len())
161 .and_then(|length| length.checked_add(1))
162 .and_then(|length| length.checked_add(field.value().len()))
163 .and_then(|length| length.checked_add(2))
164 .ok_or(Http1BuildError::LengthTooLarge)?;
165 }
166 Ok(length)
167}
168
169fn checked_sum(parts: &[usize]) -> Result<usize, Http1BuildError> {
170 parts.iter().try_fold(0usize, |total, part| {
171 total
172 .checked_add(*part)
173 .ok_or(Http1BuildError::LengthTooLarge)
174 })
175}
176
177fn write_fields(buffer: &mut [u8], offset: &mut usize, fields: &[Http1FieldRef<'_>]) {
178 for field in fields {
179 write_part(buffer, offset, field.name());
180 write_part(buffer, offset, b":");
181 write_part(buffer, offset, field.value());
182 write_part(buffer, offset, b"\r\n");
183 }
184}
185
186fn write_part(buffer: &mut [u8], offset: &mut usize, part: &[u8]) {
187 let end = *offset + part.len();
188 buffer[*offset..end].copy_from_slice(part);
189 *offset = end;
190}