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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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/",
);
}
}