|
1 |
| -//! |
2 |
| -//! A simple reverse proxy, to be used with [Hyper]. |
3 |
| -//! |
4 |
| -//! The implementation ensures that [Hop-by-hop headers] are stripped correctly in both directions, |
5 |
| -//! and adds the client's IP address to a comma-space-separated list of forwarding addresses in the |
6 |
| -//! `X-Forwarded-For` header. |
7 |
| -//! |
8 |
| -//! The implementation is based on Go's [`httputil.ReverseProxy`]. |
9 |
| -//! |
10 |
| -//! [Hyper]: http://hyper.rs/ |
11 |
| -//! [Hop-by-hop headers]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html |
12 |
| -//! [`httputil.ReverseProxy`]: https://golang.org/pkg/net/http/httputil/#ReverseProxy |
13 |
| -//! |
14 |
| -//! # Example |
15 |
| -//! |
16 |
| -//! Add these dependencies to your `Cargo.toml` file. |
17 |
| -//! |
18 |
| -//! ```toml |
19 |
| -//! [dependencies] |
20 |
| -//! hyper-reverse-proxy = "0.5" |
21 |
| -//! hyper = { version = "0.14", features = ["full"] } |
22 |
| -//! tokio = { version = "1", features = ["full"] } |
23 |
| -//! ``` |
24 |
| -//! |
25 |
| -//! To enable support for connecting to downstream HTTPS servers, enable the `https` feature: |
26 |
| -//! |
27 |
| -//! ```toml |
28 |
| -//! hyper-reverse-proxy = { version = "0.4", features = ["https"] } |
29 |
| -//! ``` |
30 |
| -//! |
31 |
| -//! The following example will set up a reverse proxy listening on `127.0.0.1:13900`, |
32 |
| -//! and will proxy these calls: |
33 |
| -//! |
34 |
| -//! * `"/target/first"` will be proxied to `http://127.0.0.1:13901` |
35 |
| -//! |
36 |
| -//! * `"/target/second"` will be proxied to `http://127.0.0.1:13902` |
37 |
| -//! |
38 |
| -//! * All other URLs will be handled by `debug_request` function, that will display request information. |
39 |
| -//! |
40 |
| -//! ```rust,no_run |
41 |
| -//! use hyper::server::conn::AddrStream; |
42 |
| -//! use hyper::service::{make_service_fn, service_fn}; |
43 |
| -//! use hyper::{Body, Request, Response, Server, StatusCode}; |
44 |
| -//! use hyper_reverse_proxy::ReverseProxy; |
45 |
| -//! use hyper_trust_dns::{RustlsHttpsConnector, TrustDnsResolver}; |
46 |
| -//! use std::net::IpAddr; |
47 |
| -//! use std::{convert::Infallible, net::SocketAddr}; |
48 |
| -//! |
49 |
| -//! lazy_static::lazy_static! { |
50 |
| -//! static ref PROXY_CLIENT: ReverseProxy<RustlsHttpsConnector> = { |
51 |
| -//! ReverseProxy::new( |
52 |
| -//! hyper::Client::builder().build::<_, hyper::Body>(TrustDnsResolver::default().into_rustls_webpki_https_connector()), |
53 |
| -//! ) |
54 |
| -//! }; |
55 |
| -//! } |
56 |
| -//! |
57 |
| -//! fn debug_request(req: &Request<Body>) -> Result<Response<Body>, Infallible> { |
58 |
| -//! let body_str = format!("{:?}", req); |
59 |
| -//! Ok(Response::new(Body::from(body_str))) |
60 |
| -//! } |
61 |
| -//! |
62 |
| -//! async fn handle(client_ip: IpAddr, req: Request<Body>) -> Result<Response<Body>, Infallible> { |
63 |
| -//! if req.uri().path().starts_with("/target/first") { |
64 |
| -//! match PROXY_CLIENT.call(client_ip, "http://127.0.0.1:13901", req) |
65 |
| -//! .await |
66 |
| -//! { |
67 |
| -//! Ok(response) => { |
68 |
| -//! Ok(response) |
69 |
| -//! }, |
70 |
| -//! Err(_error) => { |
71 |
| -//! Ok(Response::builder() |
72 |
| -//! .status(StatusCode::INTERNAL_SERVER_ERROR) |
73 |
| -//! .body(Body::empty()) |
74 |
| -//! .unwrap())}, |
75 |
| -//! } |
76 |
| -//! } else if req.uri().path().starts_with("/target/second") { |
77 |
| -//! match PROXY_CLIENT.call(client_ip, "http://127.0.0.1:13902", req) |
78 |
| -//! .await |
79 |
| -//! { |
80 |
| -//! Ok(response) => Ok(response), |
81 |
| -//! Err(_error) => Ok(Response::builder() |
82 |
| -//! .status(StatusCode::INTERNAL_SERVER_ERROR) |
83 |
| -//! .body(Body::empty()) |
84 |
| -//! .unwrap()), |
85 |
| -//! } |
86 |
| -//! } else { |
87 |
| -//! debug_request(&req) |
88 |
| -//! } |
89 |
| -//! } |
90 |
| -//! |
91 |
| -//! #[tokio::main] |
92 |
| -//! async fn main() { |
93 |
| -//! let bind_addr = "127.0.0.1:8000"; |
94 |
| -//! let addr: SocketAddr = bind_addr.parse().expect("Could not parse ip:port."); |
95 |
| -//! |
96 |
| -//! let make_svc = make_service_fn(|conn: &AddrStream| { |
97 |
| -//! let remote_addr = conn.remote_addr().ip(); |
98 |
| -//! async move { Ok::<_, Infallible>(service_fn(move |req| handle(remote_addr, req))) } |
99 |
| -//! }); |
100 |
| -//! |
101 |
| -//! let server = Server::bind(&addr).serve(make_svc); |
102 |
| -//! |
103 |
| -//! println!("Running server on {:?}", addr); |
104 |
| -//! |
105 |
| -//! if let Err(e) = server.await { |
106 |
| -//! eprintln!("server error: {}", e); |
107 |
| -//! } |
108 |
| -//! } |
109 |
| -//! |
110 |
| -//! ``` |
| 1 | +#![doc = include_str!("../README.md")] |
| 2 | + |
111 | 3 | #[macro_use]
|
112 | 4 | extern crate tracing;
|
113 | 5 |
|
|
0 commit comments