Skip to content

Commit faa187d

Browse files
edge-http: make fields in {Req,Resp}Headers non-optional
Ensures that the {Req,Resp}Headers is always complete and adheres to the HTTP spec. Saves a lot code from dealing with `Option`s. Also, `send_status_line` is removed, and inlined into `send_request` and `send_status`.
1 parent 71810bd commit faa187d

File tree

6 files changed

+109
-189
lines changed

6 files changed

+109
-189
lines changed

edge-http/src/io.rs

+80-122
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,10 @@ impl<E> std::error::Error for Error<E> where E: std::error::Error {}
100100
impl<'b, const N: usize> RequestHeaders<'b, N> {
101101
/// Parse the headers from the input stream
102102
pub async fn receive<R>(
103-
&mut self,
104103
buf: &'b mut [u8],
105104
mut input: R,
106105
exact: bool,
107-
) -> Result<(&'b mut [u8], usize), Error<R::Error>>
106+
) -> Result<(Self, &'b mut [u8], usize), Error<R::Error>>
108107
where
109108
R: Read,
110109
{
@@ -114,7 +113,8 @@ impl<'b, const N: usize> RequestHeaders<'b, N> {
114113
Err(e) => return Err(e),
115114
};
116115

117-
let mut parser = httparse::Request::new(&mut self.headers.0);
116+
let mut headers = Headers::<'b, N>::new();
117+
let mut parser = httparse::Request::new(&mut headers.0);
118118

119119
let (headers_buf, body_buf) = buf.split_at_mut(headers_len);
120120

@@ -128,31 +128,34 @@ impl<'b, const N: usize> RequestHeaders<'b, N> {
128128
unreachable!("Should not happen. HTTP header parsing is indeterminate.")
129129
}
130130

131-
self.http11 = if let Some(version) = parser.version {
132-
if version > 1 {
133-
Err(Error::InvalidHeaders)?;
134-
}
135-
136-
Some(version == 1)
137-
} else {
138-
None
131+
let http11 = match parser.version {
132+
Some(0) => false,
133+
Some(1) => true,
134+
_ => Err(Error::InvalidHeaders)?,
139135
};
140136

141-
self.method = parser.method.and_then(Method::new);
142-
self.path = parser.path;
137+
let method_str = parser.method.ok_or(Error::InvalidHeaders)?;
138+
let method = Method::new(method_str).ok_or(Error::InvalidHeaders)?;
139+
let path = parser.path.ok_or(Error::InvalidHeaders)?;
143140

144-
trace!("Received:\n{}", self);
141+
let result = Self {
142+
http11,
143+
method,
144+
path,
145+
headers,
146+
};
145147

146-
Ok((body_buf, read_len - headers_len))
148+
trace!("Received:\n{}", result);
149+
150+
Ok((result, body_buf, read_len - headers_len))
147151
} else {
148152
unreachable!("Secondary parse of already loaded buffer failed.")
149153
}
150154
}
151155

152156
/// Resolve the connection type and body type from the headers
153157
pub fn resolve<E>(&self) -> Result<(ConnectionType, BodyType), Error<E>> {
154-
self.headers
155-
.resolve::<E>(None, true, self.http11.unwrap_or(false))
158+
self.headers.resolve::<E>(None, true, self.http11)
156159
}
157160

158161
/// Send the headers to the output stream, returning the connection type and body type
@@ -164,31 +167,29 @@ impl<'b, const N: usize> RequestHeaders<'b, N> {
164167
where
165168
W: Write,
166169
{
167-
let http11 = self.http11.unwrap_or(false);
168-
169-
send_request(http11, self.method, self.path, &mut output).await?;
170+
send_request(self.http11, self.method, self.path, &mut output).await?;
170171

171172
self.headers
172-
.send(None, true, http11, chunked_if_unspecified, output)
173+
.send(None, true, self.http11, chunked_if_unspecified, output)
173174
.await
174175
}
175176
}
176177

177178
impl<'b, const N: usize> ResponseHeaders<'b, N> {
178179
/// Parse the headers from the input stream
179180
pub async fn receive<R>(
180-
&mut self,
181181
buf: &'b mut [u8],
182182
mut input: R,
183183
exact: bool,
184-
) -> Result<(&'b mut [u8], usize), Error<R::Error>>
184+
) -> Result<(Self, &'b mut [u8], usize), Error<R::Error>>
185185
where
186186
R: Read,
187187
{
188188
let (read_len, headers_len) =
189189
raw::read_reply_buf::<N, _>(&mut input, buf, false, exact).await?;
190190

191-
let mut parser = httparse::Response::new(&mut self.headers.0);
191+
let mut headers = Headers::<'b, N>::new();
192+
let mut parser = httparse::Response::new(&mut headers.0);
192193

193194
let (headers_buf, body_buf) = buf.split_at_mut(headers_len);
194195

@@ -199,22 +200,25 @@ impl<'b, const N: usize> ResponseHeaders<'b, N> {
199200
unreachable!("Should not happen. HTTP header parsing is indeterminate.")
200201
}
201202

202-
self.http11 = if let Some(version) = parser.version {
203-
if version > 1 {
204-
Err(Error::InvalidHeaders)?;
205-
}
206-
207-
Some(version == 1)
208-
} else {
209-
None
203+
let http11 = match parser.version {
204+
Some(0) => false,
205+
Some(1) => true,
206+
_ => Err(Error::InvalidHeaders)?,
210207
};
211208

212-
self.code = parser.code;
213-
self.reason = parser.reason;
209+
let code = parser.code.ok_or(Error::InvalidHeaders)?;
210+
let reason = parser.reason;
211+
212+
let result = Self {
213+
http11,
214+
code,
215+
reason,
216+
headers,
217+
};
214218

215-
trace!("Received:\n{}", self);
219+
trace!("Received:\n{}", result);
216220

217-
Ok((body_buf, read_len - headers_len))
221+
Ok((result, body_buf, read_len - headers_len))
218222
} else {
219223
unreachable!("Secondary parse of already loaded buffer failed.")
220224
}
@@ -225,11 +229,8 @@ impl<'b, const N: usize> ResponseHeaders<'b, N> {
225229
&self,
226230
request_connection_type: ConnectionType,
227231
) -> Result<(ConnectionType, BodyType), Error<E>> {
228-
self.headers.resolve::<E>(
229-
Some(request_connection_type),
230-
false,
231-
self.http11.unwrap_or(false),
232-
)
232+
self.headers
233+
.resolve::<E>(Some(request_connection_type), false, self.http11)
233234
}
234235

235236
/// Send the headers to the output stream, returning the connection type and body type
@@ -242,15 +243,13 @@ impl<'b, const N: usize> ResponseHeaders<'b, N> {
242243
where
243244
W: Write,
244245
{
245-
let http11 = self.http11.unwrap_or(false);
246-
247-
send_status(http11, self.code, self.reason, &mut output).await?;
246+
send_status(self.http11, self.code, self.reason, &mut output).await?;
248247

249248
self.headers
250249
.send(
251250
Some(request_connection_type),
252251
false,
253-
http11,
252+
self.http11,
254253
chunked_if_unspecified,
255254
output,
256255
)
@@ -260,42 +259,56 @@ impl<'b, const N: usize> ResponseHeaders<'b, N> {
260259

261260
pub(crate) async fn send_request<W>(
262261
http11: bool,
263-
method: Option<Method>,
264-
path: Option<&str>,
265-
output: W,
262+
method: Method,
263+
path: &str,
264+
mut output: W,
266265
) -> Result<(), Error<W::Error>>
267266
where
268267
W: Write,
269268
{
270-
raw::send_status_line(
271-
true,
272-
http11,
273-
method.map(|method| method.as_str()),
274-
path,
275-
output,
276-
)
277-
.await
269+
// RFC 9112: request-line = method SP request-target SP HTTP-version
270+
271+
output
272+
.write_all(method.as_str().as_bytes())
273+
.await
274+
.map_err(Error::Io)?;
275+
output.write_all(b" ").await.map_err(Error::Io)?;
276+
output.write_all(path.as_bytes()).await.map_err(Error::Io)?;
277+
output.write_all(b" ").await.map_err(Error::Io)?;
278+
raw::send_version(&mut output, http11).await?;
279+
output.write_all(b"\r\n").await.map_err(Error::Io)?;
280+
281+
Ok(())
278282
}
279283

280284
pub(crate) async fn send_status<W>(
281285
http11: bool,
282-
status: Option<u16>,
286+
status: u16,
283287
reason: Option<&str>,
284-
output: W,
288+
mut output: W,
285289
) -> Result<(), Error<W::Error>>
286290
where
287291
W: Write,
288292
{
289-
let status_str: Option<heapless::String<5>> = status.map(|status| status.try_into().unwrap());
293+
// RFC 9112: status-line = HTTP-version SP status-code SP [ reason-phrase ]
290294

291-
raw::send_status_line(
292-
false,
293-
http11,
294-
status_str.as_ref().map(|status| status.as_str()),
295-
reason,
296-
output,
297-
)
298-
.await
295+
raw::send_version(&mut output, http11).await?;
296+
output.write_all(b" ").await.map_err(Error::Io)?;
297+
let status_str: heapless::String<5> = status.try_into().unwrap();
298+
output
299+
.write_all(status_str.as_bytes())
300+
.await
301+
.map_err(Error::Io)?;
302+
output.write_all(b" ").await.map_err(Error::Io)?;
303+
if let Some(reason) = reason {
304+
output
305+
.write_all(reason.as_bytes())
306+
.await
307+
.map_err(Error::Io)?;
308+
}
309+
output.write_all(b"\r\n").await.map_err(Error::Io)?;
310+
311+
Ok(())
299312
}
300313

301314
pub(crate) async fn send_headers<'a, H, W>(
@@ -1181,61 +1194,6 @@ mod raw {
11811194
}
11821195
}
11831196

1184-
pub(crate) async fn send_status_line<W>(
1185-
request: bool,
1186-
http11: bool,
1187-
token: Option<&str>,
1188-
extra: Option<&str>,
1189-
mut output: W,
1190-
) -> Result<(), Error<W::Error>>
1191-
where
1192-
W: Write,
1193-
{
1194-
let mut written = false;
1195-
1196-
if !request {
1197-
send_version(&mut output, http11).await?;
1198-
written = true;
1199-
}
1200-
1201-
if let Some(token) = token {
1202-
if written {
1203-
output.write_all(b" ").await.map_err(Error::Io)?;
1204-
}
1205-
1206-
output
1207-
.write_all(token.as_bytes())
1208-
.await
1209-
.map_err(Error::Io)?;
1210-
1211-
written = true;
1212-
}
1213-
1214-
if written {
1215-
output.write_all(b" ").await.map_err(Error::Io)?;
1216-
}
1217-
if let Some(extra) = extra {
1218-
output
1219-
.write_all(extra.as_bytes())
1220-
.await
1221-
.map_err(Error::Io)?;
1222-
1223-
written = true;
1224-
}
1225-
1226-
if request {
1227-
if written {
1228-
output.write_all(b" ").await.map_err(Error::Io)?;
1229-
}
1230-
1231-
send_version(&mut output, http11).await?;
1232-
}
1233-
1234-
output.write_all(b"\r\n").await.map_err(Error::Io)?;
1235-
1236-
Ok(())
1237-
}
1238-
12391197
pub(crate) async fn send_version<W>(mut output: W, http11: bool) -> Result<(), Error<W::Error>>
12401198
where
12411199
W: Write,

edge-http/src/io/client.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -174,16 +174,15 @@ where
174174
let mut state = self.unbind();
175175

176176
let result = async {
177-
match send_request(http11, Some(method), Some(uri), state.io.as_mut().unwrap()).await {
177+
match send_request(http11, method, uri, state.io.as_mut().unwrap()).await {
178178
Ok(_) => (),
179179
Err(Error::Io(_)) => {
180180
if !fresh_connection {
181181
// Attempt to reconnect and re-send the request
182182
state.io = None;
183183
state.io = Some(state.socket.connect(state.addr).await.map_err(Error::Io)?);
184184

185-
send_request(http11, Some(method), Some(uri), state.io.as_mut().unwrap())
186-
.await?;
185+
send_request(http11, method, uri, state.io.as_mut().unwrap()).await?;
187186
}
188187
}
189188
Err(other) => Err(other)?,
@@ -264,13 +263,8 @@ where
264263
let mut state = self.unbind();
265264
let buf_ptr: *mut [u8] = state.buf;
266265

267-
let mut response = ResponseHeaders::new();
268-
269-
match response
270-
.receive(state.buf, &mut state.io.as_mut().unwrap(), true)
271-
.await
272-
{
273-
Ok((buf, read_len)) => {
266+
match ResponseHeaders::receive(state.buf, &mut state.io.as_mut().unwrap(), true).await {
267+
Ok((response, buf, read_len)) => {
274268
let (connection_type, body_type) =
275269
response.resolve::<T::Error>(request_connection_type)?;
276270

0 commit comments

Comments
 (0)