trillium_http/lib.rs
1#![forbid(unsafe_code)]
2#![deny(
3 clippy::dbg_macro,
4 missing_copy_implementations,
5 rustdoc::missing_crate_level_docs,
6 missing_debug_implementations,
7 nonstandard_style,
8 unused_qualifications
9)]
10#![warn(
11 missing_docs,
12 clippy::pedantic,
13 clippy::perf,
14 clippy::cargo,
15 rustdoc::broken_intra_doc_links
16)]
17#![allow(
18 clippy::must_use_candidate,
19 clippy::module_name_repetitions,
20 clippy::multiple_crate_versions
21)]
22//! This crate provides the http implementations for Trillium.
23//!
24//! ## Stability
25//!
26//! As this is primarily intended for internal use by the [Trillium
27//! crate](https://docs.trillium.rs/trillium), the api is likely to be
28//! less stable than that of the higher level abstractions in Trillium.
29//!
30//! ## Cargo features
31//!
32//! All are off by default.
33//!
34//! - **`serde`** — implements `serde::Serialize` for [`Headers`], [`HeaderName`], [`HeaderValue`],
35//! and [`HeaderValues`], and both `Serialize` and `Deserialize` for [`Method`], [`Status`], and
36//! [`Version`]. The header types are serialize-only — suited to logging and inspection rather
37//! than a faithful round-trip; reach for `rkyv_08` when you need to read the data back.
38//! - **`rkyv_08`** — implements [rkyv](https://docs.rs/rkyv) 0.8's `Archive`, `Serialize`, and
39//! `Deserialize` for [`Method`], [`Status`], [`Version`], [`HeaderName`], [`HeaderValue`],
40//! [`HeaderValues`], and [`Headers`], so they round-trip losslessly through `rkyv::to_bytes` /
41//! `rkyv::from_bytes` — non-utf8 header values and repeated values included. Suited to durable
42//! binary persistence such as an on-disk response cache.
43//! - **`http-compat-0`** and **`http-compat-1`** — conversions between the core trillium-http types
44//! and those of the [`http`](https://docs.rs/http) crate, at its 0.x and 1.x releases
45//! respectively. Enable both to interoperate with each.
46//!
47//! ## Protocol dispatch
48//!
49//! trillium-http supports HTTP/1.0, HTTP/1.1, HTTP/2, and (via `trillium-quinn`)
50//! HTTP/3 on the same listener. The version that a given connection speaks is
51//! decided at accept time:
52//!
53//! | Listener | ALPN result | First bytes | Protocol |
54//! |---|---|---|---|
55//! | TCP + TLS | `h2` | — | HTTP/2 over TLS |
56//! | TCP + TLS | `http/1.1` | — | HTTP/1.1 over TLS |
57//! | TCP + TLS | absent or other | match HTTP/2 preface (`PRI * HTTP/2.0…`) | HTTP/2 "prior knowledge" over TLS |
58//! | TCP + TLS | absent or other | anything else | HTTP/1.1 over TLS |
59//! | TCP, cleartext | — | match HTTP/2 preface | HTTP/2 "prior knowledge" (h2c) |
60//! | TCP, cleartext | — | anything else | HTTP/1.x |
61//! | QUIC | — | — | HTTP/3 |
62//!
63//! h2c via the HTTP/1.1 `Upgrade` mechanism (RFC 7540 §3.2, removed in RFC 9113)
64//! is **not** supported — if an `Upgrade: h2c` header arrives on an h1 request it
65//! is logged and ignored.
66//!
67//! The TLS acceptors shipped with trillium that advertise ALPN (`trillium-rustls` and
68//! `trillium-openssl`) advertise `h2, http/1.1` automatically. `trillium-native-tls`
69//! does not surface ALPN. Users with custom TLS configs are responsible for advertising
70//! `h2` themselves if h2 is desired. Clients on TLS stacks that don't expose an ALPN
71//! knob can still reach h2 via the prior-knowledge preface path — ALPN comes back
72//! absent and the server peeks the first 24 bytes.
73//!
74//! All h2/h3-specific tuning flows through [`HttpConfig`] — see its field
75//! documentation for the full list of knobs (stream / connection flow-control
76//! windows, max concurrent streams, max frame size, etc.).
77//!
78//! ## Example
79//!
80//! This is an elaborate example that demonstrates some of `trillium_http`'s
81//! capabilities. Please note that trillium itself provides a much more
82//! usable interface on top of `trillium_http`, at very little cost.
83//!
84//! ```
85//! fn main() -> trillium_http::Result<()> {
86//! smol::block_on(async {
87//! use async_net::TcpListener;
88//! use futures_lite::StreamExt;
89//! use std::sync::Arc;
90//! use trillium_http::HttpContext;
91//!
92//! let context = Arc::new(HttpContext::default());
93//! let listener = TcpListener::bind(("localhost", 0)).await?;
94//! let local_addr = listener.local_addr().unwrap();
95//! let server_handle = smol::spawn({
96//! let context = context.clone();
97//! async move {
98//! let mut incoming = context.swansong().interrupt(listener.incoming());
99//!
100//! while let Some(Ok(stream)) = incoming.next().await {
101//! smol::spawn(context.clone().run(stream, |mut conn| async move {
102//! conn.set_response_body("hello world");
103//! conn.set_status(200);
104//! conn
105//! }))
106//! .detach()
107//! }
108//! }
109//! });
110//!
111//! // this example uses the trillium client
112//! // any other http client would work here too
113//! let client = trillium_client::Client::new(trillium_smol::ClientConfig::default())
114//! .with_base(local_addr);
115//! let mut client_conn = client.get("/").await?;
116//!
117//! assert_eq!(client_conn.status().unwrap(), 200);
118//! assert_eq!(
119//! client_conn.response_headers().get_str("content-length"),
120//! Some("11")
121//! );
122//! assert_eq!(
123//! client_conn.response_body().read_string().await?,
124//! "hello world"
125//! );
126//!
127//! context.shut_down().await; // stop the server after one request
128//! server_handle.await; // wait for the server to shut down
129//! Ok(())
130//! })
131//! }
132//! ```
133
134#[cfg(test)]
135#[doc = include_str!("../README.md")]
136mod readme {}
137
138pub(crate) mod after_send;
139mod body;
140mod buffer;
141mod bufwriter;
142mod conn;
143mod connection_status;
144mod copy;
145mod error;
146pub mod h2;
147pub mod h3;
148pub mod headers;
149#[cfg(any(feature = "http-compat-0", feature = "http-compat-1"))]
150mod http_compat;
151#[cfg(feature = "http-compat-0")]
152pub use http_compat::http_compat0;
153#[cfg(feature = "http-compat-1")]
154pub use http_compat::http_compat1;
155mod http_config;
156mod http_context;
157mod liveness;
158mod method;
159mod mut_cow;
160mod priority;
161mod protocol_session;
162mod received_body;
163#[cfg(feature = "rkyv_08")]
164mod rkyv_08;
165mod status;
166mod synthetic;
167mod upgrade;
168mod util;
169mod version;
170
171pub use body::{Body, BodySource};
172#[cfg(feature = "unstable")]
173#[doc(hidden)]
174pub use buffer::Buffer;
175#[cfg(not(feature = "unstable"))]
176pub(crate) use buffer::Buffer;
177#[cfg(feature = "unstable")]
178pub use bufwriter::BufWriter;
179#[cfg(not(feature = "unstable"))]
180pub(crate) use bufwriter::BufWriter;
181pub use conn::Conn;
182pub use connection_status::ConnectionStatus;
183#[cfg(feature = "unstable")]
184#[doc(hidden)]
185pub use copy::copy;
186#[cfg(not(feature = "unstable"))]
187pub(crate) use copy::copy;
188pub use error::{Error, Result};
189pub use headers::{HeaderName, HeaderValue, HeaderValues, Headers, KnownHeaderName, SERVER_HEADER};
190pub use http_config::HttpConfig;
191#[cfg(feature = "unstable")]
192pub use http_context::parse_head_for_bench;
193pub use http_context::{HttpContext, run_with_initial_bytes};
194pub use method::Method;
195#[cfg(feature = "unstable")]
196#[doc(hidden)]
197pub use mut_cow::MutCow;
198#[cfg(not(feature = "unstable"))]
199pub(crate) use mut_cow::MutCow;
200pub use priority::Priority;
201#[cfg(feature = "unstable")]
202pub use protocol_session::ProtocolSession;
203#[cfg(not(feature = "unstable"))]
204pub(crate) use protocol_session::ProtocolSession;
205pub use received_body::ReceivedBody;
206#[cfg(feature = "unstable")]
207#[doc(hidden)]
208pub use received_body::{H3BodyFrameType, ReceivedBodyState};
209pub use status::Status;
210pub use swansong::Swansong;
211#[doc(hidden)]
212pub use synthetic::Synthetic;
213pub use type_set::{self, TypeSet};
214pub use upgrade::Upgrade;
215#[cfg(feature = "unstable")]
216#[doc(hidden)]
217pub use util::validate_content_length;
218pub use version::Version;
219
220/// A pre-rendered http response to send when the server is at capacity.
221pub const SERVICE_UNAVAILABLE: &[u8] = b"HTTP/1.1 503 Service Unavailable\r
222Connection: close\r
223Content-Length: 0\r
224Retry-After: 60\r
225\r\n";
226
227/// The version of this crate
228pub const CRATE_VERSION: &str = env!("CARGO_PKG_VERSION");