diff --git a/tower-http/Cargo.toml b/tower-http/Cargo.toml index 55ed7a11..9aa3f07f 100644 --- a/tower-http/Cargo.toml +++ b/tower-http/Cargo.toml @@ -46,7 +46,8 @@ flate2 = "1.0" futures-util = "0.3.14" http-body = "1.0.0" http-body-util = "0.1.0" -hyper-util = { version = "0.1", features = ["client-legacy", "http1", "tokio"] } +hyper = "1" +hyper-util = { version = "0.1", features = ["client-legacy", "http1", "server", "service", "tokio"] } once_cell = "1" serde_json = "1.0" sync_wrapper = "1" diff --git a/tower-http/src/lib.rs b/tower-http/src/lib.rs index 164fd8b4..4525b34d 100644 --- a/tower-http/src/lib.rs +++ b/tower-http/src/lib.rs @@ -11,71 +11,55 @@ //! //! # Example server //! -//! This example shows how to apply middleware from tower-http to a [`Service`] and then run -//! that service using [hyper]. +//! This example shows how to apply middleware from `tower-http` to a [`Service`] and then run +//! that service using [hyper] and [hyper-util]. //! //! ```rust,no_run //! use tower_http::{ -//! add_extension::AddExtensionLayer, //! compression::CompressionLayer, -//! propagate_header::PropagateHeaderLayer, -//! sensitive_headers::SetSensitiveRequestHeadersLayer, -//! set_header::SetResponseHeaderLayer, //! trace::TraceLayer, -//! validate_request::ValidateRequestHeaderLayer, //! }; //! use tower::{ServiceBuilder, service_fn, BoxError}; -//! use http::{Request, Response, header::{HeaderName, CONTENT_TYPE, AUTHORIZATION}}; -//! use std::{sync::Arc, net::SocketAddr, convert::Infallible, iter::once}; +//! use http::{Request, Response}; +//! use std::net::{SocketAddr, Ipv6Addr}; //! use bytes::Bytes; //! use http_body_util::Full; -//! # struct DatabaseConnectionPool; -//! # impl DatabaseConnectionPool { -//! # fn new() -> DatabaseConnectionPool { DatabaseConnectionPool } +//! use hyper_util::rt::{TokioIo, TokioExecutor}; +//! use hyper_util::service::TowerToHyperService; +//! +//! # async fn handler(_: Request) -> Result>, BoxError> { +//! # Ok(Response::new(Full::new(Bytes::from("hello")))) //! # } -//! # fn content_length_from_response(_: &http::Response) -> Option { None } -//! # async fn update_in_flight_requests_metric(count: usize) {} //! -//! // Our request handler. This is where we would implement the application logic -//! // for responding to HTTP requests... -//! async fn handler(request: Request>) -> Result>, BoxError> { -//! // ... -//! # todo!() -//! } +//! #[tokio::main] +//! async fn main() -> Result<(), BoxError> { +//! let addr = SocketAddr::from((Ipv6Addr::LOCALHOST, 8000)); +//! let listener = tokio::net::TcpListener::bind(addr).await?; +//! println!("Listening on http://{}", addr); //! -//! // Shared state across all request handlers --- in this case, a pool of database connections. -//! struct State { -//! pool: DatabaseConnectionPool, -//! } +//! loop { +//! let (socket, _) = listener.accept().await?; //! -//! #[tokio::main] -//! async fn main() { -//! // Construct the shared state. -//! let state = State { -//! pool: DatabaseConnectionPool::new(), -//! }; +//! tokio::spawn(async move { +//! let socket = TokioIo::new(socket); +//! +//! // Build our middleware stack +//! let service = ServiceBuilder::new() +//! .layer(TraceLayer::new_for_http()) +//! .layer(CompressionLayer::new()) +//! .service_fn(handler); +//! +//! // Wrap it for hyper +//! let hyper_service = TowerToHyperService::new(service); //! -//! // Use tower's `ServiceBuilder` API to build a stack of tower middleware -//! // wrapping our request handler. -//! let service = ServiceBuilder::new() -//! // Mark the `Authorization` request header as sensitive so it doesn't show in logs -//! .layer(SetSensitiveRequestHeadersLayer::new(once(AUTHORIZATION))) -//! // High level logging of requests and responses -//! .layer(TraceLayer::new_for_http()) -//! // Share an `Arc` with all requests -//! .layer(AddExtensionLayer::new(Arc::new(state))) -//! // Compress responses -//! .layer(CompressionLayer::new()) -//! // Propagate `X-Request-Id`s from requests to responses -//! .layer(PropagateHeaderLayer::new(HeaderName::from_static("x-request-id"))) -//! // If the response has a known size set the `Content-Length` header -//! .layer(SetResponseHeaderLayer::overriding(CONTENT_TYPE, content_length_from_response)) -//! // Accept only application/json, application/* and */* in a request's Accept header -//! .layer(ValidateRequestHeaderLayer::accept("application/json")) -//! // Wrap a `Service` in our middleware stack -//! .service_fn(handler); -//! # let mut service = service; -//! # tower::Service::call(&mut service, Request::new(Full::default())); +//! if let Err(err) = hyper_util::server::conn::auto::Builder::new(TokioExecutor::new()) +//! .serve_connection(socket, hyper_service) +//! .await +//! { +//! eprintln!("failed to serve connection: {err:#}"); +//! } +//! }); +//! } //! } //! ``` //! @@ -163,6 +147,7 @@ //! [http]: https://crates.io/crates/http //! [http-body]: https://crates.io/crates/http-body //! [hyper]: https://crates.io/crates/hyper +//! [hyper-util]: https://crates.io/crates/hyper-util //! [guides]: https://github.com/tower-rs/tower/tree/master/guides //! [tonic]: https://crates.io/crates/tonic //! [warp]: https://crates.io/crates/warp