http_net/write.rs
1//! The allocation-free response writer (Tier 3): where serialized bytes go
2//! ([`Output`]), a borrowed description of a response head
3//! ([`ResponseHeadRef`]), and the [`ServerConn`] methods that write into any
4//! `Output`.
5//!
6//! [`ServerConn::respond`] and this writer share one code path, so a head
7//! written here is byte for byte the head `respond` would write for the same
8//! response, with the same validation and framing rules.
9
10use alloc::vec::Vec;
11
12use crate::{date::HttpDate, error::HttpError, message::Response, server::ServerConn};
13
14/// Where serialized bytes go.
15///
16/// `Vec<u8>` is the default; a driver can write straight into its own buffer
17/// instead (a zeroizing buffer that wipes on drop, a fixed slab in a passport,
18/// a socket's send queue). [`put`](Self::put) cannot fail: an `Output` with a
19/// fixed capacity must grow, or mark itself poisoned and have its owner close
20/// the connection, because a half-written response cannot be recovered
21/// anyway. [`reserve`](Self::reserve) is a hint and may be ignored.
22///
23/// # Examples
24///
25/// ```
26/// use http_net::Output;
27///
28/// /// Counts bytes without keeping them.
29/// struct Meter(usize);
30///
31/// impl Output for Meter {
32/// fn put(&mut self, bytes: &[u8]) {
33/// self.0 += bytes.len();
34/// }
35/// }
36///
37/// let mut m = Meter(0);
38/// m.put(b"HTTP/1.1 ");
39/// m.put(b"204 No Content\r\n");
40/// assert_eq!(m.0, 25);
41/// ```
42pub trait Output {
43 /// Appends `bytes`.
44 fn put(&mut self, bytes: &[u8]);
45
46 /// Says that about `additional` more bytes are coming; an
47 /// implementation may grow once instead of several times. Optional.
48 fn reserve(&mut self, additional: usize) {
49 let _ = additional;
50 }
51}
52
53impl Output for Vec<u8> {
54 #[inline]
55 fn put(&mut self, bytes: &[u8]) {
56 self.extend_from_slice(bytes);
57 }
58
59 #[inline]
60 fn reserve(&mut self, additional: usize) {
61 Vec::reserve(self, additional);
62 }
63}
64
65impl<O: Output + ?Sized> Output for &mut O {
66 #[inline]
67 fn put(&mut self, bytes: &[u8]) {
68 (**self).put(bytes);
69 }
70
71 #[inline]
72 fn reserve(&mut self, additional: usize) {
73 (**self).reserve(additional);
74 }
75}
76
77/// How the body of a response written with
78/// [`ServerConn::write_head`] is supplied.
79///
80/// # Examples
81///
82/// ```
83/// use http_net::OutgoingBody;
84///
85/// let body = b"hello";
86/// let full = OutgoingBody::Full(body.len() as u64);
87/// assert_ne!(full, OutgoingBody::Chunked);
88/// ```
89#[non_exhaustive]
90#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
91pub enum OutgoingBody {
92 /// No body: `content-length: 0` (or nothing, for a status that never
93 /// carries one).
94 Empty,
95 /// A body of exactly this many bytes that the caller writes itself,
96 /// right after the head (for example with one vectored write of head and
97 /// body); sent with `content-length`. The response is complete once the
98 /// caller has written them.
99 Full(u64),
100 /// A streamed body of exactly this many bytes, sent with
101 /// `content-length` through `send_body` and `end_body`.
102 Length(u64),
103 /// A streamed body with chunked encoding (close-delimited to an
104 /// HTTP/1.0 client), through `send_body` and `end_body`.
105 Chunked,
106}
107
108/// What the caller must do after [`ServerConn::write_head`].
109///
110/// # Examples
111///
112/// ```
113/// use http_net::BodyPlan;
114///
115/// let plan = BodyPlan::Raw;
116/// assert!(matches!(plan, BodyPlan::Raw));
117/// ```
118#[non_exhaustive]
119#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
120pub enum BodyPlan {
121 /// The response is complete: there is no body to send (an empty body, a
122 /// `HEAD` request, a status without a body, or an upgrade).
123 None,
124 /// Write the [`OutgoingBody::Full`] bytes as they are, right after the
125 /// head; the connection already counts the response as complete.
126 Raw,
127 /// Stream the body with [`ServerConn::send_body`] (or
128 /// [`send_body_into`](ServerConn::send_body_into)) and end it with
129 /// [`ServerConn::end_body`] (or [`end_body_into`](ServerConn::end_body_into)).
130 Stream,
131}
132
133/// A response head described with borrowed data, for
134/// [`ServerConn::write_head`]: nothing is copied into an owned builder and
135/// nothing is allocated.
136///
137/// The fields are validated when the head is written, with the same rules as
138/// [`Response::header`]: token names, no framing or connection fields (the
139/// connection writes those), no control bytes or surrounding whitespace in
140/// values. A `date` field among them stops a date passed to `write_head`
141/// from being added. `upgrade` names the protocol of a `101 Switching
142/// Protocols`, as [`Response::switching_protocols`] does.
143///
144/// The struct is built with a literal, so its fields are public and it is
145/// not `#[non_exhaustive]`; use [`ResponseHeadRef::new`] to start from the
146/// defaults.
147///
148/// # Examples
149///
150/// ```
151/// use http_net::{OutgoingBody, ResponseHeadRef};
152///
153/// let fields: &[(&str, &[u8])] = &[("content-type", b"text/plain")];
154/// let head = ResponseHeadRef {
155/// status: 200,
156/// fields,
157/// body: OutgoingBody::Full(5),
158/// close: false,
159/// upgrade: None,
160/// };
161/// assert_eq!(head, ResponseHeadRef::new(200, fields, OutgoingBody::Full(5)));
162/// ```
163#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
164pub struct ResponseHeadRef<'a> {
165 /// The status code (`100..=599`; among the 1xx codes only `101`).
166 pub status: u16,
167 /// The fields, in order, as `(name, value)`.
168 pub fields: &'a [(&'a str, &'a [u8])],
169 /// How the body is supplied.
170 pub body: OutgoingBody,
171 /// Close the connection after this response.
172 pub close: bool,
173 /// The protocol a `101` switches to.
174 pub upgrade: Option<&'a str>,
175}
176
177impl<'a> ResponseHeadRef<'a> {
178 /// A head with `status`, `fields`, and `body`; no close, no upgrade.
179 ///
180 /// # Examples
181 ///
182 /// ```
183 /// use http_net::{OutgoingBody, ResponseHeadRef};
184 ///
185 /// let head = ResponseHeadRef::new(204, &[], OutgoingBody::Empty);
186 /// assert!(!head.close);
187 /// ```
188 #[must_use]
189 pub const fn new(status: u16, fields: &'a [(&'a str, &'a [u8])], body: OutgoingBody) -> Self {
190 Self {
191 status,
192 fields,
193 body,
194 close: false,
195 upgrade: None,
196 }
197 }
198}
199
200impl ServerConn {
201 /// Writes a response head described by borrowed data into any
202 /// [`Output`] and says how to send the body. Nothing is allocated; the
203 /// validation, framing fields, `connection` handling, and state changes
204 /// are those of [`respond`](Self::respond), and the bytes are the same
205 /// as `respond` would write for the equivalent [`Response`]. `date`, when
206 /// given and the fields set no `date`, is written as `date: <date>`.
207 ///
208 /// After [`BodyPlan::Raw`] write the [`OutgoingBody::Full`] bytes
209 /// yourself (for example with one vectored write of head and body); the
210 /// response then counts as complete. After [`BodyPlan::Stream`] use
211 /// [`send_body_into`](Self::send_body_into) and
212 /// [`end_body_into`](Self::end_body_into) (or the `Vec` versions).
213 ///
214 /// # Errors
215 ///
216 /// As [`respond`](Self::respond), with the field errors of
217 /// [`Response::header`] for `fields` and those of
218 /// [`Response::switching_protocols`] for `upgrade`
219 /// ([`HttpError::InvalidHeaderValue`] when it is not a protocol token,
220 /// [`HttpError::UpgradeNotOffered`] for `h2c` or a protocol the request
221 /// did not offer). An `upgrade` on a status other than `101`, or a
222 /// `101` without one, is [`HttpError::InvalidState`]. Nothing is written
223 /// on error.
224 ///
225 /// # Examples
226 ///
227 /// ```
228 /// use http_net::{BodyPlan, OutgoingBody, ResponseHeadRef, ServerConn, ServerEvent};
229 ///
230 /// let mut conn = ServerConn::new();
231 /// let _ = conn.feed(b"GET /app.js HTTP/1.1\r\nHost: a\r\n\r\n");
232 /// while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
233 ///
234 /// let body: &[u8] = b"console.log(1)";
235 /// let fields: &[(&str, &[u8])] = &[("content-type", b"text/javascript")];
236 /// let head = ResponseHeadRef::new(200, fields, OutgoingBody::Full(body.len() as u64));
237 /// let mut out = Vec::with_capacity(256);
238 /// let plan = conn.write_head(&head, None, &mut out)?;
239 /// assert_eq!(plan, BodyPlan::Raw);
240 /// assert_eq!(out, b"HTTP/1.1 200 OK\r\ncontent-length: 14\r\ncontent-type: text/javascript\r\n\r\n");
241 /// out.extend_from_slice(body); // or one vectored write of both
242 /// # Ok::<(), http_net::HttpError>(())
243 /// ```
244 pub fn write_head<O: Output + ?Sized>(
245 &mut self,
246 head: &ResponseHeadRef<'_>,
247 date: Option<&HttpDate>,
248 out: &mut O,
249 ) -> Result<BodyPlan, HttpError> {
250 self.start_response(head, date.map(HttpDate::as_bytes).map(|d| &d[..]), out)
251 }
252
253 /// [`respond`](Self::respond) into any [`Output`], with an optional
254 /// `date` as in [`respond_with_date`](Self::respond_with_date). A full
255 /// body is written after the head; a streamed one continues with
256 /// [`send_body_into`](Self::send_body_into) and
257 /// [`end_body_into`](Self::end_body_into).
258 ///
259 /// # Errors
260 ///
261 /// As [`respond`](Self::respond).
262 ///
263 /// # Examples
264 ///
265 /// ```
266 /// use http_net::{Output, Response, ServerConn, ServerEvent};
267 ///
268 /// /// A bounded output that refuses to grow past its capacity.
269 /// struct Slab { buf: [u8; 512], len: usize, overflow: bool }
270 ///
271 /// impl Output for Slab {
272 /// fn put(&mut self, bytes: &[u8]) {
273 /// match self.buf.get_mut(self.len..self.len + bytes.len()) {
274 /// Some(dst) => {
275 /// dst.copy_from_slice(bytes);
276 /// self.len += bytes.len();
277 /// }
278 /// None => self.overflow = true, // the owner closes the connection
279 /// }
280 /// }
281 /// }
282 ///
283 /// let mut conn = ServerConn::new();
284 /// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
285 /// while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
286 /// let mut slab = Slab { buf: [0; 512], len: 0, overflow: false };
287 /// conn.respond_into(&Response::text(200, "hi"), None, &mut slab)?;
288 /// assert!(!slab.overflow);
289 /// assert!(slab.buf[..slab.len].ends_with(b"\r\n\r\nhi"));
290 /// # Ok::<(), http_net::HttpError>(())
291 /// ```
292 pub fn respond_into<O: Output + ?Sized>(
293 &mut self,
294 response: &Response,
295 date: Option<&HttpDate>,
296 out: &mut O,
297 ) -> Result<(), HttpError> {
298 self.respond_dated(response, date.map(|d| &d.as_bytes()[..]), out)
299 }
300
301 /// [`send_body`](Self::send_body) into any [`Output`].
302 ///
303 /// # Errors
304 ///
305 /// As [`send_body`](Self::send_body).
306 ///
307 /// # Examples
308 ///
309 /// ```
310 /// use http_net::{BodyPlan, OutgoingBody, ResponseHeadRef, ServerConn, ServerEvent};
311 ///
312 /// let mut conn = ServerConn::new();
313 /// let _ = conn.feed(b"GET /log HTTP/1.1\r\nHost: a\r\n\r\n");
314 /// while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
315 /// let mut out = Vec::new();
316 /// let head = ResponseHeadRef::new(200, &[], OutgoingBody::Chunked);
317 /// assert_eq!(conn.write_head(&head, None, &mut out)?, BodyPlan::Stream);
318 /// conn.send_body_into(b"line\n", &mut out)?;
319 /// conn.end_body_into(&[], &mut out)?;
320 /// assert!(out.ends_with(b"5\r\nline\n\r\n0\r\n\r\n"));
321 /// # Ok::<(), http_net::HttpError>(())
322 /// ```
323 pub fn send_body_into<O: Output + ?Sized>(
324 &mut self,
325 data: &[u8],
326 out: &mut O,
327 ) -> Result<(), HttpError> {
328 self.stream_body(data, out)
329 }
330
331 /// Ends a streamed body into any [`Output`], with `trailers` (empty for
332 /// none): [`end_body`](Self::end_body) and
333 /// [`end_body_with_trailers`](Self::end_body_with_trailers) in one.
334 ///
335 /// # Errors
336 ///
337 /// As [`end_body_with_trailers`](Self::end_body_with_trailers).
338 ///
339 /// # Examples
340 ///
341 /// See [`send_body_into`](Self::send_body_into).
342 pub fn end_body_into<O: Output + ?Sized>(
343 &mut self,
344 trailers: &[(&str, &[u8])],
345 out: &mut O,
346 ) -> Result<(), HttpError> {
347 self.finish_body(trailers, out)
348 }
349}
350
351#[cfg(test)]
352mod tests {
353 use alloc::vec;
354
355 use super::*;
356 use crate::{HttpError, ServerEvent};
357
358 fn conn_after(request: &[u8]) -> ServerConn {
359 let mut conn = ServerConn::new();
360 let _ = conn.feed(request);
361 loop {
362 match conn.poll() {
363 Ok(ServerEvent::RequestEnd) | Err(_) => return conn,
364 Ok(_) => {}
365 }
366 }
367 }
368
369 const GET: &[u8] = b"GET / HTTP/1.1\r\nHost: a\r\n\r\n";
370
371 #[test]
372 fn test_write_head_full_body_plans_raw_and_completes() {
373 let mut conn = conn_after(GET);
374 let mut out = Vec::new();
375 let head = ResponseHeadRef::new(200, &[("x", b"1")], OutgoingBody::Full(3));
376 assert_eq!(conn.write_head(&head, None, &mut out), Ok(BodyPlan::Raw));
377 assert_eq!(out, b"HTTP/1.1 200 OK\r\ncontent-length: 3\r\nx: 1\r\n\r\n");
378 assert_eq!(conn.requests_served(), 1);
379 assert!(matches!(conn.poll(), Ok(ServerEvent::NeedInput)));
380 }
381
382 #[test]
383 fn test_write_head_head_request_and_bodiless_plan_none() {
384 let mut conn = conn_after(b"HEAD / HTTP/1.1\r\nHost: a\r\n\r\n");
385 let mut out = Vec::new();
386 let head = ResponseHeadRef::new(200, &[], OutgoingBody::Full(9));
387 assert_eq!(conn.write_head(&head, None, &mut out), Ok(BodyPlan::None));
388 assert!(out.ends_with(b"content-length: 9\r\n\r\n"));
389
390 let mut conn = conn_after(GET);
391 let mut out = Vec::new();
392 let head = ResponseHeadRef::new(204, &[], OutgoingBody::Empty);
393 assert_eq!(conn.write_head(&head, None, &mut out), Ok(BodyPlan::None));
394 assert_eq!(out, b"HTTP/1.1 204 No Content\r\n\r\n");
395 let mut conn = conn_after(GET);
396 let head = ResponseHeadRef::new(304, &[], OutgoingBody::Full(1));
397 assert_eq!(
398 conn.write_head(&head, None, &mut Vec::new()),
399 Err(HttpError::BodyNotAllowed)
400 );
401 }
402
403 #[test]
404 fn test_write_head_refuses_bad_fields_and_writes_nothing() {
405 for (fields, err) in [
406 (
407 &[("content-length", &b"5"[..])][..],
408 HttpError::ReservedHeader,
409 ),
410 (&[("bad name", &b"x"[..])][..], HttpError::InvalidHeaderName),
411 (&[("x", &b"a\r\nb"[..])][..], HttpError::BareCr),
412 (&[("x", &b" pad"[..])][..], HttpError::InvalidHeaderValue),
413 (&[("te", &b"trailers"[..])][..], HttpError::ReservedHeader),
414 ] {
415 let mut conn = conn_after(GET);
416 let mut out = Vec::new();
417 let head = ResponseHeadRef::new(200, fields, OutgoingBody::Empty);
418 assert_eq!(
419 conn.write_head(&head, None, &mut out),
420 Err(err),
421 "{fields:?}"
422 );
423 assert!(out.is_empty());
424 // Nothing changed: a normal response still goes out.
425 conn.respond(&Response::new(204), &mut out).unwrap();
426 }
427 }
428
429 #[test]
430 fn test_write_head_upgrade_rules() {
431 let upgrade_req =
432 b"GET / HTTP/1.1\r\nHost: a\r\nConnection: upgrade\r\nUpgrade: websocket\r\n\r\n";
433 let mut conn = conn_after(upgrade_req);
434 let mut out = Vec::new();
435 let mut head = ResponseHeadRef::new(101, &[], OutgoingBody::Empty);
436 assert!(matches!(
437 conn.write_head(&head, None, &mut out),
438 Err(HttpError::InvalidState(_))
439 ));
440 head.upgrade = Some("irc");
441 assert_eq!(
442 conn.write_head(&head, None, &mut out),
443 Err(HttpError::UpgradeNotOffered)
444 );
445 head.upgrade = Some("h2c");
446 assert_eq!(
447 conn.write_head(&head, None, &mut out),
448 Err(HttpError::UpgradeNotOffered)
449 );
450 head.upgrade = Some("a b");
451 assert_eq!(
452 conn.write_head(&head, None, &mut out),
453 Err(HttpError::InvalidHeaderValue)
454 );
455 let mut on_200 = ResponseHeadRef::new(200, &[], OutgoingBody::Empty);
456 on_200.upgrade = Some("websocket");
457 assert!(matches!(
458 conn.write_head(&on_200, None, &mut out),
459 Err(HttpError::InvalidState(_))
460 ));
461 assert!(out.is_empty());
462 head.upgrade = Some("WebSocket");
463 assert_eq!(conn.write_head(&head, None, &mut out), Ok(BodyPlan::None));
464 assert_eq!(
465 out,
466 b"HTTP/1.1 101 Switching Protocols\r\nconnection: upgrade\r\nupgrade: WebSocket\r\n\r\n"
467 );
468 assert!(conn.is_upgraded());
469 }
470
471 #[test]
472 fn test_write_head_date_unless_set() {
473 let date = HttpDate::from_unix_seconds(0);
474 let mut conn = conn_after(GET);
475 let mut out = Vec::new();
476 let head = ResponseHeadRef::new(204, &[], OutgoingBody::Empty);
477 assert_eq!(
478 conn.write_head(&head, Some(&date), &mut out),
479 Ok(BodyPlan::None)
480 );
481 assert!(
482 out.windows(35)
483 .any(|w| w == b"date: Thu, 01 Jan 1970 00:00:00 GMT")
484 );
485
486 let mut conn = conn_after(GET);
487 let mut out = Vec::new();
488 let fields: &[(&str, &[u8])] = &[("Date", b"x")];
489 let head = ResponseHeadRef::new(204, fields, OutgoingBody::Empty);
490 assert_eq!(
491 conn.write_head(&head, Some(&date), &mut out),
492 Ok(BodyPlan::None)
493 );
494 assert!(!out.windows(4).any(|w| w == b"1970"));
495 }
496
497 #[test]
498 fn test_streaming_into_output_and_state_errors() {
499 let mut conn = conn_after(GET);
500 let mut out = Vec::new();
501 assert!(matches!(
502 conn.send_body_into(b"x", &mut out),
503 Err(HttpError::InvalidState(_))
504 ));
505 let head = ResponseHeadRef::new(200, &[], OutgoingBody::Length(3));
506 assert_eq!(conn.write_head(&head, None, &mut out), Ok(BodyPlan::Stream));
507 assert!(matches!(
508 conn.write_head(&head, None, &mut out),
509 Err(HttpError::InvalidState(_))
510 ));
511 conn.send_body_into(b"ab", &mut out).unwrap();
512 assert_eq!(
513 conn.end_body_into(&[], &mut out),
514 Err(HttpError::BodyLengthMismatch)
515 );
516 conn.send_body_into(b"c", &mut out).unwrap();
517 assert_eq!(
518 conn.end_body_into(&[("x", b"1")], &mut out),
519 Err(HttpError::TrailerNotAllowed)
520 );
521 conn.end_body_into(&[], &mut out).unwrap();
522 assert!(out.ends_with(b"\r\n\r\nabc"));
523 }
524
525 #[test]
526 fn test_output_by_reference_and_reserve_hint() {
527 let mut v = vec![1u8];
528 {
529 let mut r: &mut Vec<u8> = &mut v;
530 Output::reserve(&mut r, 64);
531 r.put(b"23");
532 }
533 assert_eq!(v, b"\x0123");
534 assert!(v.capacity() >= 3);
535 }
536}