A simple reverse proxy for use with Hyper and Tokio
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
hyper-reverse-proxy/README.md

93 lines
3.6 KiB

5 years ago
7 years ago
# hyper-reverse-proxy
[![Build Status](https://travis-ci.org/brendanzab/hyper-reverse-proxy.svg?branch=master)](https://travis-ci.org/brendanzab/hyper-reverse-proxy)
[![Documentation](https://docs.rs/hyper-reverse-proxy/badge.svg)](https://docs.rs/hyper-reverse-proxy)
[![Version](https://img.shields.io/crates/v/hyper-reverse-proxy.svg)](https://crates.io/crates/hyper-reverse-proxy)
[![License](https://img.shields.io/crates/l/hyper-reverse-proxy.svg)](https://github.com/brendanzab/hyper-reverse-proxy/blob/master/LICENSE)
5 years ago
A simple reverse proxy, to be used with [Hyper].
The implementation ensures that [Hop-by-hop headers] are stripped correctly in both directions,
and adds the client's IP address to a comma-space-separated list of forwarding addresses in the
`X-Forwarded-For` header.
7 years ago
5 years ago
The implementation is based on Go's [`httputil.ReverseProxy`].
7 years ago
[Hyper]: http://hyper.rs/
5 years ago
[Hop-by-hop headers]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
7 years ago
[`httputil.ReverseProxy`]: https://golang.org/pkg/net/http/httputil/#ReverseProxy
5 years ago
# Example
Add these dependencies to your `Cargo.toml` file.
5 years ago
```toml
5 years ago
[dependencies]
3 years ago
hyper-reverse-proxy = "0.5"
hyper = { version = "0.14", features = ["full"] }
tokio = { version = "1", features = ["full"] }
5 years ago
```
The following example will set up a reverse proxy listening on `127.0.0.1:13900`,
and will proxy these calls:
* `"/target/first"` will be proxied to `http://127.0.0.1:13901`
2 years ago
5 years ago
* `"/target/second"` will be proxied to `http://127.0.0.1:13902`
2 years ago
5 years ago
* All other URLs will be handled by `debug_request` function, that will display request information.
```rust,no_run
use hyper::server::conn::AddrStream;
2 years ago
use hyper::{Body, Request, Response, Server, StatusCode};
5 years ago
use hyper::service::{service_fn, make_service_fn};
2 years ago
use std::{convert::Infallible, net::SocketAddr};
use std::net::IpAddr;
5 years ago
2 years ago
fn debug_request(req: Request<Body>) -> Result<Response<Body>, Infallible> {
5 years ago
let body_str = format!("{:?}", req);
2 years ago
Ok(Response::new(Body::from(body_str)))
5 years ago
}
2 years ago
async fn handle(client_ip: IpAddr, req: Request<Body>) -> Result<Response<Body>, Infallible> {
if req.uri().path().starts_with("/target/first") {
// will forward requests to port 13901
match hyper_reverse_proxy::call(client_ip, "http://127.0.0.1:13901", req).await {
Ok(response) => {Ok(response)}
2 years ago
Err(_error) => {Ok(Response::builder()
2 years ago
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap())}
}
} else if req.uri().path().starts_with("/target/second") {
// will forward requests to port 13902
match hyper_reverse_proxy::call(client_ip, "http://127.0.0.1:13902", req).await {
Ok(response) => {Ok(response)}
Err(_error) => {Ok(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap())}
}
} else {
debug_request(req)
}
}
#[tokio::main]
2 years ago
async fn main() {
let bind_addr = "127.0.0.1:8000";
let addr:SocketAddr = bind_addr.parse().expect("Could not parse ip:port.");
let make_svc = make_service_fn(|conn: &AddrStream| {
let remote_addr = conn.remote_addr().ip();
async move {
Ok::<_, Infallible>(service_fn(move |req| handle(remote_addr, req)))
}
5 years ago
});
let server = Server::bind(&addr).serve(make_svc);
5 years ago
println!("Running server on {:?}", addr);
if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
5 years ago
}
```