Skip to main content

vibeio_http/
lib.rs

1//! # vibeio-http
2//!
3//! High-performance HTTP/1.1, HTTP/2, and experimental HTTP/3 server implementation
4//! for the [`vibeio`] async runtime.
5//!
6//! `vibeio-http` provides protocol-specific connection handlers behind a common
7//! [`HttpProtocol`] trait. Handlers receive an `http::Request<`[`Incoming`]`>`
8//! and return an `http::Response<B>` where `B` implements
9//! [`http_body::Body`] with `bytes::Bytes` chunks.
10//!
11//! ## Feature highlights
12//!
13//! - **Zero-copy static file serving** - supports zero-copy response sending for static file serving on Linux.
14//! - **100 Continue** - Supports automatically sending `100 Continue` before the final response.
15//! - **103 Early Hints** - Supports sending `103 Early Hints` before the final response.
16//!
17//! ## Feature flags
18//!
19//! - `h1`: Enables HTTP/1.x support.
20//! - `h2`: Enables HTTP/2 support.
21//! - `h3`: Enables HTTP/3 support.
22//! - `h1-zerocopy`: Enables Linux-only zero-copy response sending for HTTP/1.x.
23//!
24//! ## Early hints
25//!
26//! Use [`send_early_hints`] from a request handler to send `103 Early Hints`
27//! before the final response.
28//!
29//! ## Example
30//!
31//! ```rust,no_run
32//! # #[cfg(feature = "h1")]
33//! # fn main() -> std::io::Result<()> {
34//! use bytes::Bytes;
35//! use http::Response;
36//! use http_body_util::Full;
37//! use vibeio::net::TcpListener;
38//! use vibeio::RuntimeBuilder;
39//! use vibeio_http::{Http1, Http1Options, HttpProtocol};
40//!
41//! let runtime = RuntimeBuilder::new().enable_timer(true).build()?;
42//!
43//! runtime.block_on(async {
44//!     let listener = TcpListener::bind("127.0.0.1:8080")?;
45//!     let (stream, _) = listener.accept().await?;
46//!     stream.set_nodelay(true)?;
47//!
48//!     Http1::new(stream.into_poll()?, Http1Options::default())
49//!         .handle(|_request| async move {
50//!             let response = Response::new(Full::new(Bytes::from_static(b"Hello World")));
51//!             Ok::<_, std::convert::Infallible>(response)
52//!         })
53//!         .await
54//! })
55//! # }
56//! # #[cfg(not(feature = "h1"))]
57//! # fn main() {}
58//! ```
59#![cfg_attr(docsrs, feature(doc_cfg))]
60
61mod early_hints;
62#[cfg(feature = "h1")]
63mod h1;
64#[cfg(feature = "h2")]
65mod h2;
66#[cfg(feature = "h3")]
67mod h3;
68mod incoming;
69mod upgrade;
70
71pub use early_hints::*;
72#[cfg(feature = "h1")]
73pub use h1::*;
74#[cfg(feature = "h2")]
75pub use h2::*;
76#[cfg(feature = "h3")]
77pub use h3::*;
78pub use incoming::*;
79pub use upgrade::*;
80
81use http::{Request, Response};
82use http_body::Body;
83
84/// A trait representing an HTTP protocol (for example, HTTP/1.1, HTTP/2, HTTP/3).
85///
86/// This trait provides a simple, type-erased interface for handling HTTP requests
87/// across different protocol versions.
88pub trait HttpProtocol: Sized {
89    fn handle<F, Fut, ResB, ResBE, ResE>(
90        self,
91        request_fn: F,
92    ) -> impl std::future::Future<Output = Result<(), std::io::Error>>
93    where
94        F: Fn(Request<Incoming>) -> Fut + 'static,
95        Fut: std::future::Future<Output = Result<Response<ResB>, ResE>> + 'static,
96        ResB: Body<Data = bytes::Bytes, Error = ResBE> + Unpin + 'static,
97        ResE: std::error::Error,
98        ResBE: std::error::Error;
99
100    #[allow(unused_variables)]
101    #[inline]
102    fn handle_with_error_fn<F, Fut, ResB, ResBE, ResE, EF, EFut, EResB, EResBE, EResE>(
103        self,
104        request_fn: F,
105        error_fn: EF,
106    ) -> impl std::future::Future<Output = Result<(), std::io::Error>>
107    where
108        F: Fn(Request<Incoming>) -> Fut + 'static,
109        Fut: std::future::Future<Output = Result<Response<ResB>, ResE>> + 'static,
110        ResB: Body<Data = bytes::Bytes, Error = ResBE> + Unpin + 'static,
111        ResE: std::error::Error,
112        ResBE: std::error::Error,
113        EF: FnOnce(bool) -> EFut,
114        EFut: std::future::Future<Output = Result<Response<EResB>, EResE>>,
115        EResB: Body<Data = bytes::Bytes, Error = EResBE> + Unpin + 'static,
116        EResE: std::error::Error,
117        EResBE: std::error::Error,
118    {
119        self.handle(request_fn)
120    }
121}