diff --git a/Cargo.toml b/Cargo.toml index 0caeb8d..806ec6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ members = [ "form", "hello-world", "http-proxy", - "http-full-proxy", "json", "json_error", "jsonrpc", diff --git a/http-full-proxy/Cargo.toml b/http-full-proxy/Cargo.toml deleted file mode 100644 index ddfe7b8..0000000 --- a/http-full-proxy/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "http-full-proxy" -version = "0.1.0" -authors = ["Rotem Yaari"] -workspace = ".." -edition = "2018" - -[dependencies] -actix-rt = "0.2" -actix-web = "1.0.0" - -clap = "2.32.0" -futures = "0.1.25" -failure = "0.1.3" -url = "1.7.1" diff --git a/http-full-proxy/README.md b/http-full-proxy/README.md deleted file mode 100644 index 55a6a68..0000000 --- a/http-full-proxy/README.md +++ /dev/null @@ -1,10 +0,0 @@ -## HTTP Full proxy example - -This proxy forwards all types of requests, including ones with body, to another HTTP server, -returning the response to the client. - -To start: - -``` shell -cargo run -``` diff --git a/http-full-proxy/src/main.rs b/http-full-proxy/src/main.rs deleted file mode 100644 index a68b46f..0000000 --- a/http-full-proxy/src/main.rs +++ /dev/null @@ -1,102 +0,0 @@ -use actix_web::client::Client; -use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer}; -use clap::{value_t, Arg}; -use futures::Future; -use std::net::ToSocketAddrs; -use url::Url; - -fn forward( - req: HttpRequest, - payload: web::Payload, - url: web::Data, - client: web::Data, -) -> impl Future { - 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) - }) -} - -fn main() -> std::io::Result<()> { - 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(); - - HttpServer::new(move || { - App::new() - .data(Client::new()) - .data(forward_url.clone()) - .wrap(middleware::Logger::default()) - .default_service(web::route().to_async(forward)) - }) - .bind((listen_addr, listen_port))? - .system_exit() - .run() -} diff --git a/http-proxy/Cargo.toml b/http-proxy/Cargo.toml index 2a7beb8..a2c8740 100644 --- a/http-proxy/Cargo.toml +++ b/http-proxy/Cargo.toml @@ -1,21 +1,14 @@ [package] name = "http-proxy" version = "0.1.0" -authors = ["Nikolay Kim "] -edition = "2018" +authors = ["Nikolay Kim ", "Rotem Yaari "] workspace = ".." - -[[bin]] -name = "proxy" -path = "src/main.rs" - -[[bin]] -name = "proxy-example-server" -path = "src/server.rs" +edition = "2018" [dependencies] actix-rt = "0.2" actix-web = { version = "1.0.0", features=["ssl"] } - -env_logger = "0.5" -futures = "0.1" +clap = "2.32.0" +futures = "0.1.25" +failure = "0.1.3" +url = "1.7.1" diff --git a/http-proxy/README.md b/http-proxy/README.md index 2bc8272..5badaca 100644 --- a/http-proxy/README.md +++ b/http-proxy/README.md @@ -1,13 +1,10 @@ -## Http proxy example +## HTTP Full proxy example -To start proxy server: +This is a relatively simple HTTP proxy, forwarding HTTP requests to another HTTP server, including +request body, headers, and streaming uploads. -```sh -cargo run --bin proxy -``` - -To start local backend server: - -```sh -cargo run --bin proxy-example-server +To start: + +``` shell +cargo run ``` diff --git a/http-proxy/src/main.rs b/http-proxy/src/main.rs index ff45ef9..a68b46f 100644 --- a/http-proxy/src/main.rs +++ b/http-proxy/src/main.rs @@ -1,52 +1,102 @@ use actix_web::client::Client; -use actix_web::{middleware, web, App, Error, HttpResponse, HttpServer}; +use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use clap::{value_t, Arg}; use futures::Future; +use std::net::ToSocketAddrs; +use url::Url; -/// Stream client request response and then send body to a server response -fn index(client: web::Data) -> impl Future { - client - .get("http://127.0.0.1:8081/") - .send() - .map_err(Error::from) // <- convert SendRequestError to an Error - .and_then(|mut resp| { - resp.body() // <- this is MessageBody type, resolves to complete body - .from_err() // <- convert PayloadError to an Error - .and_then(|body| { - // <- we got complete body, now send as server response - Ok(HttpResponse::Ok().body(body)) - }) - }) -} - -/// streaming client request to a streaming server response -fn streaming( +fn forward( + req: HttpRequest, + payload: web::Payload, + url: web::Data, client: web::Data, -) -> impl Future> { - // send client request - client - .get("https://www.rust-lang.org/") - .send() // <- connect to host and send request - .map_err(Error::from) // <- convert SendRequestError to an Error - .and_then(|resp| { - // <- we received client response - Ok(HttpResponse::Ok() - // read one chunk from client response and send this chunk to a server response - // .from_err() converts PayloadError to an Error - .streaming(resp)) +) -> impl Future { + 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) }) } fn main() -> std::io::Result<()> { - std::env::set_var("RUST_LOG", "actix_server=info,actix_web=trace"); - env_logger::init(); + 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(); - HttpServer::new(|| { + 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(); + + HttpServer::new(move || { App::new() .data(Client::new()) + .data(forward_url.clone()) .wrap(middleware::Logger::default()) - .service(web::resource("/streaming").to_async(streaming)) - .service(web::resource("/").to_async(index)) + .default_service(web::route().to_async(forward)) }) - .bind("127.0.0.1:8080")? + .bind((listen_addr, listen_port))? + .system_exit() .run() } diff --git a/http-proxy/src/server.rs b/http-proxy/src/server.rs deleted file mode 100644 index a8e7559..0000000 --- a/http-proxy/src/server.rs +++ /dev/null @@ -1,20 +0,0 @@ -use actix_web::{middleware, web, App, HttpResponse, HttpServer, Responder}; - -fn index(body: web::Bytes) -> impl Responder { - HttpResponse::Ok().body(body) -} - -fn main() -> std::io::Result<()> { - std::env::set_var("RUST_LOG", "actix_server=info,actix_web=trace"); - env_logger::init(); - - HttpServer::new(|| { - App::new() - // enable logger - .wrap(middleware::Logger::default()) - .service(web::resource("/index.html").to(|| "Hello world!")) - .service(web::resource("/").to(index)) - }) - .bind("127.0.0.1:8081")? - .run() -}