1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-06-02 13:29:24 +00:00

use rcgen for tls key generation (#1989)

This commit is contained in:
Rob Ede 2021-02-13 17:16:36 +00:00 committed by GitHub
parent 3279070f9f
commit 7fa6333a0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 226 additions and 185 deletions

View file

@ -40,11 +40,17 @@ jobs:
- name: Cache Dependencies
uses: Swatinem/rust-cache@v1.0.1
- name: Install cargo-hack
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-hack
- name: check minimal
uses: actions-rs/cargo@v1
with:
command: check
args: --workspace --no-default-features --tests
command: hack
args: --clean-per-run check --workspace --no-default-features --tests
- name: check full
uses: actions-rs/cargo@v1

View file

@ -118,13 +118,13 @@ features = ["vendored"]
optional = true
[dev-dependencies]
actix = { version = "0.11.0-beta.2", default-features = false }
rand = "0.8"
env_logger = "0.8"
serde_derive = "1.0"
brotli2 = "0.3.2"
flate2 = "1.0.13"
criterion = "0.3"
env_logger = "0.8"
flate2 = "1.0.13"
rand = "0.8"
rcgen = "0.8"
serde_derive = "1.0"
[profile.release]
lto = true

View file

@ -95,6 +95,7 @@ actix-http-test = { version = "3.0.0-beta.2", features = ["openssl"] }
actix-tls = { version = "3.0.0-beta.2", features = ["openssl"] }
criterion = "0.3"
env_logger = "0.8"
rcgen = "0.8"
serde_derive = "1.0"
tls-openssl = { version = "0.10", package = "openssl" }
tls-rustls = { version = "0.19", package = "rustls" }

View file

@ -14,7 +14,11 @@ use actix_service::{fn_service, ServiceFactoryExt};
use bytes::{Bytes, BytesMut};
use futures_util::future::{err, ok, ready};
use futures_util::stream::{once, Stream, StreamExt};
use openssl::ssl::{AlpnError, SslAcceptor, SslFiletype, SslMethod};
use openssl::{
pkey::PKey,
ssl::{SslAcceptor, SslMethod},
x509::X509,
};
async fn load_body<S>(stream: S) -> Result<BytesMut, PayloadError>
where
@ -34,29 +38,26 @@ where
Ok(body)
}
fn ssl_acceptor() -> SslAcceptor {
// load ssl keys
fn tls_config() -> SslAcceptor {
let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap();
let cert_file = cert.serialize_pem().unwrap();
let key_file = cert.serialize_private_key_pem();
let cert = X509::from_pem(cert_file.as_bytes()).unwrap();
let key = PKey::private_key_from_pem(key_file.as_bytes()).unwrap();
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_certificate(&cert).unwrap();
builder.set_private_key(&key).unwrap();
builder.set_alpn_select_callback(|_, protos| {
const H2: &[u8] = b"\x02h2";
const H11: &[u8] = b"\x08http/1.1";
if protos.windows(3).any(|window| window == H2) {
Ok(b"h2")
} else if protos.windows(9).any(|window| window == H11) {
Ok(b"http/1.1")
} else {
Err(AlpnError::NOACK)
Err(openssl::ssl::AlpnError::NOACK)
}
});
builder
.set_alpn_protos(b"\x08http/1.1\x02h2")
.expect("Can not contrust SslAcceptor");
builder.set_alpn_protos(b"\x02h2").unwrap();
builder.build()
}
@ -66,7 +67,7 @@ async fn test_h2() -> io::Result<()> {
let srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, Error>(Response::Ok().finish()))
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -85,7 +86,7 @@ async fn test_h2_1() -> io::Result<()> {
assert_eq!(req.version(), Version::HTTP_2);
ok::<_, Error>(Response::Ok().finish())
})
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -104,7 +105,7 @@ async fn test_h2_body() -> io::Result<()> {
let body = load_body(req.take_payload()).await?;
Ok::<_, Error>(Response::Ok().body(body))
})
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -133,7 +134,7 @@ async fn test_h2_content_length() {
];
ok::<_, ()>(Response::new(statuses[indx]))
})
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -195,7 +196,7 @@ async fn test_h2_headers() {
}
ok::<_, ()>(builder.body(data.clone()))
})
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
}).await;
@ -234,7 +235,7 @@ async fn test_h2_body2() {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -252,7 +253,7 @@ async fn test_h2_head_empty() {
let mut srv = test_server(move || {
HttpService::build()
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -276,7 +277,7 @@ async fn test_h2_head_binary() {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -299,7 +300,7 @@ async fn test_h2_head_binary2() {
let srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -323,7 +324,7 @@ async fn test_h2_body_length() {
Response::Ok().body(body::SizedStream::new(STR.len() as u64, body)),
)
})
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -348,7 +349,7 @@ async fn test_h2_body_chunked_explicit() {
.streaming(body),
)
})
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -376,7 +377,7 @@ async fn test_h2_response_http_error_handling() {
.body(STR),
)
}))
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -394,7 +395,7 @@ async fn test_h2_service_error() {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| err::<Response, Error>(ErrorBadRequest("error")))
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;
@ -418,7 +419,7 @@ async fn test_h2_on_connect() {
assert!(req.extensions().contains::<isize>());
ok::<_, ()>(Response::Ok().finish())
})
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;

