Skip to main content

aws_smithy_http_server/serve/
mod.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Serve utilities for running HTTP servers.
7//!
8//! This module provides a convenient [`serve`] function similar to `axum::serve`
9//! for easily serving Tower services with Hyper.
10//!
11//! ## When to Use This Module
12//!
13//! - Use [`serve`] when you need a simple, batteries-included HTTP server
14//! - For more control over the Hyper connection builder, use [`.configure_hyper()`](Serve::configure_hyper)
15//! - For Lambda environments, see the `aws-lambda` feature and `routing::lambda_handler`
16//!
17//! ## How It Works
18//!
19//! The `serve` function creates a connection acceptance loop that:
20//!
21//! 1. **Accepts connections** via the [`Listener`] trait (e.g., [`TcpListener`](tokio::net::TcpListener))
22//! 2. **Creates per-connection services** by calling the `make_service` with [`IncomingStream`]
23//! 3. **Converts Tower services to Hyper** using `TowerToHyperService`
24//! 4. **Spawns a task** for each connection to handle HTTP requests
25//!
26//! ```text
27//! ┌─────────┐      ┌──────────────┐      ┌──────────────┐      ┌────────┐
28//! │Listener │─────▶│IncomingStream│─────▶│ make_service │─────▶│ Hyper  │
29//! │ accept  │      │ (io + addr)  │      │  (Tower)     │      │ spawn  │
30//! └─────────┘      └──────────────┘      └──────────────┘      └────────┘
31//! ```
32//!
33//! The [`IncomingStream`] provides connection metadata to the service factory,
34//! allowing per-connection customization based on remote address or IO type
35//!
36//! ## HTTP Protocol Selection
37//!
38//! By default, `serve` uses Hyper's automatic HTTP/1 or HTTP/2 selection with
39//! HTTP upgrade support when both protocols are enabled. Customize settings with
40//! [`.configure_hyper()`](Serve::configure_hyper).
41//!
42//! Set `builder.http1_only()` or `builder.http2_only()` in `configure_hyper`
43//! to serve only that protocol. Other protocols are rejected by Hyper before
44//! reaching the request service. Without either setting, both protocols are
45//! automatically detected.
46//!
47//! When both protocols are enabled, `serve` uses Hyper's upgrade-capable API.
48//! With `http1_only()` or `http2_only()`, it uses the regular connection API to
49//! preserve the protocol restriction. HTTP/1-only upgrades require a custom
50//! serve loop using Hyper's native HTTP/1 builder.
51//!
52//! ## Graceful Shutdown
53//!
54//! Graceful shutdown is zero-cost when not used - no watch channels are allocated
55//! and no `tokio::select!` overhead is incurred. Call
56//! [`.with_graceful_shutdown(signal)`](Serve::with_graceful_shutdown) to enable it:
57//!
58//! ```ignore
59//! serve(listener, service)
60//!     .with_graceful_shutdown(async {
61//!         tokio::signal::ctrl_c().await.expect("failed to listen for Ctrl+C");
62//!     })
63//!     .await
64//! ```
65//!
66//! This ensures in-flight requests complete before shutdown. Use
67//! [`.with_shutdown_timeout(duration)`](ServeWithGracefulShutdown::with_shutdown_timeout)
68//! to set a maximum wait time.
69//!
70//! ## Common Patterns
71//!
72//! ### Limiting Concurrent Connections
73//!
74//! `serve` limits concurrently accepted connections to 16,384 by default. Configure
75//! or disable the limit on the server future:
76//!
77//! ```rust,ignore
78//! serve(listener, app.into_make_service())
79//!     .max_connections(1000)
80//!     .await?;
81//! ```
82//!
83//! [`ListenerExt::limit_connections`] remains available for listener-level composition.
84//! The connection permit stays attached to the socket across HTTP upgrades.
85//! Applications that downcast upgraded IO with
86//! `hyper_util::server::conn::auto::upgrade::downcast` must use
87//! `TokioIo<ConnLimiterIo<L::Io>>` as the IO type. [`IncomingStream`] continues
88//! to expose the listener's original IO type to the service factory.
89//!
90//! A one-minute header-read deadline starts when the connection task begins driving
91//! Hyper and ends when Hyper delivers the first complete request head to its service.
92//! It includes protocol negotiation and parsing for either HTTP version. Connection
93//! service creation, Tower readiness, request middleware, and body reads are excluded.
94//! Configure it with [`Serve::header_read_timeout`]. The same setting is applied to
95//! Hyper's HTTP/1 header-read timeout for subsequent requests. **Header-read timeout
96//! protection for every request is currently supported only for HTTP/1.** For HTTP/2,
97//! only the first request head on the connection is covered; later streams have no
98//! header-read deadline. HTTP/2 keep-alive pings do not provide that protection.
99//!
100//! ### Accessing Connection Information
101//!
102//! Use `.into_make_service_with_connect_info::<T>()` to access connection metadata
103//! in your handlers:
104//!
105//! ```rust,ignore
106//! use std::net::SocketAddr;
107//! use aws_smithy_http_server::request::connect_info::ConnectInfo;
108//!
109//! // In your handler:
110//! async fn my_handler(ConnectInfo(addr): ConnectInfo<SocketAddr>) -> String {
111//!     format!("Request from: {}", addr)
112//! }
113//!
114//! // When serving:
115//! serve(
116//!     listener,
117//!     app.into_make_service_with_connect_info::<SocketAddr>()
118//! ).await?;
119//! ```
120//!
121//! ### Custom TCP Settings
122//!
123//! Use [`ListenerExt::tap_io`] to configure TCP options:
124//!
125//! ```rust,ignore
126//! use aws_smithy_http_server::serve::ListenerExt;
127//!
128//! let listener = TcpListener::bind("127.0.0.1:3000")
129//!     .await?
130//!     .tap_io(|stream| {
131//!         let _ = stream.set_nodelay(true);
132//!     });
133//!
134//! serve(listener, app.into_make_service()).await?;
135//! ```
136//!
137//! ## Timeouts and Connection Management
138//!
139//! ### Available Timeout Types
140//!
141//! | Timeout Type | What It Does | How to Configure |
142//! |--------------|--------------|------------------|
143//! | **Header Read** | Per-request protection currently supports HTTP/1 only; HTTP/2 covers only the connection's first request head | 1 minute by default; override via [`.header_read_timeout()`](Serve::header_read_timeout) |
144//! | **Request** | Time limit for processing one request | Tower's `TimeoutLayer` |
145//! | **Connection Duration** | Total connection lifetime limit | Custom accept loop with `tokio::time::timeout` |
146//! | **HTTP/2 Keep-Alive** | Idle timeout between HTTP/2 requests | 20 s ping interval by default; override via `.configure_hyper()` with `.http2().keep_alive_*()` |
147//!
148//! **Examples:**
149//! - `examples/header_read_timeout.rs` - Configure header read timeout
150//! - `examples/request_timeout.rs` - Add request-level timeouts
151//! - `examples/custom_accept_loop.rs` - Implement connection duration limits
152//! - `examples/http2_keepalive.rs` - Configure HTTP/2 keep-alive
153//! - `examples/connection_limiting.rs` - Limit concurrent connections
154//! - `examples/request_concurrency_limiting.rs` - Limit concurrent requests
155//!
156//! ### Connection Duration vs Idle Timeout
157//!
158//! **Connection duration timeout**: Closes the connection after N seconds total, regardless of activity.
159//! Implemented with `tokio::time::timeout` wrapping the connection future.
160//!
161//! **Idle timeout**: Closes the connection only when inactive between requests.
162//! - HTTP/2: Available via `.keep_alive_interval()` and `.keep_alive_timeout()`
163//! - HTTP/1.1: Not available without modifying Hyper
164//!
165//! See `examples/custom_accept_loop.rs` for a working connection duration timeout example.
166//!
167//! ### Connection Limiting vs Request Limiting
168//!
169//! **Connection limiting** (`.limit_connections()`): Limits the number of TCP connections.
170//! Use this to prevent socket/file descriptor exhaustion.
171//!
172//! **Request limiting** (`ConcurrencyLimitLayer`): Limits in-flight requests.
173//! Use this to prevent work queue exhaustion. With HTTP/2, one connection can have multiple
174//! requests in flight simultaneously.
175//!
176//! Most applications should use both - they protect different layers.
177//!
178//! ## Troubleshooting
179//!
180//! ### Type Errors
181//!
182//! If you encounter complex error messages about trait bounds, check:
183//!
184//! 1. **Service Error Type**: Your service must have `Error = Infallible`
185//!    ```rust,ignore
186//!    // ✓ Correct - handlers return responses, not Results
187//!    async fn handler() -> Response<Body> { ... }
188//!
189//!    // ✗ Wrong - cannot use Result<Response, E>
190//!    async fn handler() -> Result<Response<Body>, MyError> { ... }
191//!    ```
192//!
193//! 2. **MakeService Wrapper**: Use the correct wrapper for your service:
194//!    ```rust,ignore
195//!    use aws_smithy_http_server::routing::IntoMakeService;
196//!
197//!    // For Smithy services:
198//!    app.into_make_service()
199//!
200//!    // For services with middleware:
201//!    IntoMakeService::new(service)
202//!    ```
203//!
204//! ### Graceful Shutdown Not Working
205//!
206//! If graceful shutdown doesn't wait for connections:
207//!
208//! - Ensure you call `.with_graceful_shutdown()` **before** `.await`
209//! - The signal future must be `Send + 'static`
210//! - Consider adding a timeout with `.with_shutdown_timeout()`
211//!
212//! ### Connection Limit Not Applied
213//!
214//! Remember that `.limit_connections()` applies to the listener **before** passing
215//! it to `serve()`:
216//!
217//! ```rust,ignore
218//! // ✓ Correct
219//! let listener = TcpListener::bind("127.0.0.1:3000")
220//!     .await?
221//!     .limit_connections(100);
222//! serve(listener, app.into_make_service()).await?;
223//!
224//! // ✗ Wrong - limit_connections must be called on listener
225//! serve(TcpListener::bind("127.0.0.1:3000").await?, app.into_make_service())
226//!     .limit_connections(100)  // This method doesn't exist on Serve
227//!     .await?;
228//! ```
229//!
230//! ## Advanced: Custom Connection Handling
231//!
232//! If you need per-connection customization (e.g., different Hyper settings based on
233//! the remote address), you can implement your own connection loop using the building
234//! blocks provided by this module:
235//!
236//! ```rust,ignore
237//! use aws_smithy_http_server::routing::IntoMakeService;
238//! use aws_smithy_http_server::serve::Listener;
239//! use hyper_util::rt::{TokioExecutor, TokioIo};
240//! use hyper_util::server::conn::auto::Builder;
241//! use hyper_util::service::TowerToHyperService;
242//! use tower::ServiceExt;
243//!
244//! let mut listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?;
245//! let make_service = app.into_make_service_with_connect_info::<SocketAddr>();
246//!
247//! loop {
248//!     let (stream, remote_addr) = listener.accept().await?;
249//!     let io = TokioIo::new(stream);
250//!
251//!     // Per-connection Hyper configuration
252//!     let mut builder = Builder::new(TokioExecutor::new());
253//!     if remote_addr.ip().is_loopback() {
254//!         builder = builder.http2_only();  // Local connections use HTTP/2
255//!     } else {
256//!         builder = builder.http1().keep_alive(true);  // External use HTTP/1
257//!     }
258//!
259//!     let tower_service = make_service
260//!         .ready()
261//!         .await?
262//!         .call(IncomingStream { io: &io, remote_addr })
263//!         .await?;
264//!
265//!     let hyper_service = TowerToHyperService::new(tower_service);
266//!
267//!     tokio::spawn(async move {
268//!         if let Err(err) = builder.serve_connection(io, hyper_service).await {
269//!             eprintln!("Error serving connection: {}", err);
270//!         }
271//!     });
272//! }
273//! ```
274//!
275//! This approach provides complete flexibility while still leveraging the efficient
276//! Hyper and Tower integration provided by this module.
277//!
278//! Portions of the implementation are adapted from axum
279//! (<https://github.com/tokio-rs/axum>), which is licensed under the MIT License.
280//! Copyright (c) 2019 Axum Contributors
281
282use std::convert::Infallible;
283use std::error::Error as StdError;
284use std::fmt::{self, Debug};
285use std::future::{Future, IntoFuture};
286use std::io;
287use std::marker::PhantomData;
288use std::pin::Pin;
289use std::sync::Arc;
290use std::time::Duration;
291
292use http_body::Body as HttpBody;
293use hyper::body::Incoming;
294use hyper_util::rt::{TokioExecutor, TokioIo, TokioTimer};
295use hyper_util::server::conn::auto::Builder;
296use hyper_util::server::graceful::{GracefulConnection, GracefulShutdown, Watcher};
297use hyper_util::service::TowerToHyperService;
298use tokio::sync::OwnedSemaphorePermit;
299use tower::{Service, ServiceExt as _};
300
301mod header_read_timeout;
302mod listener;
303
304use self::header_read_timeout::{HeaderReadDeadline, HeaderReadTimeoutService};
305
306use self::listener::ConnectionLimit;
307pub use self::listener::{ConnLimiter, ConnLimiterIo, Listener, ListenerExt, TapIo};
308
309use crate::settings::{default_connection_builder, ServeSettings};
310pub use crate::settings::{
311    DEFAULT_HEADER_READ_TIMEOUT, DEFAULT_HTTP2_KEEP_ALIVE_INTERVAL, DEFAULT_HTTP2_KEEP_ALIVE_TIMEOUT,
312    DEFAULT_MAX_CONNECTIONS, DEFAULT_SHUTDOWN_TIMEOUT,
313};
314
315// ============================================================================
316// Type Bounds Documentation
317// ============================================================================
318//
319// ## Body Bounds (B)
320// HTTP response bodies must satisfy:
321// - `B: HttpBody + Send + 'static` - Implement the body trait and be sendable
322// - `B::Data: Send` - Data chunks must be sendable across threads
323// - `B::Error: Into<Box<dyn StdError + Send + Sync>>` - Errors must be convertible
324//
325// ## Service Bounds (S)
326//
327// The `S` type parameter represents a **per-connection HTTP service** - a Tower service
328// that handles individual HTTP requests and returns HTTP responses.
329//
330// Required bounds:
331// - `S: Service<http::Request<Incoming>, Response = http::Response<B>, Error = Infallible>`
332//
333//   This is the core Tower Service trait. It means:
334//   * **Input**: Takes an HTTP request with a streaming body (`Incoming` from Hyper)
335//   * **Output**: Returns an HTTP response with body type `B`
336//   * **Error**: Must be `Infallible`, meaning the service never returns errors at the
337//     Tower level. Any application errors must be converted into HTTP responses
338//     (e.g., 500 Internal Server Error) before reaching this layer.
339//
340// - `S: Clone + Send + 'static`
341//   * **Clone**: Each HTTP/1.1 or HTTP/2 connection may handle multiple requests
342//     sequentially or concurrently. The service must be cloneable so each request
343//     can get its own copy.
344//   * **Send**: The service will be moved into a spawned Tokio task, so it must be
345//     safe to send across thread boundaries.
346//   * **'static**: No borrowed references - the service must own all its data since
347//     it will outlive the connection setup phase.
348//
349// - `S::Future: Send`
350//   The future returned by `Service::call()` must also be `Send` so it can be
351//   polled from any thread in Tokio's thread pool.
352//
353// ## MakeService Bounds (M)
354//
355// The `M` type parameter represents a **service factory** - a Tower service that
356// creates a new `S` service for each incoming connection. This allows customizing
357// services based on connection metadata (remote address, TLS info, etc.).
358//
359// Connection Info → Service Factory → Per-Connection Service
360//
361// Required bounds:
362// - `M: for<'a> Service<IncomingStream<'a, L>, Error = Infallible, Response = S>`
363//
364//   This is the service factory itself:
365//   * **Input**: `IncomingStream<'a, L>` - A struct containing connection metadata:
366//     - `io: &'a TokioIo<L::Io>` - A borrowed reference to the connection's IO stream
367//     - `remote_addr: L::Addr` - The remote address of the client
368//
369//   * **Output**: Returns a new `S` service instance for this specific connection
370//
371//   * **Error**: Must be `Infallible` - service creation must never fail
372//
373//   * **Higher-Rank Trait Bound (`for<'a>`)**: The factory must work
374//     with `IncomingStream` that borrows the IO with *any* lifetime `'a`. This is
375//     necessary because the IO is borrowed only temporarily during service creation,
376//     and we don't know the specific lifetime at compile time.
377//
378// - `for<'a> <M as Service<IncomingStream<'a, L>>>::Future: Send`
379//
380//   The future returned by calling the make_service must be `Send` for any lifetime,
381//   so it can be awaited across threads while creating the service.
382//
383// ## Example Flow
384//
385// ```text
386// 1. Listener.accept() → (io, remote_addr)
387// 2. make_service.call(IncomingStream { io: &io, remote_addr }) → Future<Output = S>
388// 3. service.call(request) → Future<Output = Response>
389// 4. Repeat step 3 for each request on the connection
390// ```
391//
392// ## Why These Bounds Matter
393//
394// 1. **Services can be spawned onto Tokio tasks** (Send + 'static)
395// 2. **Multiple requests can be handled per connection** (Clone)
396// 3. **Error handling is infallible** - errors become HTTP responses, not Tower errors
397// 4. **The MakeService works with borrowed connection info** - via HRTB with IncomingStream
398//    This allows inspection of connection metadata without transferring ownership
399//
400// ============================================================================
401
402/// An incoming stream that bundles connection information.
403///
404/// This struct serves as the request type for the `make_service` Tower service,
405/// allowing it to access connection-level metadata when creating per-connection services.
406///
407/// # Purpose
408///
409/// In Tower/Hyper's model, `make_service` is called once per connection to create
410/// a service that handles all HTTP requests on that connection. `IncomingStream`
411/// provides the connection information needed to customize service creation based on:
412/// - The remote address (for logging or access control)
413/// - The underlying IO type (for connection configuration)
414///
415/// # Design
416///
417/// This type holds a **reference** to the IO rather than ownership because:
418/// - The actual IO is still needed by Hyper to serve the connection after `make_service` returns
419/// - The `make_service` only needs to inspect connection metadata, not take ownership
420///
421/// # Lifetime Safety
422///
423/// The lifetime `'a` ensures the reference to IO remains valid only during the
424/// `make_service.call()` invocation. After the service is created, the IO is
425/// moved into a spawned task to handle the connection. This is safe because:
426///
427/// ```text
428/// let io = TokioIo::new(stream);           // IO created
429/// let service = make_service.call(
430///     IncomingStream { io: &io, .. }       // Borrowed during call
431/// ).await;                                  // Borrow ends
432/// tokio::spawn(serve_connection(io, ..));  // IO moved to task
433/// ```
434///
435/// The borrow checker guarantees the reference doesn't outlive the IO object.
436///
437/// Used with [`serve`] and [`crate::routing::IntoMakeServiceWithConnectInfo`].
438#[derive(Debug)]
439pub struct IncomingStream<'a, L>
440where
441    L: Listener,
442{
443    /// Reference to the IO for this connection
444    pub io: &'a TokioIo<L::Io>,
445    /// Remote address of the client
446    pub remote_addr: L::Addr,
447}
448
449impl<L> IncomingStream<'_, L>
450where
451    L: Listener,
452{
453    /// Get a reference to the inner IO type.
454    pub fn io(&self) -> &L::Io {
455        self.io.inner()
456    }
457
458    /// Returns the remote address that this stream is bound to.
459    pub fn remote_addr(&self) -> &L::Addr {
460        &self.remote_addr
461    }
462}
463
464/// Serve the service with the supplied listener.
465///
466/// By default, this limits concurrently accepted connections to 16,384. Use
467/// [`Serve::max_connections`] to configure the limit or
468/// [`Serve::disable_connection_limit`] to disable it.
469///
470/// A one-minute deadline bounds the first request head for either HTTP version and
471/// subsequent HTTP/1 header reads. Per-request header-read timeout protection is
472/// currently HTTP/1-only; later HTTP/2 streams have no header-read deadline. The
473/// default connection builder also applies a 20-second HTTP/2 keep-alive ping interval,
474/// which does not enforce a header-read deadline.
475///
476/// This implementation provides zero-cost abstraction for shutdown coordination.
477/// When graceful shutdown is not used, there is no runtime overhead - no watch channels
478/// are allocated and no `tokio::select!` is used.
479///
480/// It supports both HTTP/1 as well as HTTP/2.
481///
482/// This function accepts services wrapped with [`crate::routing::IntoMakeService`] or
483/// [`crate::routing::IntoMakeServiceWithConnectInfo`].
484///
485/// For generated Smithy services, use `.into_make_service()` or
486/// `.into_make_service_with_connect_info::<C>()`. For services wrapped with
487/// Tower middleware, use `IntoMakeService::new(service)`.
488///
489/// # Error Handling
490///
491/// Note that both `make_service` and the generated service must have `Error = Infallible`.
492/// This means:
493/// - Your service factory cannot fail when creating per-connection services
494/// - Your request handlers cannot return errors (use proper HTTP error responses instead)
495///
496/// If you need fallible service creation, consider handling errors within your
497/// `make_service` implementation and returning a service that produces error responses.
498///
499/// # Examples
500///
501/// Serving a Smithy service with a TCP listener:
502///
503/// ```rust,ignore
504/// use tokio::net::TcpListener;
505///
506/// let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
507/// aws_smithy_http_server::serve(listener, app.into_make_service()).await.unwrap();
508/// ```
509///
510/// Serving with middleware applied:
511///
512/// ```rust,ignore
513/// use tokio::net::TcpListener;
514/// use tower::Layer;
515/// use tower_http::timeout::TimeoutLayer;
516/// use http::StatusCode;
517/// use std::time::Duration;
518/// use aws_smithy_http_server::routing::IntoMakeService;
519///
520/// let app = /* ... build service ... */;
521/// let app = TimeoutLayer::new(Duration::from_secs(30)).layer(app);
522///
523/// let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
524/// aws_smithy_http_server::serve(listener, IntoMakeService::new(app)).await.unwrap();
525/// ```
526///
527/// For graceful shutdown:
528///
529/// ```rust,ignore
530/// use tokio::net::TcpListener;
531/// use tokio::signal;
532///
533/// let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
534/// aws_smithy_http_server::serve(listener, app.into_make_service())
535///     .with_graceful_shutdown(async {
536///         signal::ctrl_c().await.expect("failed to listen for Ctrl+C");
537///     })
538///     .await
539///     .unwrap();
540/// ```
541///
542/// With connection info:
543///
544/// ```rust,ignore
545/// use tokio::net::TcpListener;
546/// use std::net::SocketAddr;
547///
548/// let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();
549/// aws_smithy_http_server::serve(
550///     listener,
551///     app.into_make_service_with_connect_info::<SocketAddr>()
552/// )
553/// .await
554/// .unwrap();
555/// ```
556pub fn serve<L, M, S, B>(listener: L, make_service: M) -> Serve<L, M, S, B>
557where
558    L: Listener,
559    // Body bounds: see module documentation for details
560    B: HttpBody + Send + 'static,
561    B::Data: Send,
562    B::Error: Into<Box<dyn StdError + Send + Sync>>,
563    // Service bounds: see module documentation for details
564    S: Service<http::Request<Incoming>, Response = http::Response<B>, Error = Infallible> + Clone + Send + 'static,
565    S::Future: Send,
566    // MakeService bounds: see module documentation for details
567    M: for<'a> Service<IncomingStream<'a, L>, Error = Infallible, Response = S>,
568{
569    Serve {
570        listener,
571        make_service,
572        settings: ServeSettings::default(),
573        _marker: PhantomData,
574    }
575}
576
577/// A server future that serves HTTP connections.
578///
579/// This is the return type of [`serve`]. It implements [`IntoFuture`], so
580/// you can directly `.await` it:
581///
582/// ```ignore
583/// serve(listener, service).await?;
584/// ```
585///
586/// Before awaiting, you can configure it:
587/// - [`configure_hyper`](Self::configure_hyper) - Configure Hyper's automatic connection builder
588/// - [`max_connections`](Self::max_connections) - Configure the accepted-connection limit
589/// - [`header_read_timeout`](Self::header_read_timeout) - Configure the request-header deadline
590/// - [`with_graceful_shutdown`](Self::with_graceful_shutdown) - Enable graceful shutdown
591/// - [`local_addr`](Self::local_addr) - Get the bound address
592///
593/// Created by [`serve`].
594#[must_use = "Serve does nothing until you `.await` or call `.into_future()` on it"]
595pub struct Serve<L, M, S, B> {
596    listener: L,
597    make_service: M,
598    settings: ServeSettings,
599    _marker: PhantomData<(S, B)>,
600}
601
602impl<L, M, S, B> fmt::Debug for Serve<L, M, S, B>
603where
604    L: fmt::Debug,
605{
606    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
607        f.debug_struct("Serve")
608            .field("listener", &self.listener)
609            .field("has_hyper_config", &self.settings.hyper_builder.is_some())
610            .field("max_connections", &self.settings.max_connections)
611            .field("header_read_timeout", &self.settings.header_read_timeout)
612            .finish_non_exhaustive()
613    }
614}
615
616impl<L, M, S, B> Serve<L, M, S, B>
617where
618    L: Listener,
619{
620    /// Configure the underlying Hyper connection builder.
621    ///
622    /// This allows you to customize Hyper's HTTP/1 and HTTP/2 settings,
623    /// such as timeouts, max concurrent streams, keep-alive behavior, etc.
624    ///
625    /// **Note:** Calling this replaces the default builder entirely, opting out of the built-in
626    /// HTTP/2 defaults. You are responsible for setting your own HTTP/2 timeouts.
627    /// The connection limit and [`Self::header_read_timeout`] remain enabled.
628    /// When HTTP/1 is enabled, `serve` supplies its timer and applies
629    /// `header_read_timeout` after this configuration, overriding any HTTP/1
630    /// header-read timeout set on the builder.
631    ///
632    /// `http1_only()` and `http2_only()` restrict the accepted protocol and use
633    /// Hyper's regular connection API without HTTP/1 upgrades. When both
634    /// protocols are enabled, `serve` uses `serve_connection_with_upgrades`.
635    /// For HTTP/1-only upgrades, use a custom serve loop.
636    ///
637    /// The configuration callback runs once when this method is called. The
638    /// configured builder is shared across connections.
639    ///
640    /// # Example
641    ///
642    /// ```ignore
643    /// use std::time::Duration;
644    ///
645    /// serve(listener, service)
646    ///     .configure_hyper(|mut builder| {
647    ///         builder.http1().keep_alive(true);
648    ///         builder.http2().max_concurrent_streams(200);
649    ///         builder
650    ///     })
651    ///     .await?;
652    /// ```
653    ///
654    /// # Advanced: Per-Connection Configuration
655    ///
656    /// If you need per-connection customization (e.g., different settings based on
657    /// the remote address), you can implement your own connection loop. See the
658    /// module-level documentation for examples.
659    pub fn configure_hyper<F>(mut self, f: F) -> Self
660    where
661        F: FnOnce(
662            hyper_util::server::conn::auto::Builder<hyper_util::rt::TokioExecutor>,
663        ) -> hyper_util::server::conn::auto::Builder<hyper_util::rt::TokioExecutor>,
664    {
665        let builder = Builder::new(TokioExecutor::new());
666        self.settings.hyper_builder = Some(Arc::new(f(builder)));
667        self
668    }
669
670    /// Set the maximum number of concurrently accepted connections.
671    ///
672    /// The default limit is 16,384. Once the limit is reached, `serve` stops
673    /// accepting connections until an existing connection closes.
674    ///
675    /// Passing `0` disables the limit, equivalent to
676    /// [`disable_connection_limit`](Self::disable_connection_limit). Values
677    /// above [`tokio::sync::Semaphore::MAX_PERMITS`] are clamped to that value.
678    pub fn max_connections(mut self, max: usize) -> Self {
679        self.settings.max_connections = (max > 0).then_some(max);
680        self
681    }
682
683    /// Disable the default accepted-connection limit.
684    pub fn disable_connection_limit(mut self) -> Self {
685        self.settings.max_connections = None;
686        self
687    }
688
689    /// Set the timeout for receiving a complete request head.
690    ///
691    /// The default is one minute. The first-request deadline starts when the
692    /// connection task begins driving Hyper, after `make_service` finishes. It
693    /// includes protocol negotiation and header parsing and does not reset as
694    /// bytes arrive. It ends before Tower readiness, middleware, or body reads.
695    ///
696    /// The same setting configures Hyper's HTTP/1 header-read timeout for later
697    /// requests. **Per-request header-read timeout protection is currently supported
698    /// only for HTTP/1.** HTTP/2 is covered only until the first request head arrives;
699    /// later HTTP/2 streams have no header-read deadline. This deadline does not
700    /// limit body reads or time spent waiting for server events.
701    /// This setting takes precedence over the HTTP/1 header-read timeout supplied
702    /// through [`Self::configure_hyper`]. Pass `None` or `Some(Duration::ZERO)` to
703    /// disable both deadlines.
704    pub fn header_read_timeout(mut self, timeout: Option<Duration>) -> Self {
705        self.settings.header_read_timeout = timeout.filter(|timeout| !timeout.is_zero());
706        self
707    }
708
709    /// Enable graceful shutdown for the server.
710    pub fn with_graceful_shutdown<F>(self, signal: F) -> ServeWithGracefulShutdown<L, M, S, F, B>
711    where
712        F: Future<Output = ()> + Send + 'static,
713    {
714        ServeWithGracefulShutdown { serve: self, signal }
715    }
716
717    /// Returns the local address this server is bound to.
718    pub fn local_addr(&self) -> io::Result<L::Addr> {
719        self.listener.local_addr()
720    }
721}
722
723// Implement IntoFuture so we can await Serve directly
724impl<L, M, S, B> IntoFuture for Serve<L, M, S, B>
725where
726    L: Listener,
727    L::Addr: Debug,
728    // Body bounds
729    B: HttpBody + Send + 'static,
730    B::Data: Send,
731    B::Error: Into<Box<dyn StdError + Send + Sync>>,
732    // Service bounds
733    S: Service<http::Request<Incoming>, Response = http::Response<B>, Error = Infallible> + Clone + Send + 'static,
734    S::Future: Send,
735    // MakeService bounds
736    M: for<'a> Service<IncomingStream<'a, L>, Error = Infallible, Response = S> + Send + 'static,
737    for<'a> <M as Service<IncomingStream<'a, L>>>::Future: Send,
738{
739    type Output = io::Result<()>;
740    type IntoFuture = Pin<Box<dyn Future<Output = io::Result<()>> + Send>>;
741
742    fn into_future(self) -> Self::IntoFuture {
743        Box::pin(async move {
744            let Self {
745                mut listener,
746                mut make_service,
747                settings:
748                    ServeSettings {
749                        hyper_builder,
750                        max_connections,
751                        header_read_timeout,
752                        ..
753                    },
754                _marker,
755            } = self;
756            let connection_limiter = max_connections.map(ConnectionLimit::new).map(Arc::new);
757            let hyper_builder = connection_builder(hyper_builder, header_read_timeout);
758
759            loop {
760                let connection_permit = acquire_connection_permit(connection_limiter.as_ref()).await;
761                let (io, remote_addr) = listener.accept().await;
762                handle_connection::<L, M, S, B>(
763                    &mut make_service,
764                    io,
765                    remote_addr,
766                    &hyper_builder,
767                    header_read_timeout,
768                    None,
769                    connection_permit,
770                )
771                .await;
772            }
773        })
774    }
775}
776
777/// A server future with graceful shutdown enabled.
778///
779/// This type is created by calling [`Serve::with_graceful_shutdown`]. It implements
780/// [`IntoFuture`], so you can directly `.await` it.
781///
782/// When the shutdown signal completes, the server will:
783/// 1. Stop accepting new connections
784/// 2. Wait for all in-flight requests to complete (or until timeout if configured)
785/// 3. Return once all connections are closed
786///
787/// Configure the shutdown timeout with [`with_shutdown_timeout`](Self::with_shutdown_timeout).
788///
789/// Created by [`Serve::with_graceful_shutdown`].
790#[must_use = "ServeWithGracefulShutdown does nothing until you `.await` or call `.into_future()` on it"]
791pub struct ServeWithGracefulShutdown<L, M, S, F, B> {
792    serve: Serve<L, M, S, B>,
793    signal: F,
794}
795
796impl<L, M, S, F, B> fmt::Debug for ServeWithGracefulShutdown<L, M, S, F, B>
797where
798    L: Listener + fmt::Debug,
799{
800    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
801        f.debug_struct("ServeWithGracefulShutdown")
802            .field("listener", &self.serve.listener)
803            .field("has_hyper_config", &self.serve.settings.hyper_builder.is_some())
804            .field("shutdown_timeout", &self.serve.settings.shutdown_timeout)
805            .field("max_connections", &self.serve.settings.max_connections)
806            .field("header_read_timeout", &self.serve.settings.header_read_timeout)
807            .finish_non_exhaustive()
808    }
809}
810
811impl<L: Listener, M, S, F, B> ServeWithGracefulShutdown<L, M, S, F, B> {
812    /// Set a timeout for graceful shutdown.
813    ///
814    /// If the timeout expires before all connections complete, a warning is logged
815    /// and the server returns successfully. Note that this does **not** forcibly
816    /// terminate connections - it only stops waiting for them.
817    ///
818    /// # Example
819    ///
820    /// ```rust,ignore
821    /// use std::time::Duration;
822    ///
823    /// serve(listener, app.into_make_service())
824    ///     .with_graceful_shutdown(shutdown_signal())
825    ///     .with_shutdown_timeout(Duration::from_secs(30))
826    ///     .await?;  // Returns Ok(()) even if timeout expires
827    /// ```
828    pub fn with_shutdown_timeout(mut self, timeout: Duration) -> Self {
829        self.serve.settings.shutdown_timeout = Some(timeout);
830        self
831    }
832
833    /// Set the maximum number of concurrently accepted connections.
834    ///
835    /// The default limit is 16,384. Once the limit is reached, `serve` stops
836    /// accepting connections until an existing connection closes.
837    ///
838    /// Passing `0` disables the limit, equivalent to
839    /// [`disable_connection_limit`](Self::disable_connection_limit). Values
840    /// above [`tokio::sync::Semaphore::MAX_PERMITS`] are clamped to that value.
841    pub fn max_connections(mut self, max: usize) -> Self {
842        self.serve = self.serve.max_connections(max);
843        self
844    }
845
846    /// Disable the default accepted-connection limit.
847    pub fn disable_connection_limit(mut self) -> Self {
848        self.serve = self.serve.disable_connection_limit();
849        self
850    }
851
852    /// Set the timeout for receiving a complete request head.
853    ///
854    /// The default is one minute. Pass `None` or `Some(Duration::ZERO)` to disable it.
855    /// See [`Serve::header_read_timeout`] for details.
856    pub fn header_read_timeout(mut self, timeout: Option<Duration>) -> Self {
857        self.serve = self.serve.header_read_timeout(timeout);
858        self
859    }
860
861    /// Returns the local address this server is bound to.
862    pub fn local_addr(&self) -> io::Result<L::Addr> {
863        self.serve.local_addr()
864    }
865}
866
867// Implement IntoFuture so we can await WithGracefulShutdown directly
868impl<L, M, S, F, B> IntoFuture for ServeWithGracefulShutdown<L, M, S, F, B>
869where
870    L: Listener,
871    L::Addr: Debug,
872    // Body bounds
873    B: HttpBody + Send + 'static,
874    B::Data: Send,
875    B::Error: Into<Box<dyn StdError + Send + Sync>>,
876    // Service bounds
877    S: Service<http::Request<Incoming>, Response = http::Response<B>, Error = Infallible> + Clone + Send + 'static,
878    S::Future: Send,
879    // MakeService bounds
880    M: for<'a> Service<IncomingStream<'a, L>, Error = Infallible, Response = S> + Send + 'static,
881    for<'a> <M as Service<IncomingStream<'a, L>>>::Future: Send,
882    // Shutdown signal
883    F: Future<Output = ()> + Send + 'static,
884{
885    type Output = io::Result<()>;
886    type IntoFuture = Pin<Box<dyn Future<Output = io::Result<()>> + Send>>;
887
888    fn into_future(self) -> Self::IntoFuture {
889        Box::pin(async move {
890            let Self {
891                serve:
892                    Serve {
893                        mut listener,
894                        mut make_service,
895                        settings:
896                            ServeSettings {
897                                hyper_builder,
898                                max_connections,
899                                header_read_timeout,
900                                shutdown_timeout,
901                            },
902                        _marker,
903                    },
904                signal,
905            } = self;
906            let connection_limiter = max_connections.map(ConnectionLimit::new).map(Arc::new);
907            let hyper_builder = connection_builder(hyper_builder, header_read_timeout);
908
909            // Initialize graceful shutdown
910            let graceful = GracefulShutdown::new();
911            let mut signal = std::pin::pin!(signal);
912
913            loop {
914                let connection_permit = tokio::select! {
915                    permit = acquire_connection_permit(connection_limiter.as_ref()) => permit,
916                    _ = signal.as_mut() => {
917                        tracing::trace!("received graceful shutdown signal, not accepting new connections");
918                        break;
919                    }
920                };
921
922                tokio::select! {
923                    (io, remote_addr) = listener.accept() => {
924                        handle_connection::<L, M, S, B>(
925                            &mut make_service,
926                            io,
927                            remote_addr,
928                            &hyper_builder,
929                            header_read_timeout,
930                            Some(&graceful),
931                            connection_permit,
932                        )
933                        .await;
934                    }
935                    _ = signal.as_mut() => {
936                        tracing::trace!("received graceful shutdown signal, not accepting new connections");
937                        break;
938                    }
939                }
940            }
941
942            drop(listener);
943
944            tracing::trace!("waiting for in-flight connections to finish");
945
946            // Wait for all in-flight connections (with optional timeout)
947            match shutdown_timeout {
948                Some(timeout) => match tokio::time::timeout(timeout, graceful.shutdown()).await {
949                    Ok(_) => {
950                        tracing::trace!("all in-flight connections completed during graceful shutdown");
951                    }
952                    Err(_) => {
953                        tracing::warn!(
954                            timeout_secs = timeout.as_secs(),
955                            "graceful shutdown timeout expired, some connections may not have completed"
956                        );
957                    }
958                },
959                None => {
960                    graceful.shutdown().await;
961                    tracing::trace!("all in-flight connections completed during graceful shutdown");
962                }
963            }
964
965            Ok(())
966        })
967    }
968}
969
970/// Connection handling function.
971///
972/// Handles connections with HTTP upgrade support and optional graceful shutdown.
973async fn handle_connection<L, M, S, B>(
974    make_service: &mut M,
975    conn_io: <L as Listener>::Io,
976    remote_addr: <L as Listener>::Addr,
977    hyper_builder: &Arc<Builder<TokioExecutor>>,
978    header_read_timeout: Option<Duration>,
979    graceful: Option<&GracefulShutdown>,
980    connection_permit: Option<OwnedSemaphorePermit>,
981) where
982    L: Listener,
983    L::Addr: Debug,
984    // Body bounds
985    B: HttpBody + Send + 'static,
986    B::Data: Send,
987    B::Error: Into<Box<dyn StdError + Send + Sync>>,
988    // Service bounds
989    S: Service<http::Request<Incoming>, Response = http::Response<B>, Error = Infallible> + Clone + Send + 'static,
990    S::Future: Send,
991    // MakeService bounds
992    M: for<'a> Service<IncomingStream<'a, L>, Error = Infallible, Response = S> + Send + 'static,
993    for<'a> <M as Service<IncomingStream<'a, L>>>::Future: Send,
994{
995    let watcher = graceful.map(|g| g.watcher());
996    let tokio_io = TokioIo::new(conn_io);
997
998    tracing::trace!("connection {remote_addr:?} accepted");
999
1000    make_service
1001        .ready()
1002        .await
1003        .expect("make_service error type is Infallible and cannot fail");
1004
1005    let tower_service = make_service
1006        .call(IncomingStream {
1007            io: &tokio_io,
1008            remote_addr,
1009        })
1010        .await
1011        .expect("make_service error type is Infallible and cannot fail");
1012
1013    let hyper_service = TowerToHyperService::new(tower_service);
1014
1015    let builder = Arc::clone(hyper_builder);
1016
1017    // Preserve IncomingStream's original IO type while constructing the service.
1018    // Hyper then owns the permit through the IO, including after an HTTP upgrade.
1019    let tokio_io = TokioIo::new(ConnLimiterIo::new(tokio_io.into_inner(), connection_permit));
1020    tokio::spawn(async move {
1021        let result = if let Some(timeout) = header_read_timeout {
1022            let (service, deadline) = HeaderReadTimeoutService::new(hyper_service, timeout);
1023            serve_connection(&builder, tokio_io, service, watcher, Some(deadline)).await
1024        } else {
1025            serve_connection(&builder, tokio_io, hyper_service, watcher, None).await
1026        };
1027
1028        if let Err(err) = result {
1029            tracing::trace!(error = ?err, "failed to serve connection");
1030        }
1031    });
1032}
1033
1034async fn serve_connection<I, S, B>(
1035    builder: &Builder<TokioExecutor>,
1036    io: I,
1037    service: S,
1038    watcher: Option<Watcher>,
1039    header_deadline: Option<HeaderReadDeadline>,
1040) -> io::Result<()>
1041where
1042    I: hyper::rt::Read + hyper::rt::Write + Unpin + Send + 'static,
1043    S: hyper::service::Service<http::Request<Incoming>, Response = http::Response<B>> + Send + 'static,
1044    S::Future: Send + 'static,
1045    S::Error: Into<Box<dyn StdError + Send + Sync>>,
1046    B: HttpBody + Send + 'static,
1047    B::Data: Send,
1048    B::Error: Into<Box<dyn StdError + Send + Sync>>,
1049{
1050    // Hyper's upgrade-capable API ignores http1_only()/http2_only(), so use
1051    // it only when both protocols are enabled.
1052    if builder.is_http1_available() && builder.is_http2_available() {
1053        let connection = builder.serve_connection_with_upgrades(io, service);
1054        drive_connection(connection, watcher, header_deadline).await
1055    } else {
1056        let connection = builder.serve_connection(io, service);
1057        drive_connection(connection, watcher, header_deadline).await
1058    }
1059}
1060
1061async fn drive_connection<C>(
1062    connection: C,
1063    watcher: Option<Watcher>,
1064    header_deadline: Option<HeaderReadDeadline>,
1065) -> io::Result<()>
1066where
1067    C: GracefulConnection,
1068    C::Error: Into<Box<dyn StdError + Send + Sync>>,
1069{
1070    if let Some(watcher) = watcher {
1071        let connection = watcher.watch(connection);
1072        if let Some(deadline) = header_deadline {
1073            deadline.run(connection).await
1074        } else {
1075            connection.await.map_err(io::Error::other)
1076        }
1077    } else if let Some(deadline) = header_deadline {
1078        deadline.run(connection).await
1079    } else {
1080        connection.await.map_err(io::Error::other)
1081    }
1082}
1083
1084fn connection_builder(
1085    configured: Option<Arc<Builder<TokioExecutor>>>,
1086    header_read_timeout: Option<Duration>,
1087) -> Arc<Builder<TokioExecutor>> {
1088    let mut builder = configured
1089        .map(Arc::unwrap_or_clone)
1090        .unwrap_or_else(default_connection_builder);
1091    if builder.is_http1_available() {
1092        builder
1093            .http1()
1094            .timer(TokioTimer::new())
1095            .header_read_timeout(header_read_timeout);
1096    }
1097    Arc::new(builder)
1098}
1099
1100async fn acquire_connection_permit(connection_limiter: Option<&Arc<ConnectionLimit>>) -> Option<OwnedSemaphorePermit> {
1101    match connection_limiter {
1102        Some(limit) => Some(limit.acquire().await),
1103        None => None,
1104    }
1105}