From 607defac680be4aeae379cb832d9231c5a157f2e Mon Sep 17 00:00:00 2001 From: Marat Safin Date: Sun, 28 Jul 2019 11:33:28 +0300 Subject: [PATCH] awc rustls test --- awc/Cargo.toml | 5 ++ awc/tests/test_client.rs | 81 +--------------------------- awc/tests/test_rustls_client.rs | 95 +++++++++++++++++++++++++++++++++ awc/tests/test_ssl_client.rs | 86 +++++++++++++++++++++++++++++ 4 files changed, 187 insertions(+), 80 deletions(-) create mode 100644 awc/tests/test_rustls_client.rs create mode 100644 awc/tests/test_ssl_client.rs diff --git a/awc/Cargo.toml b/awc/Cargo.toml index a7540d7b1..36b4792d3 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -41,6 +41,10 @@ flate2-zlib = ["actix-http/flate2-zlib"] # rust backend for flate2 crate flate2-rust = ["actix-http/flate2-rust"] +# only for tests +dev-ssl = ["ssl", "actix-http-test/ssl", "actix-server/ssl", "actix-http/ssl"] +dev-rustls = ["rust-tls", "actix-http-test/rust-tls", "actix-server/rust-tls", "actix-http/rust-tls"] + [dependencies] actix-codec = "0.1.2" actix-service = "0.4.1" @@ -71,3 +75,4 @@ flate2 = "1.0.2" env_logger = "0.6" rand = "0.7" tokio-tcp = "0.1" +webpki = "0.19" diff --git a/awc/tests/test_client.rs b/awc/tests/test_client.rs index 698481e37..cb38c7315 100644 --- a/awc/tests/test_client.rs +++ b/awc/tests/test_client.rs @@ -12,11 +12,10 @@ use flate2::Compression; use futures::Future; use rand::Rng; -use actix_codec::{AsyncRead, AsyncWrite}; use actix_http::HttpService; use actix_http_test::TestServer; use actix_service::{service_fn, NewService}; -use actix_web::http::{Cookie, Version}; +use actix_web::http::Cookie; use actix_web::middleware::{BodyEncoding, Compress}; use actix_web::{http::header, web, App, Error, HttpMessage, HttpRequest, HttpResponse}; use awc::error::SendRequestError; @@ -43,30 +42,6 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ Hello World Hello World Hello World Hello World Hello World \ Hello World Hello World Hello World Hello World Hello World"; -#[cfg(feature = "ssl")] -fn ssl_acceptor( -) -> std::io::Result> { - use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; - // load ssl keys - let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - builder - .set_private_key_file("../tests/key.pem", SslFiletype::PEM) - .unwrap(); - builder - .set_certificate_chain_file("../tests/cert.pem") - .unwrap(); - builder.set_alpn_select_callback(|_, protos| { - const H2: &[u8] = b"\x02h2"; - if protos.windows(3).any(|window| window == H2) { - Ok(b"h2") - } else { - Err(openssl::ssl::AlpnError::NOACK) - } - }); - builder.set_alpn_protos(b"\x02h2")?; - Ok(actix_server::ssl::OpensslAcceptor::new(builder.build())) -} - #[test] fn test_simple() { let mut srv = @@ -207,60 +182,6 @@ fn test_connection_reuse() { assert_eq!(num.load(Ordering::Relaxed), 1); } -#[cfg(feature = "ssl")] -#[test] -fn test_connection_reuse_h2() { - let openssl = ssl_acceptor().unwrap(); - let num = Arc::new(AtomicUsize::new(0)); - let num2 = num.clone(); - - let mut srv = TestServer::new(move || { - let num2 = num2.clone(); - service_fn(move |io| { - num2.fetch_add(1, Ordering::Relaxed); - Ok(io) - }) - .and_then( - openssl - .clone() - .map_err(|e| println!("Openssl error: {}", e)), - ) - .and_then( - HttpService::build() - .h2(App::new() - .service(web::resource("/").route(web::to(|| HttpResponse::Ok())))) - .map_err(|_| ()), - ) - }); - - // disable ssl verification - use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode}; - - let mut builder = SslConnector::builder(SslMethod::tls()).unwrap(); - builder.set_verify(SslVerifyMode::NONE); - let _ = builder - .set_alpn_protos(b"\x02h2\x08http/1.1") - .map_err(|e| log::error!("Can not set alpn protocol: {:?}", e)); - - let client = awc::Client::build() - .connector(awc::Connector::new().ssl(builder.build()).finish()) - .finish(); - - // req 1 - let request = client.get(srv.surl("/")).send(); - let response = srv.block_on(request).unwrap(); - assert!(response.status().is_success()); - - // req 2 - let req = client.post(srv.surl("/")); - let response = srv.block_on_fn(move || req.send()).unwrap(); - assert!(response.status().is_success()); - assert_eq!(response.version(), Version::HTTP_2); - - // one connection - assert_eq!(num.load(Ordering::Relaxed), 1); -} - #[test] fn test_connection_force_close() { let num = Arc::new(AtomicUsize::new(0)); diff --git a/awc/tests/test_rustls_client.rs b/awc/tests/test_rustls_client.rs new file mode 100644 index 000000000..eda5e85c8 --- /dev/null +++ b/awc/tests/test_rustls_client.rs @@ -0,0 +1,95 @@ +#![cfg(feature = "rustls")] +use rustls::{internal::pemfile, NoClientAuth, ClientConfig}; + +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::fs::File; +use std::io::{BufReader, Result}; + +use actix_server::ssl::RustlsAcceptor; +use actix_codec::{AsyncRead, AsyncWrite}; +use actix_http::HttpService; +use actix_http_test::TestServer; +use actix_service::{service_fn, NewService}; +use actix_web::http::Version; +use actix_web::{web, App, HttpResponse}; + +fn ssl_acceptor() -> Result> { + use rustls::ServerConfig; + // load ssl keys + let mut key_file = BufReader::new(File::open("../tests/key.pem").expect("key file")); + let mut cert_file = BufReader::new(File::open("../tests/cert.pem").expect("cert file")); + let key_der = pemfile::pkcs8_private_keys(&mut key_file).expect("key der").pop().expect("key not found"); + let cert_chain = pemfile::certs(&mut cert_file).expect("cert chain"); + let mut builder = ServerConfig::new(Arc::new(NoClientAuth)); + builder.set_single_cert(cert_chain, key_der).expect("set single cert"); + let protos = vec![b"h2".to_vec()]; + builder.set_protocols(&protos); + Ok(RustlsAcceptor::new(builder)) +} + +mod danger { + pub struct NoCertificateVerification {} + + impl rustls::ServerCertVerifier for NoCertificateVerification { + fn verify_server_cert(&self, + _roots: &rustls::RootCertStore, + _presented_certs: &[rustls::Certificate], + _dns_name: webpki::DNSNameRef<'_>, + _ocsp: &[u8]) -> Result { + Ok(rustls::ServerCertVerified::assertion()) + } + } +} + +#[test] +fn test_connection_reuse_h2() { + let rustls = ssl_acceptor().unwrap(); + let num = Arc::new(AtomicUsize::new(0)); + let num2 = num.clone(); + + let mut srv = TestServer::new(move || { + let num2 = num2.clone(); + service_fn(move |io| { + num2.fetch_add(1, Ordering::Relaxed); + Ok(io) + }) + .and_then( + rustls + .clone() + .map_err(|e| println!("Rustls error: {}", e)), + ) + .and_then( + HttpService::build() + .h2(App::new() + .service(web::resource("/").route(web::to(|| HttpResponse::Ok())))) + .map_err(|_| ()), + ) + }); + + // disable ssl verification + // use rustls::ssl::{SslConnector, SslMethod, SslVerifyMode}; + + let mut config = ClientConfig::new(); + let protos = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; + config.set_protocols(&protos); + config.dangerous().set_certificate_verifier(Arc::new(danger::NoCertificateVerification{})); + + let client = awc::Client::build() + .connector(awc::Connector::new().ssl(Arc::new(config)).finish()) + .finish(); + + // req 1 + let request = client.get(srv.surl("/")).send(); + let response = srv.block_on(request).unwrap(); + assert!(response.status().is_success()); + + // req 2 + let req = client.post(srv.surl("/")); + let response = srv.block_on_fn(move || req.send()).unwrap(); + assert!(response.status().is_success()); + assert_eq!(response.version(), Version::HTTP_2); + + // one connection + assert_eq!(num.load(Ordering::Relaxed), 1); +} diff --git a/awc/tests/test_ssl_client.rs b/awc/tests/test_ssl_client.rs new file mode 100644 index 000000000..68cf4c7b9 --- /dev/null +++ b/awc/tests/test_ssl_client.rs @@ -0,0 +1,86 @@ +#![cfg(feature = "ssl")] +use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod, SslConnector, SslVerifyMode}; +use actix_server::ssl::OpensslAcceptor; + +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::io::Result; + +use actix_codec::{AsyncRead, AsyncWrite}; +use actix_http::HttpService; +use actix_http_test::TestServer; +use actix_service::{service_fn, NewService}; +use actix_web::http::Version; +use actix_web::{web, App, HttpResponse}; + +fn ssl_acceptor() -> Result> { + // load ssl keys + let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + builder + .set_private_key_file("../tests/key.pem", SslFiletype::PEM) + .unwrap(); + builder + .set_certificate_chain_file("../tests/cert.pem") + .unwrap(); + builder.set_alpn_select_callback(|_, protos| { + const H2: &[u8] = b"\x02h2"; + if protos.windows(3).any(|window| window == H2) { + Ok(b"h2") + } else { + Err(openssl::ssl::AlpnError::NOACK) + } + }); + builder.set_alpn_protos(b"\x02h2")?; + Ok(actix_server::ssl::OpensslAcceptor::new(builder.build())) +} + +#[test] +fn test_connection_reuse_h2() { + let openssl = ssl_acceptor().unwrap(); + let num = Arc::new(AtomicUsize::new(0)); + let num2 = num.clone(); + + let mut srv = TestServer::new(move || { + let num2 = num2.clone(); + service_fn(move |io| { + num2.fetch_add(1, Ordering::Relaxed); + Ok(io) + }) + .and_then( + openssl + .clone() + .map_err(|e| println!("Openssl error: {}", e)), + ) + .and_then( + HttpService::build() + .h2(App::new() + .service(web::resource("/").route(web::to(|| HttpResponse::Ok())))) + .map_err(|_| ()), + ) + }); + + // disable ssl verification + let mut builder = SslConnector::builder(SslMethod::tls()).unwrap(); + builder.set_verify(SslVerifyMode::NONE); + let _ = builder + .set_alpn_protos(b"\x02h2\x08http/1.1") + .map_err(|e| log::error!("Can not set alpn protocol: {:?}", e)); + + let client = awc::Client::build() + .connector(awc::Connector::new().ssl(builder.build()).finish()) + .finish(); + + // req 1 + let request = client.get(srv.surl("/")).send(); + let response = srv.block_on(request).unwrap(); + assert!(response.status().is_success()); + + // req 2 + let req = client.post(srv.surl("/")); + let response = srv.block_on_fn(move || req.send()).unwrap(); + assert!(response.status().is_success()); + assert_eq!(response.version(), Version::HTTP_2); + + // one connection + assert_eq!(num.load(Ordering::Relaxed), 1); +}