Add example and remove dependency on void crate
This commit is contained in:
parent
db21a7b721
commit
217cecd14e
@ -22,4 +22,6 @@ futures = "0.1.14"
|
|||||||
hyper = "0.11.0"
|
hyper = "0.11.0"
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
unicase = "2.0.0"
|
unicase = "2.0.0"
|
||||||
void = "1.0.2"
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio-core = "0.1.8"
|
||||||
|
68
src/lib.rs
68
src/lib.rs
@ -1,4 +1,55 @@
|
|||||||
//! A simple reverse proxy, to be used with Hyper and Tokio.
|
//! A simple reverse proxy, to be used with Hyper and Tokio.
|
||||||
|
//!
|
||||||
|
//! 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.
|
||||||
|
//!
|
||||||
|
//! The implementation is based on Go's [`httputil.ReverseProxy`].
|
||||||
|
//!
|
||||||
|
//! [Hop-by-hop headers]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
|
||||||
|
//! [`httputil.ReverseProxy`]: https://golang.org/pkg/net/http/httputil/#ReverseProxy
|
||||||
|
//!
|
||||||
|
//! ```rust,no_run
|
||||||
|
//! extern crate futures;
|
||||||
|
//! extern crate hyper;
|
||||||
|
//! extern crate hyper_reverse_proxy;
|
||||||
|
//! extern crate tokio_core;
|
||||||
|
//!
|
||||||
|
//! fn run() -> hyper::Result<()> {
|
||||||
|
//! use futures::Stream;
|
||||||
|
//! use hyper::Client;
|
||||||
|
//! use hyper::server::Http;
|
||||||
|
//! use hyper_reverse_proxy::ReverseProxy;
|
||||||
|
//! use tokio_core::net::TcpListener;
|
||||||
|
//! use tokio_core::reactor::Core;
|
||||||
|
//! use std::net::{SocketAddr, Ipv4Addr};
|
||||||
|
//!
|
||||||
|
//! let mut core = Core::new()?;
|
||||||
|
//! let handle = core.handle();
|
||||||
|
//! let listen_addr = SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 8080);
|
||||||
|
//! let listener = TcpListener::bind(&listen_addr, &handle)?;
|
||||||
|
//!
|
||||||
|
//! let http = Http::new();
|
||||||
|
//! let server = listener.incoming().for_each(|(socket, addr)| {
|
||||||
|
//! let service = ReverseProxy::new(Client::new(&handle), Some(addr.ip()));
|
||||||
|
//! http.bind_connection(&handle, socket, addr, service);
|
||||||
|
//! Ok(())
|
||||||
|
//! });
|
||||||
|
//!
|
||||||
|
//! core.run(server)?;
|
||||||
|
//!
|
||||||
|
//! Ok(())
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn main() {
|
||||||
|
//! use std::io::Write;
|
||||||
|
//!
|
||||||
|
//! if let Err(error) = run() {
|
||||||
|
//! write!(&mut std::io::stderr(), "{}", error).expect("Error writing to stderr");
|
||||||
|
//! std::process::exit(1);
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -6,14 +57,12 @@ extern crate hyper;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate unicase;
|
extern crate unicase;
|
||||||
extern crate void;
|
|
||||||
|
|
||||||
use futures::future::Future;
|
use futures::future::Future;
|
||||||
use hyper::{Body, Headers, Request, Response, StatusCode};
|
use hyper::{Body, Headers, Request, Response, StatusCode};
|
||||||
use hyper::server::Service;
|
use hyper::server::Service;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use void::Void;
|
|
||||||
|
|
||||||
fn is_hop_header(name: &str) -> bool {
|
fn is_hop_header(name: &str) -> bool {
|
||||||
use unicase::Ascii;
|
use unicase::Ascii;
|
||||||
@ -99,15 +148,6 @@ fn create_proxied_response<B>(mut response: Response<B>) -> Response<B> {
|
|||||||
|
|
||||||
/// A `Service` that takes an incoming request, sends it to a given `Client`, then proxies back
|
/// A `Service` that takes an incoming request, sends it to a given `Client`, then proxies back
|
||||||
/// the response.
|
/// the response.
|
||||||
///
|
|
||||||
/// 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.
|
|
||||||
///
|
|
||||||
/// The implementation is based on Go's [`httputil.ReverseProxy`].
|
|
||||||
///
|
|
||||||
/// [Hop-by-hop headers]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
|
|
||||||
/// [`httputil.ReverseProxy`]: https://golang.org/pkg/net/http/httputil/#ReverseProxy
|
|
||||||
pub struct ReverseProxy<C: Service, B = Body> {
|
pub struct ReverseProxy<C: Service, B = Body> {
|
||||||
client: C,
|
client: C,
|
||||||
remote_ip: Option<IpAddr>,
|
remote_ip: Option<IpAddr>,
|
||||||
@ -133,7 +173,7 @@ impl<C: Service, B> ReverseProxy<C, B> {
|
|||||||
// could use an entry API like `std::collections::HashMap`?
|
// could use an entry API like `std::collections::HashMap`?
|
||||||
if request.headers().has::<XForwardedFor>() {
|
if request.headers().has::<XForwardedFor>() {
|
||||||
if let Some(prior) = request.headers_mut().get_mut::<XForwardedFor>() {
|
if let Some(prior) = request.headers_mut().get_mut::<XForwardedFor>() {
|
||||||
prior.0.push(ip);
|
prior.push(ip);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let header = XForwardedFor(vec![ip]);
|
let header = XForwardedFor(vec![ip]);
|
||||||
@ -154,8 +194,8 @@ where
|
|||||||
{
|
{
|
||||||
type Request = Request<B>;
|
type Request = Request<B>;
|
||||||
type Response = Response<B>;
|
type Response = Response<B>;
|
||||||
type Error = Void;
|
type Error = hyper::Error;
|
||||||
type Future = Box<Future<Item = Response<B>, Error = Void>>;
|
type Future = Box<Future<Item = Response<B>, Error = hyper::Error>>;
|
||||||
|
|
||||||
fn call(&self, request: Self::Request) -> Self::Future {
|
fn call(&self, request: Self::Request) -> Self::Future {
|
||||||
let proxied_request = self.create_proxied_request(request);
|
let proxied_request = self.create_proxied_request(request);
|
||||||
|
Loading…
Reference in New Issue
Block a user