2019-03-27 07:33:13 +01:00
|
|
|
use actix_web::client::Client;
|
2019-08-19 20:42:31 +02:00
|
|
|
use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer};
|
|
|
|
use clap::{value_t, Arg};
|
2019-03-27 07:33:13 +01:00
|
|
|
use futures::Future;
|
2019-08-19 20:42:31 +02:00
|
|
|
use std::net::ToSocketAddrs;
|
|
|
|
use url::Url;
|
2018-04-13 03:18:42 +02:00
|
|
|
|
2019-08-19 20:42:31 +02:00
|
|
|
fn forward(
|
|
|
|
req: HttpRequest,
|
|
|
|
payload: web::Payload,
|
|
|
|
url: web::Data<Url>,
|
2019-03-27 07:33:13 +01:00
|
|
|
client: web::Data<Client>,
|
2019-08-19 20:42:31 +02:00
|
|
|
) -> impl Future<Item = HttpResponse, Error = Error> {
|
|
|
|
let mut new_url = url.get_ref().clone();
|
|
|
|
new_url.set_path(req.uri().path());
|
|
|
|
new_url.set_query(req.uri().query());
|
|
|
|
|
|
|
|
let forwarded_req = client
|
|
|
|
.request_from(new_url.as_str(), req.head())
|
|
|
|
.no_decompress();
|
|
|
|
let forwarded_req = if let Some(addr) = req.head().peer_addr {
|
|
|
|
forwarded_req.header("x-forwarded-for", format!("{}", addr.ip()))
|
|
|
|
} else {
|
|
|
|
forwarded_req
|
|
|
|
};
|
|
|
|
|
|
|
|
forwarded_req
|
|
|
|
.send_stream(payload)
|
|
|
|
.map_err(Error::from)
|
|
|
|
.map(|res| {
|
|
|
|
let mut client_resp = HttpResponse::build(res.status());
|
|
|
|
for (header_name, header_value) in res
|
|
|
|
.headers()
|
|
|
|
.iter()
|
|
|
|
.filter(|(h, _)| *h != "connection" && *h != "content-length")
|
|
|
|
{
|
|
|
|
client_resp.header(header_name.clone(), header_value.clone());
|
|
|
|
}
|
|
|
|
client_resp.streaming(res)
|
2018-04-13 03:18:42 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-03-27 07:33:13 +01:00
|
|
|
fn main() -> std::io::Result<()> {
|
2019-08-19 20:42:31 +02:00
|
|
|
let matches = clap::App::new("HTTP Proxy")
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("listen_addr")
|
|
|
|
.takes_value(true)
|
|
|
|
.value_name("LISTEN ADDR")
|
|
|
|
.index(1)
|
|
|
|
.required(true),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("listen_port")
|
|
|
|
.takes_value(true)
|
|
|
|
.value_name("LISTEN PORT")
|
|
|
|
.index(2)
|
|
|
|
.required(true),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("forward_addr")
|
|
|
|
.takes_value(true)
|
|
|
|
.value_name("FWD ADDR")
|
|
|
|
.index(3)
|
|
|
|
.required(true),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("forward_port")
|
|
|
|
.takes_value(true)
|
|
|
|
.value_name("FWD PORT")
|
|
|
|
.index(4)
|
|
|
|
.required(true),
|
|
|
|
)
|
|
|
|
.get_matches();
|
|
|
|
|
|
|
|
let listen_addr = matches.value_of("listen_addr").unwrap();
|
|
|
|
let listen_port = value_t!(matches, "listen_port", u16).unwrap_or_else(|e| e.exit());
|
|
|
|
|
|
|
|
let forwarded_addr = matches.value_of("forward_addr").unwrap();
|
|
|
|
let forwarded_port =
|
|
|
|
value_t!(matches, "forward_port", u16).unwrap_or_else(|e| e.exit());
|
|
|
|
|
|
|
|
let forward_url = Url::parse(&format!(
|
|
|
|
"http://{}",
|
|
|
|
(forwarded_addr, forwarded_port)
|
|
|
|
.to_socket_addrs()
|
|
|
|
.unwrap()
|
|
|
|
.next()
|
|
|
|
.unwrap()
|
|
|
|
))
|
|
|
|
.unwrap();
|
2018-04-13 03:18:42 +02:00
|
|
|
|
2019-08-19 20:42:31 +02:00
|
|
|
HttpServer::new(move || {
|
2018-05-08 03:55:18 +02:00
|
|
|
App::new()
|
2019-03-27 07:33:13 +01:00
|
|
|
.data(Client::new())
|
2019-08-19 20:42:31 +02:00
|
|
|
.data(forward_url.clone())
|
2019-03-27 07:33:13 +01:00
|
|
|
.wrap(middleware::Logger::default())
|
2019-08-19 20:42:31 +02:00
|
|
|
.default_service(web::route().to_async(forward))
|
2019-03-10 03:03:09 +01:00
|
|
|
})
|
2019-08-19 20:42:31 +02:00
|
|
|
.bind((listen_addr, listen_port))?
|
|
|
|
.system_exit()
|
2019-03-27 07:33:13 +01:00
|
|
|
.run()
|
2018-04-13 03:18:42 +02:00
|
|
|
}
|