mirror of
https://github.com/actix/examples
synced 2024-11-23 22:41:07 +01:00
Merge pull request #165 from actix/vmalloc/remove-old-proxy
Remove old http-proxy, use the full version as the official http-proxy example
This commit is contained in:
commit
6272b56699
@ -14,7 +14,6 @@ members = [
|
|||||||
"form",
|
"form",
|
||||||
"hello-world",
|
"hello-world",
|
||||||
"http-proxy",
|
"http-proxy",
|
||||||
"http-full-proxy",
|
|
||||||
"json",
|
"json",
|
||||||
"json_error",
|
"json_error",
|
||||||
"jsonrpc",
|
"jsonrpc",
|
||||||
|
@ -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"
|
|
@ -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 <listen addr> <listen port> <forward addr> <forward port>
|
|
||||||
```
|
|
@ -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<Url>,
|
|
||||||
client: web::Data<Client>,
|
|
||||||
) -> 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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
@ -1,21 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "http-proxy"
|
name = "http-proxy"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>", "Rotem Yaari <vmalloc@gmail.com>"]
|
||||||
edition = "2018"
|
|
||||||
workspace = ".."
|
workspace = ".."
|
||||||
|
edition = "2018"
|
||||||
[[bin]]
|
|
||||||
name = "proxy"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "proxy-example-server"
|
|
||||||
path = "src/server.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-rt = "0.2"
|
actix-rt = "0.2"
|
||||||
actix-web = { version = "1.0.0", features=["ssl"] }
|
actix-web = { version = "1.0.0", features=["ssl"] }
|
||||||
|
clap = "2.32.0"
|
||||||
env_logger = "0.5"
|
futures = "0.1.25"
|
||||||
futures = "0.1"
|
failure = "0.1.3"
|
||||||
|
url = "1.7.1"
|
||||||
|
@ -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
|
To start:
|
||||||
cargo run --bin proxy
|
|
||||||
```
|
``` shell
|
||||||
|
cargo run <listen addr> <listen port> <forward addr> <forward port>
|
||||||
To start local backend server:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cargo run --bin proxy-example-server
|
|
||||||
```
|
```
|
||||||
|
@ -1,52 +1,102 @@
|
|||||||
use actix_web::client::Client;
|
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 futures::Future;
|
||||||
|
use std::net::ToSocketAddrs;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
/// Stream client request response and then send body to a server response
|
fn forward(
|
||||||
fn index(client: web::Data<Client>) -> impl Future<Item = HttpResponse, Error = Error> {
|
req: HttpRequest,
|
||||||
client
|
payload: web::Payload,
|
||||||
.get("http://127.0.0.1:8081/")
|
url: web::Data<Url>,
|
||||||
.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(
|
|
||||||
client: web::Data<Client>,
|
client: web::Data<Client>,
|
||||||
) -> impl Future<Item = HttpResponse, Error = impl Into<Error>> {
|
) -> impl Future<Item = HttpResponse, Error = Error> {
|
||||||
// send client request
|
let mut new_url = url.get_ref().clone();
|
||||||
client
|
new_url.set_path(req.uri().path());
|
||||||
.get("https://www.rust-lang.org/")
|
new_url.set_query(req.uri().query());
|
||||||
.send() // <- connect to host and send request
|
|
||||||
.map_err(Error::from) // <- convert SendRequestError to an Error
|
let forwarded_req = client
|
||||||
.and_then(|resp| {
|
.request_from(new_url.as_str(), req.head())
|
||||||
// <- we received client response
|
.no_decompress();
|
||||||
Ok(HttpResponse::Ok()
|
let forwarded_req = if let Some(addr) = req.head().peer_addr {
|
||||||
// read one chunk from client response and send this chunk to a server response
|
forwarded_req.header("x-forwarded-for", format!("{}", addr.ip()))
|
||||||
// .from_err() converts PayloadError to an Error
|
} else {
|
||||||
.streaming(resp))
|
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<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
std::env::set_var("RUST_LOG", "actix_server=info,actix_web=trace");
|
let matches = clap::App::new("HTTP Proxy")
|
||||||
env_logger::init();
|
.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()
|
App::new()
|
||||||
.data(Client::new())
|
.data(Client::new())
|
||||||
|
.data(forward_url.clone())
|
||||||
.wrap(middleware::Logger::default())
|
.wrap(middleware::Logger::default())
|
||||||
.service(web::resource("/streaming").to_async(streaming))
|
.default_service(web::route().to_async(forward))
|
||||||
.service(web::resource("/").to_async(index))
|
|
||||||
})
|
})
|
||||||
.bind("127.0.0.1:8080")?
|
.bind((listen_addr, listen_port))?
|
||||||
|
.system_exit()
|
||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
@ -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()
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user