port lib to hyper 0.13 and future 0.3

pull/12/head
Jan Kantert 4 years ago committed by Felipe Noronha
parent b53642da26
commit d838516387
  1. 2
      .gitignore
  2. 15
      Cargo.toml
  3. 156
      src/lib.rs

2
.gitignore vendored

@ -1,3 +1,5 @@
/target/ /target/
**/*.rs.bk **/*.rs.bk
Cargo.lock Cargo.lock
/.idea
*.swp

@ -1,7 +1,7 @@
[package] [package]
name = "hyper-reverse-proxy" name = "hyper-reverse-proxy"
version = "0.4.0" version = "0.5.0"
authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>", "Felipe Noronha <felipenoris@gmail.com>"] authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>", "Felipe Noronha <felipenoris@gmail.com>", "Jan Kantert <jan-hyper-reverse-proxy@kantert.net>"]
license = "Apache-2.0" license = "Apache-2.0"
description = "A simple reverse proxy, to be used with Hyper and Tokio." description = "A simple reverse proxy, to be used with Hyper and Tokio."
homepage = "https://github.com/felipenoris/hyper-reverse-proxy" homepage = "https://github.com/felipenoris/hyper-reverse-proxy"
@ -19,7 +19,10 @@ include = [
] ]
[dependencies] [dependencies]
hyper = "0.12" hyper = "0.13"
futures = "0.1" futures = "0.3"
lazy_static = "1.3" lazy_static = "1.4"
unicase = "2.3" unicase = "2.6"
[dev-dependencies]
tokio = { version = "0.2", features = ["full"] }