View file

@ -31,14 +31,19 @@ where
Ok(body)
}
fn ssl_acceptor() -> RustlsServerConfig {
// load ssl keys
fn tls_config() -> RustlsServerConfig {
let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap();
let cert_file = cert.serialize_pem().unwrap();
let key_file = cert.serialize_private_key_pem();
let mut config = RustlsServerConfig::new(NoClientAuth::new());
let cert_file = &mut BufReader::new(File::open("../tests/cert.pem").unwrap());
let key_file = &mut BufReader::new(File::open("../tests/key.pem").unwrap());
let cert_file = &mut BufReader::new(cert_file.as_bytes());
let key_file = &mut BufReader::new(key_file.as_bytes());
let cert_chain = certs(cert_file).unwrap();
let mut keys = pkcs8_private_keys(key_file).unwrap();
config.set_single_cert(cert_chain, keys.remove(0)).unwrap();
config
}
@ -47,7 +52,7 @@ async fn test_h1() -> io::Result<()> {
let srv = test_server(move || {
HttpService::build()
.h1(|_| future::ok::<_, Error>(Response::Ok().finish()))
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -61,7 +66,7 @@ async fn test_h2() -> io::Result<()> {
let srv = test_server(move || {
HttpService::build()
.h2(|_| future::ok::<_, Error>(Response::Ok().finish()))
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -79,7 +84,7 @@ async fn test_h1_1() -> io::Result<()> {
assert_eq!(req.version(), Version::HTTP_11);
future::ok::<_, Error>(Response::Ok().finish())
})
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -97,7 +102,7 @@ async fn test_h2_1() -> io::Result<()> {
assert_eq!(req.version(), Version::HTTP_2);
future::ok::<_, Error>(Response::Ok().finish())
})
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -115,7 +120,7 @@ async fn test_h2_body1() -> io::Result<()> {
let body = load_body(req.take_payload()).await?;
Ok::<_, Error>(Response::Ok().body(body))
})
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -143,7 +148,7 @@ async fn test_h2_content_length() {
];
future::ok::<_, ()>(Response::new(statuses[indx]))
})
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -203,7 +208,7 @@ async fn test_h2_headers() {
}
future::ok::<_, ()>(config.body(data.clone()))
})
.rustls(ssl_acceptor())
.rustls(tls_config())
}).await;
let response = srv.sget("/").send().await.unwrap();
@ -241,7 +246,7 @@ async fn test_h2_body2() {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -258,7 +263,7 @@ async fn test_h2_head_empty() {
let mut srv = test_server(move || {
HttpService::build()
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -284,7 +289,7 @@ async fn test_h2_head_binary() {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -309,7 +314,7 @@ async fn test_h2_head_binary2() {
let srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -335,7 +340,7 @@ async fn test_h2_body_length() {
Response::Ok().body(body::SizedStream::new(STR.len() as u64, body)),
)
})
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -359,7 +364,7 @@ async fn test_h2_body_chunked_explicit() {
.streaming(body),
)
})
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -388,7 +393,7 @@ async fn test_h2_response_http_error_handling() {
)
}))
}))
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -405,7 +410,7 @@ async fn test_h2_service_error() {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| err::<Response, Error>(error::ErrorBadRequest("error")))
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;
@ -422,7 +427,7 @@ async fn test_h1_service_error() {
let mut srv = test_server(move || {
HttpService::build()
.h1(|_| err::<Response, Error>(error::ErrorBadRequest("error")))
.rustls(ssl_acceptor())
.rustls(tls_config())
})
.await;

View file

@ -7,17 +7,23 @@ use actix_http_test::test_server;
use actix_service::{map_config, ServiceFactoryExt};
use actix_web::http::Version;
use actix_web::{dev::AppConfig, web, App, HttpResponse};
use openssl::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod, SslVerifyMode};
use openssl::{
pkey::PKey,
ssl::{SslAcceptor, SslConnector, SslMethod, SslVerifyMode},
x509::X509,
};
fn tls_config() -> SslAcceptor {
let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap();
let cert_file = cert.serialize_pem().unwrap();
let key_file = cert.serialize_private_key_pem();
let cert = X509::from_pem(cert_file.as_bytes()).unwrap();
let key = PKey::private_key_from_pem(key_file.as_bytes()).unwrap();
fn ssl_acceptor() -> SslAcceptor {
// 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_certificate(&cert).unwrap();
builder.set_private_key(&key).unwrap();
builder.set_alpn_select_callback(|_, protos| {
const H2: &[u8] = b"\x02h2";
if protos.windows(3).any(|window| window == H2) {
@ -27,6 +33,7 @@ fn ssl_acceptor() -> SslAcceptor {
}
});
builder.set_alpn_protos(b"\x02h2").unwrap();
builder.build()
}
@ -38,7 +45,7 @@ async fn test_connection_window_size() {
App::new().service(web::resource("/").route(web::to(HttpResponse::Ok))),
|_| AppConfig::default(),
))
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ())
})
.await;

