mini-serve 0.13.8

An HTTP server: trie router, middleware, CORS, optional TLS. Built on hyper + tokio.
Documentation
use hyper::header::HeaderValue;
use hyper::{Response, StatusCode};
use http_body_util::combinators::BoxBody;
use http_body_util::{BodyExt, Full};
use hyper::body::Bytes;
use serde::Serialize;

use crate::error::ServeError;
use crate::handler::ResponseBody;

/// Build a JSON response with the given status code and serializable value.
///
/// Sets `Content-Type: application/json` and `Content-Length` headers.
/// Returns `500 Internal Server Error` if serialization fails.
pub fn json<T: Serialize>(status: StatusCode, value: &T) -> Result<Response<ResponseBody>, ServeError> {
	let body = serde_json::to_string(value)
		.map_err(|_| ServeError::new(500, "failed to serialize response"))?;
	let len = body.len();
	let mut resp = Response::new(BoxBody::new(
		Full::new(Bytes::from(body)).map_err(|never: std::convert::Infallible| match never {}),
	));
	*resp.status_mut() = status;

	// Const `HeaderName`s and a static value: a `&str` here would be re-parsed
	// into a `HeaderName` on every response, which showed up in the profile as
	// `header::name::parse_hdr`.
	//
	// `insert`, not `Response::builder().header(…)`, which routes to `try_append` and
	// scans the map for an existing entry of that name — 4.58% of this crate's profile
	// against axum's 1.82%, for a map we just created and know to be empty.
	//
	// This is safe here and is *not* a technique to apply elsewhere: `insert` replaces
	// where `append` adds, which is invisible for `Content-Type` and `Content-Length`
	// (single-valued by definition) and destructive for headers that may legitimately
	// repeat — `Set-Cookie`, and above all `Vary`, where dropping a value is a
	// cache-poisoning vector. `cors.rs` already emits `vary: origin`. Any other call
	// site needs its own analysis of whether that header can repeat.
	let headers = resp.headers_mut();
	headers.insert(hyper::header::CONTENT_TYPE, HeaderValue::from_static("application/json"));
	headers.insert(hyper::header::CONTENT_LENGTH, len.into());
	Ok(resp)
}