@ -17,9 +17,10 @@
//! //!
//! ```toml //! ```toml
//! [dependencies] //! [dependencies]
//! hyper-reverse-proxy = "0.4" //! hyper-reverse-proxy = "0.5"
//! hyper = "0.12" //! hyper = "0.13"
//! futures = "0.1" //! futures = "0.3"
//! tokio = { version = "0.2", features = ["full"] }
//! ``` //! ```
//! //!
//! The following example will set up a reverse proxy listening on `127.0.0.1:13900`, //! The following example will set up a reverse proxy listening on `127.0.0.1:13900`,
@ -36,62 +37,59 @@
//! use hyper::{Body, Request, Response, Server}; //! use hyper::{Body, Request, Response, Server};
//! use hyper::service::{service_fn, make_service_fn}; //! use hyper::service::{service_fn, make_service_fn};
//! use futures::future::{self, Future}; //! use futures::future::{self, Future};
//! use std::{convert::Infallible, net::SocketAddr};
//! use hyper::http::uri::InvalidUri;
//! use std::net::IpAddr;
//! //!
//! type BoxFut = Box<Future<Item=Response<Body>, Error=hyper::Error> + Send>; //! fn debug_request(req: Request<Body>) -> Result<Response<Body>, Infallible> {
//!
//! fn debug_request(req: Request<Body>) -> BoxFut {
//! let body_str = format!("{:?}", req); //! let body_str = format!("{:?}", req);
//! let response = Response::new(Body::from(body_str)); //! Ok(Response::new(Body::from(body_str)))
//! Box::new(future::ok(response))
//! } //! }
//! //!
//! fn main() { //! async fn handle(client_ip: IpAddr, req: Request<Body>) -> Result<Response<Body>, Infallible> {
//! //! if req.uri().path().starts_with("/target/first") {
//! // This is our socket address... //! // will forward requests to port 13901
//! let addr = ([127, 0, 0, 1], 13900).into(); //! Ok(hyper_reverse_proxy::call(client_ip, "http://127.0.0.1:13901", req).await.unwrap())
//!
//! // A `Service` is needed for every connection.
//! let make_svc = make_service_fn(|socket: &AddrStream| {
//! let remote_addr = socket.remote_addr();
//! service_fn(move |req: Request<Body>| { // returns BoxFut
//! //!
//! if req.uri().path().starts_with("/target/first") { //! } else if req.uri().path().starts_with("/target/second") {
//! //!
//! // will forward requests to port 13901 //! // will forward requests to port 13902
//! return hyper_reverse_proxy::call(remote_addr.ip(), "http://127.0.0.1:13901", req) //! Ok(hyper_reverse_proxy::call(client_ip, "http://127.0.0.1:13902", req).await.unwrap())
//! //!
//! } else if req.uri().path().starts_with("/target/second") { //! } else {
//! debug_request(req)
//! }
//! }
//! //!
//! // will forward requests to port 13902 //! #[tokio::main]
//! return hyper_reverse_proxy::call(remote_addr.ip(), "http://127.0.0.1:13902", req) //! async fn main() {
//! let bind_addr = "127.0.0.1:8000";
//! let addr:SocketAddr = bind_addr.parse().expect("Could not parse ip:port.");
//! //!
//! } else { //! let make_svc = make_service_fn(|conn: &AddrStream| {
//! debug_request(req) //! let remote_addr = conn.remote_addr().ip();
//! } //! async move {
//! }) //! Ok::<_, Infallible>(service_fn(move |req| handle(remote_addr, req)))
//! }
//! }); //! });
//! //!
//! let server = Server::bind(&addr) //! let server = Server::bind(&addr).serve(make_svc);
//! .serve(make_svc)
//! .map_err(|e| eprintln!("server error: {}", e));
//! //!
//! println!("Running server on {:?}", addr); //! if let Err(e) = server.await {
//! eprintln!("server error: {}", e);
//! }
//! //!
//! // Run this server for... forever! //! println!("Running server on {:?}", addr);
//! hyper::rt::run(server);
//! } //! }
//! ``` //! ```
//! //!
use hyper::Body;
use std::net::IpAddr;
use std::str::FromStr;
use hyper::header::{HeaderMap, HeaderValue}; use hyper::header::{HeaderMap, HeaderValue};
use hyper::{Request, Response, Client, Uri, StatusCode}; use hyper::http::uri::InvalidUri;
use futures::future::{self, Future}; use hyper::{Body, Client, Request, Response, StatusCode, Uri};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use std::net::IpAddr;
type BoxFut = Box<Future<Item=Response<Body>, Error=hyper::Error> + Send>; use std::str::FromStr;
fn is_hop_header(name: &str) -> bool { fn is_hop_header(name: &str) -> bool {
use unicase::Ascii; use unicase::Ascii;
@ -133,66 +131,58 @@ fn create_proxied_response<B>(mut response: Response<B>) -> Response<B> {
response response
} }
fn forward_uri<B>(forward_url: &str, req: &Request<B>) -> Uri { fn forward_uri<B>(forward_url: &str, req: &Request<B>) -> Result<Uri, InvalidUri> {
let forward_uri = match req.uri().query() { let forward_uri = match req.uri().query() {
Some(query) => format!("{}{}?{}", forward_url, req.uri().path(), query), Some(query) => format!("{}{}?{}", forward_url, req.uri().path(), query),
None => format!("{}{}", forward_url, req.uri().path()), None => format!("{}{}", forward_url, req.uri().path()),
}; };
Uri::from_str(forward_uri.as_str()).unwrap() Uri::from_str(forward_uri.as_str())
} }
fn create_proxied_request<B>(client_ip: IpAddr, forward_url: &str, mut request: Request<B>) -> Request<B> { fn create_proxied_request<B>(
client_ip: IpAddr,
forward_url: &str,
mut request: Request<B>,
) -> Result<Request<B>, InvalidUri> {
*request.headers_mut() = remove_hop_headers(request.headers()); *request.headers_mut() = remove_hop_headers(request.headers());
*request.uri_mut() = forward_uri(forward_url, &request); *request.uri_mut() = forward_uri(forward_url, &request)?;
let x_forwarded_for_header_name = "x-forwarded-for"; let x_forwarded_for_header_name = "x-forwarded-for";
// Add forwarding information in the headers // Add forwarding information in the headers
match request.headers_mut().entry(x_forwarded_for_header_name) { match request.headers_mut().entry(x_forwarded_for_header_name) {
hyper::header::Entry::Vacant(entry) => {
Ok(header_entry) => { entry.insert(client_ip.to_string().parse().unwrap());
match header_entry {
hyper::header::Entry::Vacant(entry) => {
let addr = format!("{}", client_ip);
entry.insert(addr.parse().unwrap());
},
hyper::header::Entry::Occupied(mut entry) => {
let addr = format!("{}, {}", entry.get().to_str().unwrap(), client_ip);
entry.insert(addr.parse().unwrap());
}
}
} }
// shouldn't happen... hyper::header::Entry::Occupied(mut entry) => {
Err(_) => panic!("Invalid header name: {}", x_forwarded_for_header_name), let addr = format!("{}, {}", entry.get().to_str().unwrap(), client_ip);
entry.insert(addr.parse().unwrap());
}
} }
request Ok(request)
} }
pub fn call(client_ip: IpAddr, forward_uri: &str, request: Request<Body>) -> BoxFut { pub async fn call(
client_ip: IpAddr,
let proxied_request = create_proxied_request(client_ip, forward_uri, request); forward_uri: &str,
request: Request<Body>,
let client = Client::new(); ) -> Result<Response<Body>, InvalidUri> {
let response = client.request(proxied_request).then(|response| { let proxied_request = create_proxied_request(client_ip, &forward_uri, request)?;
let proxied_response = match response { let client = Client::new();
Ok(response) => create_proxied_response(response), let response = client.request(proxied_request).await;
Err(error) => { let proxied_response = match response {
println!("Error: {}", error); // TODO: Configurable logging Ok(response) => create_proxied_response(response),
Response::builder() Err(error) => {
.status(StatusCode::INTERNAL_SERVER_ERROR) println!("Error: {}", error); // TODO: Configurable logging
.body(Body::empty()) Response::builder()
.unwrap() .status(StatusCode::SERVICE_UNAVAILABLE)
}, .body(Body::empty())
}; .unwrap()
}
};
future::ok(proxied_response) Ok(proxied_response)
});
Box::new(response)
} }

Loading…
Cancel
Save