View file

@ -11,17 +11,23 @@ use actix_service::{map_config, pipeline_factory, ServiceFactoryExt};
use actix_web::http::Version;
use actix_web::{dev::AppConfig, web, App, HttpResponse};
use futures_util::future::ok;
use openssl::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod, SslVerifyMode};
use openssl::{
pkey::PKey,
ssl::{SslAcceptor, SslConnector, SslMethod, SslVerifyMode},
x509::X509,
};
fn tls_config() -> SslAcceptor {
let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap();
let cert_file = cert.serialize_pem().unwrap();
let key_file = cert.serialize_private_key_pem();
let cert = X509::from_pem(cert_file.as_bytes()).unwrap();
let key = PKey::private_key_from_pem(key_file.as_bytes()).unwrap();
fn ssl_acceptor() -> SslAcceptor {
// 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_certificate(&cert).unwrap();
builder.set_private_key(&key).unwrap();
builder.set_alpn_select_callback(|_, protos| {
const H2: &[u8] = b"\x02h2";
if protos.windows(3).any(|window| window == H2) {
@ -31,6 +37,7 @@ fn ssl_acceptor() -> SslAcceptor {
}
});
builder.set_alpn_protos(b"\x02h2").unwrap();
builder.build()
}
@ -51,7 +58,7 @@ async fn test_connection_reuse_h2() {
App::new().service(web::resource("/").route(web::to(HttpResponse::Ok))),
|_| AppConfig::default(),
))
.openssl(ssl_acceptor())
.openssl(tls_config())
.map_err(|_| ()),
)
})

View file

@ -99,8 +99,10 @@ pub mod test;
pub(crate) mod types;
pub mod web;
#[cfg(feature = "cookies")]
pub use actix_http::cookie;
pub use actix_http::Response as HttpResponse;
pub use actix_http::{body, cookie, http, Error, HttpMessage, ResponseError, Result};
pub use actix_http::{body, http, Error, HttpMessage, ResponseError, Result};
pub use actix_rt as rt;
pub use actix_web_codegen::*;

View file

