1
0
mirror of https://github.com/actix/examples synced 2025-06-28 18:00:37 +02:00

improve awc_http example

This commit is contained in:
Rob Ede
2022-02-02 01:17:10 +00:00
parent 3cd842fbd5
commit 9aef457a78
4 changed files with 124 additions and 39 deletions

View File

@ -5,6 +5,11 @@ authors = ["dowwie <dkcdkg@gmail.com>"]
edition = "2021"
[dependencies]
actix-web = "4.0.0-beta.21"
awc = {version = "3.0.0-beta.19", features = ["openssl"]}
openssl = "0.10.38"
actix-web = "4.0.0-rc.1"
awc = { version = "3.0.0-beta.19", features = ["rustls"] }
env_logger = "0.9"
log = "0.4"
mime = "0.3"
rustls = "0.20"
webpki-roots = "0.22"

View File

@ -1,9 +1,5 @@
The goal of this example is to show you how to use the actix-web client (awc)
for https related communication. As of actix-web 2.0.0, one must be very
careful about setting up https communication. **You could use the default
awc api without configuring ssl but performance will be severely diminished**.
The goal of this example is to show you how to use the `awc` for secure HTTPS communication using Rustls.
This example downloads a 1MB image from wikipedia.
It uses best practices for efficient client set up and demonstrates how to increase the default payload limit.
To run:
> curl http://localhost:3000 -o image.jpg
This example downloads a 10MB image from Wikipedia when hitting a server route. `cargo run` this example and go to <http://localhost:8080/> in your browser.

View File

@ -1,40 +1,83 @@
use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer};
use awc::{Client, Connector};
use openssl::ssl::{SslConnector, SslMethod};
use std::{sync::Arc, time::Instant};
async fn index(_req: HttpRequest) -> HttpResponse {
let builder = SslConnector::builder(SslMethod::tls()).unwrap();
use actix_web::{get, middleware, web::Data, App, HttpResponse, HttpServer};
use awc::{http::header, Client, Connector};
use rustls::{ClientConfig, OwnedTrustAnchor, RootCertStore};
let client = Client::builder()
.connector(Connector::new().openssl(builder.build()))
.finish();
const MAP_URL: &str =
"https://upload.wikimedia.org/wikipedia/commons/f/ff/Pizigani_1367_Chart_10MB.jpg";
let now = std::time::Instant::now();
let payload =
client
.get("https://upload.wikimedia.org/wikipedia/commons/b/b9/Pizigani_1367_Chart_1MB.jpg")
.send()
.await
.unwrap()
#[get("/")]
async fn fetch_image(client: Data<Client>) -> HttpResponse {
let start = Instant::now();
let mut res = client.get(MAP_URL).send().await.unwrap();
if !res.status().is_success() {
log::error!("Wikipedia did not return expected image");
return HttpResponse::InternalServerError().finish();
}
let payload = res
.body()
.limit(20_000_000) // sets max allowable payload size
// expected image is larger than default body limit
.limit(20_000_000) // 20MB
.await
.unwrap();
println!(
"awc time elapsed while reading bytes into memory: {} ms",
now.elapsed().as_millis()
log::info!(
"it took {}ms to download image to memory",
start.elapsed().as_millis()
);
HttpResponse::Ok().content_type("image/jpeg").body(payload)
HttpResponse::Ok()
.content_type(mime::IMAGE_JPEG)
.body(payload)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let port = 3000;
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
HttpServer::new(|| App::new().service(web::resource("/").to(index)))
.bind(("0.0.0.0", port))?
.run()
.await
let client_tls_config = Arc::new(rustls_config());
log::info!("starting HTTP serer at http://localhost:8080");
HttpServer::new(move || {
// create client _inside_ `HttpServer::new` closure to have one per worker thread
let client = Client::builder()
// Wikipedia requires a User-Agent header to make requests
.add_default_header((header::USER_AGENT, "awc-example/1.0"))
// a "connector" wraps the stream into an encrypted connection
.connector(Connector::new().rustls(Arc::clone(&client_tls_config)))
.finish();
App::new()
.wrap(middleware::Logger::default())
.app_data(Data::new(client))
.service(fetch_image)
})
.bind(("127.0.0.1", 8080))?
.workers(2)
.run()
.await
}
/// Create simple rustls client config from root certificates.
fn rustls_config() -> ClientConfig {
let mut root_store = RootCertStore::empty();
root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(
|ta| {
OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
},
));
rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth()
}