updates to hyper 0.12.16

This commit is contained in:
Felipe Noronha 2018-11-24 13:27:20 -02:00
parent d45b2f71d0
commit 692d287ee4
2 changed files with 119 additions and 13 deletions

View File

@ -1,12 +1,12 @@
[package]
name = "hyper-reverse-proxy"
version = "0.2.1"
authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>"]
version = "0.3.0"
authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>", "Felipe Noronha <felipenoris@gmail.com>"]
license = "Apache-2.0"
description = "A simple reverse proxy, to be used with Hyper and Tokio."
homepage = "https://github.com/brendanzab/hyper-reverse-proxy"
homepage = "https://github.com/felipenoris/hyper-reverse-proxy"
documentation = "https://docs.rs/hyper-reverse-proxy"
repository = "https://github.com/brendanzab/hyper-reverse-proxy"
repository = "https://github.com/felipenoris/hyper-reverse-proxy"
keywords = ["http", "hyper"]
categories = ["network-programming", "web-programming"]
readme = "README.md"
@ -18,12 +18,7 @@ include = [
]
[dependencies]
futures = "0.1.14"
hyper = "0.11.0"
lazy_static = "0.2"
unicase = "2.0.0"
[dev-dependencies]
error-chain = "0.10.0"
tokio-core = "0.1.8"
tokio-signal = "0.1.2"
hyper = "0.12.16"
futures = "0.1"
lazy_static = "1.1"
unicase = "2.2"

111
src/lib.rs Normal file
View File

@ -0,0 +1,111 @@
extern crate hyper;
extern crate futures;
extern crate lazy_static;
extern crate unicase;
use hyper::Body;
use std::net::IpAddr;
use std::str::FromStr;
use hyper::header::{HeaderMap, HeaderValue};
use hyper::{Request, Response, Client, Uri, StatusCode};
use futures::future::{self, Future};
use lazy_static::lazy_static;
type BoxFut = Box<Future<Item=Response<Body>, Error=hyper::Error> + Send>;
fn is_hop_header(name: &str) -> bool {
use unicase::Ascii;
// A list of the headers, using `unicase` to help us compare without
// worrying about the case, and `lazy_static!` to prevent reallocation
// of the vector.
lazy_static! {
static ref HOP_HEADERS: Vec<Ascii<&'static str>> = vec![
Ascii::new("Connection"),
Ascii::new("Keep-Alive"),
Ascii::new("Proxy-Authenticate"),
Ascii::new("Proxy-Authorization"),
Ascii::new("Te"),
Ascii::new("Trailers"),
Ascii::new("Transfer-Encoding"),
Ascii::new("Upgrade"),
];
}
HOP_HEADERS.iter().any(|h| h == &name)
}
/// Returns a clone of the headers without the [hop-by-hop headers].
///
/// [hop-by-hop headers]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
fn remove_hop_headers(headers: &HeaderMap<HeaderValue>) -> HeaderMap<HeaderValue> {
let mut result = HeaderMap::new();
for (k, v) in headers.iter() {
if !is_hop_header(k.as_str()) {
result.insert(k.clone(), v.clone());
}
}
result
}
fn create_proxied_response<B>(mut response: Response<B>) -> Response<B> {
*response.headers_mut() = remove_hop_headers(response.headers());
response
}
fn forward_uri<B>(forward_url: &str, req: &Request<B>) -> Uri {
let forward_uri = match req.uri().query() {
Some(query) => format!("{}{}?{}", forward_url, req.uri().path(), query),
None => format!("{}{}", forward_url, req.uri().path()),
};
Uri::from_str(forward_uri.as_str()).unwrap()
}
fn create_proxied_request<B>(client_ip: IpAddr, forward_url: &str, mut request: Request<B>) -> Request<B> {
*request.headers_mut() = remove_hop_headers(request.headers());
*request.uri_mut() = forward_uri(forward_url, &request);
// Add forwarding information in the headers
match request.headers_mut().entry("x-forwarded-for") {
Ok(hyper::header::Entry::Vacant(entry)) => {
let addr = format!("{}", client_ip);
entry.insert(addr.parse().unwrap());
},
Ok(hyper::header::Entry::Occupied(mut entry)) => {
let addr = format!("{}, {}", entry.get().to_str().unwrap(), client_ip);
entry.insert(addr.parse().unwrap());
},
_ => (), // silently fails to add x-forwarded-for header
}
request
}
pub fn call(client_ip: IpAddr, forward_uri: &str, request: Request<Body>) -> BoxFut {
let proxied_request = create_proxied_request(client_ip, forward_uri, request);
let client = Client::new();
let response = client.request(proxied_request).then(|response| {
let proxied_response = match response {
Ok(response) => create_proxied_response(response),
Err(error) => {
println!("Error: {}", error); // TODO: Configurable logging
Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap()
},
};
future::ok(proxied_response)
});
Box::new(response)
}