@ -123,18 +123,24 @@ impl<B: MessageBody + Unpin + 'static> MapServiceResponseBody for ServiceRespons
#[cfg(test)]
mod tests {
// easier to code when cookies feature is disabled
#![allow(unused_imports)]
use super::*;
use actix_service::IntoService;
use crate::dev::ServiceRequest;
use crate::http::StatusCode;
use crate::middleware::{Compress, Condition, Logger};
use crate::middleware::{self, Condition, Logger};
use crate::test::{call_service, init_service, TestRequest};
use crate::{web, App, HttpResponse};
#[actix_rt::test]
#[cfg(feature = "cookies")]
async fn test_scope_middleware() {
use crate::middleware::Compress;
let logger = Logger::default();
let compress = Compress::default();
@ -154,7 +160,10 @@ mod tests {
}
#[actix_rt::test]
#[cfg(feature = "cookies")]
async fn test_resource_scope_middleware() {
use crate::middleware::Compress;
let logger = Logger::default();
let compress = Compress::default();

View file

@ -429,12 +429,14 @@ mod tests {
}
#[test]
#[cfg(feature = "cookies")]
fn test_no_request_cookies() {
let req = TestRequest::default().to_http_request();
assert!(req.cookies().unwrap().is_empty());
}
#[test]
#[cfg(feature = "cookies")]
fn test_request_cookies() {
let req = TestRequest::default()
.append_header((header::COOKIE, "cookie1=value1"))

View file

@ -6,10 +6,12 @@ use std::sync::mpsc;
use std::{fmt, net, thread, time};
use actix_codec::{AsyncRead, AsyncWrite, Framed};
#[cfg(feature = "cookies")]
use actix_http::cookie::Cookie;
use actix_http::http::header::{ContentType, IntoHeaderPair};
use actix_http::http::{Method, StatusCode, Uri, Version};
use actix_http::test::TestRequest as HttpTestRequest;
use actix_http::{cookie::Cookie, ws, Extensions, HttpService, Request};
use actix_http::{ws, Extensions, HttpService, Request};
use actix_router::{Path, ResourceDef, Url};
use actix_rt::{time::sleep, System};
use actix_service::{map_config, IntoService, IntoServiceFactory, Service, ServiceFactory};
@ -438,6 +440,7 @@ impl TestRequest {
}
/// Set cookie for this request.
#[cfg(feature = "cookies")]
pub fn cookie(mut self, cookie: Cookie<'_>) -> Self {
self.req.cookie(cookie);
self

View file

@ -1,19 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDEDCCAfgCCQCQdmIZc/Ib/jANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQGEwJ1
czELMAkGA1UECAwCY2ExCzAJBgNVBAcMAnNmMSEwHwYJKoZIhvcNAQkBFhJmYWZo
cmQ5MUBnbWFpbC5jb20wHhcNMTkxMTE5MTEwNjU1WhcNMjkxMTE2MTEwNjU1WjBK
MQswCQYDVQQGEwJ1czELMAkGA1UECAwCY2ExCzAJBgNVBAcMAnNmMSEwHwYJKoZI
hvcNAQkBFhJmYWZocmQ5MUBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQDcnaz12CKzUL7248V7Axhms/O9UQXfAdw0yolEfC3P5jADa/1C
+kLWKjAc2coqDSbGsrsR6KiH2g06Kunx+tSGqUO+Sct7HEehmxndiSwx/hfMWezy
XRe/olcHFTeCk/Tllz4xGEplhPua6GLhJygLOhAMiV8cwCYrgyPqsDduExLDFCqc
K2xntIPreumXpiE3QY4+MWyteiJko4IWDFf/UwwsdCY5MlFfw1F/Uv9vz7FfOfvu
GccHd/ex8cOwotUqd6emZb+0bVE24Sv8U+yLnHIVx/tOkxgMAnJEpAnf2G3Wp3zU
b2GJosbmfGaf+xTfnGGhTLLL7kCtva+NvZr5AgMBAAEwDQYJKoZIhvcNAQELBQAD
ggEBANftoL8zDGrjCwWvct8kOOqset2ukK8vjIGwfm88CKsy0IfSochNz2qeIu9R
ZuO7c0pfjmRkir9ZQdq9vXgG3ccL9UstFsferPH9W3YJ83kgXg3fa0EmCiN/0hwz
6Ij1ZBiN1j3+d6+PJPgyYFNu2nGwox5mJ9+aRAGe0/9c63PEOY8P2TI4HsiPmYSl
fFR8k/03vr6e+rTKW85BgctjvYKe/TnFxeCQ7dZ+na7vlEtch4tNmy6O/vEk2kCt
5jW0DUxhmRsv2wGmfFRI0+LotHjoXQQZi6nN5aGL3odaGF3gYwIVlZNd3AdkwDQz
BzG0ZwXuDDV9bSs3MfWEWcy4xuU=
-----END CERTIFICATE-----

View file

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDcnaz12CKzUL72
48V7Axhms/O9UQXfAdw0yolEfC3P5jADa/1C+kLWKjAc2coqDSbGsrsR6KiH2g06
Kunx+tSGqUO+Sct7HEehmxndiSwx/hfMWezyXRe/olcHFTeCk/Tllz4xGEplhPua
6GLhJygLOhAMiV8cwCYrgyPqsDduExLDFCqcK2xntIPreumXpiE3QY4+MWyteiJk
o4IWDFf/UwwsdCY5MlFfw1F/Uv9vz7FfOfvuGccHd/ex8cOwotUqd6emZb+0bVE2
4Sv8U+yLnHIVx/tOkxgMAnJEpAnf2G3Wp3zUb2GJosbmfGaf+xTfnGGhTLLL7kCt
va+NvZr5AgMBAAECggEBAKoU0UwzVgVCQgca8Jt2dnBvWYDhnxIfYAI/BvaKedMm
1ms87OKfB7oOiksjyI0E2JklH72dzZf2jm4CuZt5UjGC+xwPzlTaJ4s6hQVbBHyC
NRyxU1BCXtW5tThbrhD4OjxqjmLRJEIB9OunLtwAEQoeuFLB8Va7+HFhR+Zd9k3f
7aVA93pC5A50NRbZlke4miJ3Q8n7ZF0+UmxkBfm3fbqLk7aMWkoEKwLLTadjRlu1
bBp0YDStX66I/p1kujqBOdh6VpPvxFOa1sV9pq0jeiGc9YfSkzRSKzIn8GoyviFB
fHeszQdNlcnrSDSNnMABAw+ZpxUO7SCaftjwejEmKZUCgYEA+TY43VpmV95eY7eo
WKwGepiHE0fwQLuKGELmZdZI80tFi73oZMuiB5WzwmkaKGcJmm7KGE9KEvHQCo9j
xvmktBR0VEZH8pmVfun+4h6+0H7m/NKMBBeOyv/IK8jBgHjkkB6e6nmeR7CqTxCw
tf9tbajl1QN8gNzXZSjBDT/lanMCgYEA4qANOKOSiEARtgwyXQeeSJcM2uPv6zF3
ffM7vjSedtuEOHUSVeyBP/W8KDt7zyPppO/WNbURHS+HV0maS9yyj6zpVS2HGmbs
3fetswsQ+zYVdokW89x4oc2z4XOGHd1LcSlyhRwPt0u2g1E9L0irwTQLWU0npFmG
PRf7sN9+LeMCgYAGkDUDL2ROoB6gRa/7Vdx90hKMoXJkYgwLA4gJ2pDlR3A3c/Lw
5KQJyxmG3zm/IqeQF6be6QesZA30mT4peV2rGHbP2WH/s6fKReNelSy1VQJEWk8x
tGUgV4gwDwN5nLV4TjYlOrq+bJqvpmLhCC8bmj0jVQosYqSRl3cuICasnQKBgGlV
VO/Xb1su1EyWPK5qxRIeSxZOTYw2sMB01nbgxCqge0M2fvA6/hQ5ZlwY0cIEgits
YlcSMsMq/TAAANxz1vbaupUhlSMbZcsBvNV0Nk9c4vr2Wxm7hsJF9u66IEMvQUp2
pkjiMxfR9CHzF4orr9EcHI5EQ0Grbq5kwFKEfoRbAoGAcWoFPILeJOlp2yW/Ds3E
g2fQdI9BAamtEZEaslJmZMmsDTg5ACPcDkOSFEQIaJ7wLPXeZy74FVk/NrY5F8Gz
bjX9OD/xzwp852yW5L9r62vYJakAlXef5jI6CFdYKDDCcarU0S7W5k6kq9n+wrBR
i1NklYmUAMr2q59uJA5zsic=
-----END PRIVATE KEY-----

View file

@ -73,15 +73,22 @@ async fn test_start() {
#[cfg(feature = "openssl")]
fn ssl_acceptor() -> std::io::Result<SslAcceptorBuilder> {
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
// load ssl keys
use openssl::{
pkey::PKey,
ssl::{SslAcceptor, SslMethod},
x509::X509,
};
let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap();
let cert_file = cert.serialize_pem().unwrap();
let key_file = cert.serialize_private_key_pem();
let cert = X509::from_pem(cert_file.as_bytes()).unwrap();
let key = PKey::private_key_from_pem(key_file.as_bytes()).unwrap();
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_certificate(&cert).unwrap();
builder.set_private_key(&key).unwrap();
Ok(builder)
}

View file

@ -21,6 +21,11 @@ use flate2::{
Compression,
};
use futures_util::ready;
use openssl::{
pkey::PKey,
ssl::{SslAcceptor, SslMethod},
x509::X509,
};
use rand::{distributions::Alphanumeric, Rng};
use actix_web::dev::BodyEncoding;
@ -49,6 +54,30 @@ 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";
fn openssl_config() -> SslAcceptor {
let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap();
let cert_file = cert.serialize_pem().unwrap();
let key_file = cert.serialize_private_key_pem();
let cert = X509::from_pem(cert_file.as_bytes()).unwrap();
let key = PKey::private_key_from_pem(key_file.as_bytes()).unwrap();
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_certificate(&cert).unwrap();
builder.set_private_key(&key).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").unwrap();
builder.build()
}
struct TestBody {
data: Bytes,
chunk_size: usize,
@ -700,18 +729,8 @@ async fn test_brotli_encoding_large() {
#[cfg(feature = "openssl")]
#[actix_rt::test]
async fn test_brotli_encoding_large_openssl() {
// load ssl keys
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
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();
let data = STR.repeat(10);
let srv = test::start_with(test::config().openssl(builder.build()), move || {
let srv = test::start_with(test::config().openssl(openssl_config()), move || {
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
HttpResponse::Ok()
.encoding(actix_web::http::ContentEncoding::Identity)
@ -739,53 +758,72 @@ async fn test_brotli_encoding_large_openssl() {
}
#[cfg(all(feature = "rustls", feature = "openssl"))]
#[actix_rt::test]
async fn test_reading_deflate_encoding_large_random_rustls() {
use rustls::internal::pemfile::{certs, pkcs8_private_keys};
use rustls::{NoClientAuth, ServerConfig};
use std::fs::File;
mod plus_rustls {
use std::io::BufReader;
let data = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(160_000)
.map(char::from)
.collect::<String>();
use rustls::{
internal::pemfile::{certs, pkcs8_private_keys},
NoClientAuth, ServerConfig as RustlsServerConfig,
};
// load ssl keys
let mut config = ServerConfig::new(NoClientAuth::new());
let cert_file = &mut BufReader::new(File::open("tests/cert.pem").unwrap());
let key_file = &mut BufReader::new(File::open("tests/key.pem").unwrap());
let cert_chain = certs(cert_file).unwrap();
let mut keys = pkcs8_private_keys(key_file).unwrap();
config.set_single_cert(cert_chain, keys.remove(0)).unwrap();
use super::*;
let srv = test::start_with(test::config().rustls(config), || {
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
HttpResponse::Ok()
.encoding(actix_web::http::ContentEncoding::Identity)
.body(bytes)
})))
});
fn rustls_config() -> RustlsServerConfig {
let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap();
let cert_file = cert.serialize_pem().unwrap();
let key_file = cert.serialize_private_key_pem();
// encode data
let mut e = ZlibEncoder::new(Vec::new(), Compression::default());
e.write_all(data.as_ref()).unwrap();
let enc = e.finish().unwrap();
let mut config = RustlsServerConfig::new(NoClientAuth::new());
let cert_file = &mut BufReader::new(cert_file.as_bytes());
let key_file = &mut BufReader::new(key_file.as_bytes());
// client request
let req = srv
.post("/")
.insert_header((actix_web::http::header::CONTENT_ENCODING, "deflate"))
.send_stream(TestBody::new(Bytes::from(enc), 1024));
let cert_chain = certs(cert_file).unwrap();
let mut keys = pkcs8_private_keys(key_file).unwrap();
config.set_single_cert(cert_chain, keys.remove(0)).unwrap();
let mut response = req.await.unwrap();
assert!(response.status().is_success());
config
}
// read response
let bytes = response.body().await.unwrap();
assert_eq!(bytes.len(), data.len());
assert_eq!(bytes, Bytes::from(data));
#[actix_rt::test]
async fn test_reading_deflate_encoding_large_random_rustls() {
use rustls::internal::pemfile::{certs, pkcs8_private_keys};
use rustls::{NoClientAuth, ServerConfig};
use std::fs::File;
use std::io::BufReader;
let data = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(160_000)
.map(char::from)
.collect::<String>();
let srv = test::start_with(test::config().rustls(rustls_config()), || {
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
HttpResponse::Ok()
.encoding(actix_web::http::ContentEncoding::Identity)
.body(bytes)
})))
});
// encode data
let mut e = ZlibEncoder::new(Vec::new(), Compression::default());
e.write_all(data.as_ref()).unwrap();
let enc = e.finish().unwrap();
// client request
let req = srv
.post("/")
.insert_header((actix_web::http::header::CONTENT_ENCODING, "deflate"))
.send_stream(TestBody::new(Bytes::from(enc), 1024));
let mut response = req.await.unwrap();
assert!(response.status().is_success());
// read response
let bytes = response.body().await.unwrap();
assert_eq!(bytes.len(), data.len());
assert_eq!(bytes, Bytes::from(data));
}
}
#[actix_rt::test]