1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
extern crate iron; #[cfg(test)] extern crate iron_test; extern crate url; use iron::prelude::*; use iron::Url; use iron::BeforeMiddleware; use std::str; pub struct ReverseProxyMiddleware; impl BeforeMiddleware for ReverseProxyMiddleware { fn before(&self, req: &mut Request) -> IronResult<()> { if let Some(xfh) = req.headers.get_raw("x-forwarded-host") { let mut url: url::Url = req.url.clone().into(); url.set_host(Some(str::from_utf8(&xfh[0]).unwrap())) .unwrap(); if let Some(xfp) = req.headers.get_raw("x-forwarded-proto") { url.set_scheme(str::from_utf8(&xfp[0]).unwrap()).unwrap(); } if let Some(xfp) = req.headers.get_raw("x-forwarded-port") { let port = str::from_utf8(&xfp[0]).unwrap().parse().unwrap(); match (url.scheme(), port) { ("http", 80) | ("https", 443) => url.set_port(None).unwrap(), _ => url.set_port(Some(port)).unwrap(), } } req.url = Url::from_generic_url(url).unwrap(); } Ok(()) } } #[cfg(test)] mod tests { use super::ReverseProxyMiddleware; use iron::BeforeMiddleware; use iron::Url; use iron::headers::Headers; use iron::request::Request; use iron::response::Response; use iron_test::request; fn test_middleware(url: &str, headers: &[(&str, &[u8])], result: &str) { let mut h = Headers::new(); for &(k, v) in headers { h.set_raw(k.to_string(), vec![v.to_vec()]); } let result = Url::parse(result).unwrap(); request::get(url, h, &move |req: &mut Request| { ReverseProxyMiddleware.before(req).unwrap(); assert_eq!(req.url, result); Ok(Response::new()) }).unwrap(); } #[test] fn it_works() { test_middleware("http://localhost:3000/", &[], "http://localhost:3000/"); test_middleware( "http://localhost:3000/", &[("x-forwarded-host", b"thing")], "http://thing:3000/", ); test_middleware( "http://localhost:3000/", &[("x-forwarded-host", b"thing"), ("x-forwarded-port", b"80")], "http://thing/", ); test_middleware( "http://localhost:3000/", &[ ("x-forwarded-host", b"thing"), ("x-forwarded-port", b"80"), ("x-forwarded-proto", b"https"), ], "https://thing:80/", ); } }