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