Skip to main content

static_web_server/
body.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// This file is part of Static Web Server.
3// See https://static-web-server.net/ for more information
4// Copyright (C) 2019-present Jose Quintana <joseluisq.net>
5
6//! Unified HTTP response body type and constructor helpers.
7//!
8//! This module provides a single concrete body type alias and a small set of
9//! constructor functions.
10
11use bytes::Bytes;
12use http_body::Frame;
13use http_body_util::{BodyExt, Empty, Full, StreamBody, combinators::BoxBody};
14use std::io;
15
16/// Unified response body type used throughout the server.
17///
18/// A type-erased boxed body backed by [`http_body_util::combinators::BoxBody`]
19/// with [`bytes::Bytes`] data frames and [`io::Error`] errors.
20///
21/// This single type covers all body variants used by the server:
22/// - Empty bodies (for HEAD responses, OPTIONS, redirects)
23/// - In-memory byte buffers (for generated HTML, Prometheus metrics, health checks)
24/// - File streams ([`crate::fs::stream::FileStream`])
25/// - Compressed streams (gzip/brotli/deflate/zstd encoders)
26/// - In-memory cached file streams ([`crate::mem_cache::stream::MemCacheFileStream`])
27pub type Body = BoxBody<Bytes, io::Error>;
28
29/// Creates an empty body (zero bytes).
30///
31/// Replaces `hyper::Body::empty()`.
32#[inline]
33pub fn empty() -> Body {
34    Empty::new().map_err(|never| match never {}).boxed()
35}
36
37/// Creates a full body from in-memory bytes.
38///
39/// Replaces `hyper::Body::from(x)` for byte buffers and strings.
40/// Accepts anything that converts into [`Bytes`]: `String`, `Vec<u8>`, `&'static str`,
41/// `&'static [u8]`, or `Bytes` directly.
42#[inline]
43pub fn full(bytes: impl Into<Bytes>) -> Body {
44    Full::new(bytes.into())
45        .map_err(|never| match never {})
46        .boxed()
47}
48
49/// Creates a streaming body from an async byte stream.
50///
51/// Replaces `hyper::Body::wrap_stream(s)`.
52///
53/// The stream must yield `Result<Bytes, io::Error>`. Each successful item is
54/// wrapped as an HTTP data [`Frame`] before being fed into the body.
55pub fn stream<S>(s: S) -> Body
56where
57    S: futures_util::TryStream<Ok = Bytes, Error = io::Error> + Send + Sync + 'static,
58{
59    use futures_util::TryStreamExt as _;
60    StreamBody::new(s.map_ok(Frame::data)).boxed()
61}