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