Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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);
//!
//! // 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