http2_proxy/
http2-proxy.rs1mod server {
2 use std::convert::Infallible;
3 use std::net::SocketAddr;
4
5 use http_body_util::Full;
6 use hyper::body::Bytes;
7 use hyper::server::conn::http2;
8 use hyper::service::service_fn;
9 use hyper::{Request, Response};
10 use hyper_util::rt::{TokioExecutor, TokioIo};
11 use tokio::net::TcpListener;
12
13 async fn hello(
14 request: Request<hyper::body::Incoming>,
15 ) -> Result<Response<Full<Bytes>>, Infallible> {
16 let uri = request.uri();
17
18 let response = match uri.path() {
19 "/healthz" => Bytes::from("We're healthy"),
20 "/hello" => Bytes::from("Hello world"),
21 _ => Bytes::from("Standard response"),
22 };
23
24 Ok(Response::new(Full::new(response)))
25 }
26
27 pub(super) async fn serve() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
28 let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
29
30 let listener = TcpListener::bind(addr).await?;
32
33 loop {
34 let (stream, _) = listener.accept().await?;
35 let io = TokioIo::new(stream);
36
37 tokio::task::spawn(async move {
38 if let Err(error) = http2::Builder::new(TokioExecutor::new())
39 .serve_connection(io, service_fn(hello))
40 .await
41 {
42 eprintln!("Error serving connection: {}", error);
43 }
44 });
45 }
46 }
47}
48
49mod proxy {
50 use axum::Router;
51 use http::uri::Scheme;
52 use tower_proxy::builder;
53 use tower_proxy::client::Builder;
54
55 pub(super) async fn serve() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
56 let proxy_service_builder = builder(
57 Builder::new(hyper_util::rt::TokioExecutor::new())
58 .http2_only(true)
59 .build_http(),
60 Scheme::HTTP,
61 "127.0.0.1:3000",
62 )?;
63
64 let svc: tower_proxy::ReusedService<
65 tower_proxy::Identity,
66 tower_proxy::client::HttpConnector,
67 axum::body::Body,
68 > = proxy_service_builder.build(tower_proxy::rewrite::Identity {});
69
70 let router = Router::new().fallback_service(svc);
71
72 let listener = tokio::net::TcpListener::bind("127.0.0.1:2000")
73 .await
74 .unwrap();
75
76 axum::serve(listener, router).await?;
77
78 Ok(())
79 }
80}
81
82#[tokio::main]
83async fn main() {
84 let _server = tokio::task::spawn(server::serve());
85
86 let _proxy = tokio::task::spawn(proxy::serve());
87
88 let text = reqwest::get("http://127.0.0.1:2000/hello")
89 .await
90 .unwrap()
91 .text()
92 .await;
93
94 assert!(
95 matches!(text.as_deref(), Ok("Hello world")),
96 "Server returned response"
97 );
98}