crates/knut-wasm-host/src/response.rs
//! The one body type every host response carries, and the three ways to build one.
//!
//! `Full<Bytes>` and nothing cleverer: a file, a redirect and a refusal are all
//! one-shot bodies whose length is known, and the bytes are already in memory
//! (refcounted, so a response is a pointer clone). The *streaming* body lives in
//! [`crate::sse`] and is a separate type on purpose — a caller mounts the file host
//! and the frame stream at different routes.
use bytes::Bytes;
use http_body_util::Full;
use hyper::http::{Response, StatusCode, header};
/// The body of every response this host builds.
pub type HostBody = Full<Bytes>;
/// `status` + `content-type` + bytes.
#[must_use]
pub fn bytes_response(
status: StatusCode,
content_type: &str,
body: Bytes,
) -> Response<HostBody> {
Response::builder()
.status(status)
.header(header::CONTENT_TYPE, content_type)
.body(Full::new(body))
.expect("a status and a content type always build a response")
}
/// A plain-text response — what every refusal is. Text, so a browser shows it and a
/// terminal can read it, and never a blank page.
#[must_use]
pub fn text_response(status: StatusCode, text: impl Into<Bytes>) -> Response<HostBody> {
bytes_response(status, "text/plain; charset=utf-8", text.into())
}
/// A `303 See Other` to `location`, with an empty body.
#[must_use]
pub fn redirect_response(location: &str) -> Response<HostBody> {
Response::builder()
.status(StatusCode::SEE_OTHER)
.header(header::LOCATION, location)
.body(Full::new(Bytes::new()))
.expect("a location header always builds a redirect")
}