Skip to main content

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");