Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion tower-http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
87 changes: 36 additions & 51 deletions tower-http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, BoxError> {
//! # Ok(Response::new(Full::new(Bytes::from("hello"))))
//! # }
//! # fn content_length_from_response<B>(_: &http::Response<B>) -> Option<http::HeaderValue> { 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<Full<Bytes>>) -> Result<Response<Full<Bytes>>, 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);
//!
Comment thread
jplatte marked this conversation as resolved.
Outdated
//! // 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<State>` 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:#}");
//! }
//! });
//! }
//! }
//! ```
//!
Expand Down Expand Up @@ -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
Expand Down