mirror of
https://github.com/actix/actix-web.git
synced 2024-11-26 03:21:08 +00:00
add rustls support for actix-http and awc (#998)
* add rustls support for actix-http and awc * fix features conflict * remove unnecessary duplication * test server with rust-tls * fix * test rustls * awc rustls test * format * tests * fix dependencies * fixes and add changes * remove test-server and Cargo.toml dev-dependencies changes * cargo fmt
This commit is contained in:
parent
0d9ea41047
commit
cb19ebfe0c
21 changed files with 1317 additions and 674 deletions
|
@ -105,9 +105,9 @@ openssl = { version="0.10", optional = true }
|
||||||
rustls = { version = "0.15", optional = true }
|
rustls = { version = "0.15", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix = { version = "0.8.3" }
|
actix = "0.8.3"
|
||||||
actix-http = { version = "0.2.5", features=["ssl", "brotli", "flate2-zlib"] }
|
actix-connect = "0.2.2"
|
||||||
actix-http-test = { version = "0.2.4", features=["ssl"] }
|
actix-http-test = "0.2.4"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
env_logger = "0.6"
|
env_logger = "0.6"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
* Add `Clone` impl for `HeaderMap`
|
* Add `Clone` impl for `HeaderMap`
|
||||||
|
* Add `rustls` support
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "actix-http"
|
name = "actix-http"
|
||||||
version = "0.2.7"
|
version = "0.2.8"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix http primitives"
|
description = "Actix http primitives"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -27,6 +27,7 @@ default = []
|
||||||
|
|
||||||
# openssl
|
# openssl
|
||||||
ssl = ["openssl", "actix-connect/ssl"]
|
ssl = ["openssl", "actix-connect/ssl"]
|
||||||
|
rust-tls = ["rustls", "webpki-roots", "actix-connect/rust-tls"]
|
||||||
|
|
||||||
# brotli encoding, requires c compiler
|
# brotli encoding, requires c compiler
|
||||||
brotli = ["brotli2"]
|
brotli = ["brotli2"]
|
||||||
|
@ -46,7 +47,7 @@ secure-cookies = ["ring"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-service = "0.4.1"
|
actix-service = "0.4.1"
|
||||||
actix-codec = "0.1.2"
|
actix-codec = "0.1.2"
|
||||||
actix-connect = "0.2.1"
|
actix-connect = "0.2.2"
|
||||||
actix-utils = "0.4.4"
|
actix-utils = "0.4.4"
|
||||||
actix-server-config = "0.1.2"
|
actix-server-config = "0.1.2"
|
||||||
actix-threadpool = "0.1.1"
|
actix-threadpool = "0.1.1"
|
||||||
|
@ -93,6 +94,8 @@ flate2 = { version="1.0.7", optional = true, default-features = false }
|
||||||
# optional deps
|
# optional deps
|
||||||
failure = { version = "0.1.5", optional = true }
|
failure = { version = "0.1.5", optional = true }
|
||||||
openssl = { version="0.10", optional = true }
|
openssl = { version="0.10", optional = true }
|
||||||
|
rustls = { version = "0.15.2", optional = true }
|
||||||
|
webpki-roots = { version = "0.16", optional = true }
|
||||||
chrono = "0.4.6"
|
chrono = "0.4.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -17,9 +17,21 @@ use super::pool::{ConnectionPool, Protocol};
|
||||||
use super::Connect;
|
use super::Connect;
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(feature = "ssl")]
|
||||||
use openssl::ssl::SslConnector;
|
use openssl::ssl::SslConnector as OpensslConnector;
|
||||||
|
|
||||||
#[cfg(not(feature = "ssl"))]
|
#[cfg(feature = "rust-tls")]
|
||||||
|
use rustls::ClientConfig;
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "ssl", feature = "rust-tls"))]
|
||||||
|
enum SslConnector {
|
||||||
|
#[cfg(feature = "ssl")]
|
||||||
|
Openssl(OpensslConnector),
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
Rustls(Arc<ClientConfig>),
|
||||||
|
}
|
||||||
|
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]
|
||||||
type SslConnector = ();
|
type SslConnector = ();
|
||||||
|
|
||||||
/// Manages http client network connectivity
|
/// Manages http client network connectivity
|
||||||
|
@ -46,6 +58,9 @@ pub struct Connector<T, U> {
|
||||||
_t: PhantomData<U>,
|
_t: PhantomData<U>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait Io: AsyncRead + AsyncWrite {}
|
||||||
|
impl<T: AsyncRead + AsyncWrite> Io for T {}
|
||||||
|
|
||||||
impl Connector<(), ()> {
|
impl Connector<(), ()> {
|
||||||
#[allow(clippy::new_ret_no_self)]
|
#[allow(clippy::new_ret_no_self)]
|
||||||
pub fn new() -> Connector<
|
pub fn new() -> Connector<
|
||||||
|
@ -61,13 +76,23 @@ impl Connector<(), ()> {
|
||||||
{
|
{
|
||||||
use openssl::ssl::SslMethod;
|
use openssl::ssl::SslMethod;
|
||||||
|
|
||||||
let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap();
|
let mut ssl = OpensslConnector::builder(SslMethod::tls()).unwrap();
|
||||||
let _ = ssl
|
let _ = ssl
|
||||||
.set_alpn_protos(b"\x02h2\x08http/1.1")
|
.set_alpn_protos(b"\x02h2\x08http/1.1")
|
||||||
.map_err(|e| error!("Can not set alpn protocol: {:?}", e));
|
.map_err(|e| error!("Can not set alpn protocol: {:?}", e));
|
||||||
ssl.build()
|
SslConnector::Openssl(ssl.build())
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "ssl"))]
|
#[cfg(all(not(feature = "ssl"), feature = "rust-tls"))]
|
||||||
|
{
|
||||||
|
let protos = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
|
||||||
|
let mut config = ClientConfig::new();
|
||||||
|
config.set_protocols(&protos);
|
||||||
|
config
|
||||||
|
.root_store
|
||||||
|
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||||
|
SslConnector::Rustls(Arc::new(config))
|
||||||
|
}
|
||||||
|
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -127,8 +152,14 @@ where
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(feature = "ssl")]
|
||||||
/// Use custom `SslConnector` instance.
|
/// Use custom `SslConnector` instance.
|
||||||
pub fn ssl(mut self, connector: SslConnector) -> Self {
|
pub fn ssl(mut self, connector: OpensslConnector) -> Self {
|
||||||
self.ssl = connector;
|
self.ssl = SslConnector::Openssl(connector);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
pub fn rustls(mut self, connector: Arc<ClientConfig>) -> Self {
|
||||||
|
self.ssl = SslConnector::Rustls(connector);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +213,7 @@ where
|
||||||
self,
|
self,
|
||||||
) -> impl Service<Request = Connect, Response = impl Connection, Error = ConnectError>
|
) -> impl Service<Request = Connect, Response = impl Connection, Error = ConnectError>
|
||||||
+ Clone {
|
+ Clone {
|
||||||
#[cfg(not(feature = "ssl"))]
|
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]
|
||||||
{
|
{
|
||||||
let connector = TimeoutService::new(
|
let connector = TimeoutService::new(
|
||||||
self.timeout,
|
self.timeout,
|
||||||
|
@ -207,10 +238,16 @@ where
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(any(feature = "ssl", feature = "rust-tls"))]
|
||||||
{
|
{
|
||||||
const H2: &[u8] = b"h2";
|
const H2: &[u8] = b"h2";
|
||||||
|
#[cfg(feature = "ssl")]
|
||||||
use actix_connect::ssl::OpensslConnector;
|
use actix_connect::ssl::OpensslConnector;
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
use actix_connect::ssl::RustlsConnector;
|
||||||
|
use actix_service::boxed::service;
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
use rustls::Session;
|
||||||
|
|
||||||
let ssl_service = TimeoutService::new(
|
let ssl_service = TimeoutService::new(
|
||||||
self.timeout,
|
self.timeout,
|
||||||
|
@ -218,8 +255,10 @@ where
|
||||||
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
|
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
|
||||||
})
|
})
|
||||||
.map_err(ConnectError::from)
|
.map_err(ConnectError::from)
|
||||||
.and_then(
|
.and_then(match self.ssl {
|
||||||
OpensslConnector::service(self.ssl)
|
#[cfg(feature = "ssl")]
|
||||||
|
SslConnector::Openssl(ssl) => service(
|
||||||
|
OpensslConnector::service(ssl)
|
||||||
.map_err(ConnectError::from)
|
.map_err(ConnectError::from)
|
||||||
.map(|stream| {
|
.map(|stream| {
|
||||||
let sock = stream.into_parts().0;
|
let sock = stream.into_parts().0;
|
||||||
|
@ -230,12 +269,32 @@ where
|
||||||
.map(|protos| protos.windows(2).any(|w| w == H2))
|
.map(|protos| protos.windows(2).any(|w| w == H2))
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
if h2 {
|
if h2 {
|
||||||
(sock, Protocol::Http2)
|
(Box::new(sock) as Box<Io>, Protocol::Http2)
|
||||||
} else {
|
} else {
|
||||||
(sock, Protocol::Http1)
|
(Box::new(sock) as Box<Io>, Protocol::Http1)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
SslConnector::Rustls(ssl) => service(
|
||||||
|
RustlsConnector::service(ssl)
|
||||||
|
.map_err(ConnectError::from)
|
||||||
|
.map(|stream| {
|
||||||
|
let sock = stream.into_parts().0;
|
||||||
|
let h2 = sock
|
||||||
|
.get_ref()
|
||||||
|
.1
|
||||||
|
.get_alpn_protocol()
|
||||||
|
.map(|protos| protos.windows(2).any(|w| w == H2))
|
||||||
|
.unwrap_or(false);
|
||||||
|
if h2 {
|
||||||
|
(Box::new(sock) as Box<Io>, Protocol::Http2)
|
||||||
|
} else {
|
||||||
|
(Box::new(sock) as Box<Io>, Protocol::Http1)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
.map_err(|e| match e {
|
.map_err(|e| match e {
|
||||||
TimeoutError::Service(e) => e,
|
TimeoutError::Service(e) => e,
|
||||||
|
@ -275,7 +334,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "ssl"))]
|
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]
|
||||||
mod connect_impl {
|
mod connect_impl {
|
||||||
use futures::future::{err, Either, FutureResult};
|
use futures::future::{err, Either, FutureResult};
|
||||||
use futures::Poll;
|
use futures::Poll;
|
||||||
|
@ -337,7 +396,7 @@ mod connect_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(any(feature = "ssl", feature = "rust-tls"))]
|
||||||
mod connect_impl {
|
mod connect_impl {
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDPjCCAiYCCQCmkoCBehOyYTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJV
|
|
||||||
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMRAwDgYDVQQKDAdDb21wYW55MQww
|
|
||||||
CgYDVQQLDANPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xOTAzMjky
|
|
||||||
MzE5MDlaFw0yMDAzMjgyMzE5MDlaMGExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJD
|
|
||||||
QTELMAkGA1UEBwwCU0YxEDAOBgNVBAoMB0NvbXBhbnkxDDAKBgNVBAsMA09yZzEY
|
|
||||||
MBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
|
||||||
MIIBCgKCAQEA2uFoWm74qumqIIsBBf/rgP3ZtZw6dRQhVoYjIwYk00T1RLmmbt8r
|
|
||||||
YNh3lehmnrQlM/YC3dzcspucGqIfvs5FEReh/vgvsqY3lfy47Q1zzdtBrKq2ZBro
|
|
||||||
AuJUe4ayMYz/L/2jAtPtGDQqWyzhKv6x/oz6N/tKqlzoGbjSGSJUqKAV+Tuo4YI4
|
|
||||||
xw3r/RJg3I3+ruXOgM65GBdja7usI/BhseEOp9VXotoTEItGmvG2RFZ4A7cN124x
|
|
||||||
giFl2IeYuC60jteZ+bnhPiqxcdzf3K4dnZlzrYma+FxwWbaow4wlpQcZVFdZ+K/Y
|
|
||||||
p/Bbm/FDKoUHnEdn/QAanTruRxSGdai0owIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
|
|
||||||
AQAEWn3WAwAbd64f5jo2w4076s2qFiCJjPWoxO6bO75FgFFtw/NNev8pxGVw1ehg
|
|
||||||
HiTO6VRYolL5S/RKOchjA83AcDEBjgf8fKtvTmE9kxZSUIo4kIvv8V9ZM72gJhDN
|
|
||||||
8D/lXduTZ9JMwLOa1NUB8/I6CbaU3VzWkfodArKKpQF3M+LLgK03i12PD0KPQ5zv
|
|
||||||
bwaNoQo6cTmPNIdsVZETRvPqONiCUaQV57G74dGtjeirCh/DO5EYRtb1thgS7TGm
|
|
||||||
+Xg8OC5vZ6g0+xsrSqDBmWNtlI7S3bsL5C3LIEOOAL1ZJHRy2KvIGQ9ipb3XjnKS
|
|
||||||
N7/wlQduRyPH7oaD/o4xf5Gt
|
|
||||||
-----END CERTIFICATE-----
|
|
|
@ -1,27 +0,0 @@
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEpQIBAAKCAQEA2uFoWm74qumqIIsBBf/rgP3ZtZw6dRQhVoYjIwYk00T1RLmm
|
|
||||||
bt8rYNh3lehmnrQlM/YC3dzcspucGqIfvs5FEReh/vgvsqY3lfy47Q1zzdtBrKq2
|
|
||||||
ZBroAuJUe4ayMYz/L/2jAtPtGDQqWyzhKv6x/oz6N/tKqlzoGbjSGSJUqKAV+Tuo
|
|
||||||
4YI4xw3r/RJg3I3+ruXOgM65GBdja7usI/BhseEOp9VXotoTEItGmvG2RFZ4A7cN
|
|
||||||
124xgiFl2IeYuC60jteZ+bnhPiqxcdzf3K4dnZlzrYma+FxwWbaow4wlpQcZVFdZ
|
|
||||||
+K/Yp/Bbm/FDKoUHnEdn/QAanTruRxSGdai0owIDAQABAoIBAQC4lzyQd+ITEbi+
|
|
||||||
dTxJuQj94hgHB1htgKqU888SLI5F9nP6n67y9hb5N9WygSp6UWbGqYTFYwxlPMKr
|
|
||||||
22p2WjL5NTsTcm+XdIKQZW/3y06Mn4qFefsT9XURaZriCjihfU2BRaCCNARSUzwd
|
|
||||||
ZH4I6n9mM7KaH71aa7v6ZVoahE9tXPR6hM+SHQEySW4pWkEu98VpNNeIt6vP7WF9
|
|
||||||
ONGbRa+0En4xgkuaxem2ZYa/GZFFtdQRkroNMhIRlfcPpkjy8DCc8E5RAkOzKC3O
|
|
||||||
lnxQwt+tdNNkGZz02ed2hx/YHPwFYy76y6hK5dxq74iKIaOc8U5t0HjB1zVfwiR0
|
|
||||||
5mcxMncxAoGBAP+RivwXZ4FcxDY1uyziF+rwlC/1RujQFEWXIxsXCnba5DH3yKul
|
|
||||||
iKEIZPZtGhpsnQe367lcXcn7tztuoVjpAnk5L+hQY64tLwYbHeRcOMJ75C2y8FFC
|
|
||||||
NeG5sQsrk3IU1+jhGvrbE7UgOeAuWJmv0M1vPNB/+hGoZBW5W5uU1x89AoGBANtA
|
|
||||||
AhLtAcqQ/Qh2SpVhLljh7U85Be9tbCGua09clkYFzh3bcoBolXKH18Veww0TP0yF
|
|
||||||
0748CKw1A+ITbTVFV+vKvi4jzIxS7mr4wYtVCMssbttQN7y3l30IDxJwa9j3zTJx
|
|
||||||
IUn5OMMLv1JyitLId8HdOy1AdU3MkpJzdLyi1mFfAoGBAL3kL4fGABM/kU7SN6RO
|
|
||||||
zgS0AvdrYOeljBp1BRGg2hab58g02vamxVEZgqMTR7zwjPDqOIz+03U7wda4Ccyd
|
|
||||||
PUhDNJSB/r6xNepshZZi642eLlnCRguqjYyNw72QADtYv2B6uehAlXEUY8xtw0lW
|
|
||||||
OGgcSeyF2pH6M3tswWNlgT3lAoGAQ/BttBelOnP7NKgTLH7Usc4wjyAIaszpePZn
|
|
||||||
Ykw6dLBP0oixzoCZ7seRYSOgJWkVcEz39Db+KP60mVWTvbIjMHm+vOVy+Pip0JQM
|
|
||||||
xXQwKWU3ZNZSrzPkyWW55ejYQn9nIn5T5mxH3ojBXHcJ9Y8RLQ20zKzwrI77zE3i
|
|
||||||
mqGK9NkCgYEAq3dzHI0DGAJrR19sWl2LcqI19sj5a91tHx4cl1dJXS/iApOLLieU
|
|
||||||
zyUGkwfsqjHPAZ7GacICeBojIn/7KdPdlSKAbGVAU3d4qzvFS0qmWzObplBz3niT
|
|
||||||
Xnep2XLaVXqwlFJZZ6AHeKzYmMH0d0raiou2bpEUBqYizy2fi3NI4mA=
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
462
actix-http/tests/test_rustls_server.rs
Normal file
462
actix-http/tests/test_rustls_server.rs
Normal file
|
@ -0,0 +1,462 @@
|
||||||
|
#![cfg(feature = "rust-tls")]
|
||||||
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
|
use actix_http::error::PayloadError;
|
||||||
|
use actix_http::http::header::{self, HeaderName, HeaderValue};
|
||||||
|
use actix_http::http::{Method, StatusCode, Version};
|
||||||
|
use actix_http::{body, error, Error, HttpService, Request, Response};
|
||||||
|
use actix_http_test::TestServer;
|
||||||
|
use actix_server::ssl::RustlsAcceptor;
|
||||||
|
use actix_server_config::ServerConfig;
|
||||||
|
use actix_service::{new_service_cfg, NewService};
|
||||||
|
|
||||||
|
use bytes::{Bytes, BytesMut};
|
||||||
|
use futures::future::{self, ok, Future};
|
||||||
|
use futures::stream::{once, Stream};
|
||||||
|
use rustls::{
|
||||||
|
internal::pemfile::{certs, pkcs8_private_keys},
|
||||||
|
NoClientAuth, ServerConfig as RustlsServerConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufReader, Result};
|
||||||
|
|
||||||
|
fn load_body<S>(stream: S) -> impl Future<Item = BytesMut, Error = PayloadError>
|
||||||
|
where
|
||||||
|
S: Stream<Item = Bytes, Error = PayloadError>,
|
||||||
|
{
|
||||||
|
stream.fold(BytesMut::new(), move |mut body, chunk| {
|
||||||
|
body.extend_from_slice(&chunk);
|
||||||
|
Ok::<_, PayloadError>(body)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ssl_acceptor<T: AsyncRead + AsyncWrite>() -> Result<RustlsAcceptor<T, ()>> {
|
||||||
|
// load ssl keys
|
||||||
|
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_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 protos = vec![b"h2".to_vec()];
|
||||||
|
config.set_protocols(&protos);
|
||||||
|
Ok(RustlsAcceptor::new(config))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2() -> Result<()> {
|
||||||
|
let rustls = ssl_acceptor()?;
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| future::ok::<_, Error>(Response::Ok().finish()))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_1() -> Result<()> {
|
||||||
|
let rustls = ssl_acceptor()?;
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.finish(|req: Request| {
|
||||||
|
assert!(req.peer_addr().is_some());
|
||||||
|
assert_eq!(req.version(), Version::HTTP_2);
|
||||||
|
future::ok::<_, Error>(Response::Ok().finish())
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_body() -> Result<()> {
|
||||||
|
let data = "HELLOWORLD".to_owned().repeat(64 * 1024);
|
||||||
|
let rustls = ssl_acceptor()?;
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|mut req: Request<_>| {
|
||||||
|
load_body(req.take_payload())
|
||||||
|
.and_then(|body| Ok(Response::Ok().body(body)))
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send_body(data.clone())).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
let body = srv.load_body(response).unwrap();
|
||||||
|
assert_eq!(&body, data.as_bytes());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_content_length() {
|
||||||
|
let rustls = ssl_acceptor().unwrap();
|
||||||
|
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|req: Request| {
|
||||||
|
let indx: usize = req.uri().path()[1..].parse().unwrap();
|
||||||
|
let statuses = [
|
||||||
|
StatusCode::NO_CONTENT,
|
||||||
|
StatusCode::CONTINUE,
|
||||||
|
StatusCode::SWITCHING_PROTOCOLS,
|
||||||
|
StatusCode::PROCESSING,
|
||||||
|
StatusCode::OK,
|
||||||
|
StatusCode::NOT_FOUND,
|
||||||
|
];
|
||||||
|
future::ok::<_, ()>(Response::new(statuses[indx]))
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let header = HeaderName::from_static("content-length");
|
||||||
|
let value = HeaderValue::from_static("0");
|
||||||
|
|
||||||
|
{
|
||||||
|
for i in 0..4 {
|
||||||
|
let req = srv
|
||||||
|
.request(Method::GET, srv.surl(&format!("/{}", i)))
|
||||||
|
.send();
|
||||||
|
let response = srv.block_on(req).unwrap();
|
||||||
|
assert_eq!(response.headers().get(&header), None);
|
||||||
|
|
||||||
|
let req = srv
|
||||||
|
.request(Method::HEAD, srv.surl(&format!("/{}", i)))
|
||||||
|
.send();
|
||||||
|
let response = srv.block_on(req).unwrap();
|
||||||
|
assert_eq!(response.headers().get(&header), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 4..6 {
|
||||||
|
let req = srv
|
||||||
|
.request(Method::GET, srv.surl(&format!("/{}", i)))
|
||||||
|
.send();
|
||||||
|
let response = srv.block_on(req).unwrap();
|
||||||
|
assert_eq!(response.headers().get(&header), Some(&value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_headers() {
|
||||||
|
let data = STR.repeat(10);
|
||||||
|
let data2 = data.clone();
|
||||||
|
let rustls = ssl_acceptor().unwrap();
|
||||||
|
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
let data = data.clone();
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build().h2(move |_| {
|
||||||
|
let mut config = Response::Ok();
|
||||||
|
for idx in 0..90 {
|
||||||
|
config.header(
|
||||||
|
format!("X-TEST-{}", idx).as_str(),
|
||||||
|
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
future::ok::<_, ()>(config.body(data.clone()))
|
||||||
|
}).map_err(|_| ()))
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from(data2));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_body2() {
|
||||||
|
let rustls = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_head_empty() {
|
||||||
|
let rustls = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.shead("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
assert_eq!(response.version(), Version::HTTP_2);
|
||||||
|
|
||||||
|
{
|
||||||
|
let len = response
|
||||||
|
.headers()
|
||||||
|
.get(http::header::CONTENT_LENGTH)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert!(bytes.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_head_binary() {
|
||||||
|
let rustls = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| {
|
||||||
|
ok::<_, ()>(
|
||||||
|
Response::Ok().content_length(STR.len() as u64).body(STR),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.shead("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
{
|
||||||
|
let len = response
|
||||||
|
.headers()
|
||||||
|
.get(http::header::CONTENT_LENGTH)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert!(bytes.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_head_binary2() {
|
||||||
|
let rustls = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.shead("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
{
|
||||||
|
let len = response
|
||||||
|
.headers()
|
||||||
|
.get(http::header::CONTENT_LENGTH)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_body_length() {
|
||||||
|
let rustls = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| {
|
||||||
|
let body = once(Ok(Bytes::from_static(STR.as_ref())));
|
||||||
|
ok::<_, ()>(
|
||||||
|
Response::Ok()
|
||||||
|
.body(body::SizedStream::new(STR.len() as u64, body)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_body_chunked_explicit() {
|
||||||
|
let rustls = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| {
|
||||||
|
let body =
|
||||||
|
once::<_, Error>(Ok(Bytes::from_static(STR.as_ref())));
|
||||||
|
ok::<_, ()>(
|
||||||
|
Response::Ok()
|
||||||
|
.header(header::TRANSFER_ENCODING, "chunked")
|
||||||
|
.streaming(body),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
assert!(!response.headers().contains_key(header::TRANSFER_ENCODING));
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
|
||||||
|
// decode
|
||||||
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_response_http_error_handling() {
|
||||||
|
let rustls = ssl_acceptor().unwrap();
|
||||||
|
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(new_service_cfg(|_: &ServerConfig| {
|
||||||
|
Ok::<_, ()>(|_| {
|
||||||
|
let broken_header = Bytes::from_static(b"\0\0\0");
|
||||||
|
ok::<_, ()>(
|
||||||
|
Response::Ok()
|
||||||
|
.header(http::header::CONTENT_TYPE, broken_header)
|
||||||
|
.body(STR),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(b"failed to parse header value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_service_error() {
|
||||||
|
let rustls = ssl_acceptor().unwrap();
|
||||||
|
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
rustls
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Rustls error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| Err::<Response, Error>(error::ErrorBadRequest("error")))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert!(bytes.is_empty());
|
||||||
|
}
|
|
@ -2,32 +2,19 @@ use std::io::{Read, Write};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{net, thread};
|
use std::{net, thread};
|
||||||
|
|
||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
|
||||||
use actix_http_test::TestServer;
|
use actix_http_test::TestServer;
|
||||||
use actix_server_config::ServerConfig;
|
use actix_server_config::ServerConfig;
|
||||||
use actix_service::{new_service_cfg, service_fn, NewService};
|
use actix_service::{new_service_cfg, service_fn, NewService};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::Bytes;
|
||||||
use futures::future::{self, ok, Future};
|
use futures::future::{self, ok, Future};
|
||||||
use futures::stream::{once, Stream};
|
use futures::stream::{once, Stream};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use tokio_timer::sleep;
|
use tokio_timer::sleep;
|
||||||
|
|
||||||
use actix_http::error::PayloadError;
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body, error, http, http::header, Error, HttpService, KeepAlive, Request, Response,
|
body, error, http, http::header, Error, HttpService, KeepAlive, Request, Response,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
fn load_body<S>(stream: S) -> impl Future<Item = BytesMut, Error = PayloadError>
|
|
||||||
where
|
|
||||||
S: Stream<Item = Bytes, Error = PayloadError>,
|
|
||||||
{
|
|
||||||
stream.fold(BytesMut::new(), move |mut body, chunk| {
|
|
||||||
body.extend_from_slice(&chunk);
|
|
||||||
Ok::<_, PayloadError>(body)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_h1() {
|
fn test_h1() {
|
||||||
let mut srv = TestServer::new(|| {
|
let mut srv = TestServer::new(|| {
|
||||||
|
@ -64,101 +51,6 @@ fn test_h1_2() {
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
fn ssl_acceptor<T: AsyncRead + AsyncWrite>(
|
|
||||||
) -> std::io::Result<actix_server::ssl::OpensslAcceptor<T, ()>> {
|
|
||||||
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()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2() -> std::io::Result<()> {
|
|
||||||
let openssl = ssl_acceptor()?;
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.h2(|_| future::ok::<_, Error>(Response::Ok().finish()))
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
|
||||||
assert!(response.status().is_success());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_1() -> std::io::Result<()> {
|
|
||||||
let openssl = ssl_acceptor()?;
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.finish(|req: Request| {
|
|
||||||
assert!(req.peer_addr().is_some());
|
|
||||||
assert_eq!(req.version(), http::Version::HTTP_2);
|
|
||||||
future::ok::<_, Error>(Response::Ok().finish())
|
|
||||||
})
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
|
||||||
assert!(response.status().is_success());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_body() -> std::io::Result<()> {
|
|
||||||
let data = "HELLOWORLD".to_owned().repeat(64 * 1024);
|
|
||||||
let openssl = ssl_acceptor()?;
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.h2(|mut req: Request<_>| {
|
|
||||||
load_body(req.take_payload())
|
|
||||||
.and_then(|body| Ok(Response::Ok().body(body)))
|
|
||||||
})
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.sget("/").send_body(data.clone())).unwrap();
|
|
||||||
assert!(response.status().is_success());
|
|
||||||
|
|
||||||
let body = srv.load_body(response).unwrap();
|
|
||||||
assert_eq!(&body, data.as_bytes());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_expect_continue() {
|
fn test_expect_continue() {
|
||||||
let srv = TestServer::new(|| {
|
let srv = TestServer::new(|| {
|
||||||
|
@ -457,65 +349,6 @@ fn test_content_length() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_content_length() {
|
|
||||||
use actix_http::http::{
|
|
||||||
header::{HeaderName, HeaderValue},
|
|
||||||
StatusCode,
|
|
||||||
};
|
|
||||||
let openssl = ssl_acceptor().unwrap();
|
|
||||||
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.h2(|req: Request| {
|
|
||||||
let indx: usize = req.uri().path()[1..].parse().unwrap();
|
|
||||||
let statuses = [
|
|
||||||
StatusCode::NO_CONTENT,
|
|
||||||
StatusCode::CONTINUE,
|
|
||||||
StatusCode::SWITCHING_PROTOCOLS,
|
|
||||||
StatusCode::PROCESSING,
|
|
||||||
StatusCode::OK,
|
|
||||||
StatusCode::NOT_FOUND,
|
|
||||||
];
|
|
||||||
future::ok::<_, ()>(Response::new(statuses[indx]))
|
|
||||||
})
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let header = HeaderName::from_static("content-length");
|
|
||||||
let value = HeaderValue::from_static("0");
|
|
||||||
|
|
||||||
{
|
|
||||||
for i in 0..4 {
|
|
||||||
let req = srv
|
|
||||||
.request(http::Method::GET, srv.surl(&format!("/{}", i)))
|
|
||||||
.send();
|
|
||||||
let response = srv.block_on(req).unwrap();
|
|
||||||
assert_eq!(response.headers().get(&header), None);
|
|
||||||
|
|
||||||
let req = srv
|
|
||||||
.request(http::Method::HEAD, srv.surl(&format!("/{}", i)))
|
|
||||||
.send();
|
|
||||||
let response = srv.block_on(req).unwrap();
|
|
||||||
assert_eq!(response.headers().get(&header), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 4..6 {
|
|
||||||
let req = srv
|
|
||||||
.request(http::Method::GET, srv.surl(&format!("/{}", i)))
|
|
||||||
.send();
|
|
||||||
let response = srv.block_on(req).unwrap();
|
|
||||||
assert_eq!(response.headers().get(&header), Some(&value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_h1_headers() {
|
fn test_h1_headers() {
|
||||||
let data = STR.repeat(10);
|
let data = STR.repeat(10);
|
||||||
|
@ -555,51 +388,6 @@ fn test_h1_headers() {
|
||||||
assert_eq!(bytes, Bytes::from(data2));
|
assert_eq!(bytes, Bytes::from(data2));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_headers() {
|
|
||||||
let data = STR.repeat(10);
|
|
||||||
let data2 = data.clone();
|
|
||||||
let openssl = ssl_acceptor().unwrap();
|
|
||||||
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
let data = data.clone();
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build().h2(move |_| {
|
|
||||||
let mut builder = Response::Ok();
|
|
||||||
for idx in 0..90 {
|
|
||||||
builder.header(
|
|
||||||
format!("X-TEST-{}", idx).as_str(),
|
|
||||||
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
|
||||||
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
future::ok::<_, ()>(builder.body(data.clone()))
|
|
||||||
}).map_err(|_| ()))
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
|
||||||
assert!(response.status().is_success());
|
|
||||||
|
|
||||||
// read response
|
|
||||||
let bytes = srv.load_body(response).unwrap();
|
|
||||||
assert_eq!(bytes, Bytes::from(data2));
|
|
||||||
}
|
|
||||||
|
|
||||||
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
|
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 \
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
@ -636,29 +424,6 @@ fn test_h1_body() {
|
||||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_body2() {
|
|
||||||
let openssl = ssl_acceptor().unwrap();
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.h2(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
|
||||||
assert!(response.status().is_success());
|
|
||||||
|
|
||||||
// read response
|
|
||||||
let bytes = srv.load_body(response).unwrap();
|
|
||||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_h1_head_empty() {
|
fn test_h1_head_empty() {
|
||||||
let mut srv = TestServer::new(|| {
|
let mut srv = TestServer::new(|| {
|
||||||
|
@ -681,38 +446,6 @@ fn test_h1_head_empty() {
|
||||||
assert!(bytes.is_empty());
|
assert!(bytes.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_head_empty() {
|
|
||||||
let openssl = ssl_acceptor().unwrap();
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.shead("/").send()).unwrap();
|
|
||||||
assert!(response.status().is_success());
|
|
||||||
assert_eq!(response.version(), http::Version::HTTP_2);
|
|
||||||
|
|
||||||
{
|
|
||||||
let len = response
|
|
||||||
.headers()
|
|
||||||
.get(http::header::CONTENT_LENGTH)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
// read response
|
|
||||||
let bytes = srv.load_body(response).unwrap();
|
|
||||||
assert!(bytes.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_h1_head_binary() {
|
fn test_h1_head_binary() {
|
||||||
let mut srv = TestServer::new(|| {
|
let mut srv = TestServer::new(|| {
|
||||||
|
@ -737,41 +470,6 @@ fn test_h1_head_binary() {
|
||||||
assert!(bytes.is_empty());
|
assert!(bytes.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_head_binary() {
|
|
||||||
let openssl = ssl_acceptor().unwrap();
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.h2(|_| {
|
|
||||||
ok::<_, ()>(
|
|
||||||
Response::Ok().content_length(STR.len() as u64).body(STR),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.shead("/").send()).unwrap();
|
|
||||||
assert!(response.status().is_success());
|
|
||||||
|
|
||||||
{
|
|
||||||
let len = response
|
|
||||||
.headers()
|
|
||||||
.get(http::header::CONTENT_LENGTH)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
// read response
|
|
||||||
let bytes = srv.load_body(response).unwrap();
|
|
||||||
assert!(bytes.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_h1_head_binary2() {
|
fn test_h1_head_binary2() {
|
||||||
let mut srv = TestServer::new(|| {
|
let mut srv = TestServer::new(|| {
|
||||||
|
@ -790,33 +488,6 @@ fn test_h1_head_binary2() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_head_binary2() {
|
|
||||||
let openssl = ssl_acceptor().unwrap();
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.shead("/").send()).unwrap();
|
|
||||||
assert!(response.status().is_success());
|
|
||||||
|
|
||||||
{
|
|
||||||
let len = response
|
|
||||||
.headers()
|
|
||||||
.get(http::header::CONTENT_LENGTH)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_h1_body_length() {
|
fn test_h1_body_length() {
|
||||||
let mut srv = TestServer::new(|| {
|
let mut srv = TestServer::new(|| {
|
||||||
|
@ -836,35 +507,6 @@ fn test_h1_body_length() {
|
||||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_body_length() {
|
|
||||||
let openssl = ssl_acceptor().unwrap();
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.h2(|_| {
|
|
||||||
let body = once(Ok(Bytes::from_static(STR.as_ref())));
|
|
||||||
ok::<_, ()>(
|
|
||||||
Response::Ok()
|
|
||||||
.body(body::SizedStream::new(STR.len() as u64, body)),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
|
||||||
assert!(response.status().is_success());
|
|
||||||
|
|
||||||
// read response
|
|
||||||
let bytes = srv.load_body(response).unwrap();
|
|
||||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_h1_body_chunked_explicit() {
|
fn test_h1_body_chunked_explicit() {
|
||||||
let mut srv = TestServer::new(|| {
|
let mut srv = TestServer::new(|| {
|
||||||
|
@ -897,40 +539,6 @@ fn test_h1_body_chunked_explicit() {
|
||||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_body_chunked_explicit() {
|
|
||||||
let openssl = ssl_acceptor().unwrap();
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.h2(|_| {
|
|
||||||
let body =
|
|
||||||
once::<_, Error>(Ok(Bytes::from_static(STR.as_ref())));
|
|
||||||
ok::<_, ()>(
|
|
||||||
Response::Ok()
|
|
||||||
.header(header::TRANSFER_ENCODING, "chunked")
|
|
||||||
.streaming(body),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
|
||||||
assert!(response.status().is_success());
|
|
||||||
assert!(!response.headers().contains_key(header::TRANSFER_ENCODING));
|
|
||||||
|
|
||||||
// read response
|
|
||||||
let bytes = srv.load_body(response).unwrap();
|
|
||||||
|
|
||||||
// decode
|
|
||||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_h1_body_chunked_implicit() {
|
fn test_h1_body_chunked_implicit() {
|
||||||
let mut srv = TestServer::new(|| {
|
let mut srv = TestServer::new(|| {
|
||||||
|
@ -980,39 +588,6 @@ fn test_h1_response_http_error_handling() {
|
||||||
assert_eq!(bytes, Bytes::from_static(b"failed to parse header value"));
|
assert_eq!(bytes, Bytes::from_static(b"failed to parse header value"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_response_http_error_handling() {
|
|
||||||
let openssl = ssl_acceptor().unwrap();
|
|
||||||
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.h2(new_service_cfg(|_: &ServerConfig| {
|
|
||||||
Ok::<_, ()>(|_| {
|
|
||||||
let broken_header = Bytes::from_static(b"\0\0\0");
|
|
||||||
ok::<_, ()>(
|
|
||||||
Response::Ok()
|
|
||||||
.header(http::header::CONTENT_TYPE, broken_header)
|
|
||||||
.body(STR),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
|
||||||
assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
|
|
||||||
|
|
||||||
// read response
|
|
||||||
let bytes = srv.load_body(response).unwrap();
|
|
||||||
assert_eq!(bytes, Bytes::from_static(b"failed to parse header value"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_h1_service_error() {
|
fn test_h1_service_error() {
|
||||||
let mut srv = TestServer::new(|| {
|
let mut srv = TestServer::new(|| {
|
||||||
|
@ -1027,27 +602,3 @@ fn test_h1_service_error() {
|
||||||
let bytes = srv.load_body(response).unwrap();
|
let bytes = srv.load_body(response).unwrap();
|
||||||
assert_eq!(bytes, Bytes::from_static(b"error"));
|
assert_eq!(bytes, Bytes::from_static(b"error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssl")]
|
|
||||||
#[test]
|
|
||||||
fn test_h2_service_error() {
|
|
||||||
let openssl = ssl_acceptor().unwrap();
|
|
||||||
|
|
||||||
let mut srv = TestServer::new(move || {
|
|
||||||
openssl
|
|
||||||
.clone()
|
|
||||||
.map_err(|e| println!("Openssl error: {}", e))
|
|
||||||
.and_then(
|
|
||||||
HttpService::build()
|
|
||||||
.h2(|_| Err::<Response, Error>(error::ErrorBadRequest("error")))
|
|
||||||
.map_err(|_| ()),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
|
||||||
assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
|
|
||||||
|
|
||||||
// read response
|
|
||||||
let bytes = srv.load_body(response).unwrap();
|
|
||||||
assert!(bytes.is_empty());
|
|
||||||
}
|
|
||||||
|
|
455
actix-http/tests/test_ssl_server.rs
Normal file
455
actix-http/tests/test_ssl_server.rs
Normal file
|
@ -0,0 +1,455 @@
|
||||||
|
#![cfg(feature = "ssl")]
|
||||||
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
|
use actix_http::error::{ErrorBadRequest, PayloadError};
|
||||||
|
use actix_http::http::header::{self, HeaderName, HeaderValue};
|
||||||
|
use actix_http::http::{Method, StatusCode, Version};
|
||||||
|
use actix_http::{body, Error, HttpService, Request, Response};
|
||||||
|
use actix_http_test::TestServer;
|
||||||
|
use actix_server::ssl::OpensslAcceptor;
|
||||||
|
use actix_server_config::ServerConfig;
|
||||||
|
use actix_service::{new_service_cfg, NewService};
|
||||||
|
|
||||||
|
use bytes::{Bytes, BytesMut};
|
||||||
|
use futures::future::{ok, Future};
|
||||||
|
use futures::stream::{once, Stream};
|
||||||
|
use openssl::ssl::{AlpnError, SslAcceptor, SslFiletype, SslMethod};
|
||||||
|
use std::io::Result;
|
||||||
|
|
||||||
|
fn load_body<S>(stream: S) -> impl Future<Item = BytesMut, Error = PayloadError>
|
||||||
|
where
|
||||||
|
S: Stream<Item = Bytes, Error = PayloadError>,
|
||||||
|
{
|
||||||
|
stream.fold(BytesMut::new(), move |mut body, chunk| {
|
||||||
|
body.extend_from_slice(&chunk);
|
||||||
|
Ok::<_, PayloadError>(body)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ssl_acceptor<T: AsyncRead + AsyncWrite>() -> Result<OpensslAcceptor<T, ()>> {
|
||||||
|
// 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(AlpnError::NOACK)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.set_alpn_protos(b"\x02h2")?;
|
||||||
|
Ok(OpensslAcceptor::new(builder.build()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2() -> Result<()> {
|
||||||
|
let openssl = ssl_acceptor()?;
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| ok::<_, Error>(Response::Ok().finish()))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_1() -> Result<()> {
|
||||||
|
let openssl = ssl_acceptor()?;
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.finish(|req: Request| {
|
||||||
|
assert!(req.peer_addr().is_some());
|
||||||
|
assert_eq!(req.version(), Version::HTTP_2);
|
||||||
|
ok::<_, Error>(Response::Ok().finish())
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_body() -> Result<()> {
|
||||||
|
let data = "HELLOWORLD".to_owned().repeat(64 * 1024);
|
||||||
|
let openssl = ssl_acceptor()?;
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|mut req: Request<_>| {
|
||||||
|
load_body(req.take_payload())
|
||||||
|
.and_then(|body| Ok(Response::Ok().body(body)))
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send_body(data.clone())).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
let body = srv.load_body(response).unwrap();
|
||||||
|
assert_eq!(&body, data.as_bytes());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_content_length() {
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|req: Request| {
|
||||||
|
let indx: usize = req.uri().path()[1..].parse().unwrap();
|
||||||
|
let statuses = [
|
||||||
|
StatusCode::NO_CONTENT,
|
||||||
|
StatusCode::CONTINUE,
|
||||||
|
StatusCode::SWITCHING_PROTOCOLS,
|
||||||
|
StatusCode::PROCESSING,
|
||||||
|
StatusCode::OK,
|
||||||
|
StatusCode::NOT_FOUND,
|
||||||
|
];
|
||||||
|
ok::<_, ()>(Response::new(statuses[indx]))
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let header = HeaderName::from_static("content-length");
|
||||||
|
let value = HeaderValue::from_static("0");
|
||||||
|
|
||||||
|
{
|
||||||
|
for i in 0..4 {
|
||||||
|
let req = srv
|
||||||
|
.request(Method::GET, srv.surl(&format!("/{}", i)))
|
||||||
|
.send();
|
||||||
|
let response = srv.block_on(req).unwrap();
|
||||||
|
assert_eq!(response.headers().get(&header), None);
|
||||||
|
|
||||||
|
let req = srv
|
||||||
|
.request(Method::HEAD, srv.surl(&format!("/{}", i)))
|
||||||
|
.send();
|
||||||
|
let response = srv.block_on(req).unwrap();
|
||||||
|
assert_eq!(response.headers().get(&header), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 4..6 {
|
||||||
|
let req = srv
|
||||||
|
.request(Method::GET, srv.surl(&format!("/{}", i)))
|
||||||
|
.send();
|
||||||
|
let response = srv.block_on(req).unwrap();
|
||||||
|
assert_eq!(response.headers().get(&header), Some(&value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_headers() {
|
||||||
|
let data = STR.repeat(10);
|
||||||
|
let data2 = data.clone();
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
let data = data.clone();
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build().h2(move |_| {
|
||||||
|
let mut builder = Response::Ok();
|
||||||
|
for idx in 0..90 {
|
||||||
|
builder.header(
|
||||||
|
format!("X-TEST-{}", idx).as_str(),
|
||||||
|
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
|
||||||
|
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ok::<_, ()>(builder.body(data.clone()))
|
||||||
|
}).map_err(|_| ()))
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from(data2));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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 \
|
||||||
|
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";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_body2() {
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_head_empty() {
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.shead("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
assert_eq!(response.version(), Version::HTTP_2);
|
||||||
|
|
||||||
|
{
|
||||||
|
let len = response.headers().get(header::CONTENT_LENGTH).unwrap();
|
||||||
|
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert!(bytes.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_head_binary() {
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| {
|
||||||
|
ok::<_, ()>(
|
||||||
|
Response::Ok().content_length(STR.len() as u64).body(STR),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.shead("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
{
|
||||||
|
let len = response.headers().get(header::CONTENT_LENGTH).unwrap();
|
||||||
|
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert!(bytes.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_head_binary2() {
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.shead("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
{
|
||||||
|
let len = response.headers().get(header::CONTENT_LENGTH).unwrap();
|
||||||
|
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_body_length() {
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| {
|
||||||
|
let body = once(Ok(Bytes::from_static(STR.as_ref())));
|
||||||
|
ok::<_, ()>(
|
||||||
|
Response::Ok()
|
||||||
|
.body(body::SizedStream::new(STR.len() as u64, body)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_body_chunked_explicit() {
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| {
|
||||||
|
let body =
|
||||||
|
once::<_, Error>(Ok(Bytes::from_static(STR.as_ref())));
|
||||||
|
ok::<_, ()>(
|
||||||
|
Response::Ok()
|
||||||
|
.header(header::TRANSFER_ENCODING, "chunked")
|
||||||
|
.streaming(body),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
assert!(!response.headers().contains_key(header::TRANSFER_ENCODING));
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
|
||||||
|
// decode
|
||||||
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_response_http_error_handling() {
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(new_service_cfg(|_: &ServerConfig| {
|
||||||
|
Ok::<_, ()>(|_| {
|
||||||
|
let broken_header = Bytes::from_static(b"\0\0\0");
|
||||||
|
ok::<_, ()>(
|
||||||
|
Response::Ok()
|
||||||
|
.header(header::CONTENT_TYPE, broken_header)
|
||||||
|
.body(STR),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(b"failed to parse header value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_service_error() {
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.h2(|_| Err::<Response, Error>(ErrorBadRequest("error")))
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.load_body(response).unwrap();
|
||||||
|
assert!(bytes.is_empty());
|
||||||
|
}
|
|
@ -142,7 +142,6 @@ fn test_body() {
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
assert_eq!(response.status(), http::StatusCode::NO_CONTENT);
|
assert_eq!(response.status(), http::StatusCode::NO_CONTENT);
|
||||||
|
|
||||||
let mut srv = TestServer::new(|| HttpService::new(App::new().service(auto_sync)));
|
|
||||||
let request = srv.request(http::Method::GET, srv.url("/test"));
|
let request = srv.request(http::Method::GET, srv.url("/test"));
|
||||||
let response = srv.block_on(request.send()).unwrap();
|
let response = srv.block_on(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## [0.2.3] - 2019-07-xx
|
||||||
|
|
||||||
|
* Add `rustls` support
|
||||||
|
|
||||||
## [0.2.2] - 2019-07-01
|
## [0.2.2] - 2019-07-01
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "awc"
|
name = "awc"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix http client."
|
description = "Actix http client."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -29,6 +29,9 @@ default = ["brotli", "flate2-zlib"]
|
||||||
# openssl
|
# openssl
|
||||||
ssl = ["openssl", "actix-http/ssl"]
|
ssl = ["openssl", "actix-http/ssl"]
|
||||||
|
|
||||||
|
# rustls
|
||||||
|
rust-tls = ["rustls", "actix-http/rust-tls"]
|
||||||
|
|
||||||
# brotli encoding, requires c compiler
|
# brotli encoding, requires c compiler
|
||||||
brotli = ["actix-http/brotli"]
|
brotli = ["actix-http/brotli"]
|
||||||
|
|
||||||
|
@ -41,7 +44,7 @@ flate2-rust = ["actix-http/flate2-rust"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.1.2"
|
actix-codec = "0.1.2"
|
||||||
actix-service = "0.4.1"
|
actix-service = "0.4.1"
|
||||||
actix-http = "0.2.4"
|
actix-http = "0.2.8"
|
||||||
base64 = "0.10.1"
|
base64 = "0.10.1"
|
||||||
bytes = "0.4"
|
bytes = "0.4"
|
||||||
derive_more = "0.15.0"
|
derive_more = "0.15.0"
|
||||||
|
@ -55,6 +58,7 @@ serde_json = "1.0"
|
||||||
serde_urlencoded = "0.5.3"
|
serde_urlencoded = "0.5.3"
|
||||||
tokio-timer = "0.2.8"
|
tokio-timer = "0.2.8"
|
||||||
openssl = { version="0.10", optional = true }
|
openssl = { version="0.10", optional = true }
|
||||||
|
rustls = { version = "0.15.2", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "0.2.2"
|
actix-rt = "0.2.2"
|
||||||
|
@ -62,9 +66,11 @@ actix-web = { version = "1.0.0", features=["ssl"] }
|
||||||
actix-http = { version = "0.2.4", features=["ssl"] }
|
actix-http = { version = "0.2.4", features=["ssl"] }
|
||||||
actix-http-test = { version = "0.2.0", features=["ssl"] }
|
actix-http-test = { version = "0.2.0", features=["ssl"] }
|
||||||
actix-utils = "0.4.1"
|
actix-utils = "0.4.1"
|
||||||
actix-server = { version = "0.5.1", features=["ssl"] }
|
actix-server = { version = "0.6.0", features=["ssl", "rust-tls"] }
|
||||||
brotli2 = { version="0.3.2" }
|
brotli2 = { version="0.3.2" }
|
||||||
flate2 = { version="1.0.2" }
|
flate2 = { version="1.0.2" }
|
||||||
env_logger = "0.6"
|
env_logger = "0.6"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
tokio-tcp = "0.1"
|
tokio-tcp = "0.1"
|
||||||
|
webpki = "0.19"
|
||||||
|
rustls = { version = "0.15.2", features = ["dangerous_configuration"] }
|
||||||
|
|
|
@ -12,11 +12,10 @@ use flate2::Compression;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
|
||||||
use actix_http::HttpService;
|
use actix_http::HttpService;
|
||||||
use actix_http_test::TestServer;
|
use actix_http_test::TestServer;
|
||||||
use actix_service::{service_fn, NewService};
|
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::middleware::{BodyEncoding, Compress};
|
||||||
use actix_web::{http::header, web, App, Error, HttpMessage, HttpRequest, HttpResponse};
|
use actix_web::{http::header, web, App, Error, HttpMessage, HttpRequest, HttpResponse};
|
||||||
use awc::error::SendRequestError;
|
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 \
|
||||||
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<T: AsyncRead + AsyncWrite>(
|
|
||||||
) -> std::io::Result<actix_server::ssl::OpensslAcceptor<T, ()>> {
|
|
||||||
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]
|
#[test]
|
||||||
fn test_simple() {
|
fn test_simple() {
|
||||||
let mut srv =
|
let mut srv =
|
||||||
|
@ -207,60 +182,6 @@ fn test_connection_reuse() {
|
||||||
assert_eq!(num.load(Ordering::Relaxed), 1);
|
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]
|
#[test]
|
||||||
fn test_connection_force_close() {
|
fn test_connection_force_close() {
|
||||||
let num = Arc::new(AtomicUsize::new(0));
|
let num = Arc::new(AtomicUsize::new(0));
|
||||||
|
|
96
awc/tests/test_rustls_client.rs
Normal file
96
awc/tests/test_rustls_client.rs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#![cfg(feature = "rust-tls")]
|
||||||
|
use rustls::{
|
||||||
|
internal::pemfile::{certs, pkcs8_private_keys},
|
||||||
|
ClientConfig, NoClientAuth,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufReader, Result};
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
|
use actix_http::HttpService;
|
||||||
|
use actix_http_test::TestServer;
|
||||||
|
use actix_server::ssl::RustlsAcceptor;
|
||||||
|
use actix_service::{service_fn, NewService};
|
||||||
|
use actix_web::http::Version;
|
||||||
|
use actix_web::{web, App, HttpResponse};
|
||||||
|
|
||||||
|
fn ssl_acceptor<T: AsyncRead + AsyncWrite>() -> Result<RustlsAcceptor<T, ()>> {
|
||||||
|
use rustls::ServerConfig;
|
||||||
|
// 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();
|
||||||
|
let protos = vec![b"h2".to_vec()];
|
||||||
|
config.set_protocols(&protos);
|
||||||
|
Ok(RustlsAcceptor::new(config))
|
||||||
|
}
|
||||||
|
|
||||||
|
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<rustls::ServerCertVerified, rustls::TLSError> {
|
||||||
|
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
|
||||||
|
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().rustls(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);
|
||||||
|
}
|
86
awc/tests/test_ssl_client.rs
Normal file
86
awc/tests/test_ssl_client.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#![cfg(feature = "ssl")]
|
||||||
|
use openssl::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod, SslVerifyMode};
|
||||||
|
|
||||||
|
use std::io::Result;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
|
use actix_http::HttpService;
|
||||||
|
use actix_http_test::TestServer;
|
||||||
|
use actix_server::ssl::OpensslAcceptor;
|
||||||
|
use actix_service::{service_fn, NewService};
|
||||||
|
use actix_web::http::Version;
|
||||||
|
use actix_web::{web, App, HttpResponse};
|
||||||
|
|
||||||
|
fn ssl_acceptor<T: AsyncRead + AsyncWrite>() -> Result<OpensslAcceptor<T, ()>> {
|
||||||
|
// 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);
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ fn no_params() -> &'static str {
|
||||||
"Hello world!\r\n"
|
"Hello world!\r\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "uds")]
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
|
std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
@ -47,3 +48,6 @@ fn main() -> std::io::Result<()> {
|
||||||
.workers(1)
|
.workers(1)
|
||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "uds"))]
|
||||||
|
fn main() {}
|
||||||
|
|
|
@ -36,6 +36,7 @@ actix-service = "0.4.1"
|
||||||
actix-server = "0.6.0"
|
actix-server = "0.6.0"
|
||||||
actix-utils = "0.4.1"
|
actix-utils = "0.4.1"
|
||||||
awc = "0.2.2"
|
awc = "0.2.2"
|
||||||
|
actix-connect = "0.2.2"
|
||||||
|
|
||||||
base64 = "0.10"
|
base64 = "0.10"
|
||||||
bytes = "0.4"
|
bytes = "0.4"
|
||||||
|
|
|
@ -163,6 +163,10 @@ impl TestServer {
|
||||||
Ok::<Client, ()>(Client::build().connector(connector).finish())
|
Ok::<Client, ()>(Client::build().connector(connector).finish())
|
||||||
}))
|
}))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
rt.block_on(lazy(
|
||||||
|
|| Ok::<_, ()>(actix_connect::start_default_resolver()),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
System::set_current(system);
|
System::set_current(system);
|
||||||
TestServerRuntime { addr, rt, client }
|
TestServerRuntime { addr, rt, client }
|
||||||
}
|
}
|
||||||
|
@ -212,18 +216,18 @@ impl TestServerRuntime {
|
||||||
/// Construct test server url
|
/// Construct test server url
|
||||||
pub fn url(&self, uri: &str) -> String {
|
pub fn url(&self, uri: &str) -> String {
|
||||||
if uri.starts_with('/') {
|
if uri.starts_with('/') {
|
||||||
format!("http://127.0.0.1:{}{}", self.addr.port(), uri)
|
format!("http://localhost:{}{}", self.addr.port(), uri)
|
||||||
} else {
|
} else {
|
||||||
format!("http://127.0.0.1:{}/{}", self.addr.port(), uri)
|
format!("http://localhost:{}/{}", self.addr.port(), uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct test https server url
|
/// Construct test https server url
|
||||||
pub fn surl(&self, uri: &str) -> String {
|
pub fn surl(&self, uri: &str) -> String {
|
||||||
if uri.starts_with('/') {
|
if uri.starts_with('/') {
|
||||||
format!("https://127.0.0.1:{}{}", self.addr.port(), uri)
|
format!("https://localhost:{}{}", self.addr.port(), uri)
|
||||||
} else {
|
} else {
|
||||||
format!("https://127.0.0.1:{}/{}", self.addr.port(), uri)
|
format!("https://localhost:{}/{}", self.addr.port(), uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,32 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIDPjCCAiYCCQCmkoCBehOyYTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJV
|
MIIFfjCCA2agAwIBAgIJAOIBvp/w68KrMA0GCSqGSIb3DQEBCwUAMGsxCzAJBgNV
|
||||||
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMRAwDgYDVQQKDAdDb21wYW55MQww
|
BAYTAlJVMRkwFwYDVQQIDBBTYWludC1QZXRlcnNidXJnMRkwFwYDVQQHDBBTYWlu
|
||||||
CgYDVQQLDANPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xOTAzMjky
|
dC1QZXRlcnNidXJnMRIwEAYDVQQKDAlLdXBpYmlsZXQxEjAQBgNVBAMMCWxvY2Fs
|
||||||
MzE5MDlaFw0yMDAzMjgyMzE5MDlaMGExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJD
|
aG9zdDAgFw0xOTA3MjcxODIzMTJaGA8zMDE5MDcyNzE4MjMxMlowazELMAkGA1UE
|
||||||
QTELMAkGA1UEBwwCU0YxEDAOBgNVBAoMB0NvbXBhbnkxDDAKBgNVBAsMA09yZzEY
|
BhMCUlUxGTAXBgNVBAgMEFNhaW50LVBldGVyc2J1cmcxGTAXBgNVBAcMEFNhaW50
|
||||||
MBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
LVBldGVyc2J1cmcxEjAQBgNVBAoMCUt1cGliaWxldDESMBAGA1UEAwwJbG9jYWxo
|
||||||
MIIBCgKCAQEA2uFoWm74qumqIIsBBf/rgP3ZtZw6dRQhVoYjIwYk00T1RLmmbt8r
|
b3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuiQZzTO3gRRPr6ZH
|
||||||
YNh3lehmnrQlM/YC3dzcspucGqIfvs5FEReh/vgvsqY3lfy47Q1zzdtBrKq2ZBro
|
wcmKqkoXig9taCCqx72Qvb9tvCLhQLE1dDPZV8I/r8bx+mM4Yz3r0Hm5LxTIhCM9
|
||||||
AuJUe4ayMYz/L/2jAtPtGDQqWyzhKv6x/oz6N/tKqlzoGbjSGSJUqKAV+Tuo4YI4
|
p3/abuiJAZENC/VkxgFzBGg7KGLSFmzU+A8Ft+2mrKmj5MpIPBCxDeVg80TCQOJy
|
||||||
xw3r/RJg3I3+ruXOgM65GBdja7usI/BhseEOp9VXotoTEItGmvG2RFZ4A7cN124x
|
hj+NU3PpBo9nxTgxWNWO6X+ZovZohdp78fYLLtns8rxjug3FVzdPrrLnBvihkGlq
|
||||||
giFl2IeYuC60jteZ+bnhPiqxcdzf3K4dnZlzrYma+FxwWbaow4wlpQcZVFdZ+K/Y
|
gfImkh+vZxMTj1OgtxyCOhdbO4Ol4jCbn7a5yIw+iixHOEgBQfTQopRP7z1PEUV2
|
||||||
p/Bbm/FDKoUHnEdn/QAanTruRxSGdai0owIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
|
WIy2VEGzvQDlj2OyzH86T1IOFV5rz5MjdZuW0qNzeS0w3Jzgp/olSbIZLhGAaIk0
|
||||||
AQAEWn3WAwAbd64f5jo2w4076s2qFiCJjPWoxO6bO75FgFFtw/NNev8pxGVw1ehg
|
gN7y9XvSHqs7rO0wW+467ico7+uP1ScGgPgJA5fGu7ahp7F7G3ZSoAqAcS60wYsX
|
||||||
HiTO6VRYolL5S/RKOchjA83AcDEBjgf8fKtvTmE9kxZSUIo4kIvv8V9ZM72gJhDN
|
kStoA3RWAuqste6aChv1tlgTt+Rhk8qjGhuh0ng2qVnTGyo2T3OCHB/c47Bcsp6L
|
||||||
8D/lXduTZ9JMwLOa1NUB8/I6CbaU3VzWkfodArKKpQF3M+LLgK03i12PD0KPQ5zv
|
xiyTCnQIPH3fh2iO/SC7gPw3jihPMCAQZYlkC3MhMk974rn2zs9cKtJ8ubnG2m5F
|
||||||
bwaNoQo6cTmPNIdsVZETRvPqONiCUaQV57G74dGtjeirCh/DO5EYRtb1thgS7TGm
|
VFVYmduRqS/YQS/O802jVCFdc8KDmoeAYNuHzgRZjQv9018UUeW3jtWKnopJnWs5
|
||||||
+Xg8OC5vZ6g0+xsrSqDBmWNtlI7S3bsL5C3LIEOOAL1ZJHRy2KvIGQ9ipb3XjnKS
|
ae9pbtmYeOtc7OovOxT7J2AaVfUkHRhmlqWZMzEJTcZws0fRPTZDifFJ5LFWbZsC
|
||||||
N7/wlQduRyPH7oaD/o4xf5Gt
|
zW4tCKBKvYM9eAnbb+abiHXlY1MCAwEAAaMjMCEwHwYDVR0RBBgwFoIJbG9jYWxo
|
||||||
|
b3N0ggkxMjcuMC4wLjEwDQYJKoZIhvcNAQELBQADggIBAC1EU4SVCfUKc7JbhYRf
|
||||||
|
P87F+8e13bBTLxevJdnTCH3Xw2AN8UPmwQ2vv9Mv2FMulMBQ7yLnQLGtgGUua2OE
|
||||||
|
XO+EdBBEKnglo9cwXGzU6qHhaiCeXZDM8s53qOOrD42XsDsY0nOoFYqDLW3WixP9
|
||||||
|
f1fWbcEf6+ktlvqi/1/3R6QtQR+6LS43enbsYHq8aAP60NrpXxdXxEoUwW6Z/sje
|
||||||
|
XAQluH8jzledwJcY8bXRskAHZlE4kGlOVuGgnyI3BXyLiwB4g9smFzYIs98iAGmV
|
||||||
|
7ZBaR5IIiRCtoKBG+SngM7Log0bHphvFPjDDvgqWYiWaOHboYM60Y2Z/gRbcjuMU
|
||||||
|
WZX64jw29fa8UPFdtGTupt+iuO7iXnHnm0lBBK36rVdOvsZup76p6L4BXmFsRmFK
|
||||||
|
qJ2Zd8uWNPDq80Am0mYaAqENuIANHHJXX38SesC+QO+G2JZt6vCwkGk/Qune4GIg
|
||||||
|
1GwhvsDRfTQopSxg1rdPwPM7HWeTfUGHZ34B5p/iILA3o6PfYQU8fNAWIsCDkRX2
|
||||||
|
MrgDgCnLZxKb6pjR4DYNAdPwkxyMFACZ2T46z6WvLWFlnkK5nbZoqsOsp+GJHole
|
||||||
|
llafhrelXEzt3zFR0q4zGcqheJDI+Wy+fBy3XawgAc4eN0T2UCzL/jKxKgzlzSU3
|
||||||
|
+xh1SDNjFLRd6sGzZHPMgXN0
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
|
@ -1,27 +1,52 @@
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
MIIEpQIBAAKCAQEA2uFoWm74qumqIIsBBf/rgP3ZtZw6dRQhVoYjIwYk00T1RLmm
|
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQC6JBnNM7eBFE+v
|
||||||
bt8rYNh3lehmnrQlM/YC3dzcspucGqIfvs5FEReh/vgvsqY3lfy47Q1zzdtBrKq2
|
pkfByYqqSheKD21oIKrHvZC9v228IuFAsTV0M9lXwj+vxvH6YzhjPevQebkvFMiE
|
||||||
ZBroAuJUe4ayMYz/L/2jAtPtGDQqWyzhKv6x/oz6N/tKqlzoGbjSGSJUqKAV+Tuo
|
Iz2nf9pu6IkBkQ0L9WTGAXMEaDsoYtIWbNT4DwW37aasqaPkykg8ELEN5WDzRMJA
|
||||||
4YI4xw3r/RJg3I3+ruXOgM65GBdja7usI/BhseEOp9VXotoTEItGmvG2RFZ4A7cN
|
4nKGP41Tc+kGj2fFODFY1Y7pf5mi9miF2nvx9gsu2ezyvGO6DcVXN0+usucG+KGQ
|
||||||
124xgiFl2IeYuC60jteZ+bnhPiqxcdzf3K4dnZlzrYma+FxwWbaow4wlpQcZVFdZ
|
aWqB8iaSH69nExOPU6C3HII6F1s7g6XiMJuftrnIjD6KLEc4SAFB9NCilE/vPU8R
|
||||||
+K/Yp/Bbm/FDKoUHnEdn/QAanTruRxSGdai0owIDAQABAoIBAQC4lzyQd+ITEbi+
|
RXZYjLZUQbO9AOWPY7LMfzpPUg4VXmvPkyN1m5bSo3N5LTDcnOCn+iVJshkuEYBo
|
||||||
dTxJuQj94hgHB1htgKqU888SLI5F9nP6n67y9hb5N9WygSp6UWbGqYTFYwxlPMKr
|
iTSA3vL1e9Ieqzus7TBb7jruJyjv64/VJwaA+AkDl8a7tqGnsXsbdlKgCoBxLrTB
|
||||||
22p2WjL5NTsTcm+XdIKQZW/3y06Mn4qFefsT9XURaZriCjihfU2BRaCCNARSUzwd
|
ixeRK2gDdFYC6qy17poKG/W2WBO35GGTyqMaG6HSeDapWdMbKjZPc4IcH9zjsFyy
|
||||||
ZH4I6n9mM7KaH71aa7v6ZVoahE9tXPR6hM+SHQEySW4pWkEu98VpNNeIt6vP7WF9
|
novGLJMKdAg8fd+HaI79ILuA/DeOKE8wIBBliWQLcyEyT3viufbOz1wq0ny5ucba
|
||||||
ONGbRa+0En4xgkuaxem2ZYa/GZFFtdQRkroNMhIRlfcPpkjy8DCc8E5RAkOzKC3O
|
bkVUVViZ25GpL9hBL87zTaNUIV1zwoOah4Bg24fOBFmNC/3TXxRR5beO1Yqeikmd
|
||||||
lnxQwt+tdNNkGZz02ed2hx/YHPwFYy76y6hK5dxq74iKIaOc8U5t0HjB1zVfwiR0
|
azlp72lu2Zh461zs6i87FPsnYBpV9SQdGGaWpZkzMQlNxnCzR9E9NkOJ8UnksVZt
|
||||||
5mcxMncxAoGBAP+RivwXZ4FcxDY1uyziF+rwlC/1RujQFEWXIxsXCnba5DH3yKul
|
mwLNbi0IoEq9gz14Cdtv5puIdeVjUwIDAQABAoICAQCZVVezw+BsAjFKPi1qIv2J
|
||||||
iKEIZPZtGhpsnQe367lcXcn7tztuoVjpAnk5L+hQY64tLwYbHeRcOMJ75C2y8FFC
|
HZOadO7pEc/czflHdUON8SWgxtmDqZpmQmt3/ugiHE284qs4hqzXbcVnpCgLrLRh
|
||||||
NeG5sQsrk3IU1+jhGvrbE7UgOeAuWJmv0M1vPNB/+hGoZBW5W5uU1x89AoGBANtA
|
HEiP887NhQ3IVjVK8hmZQR5SvsAIv0c0ph3gqbWKqF8sq4tOKR/eBUwHawJwODXR
|
||||||
AhLtAcqQ/Qh2SpVhLljh7U85Be9tbCGua09clkYFzh3bcoBolXKH18Veww0TP0yF
|
AvB4KPWQbqOny/P3wNbseRLNAJeNT+MSaw5XPnzgLKvdFoEbJeBNy847Sbsk5DaF
|
||||||
0748CKw1A+ITbTVFV+vKvi4jzIxS7mr4wYtVCMssbttQN7y3l30IDxJwa9j3zTJx
|
tHgm7n30WS1Q6bkU5VyP//hMBUKNJFaSL4TtCWB5qkbu8B5VbtsR9m0FizTb6L3h
|
||||||
IUn5OMMLv1JyitLId8HdOy1AdU3MkpJzdLyi1mFfAoGBAL3kL4fGABM/kU7SN6RO
|
VmYbUXvIzJXjAwMjiDJ1w9wHl+tj3BE33tEmhuVzNf+SH+tLc9xuKJighDWt2vpD
|
||||||
zgS0AvdrYOeljBp1BRGg2hab58g02vamxVEZgqMTR7zwjPDqOIz+03U7wda4Ccyd
|
eTpZ1qest26ANLOmNXWVCVTGpcWvOu5yhG/P7En10EzjFruMfHAFdwLm1gMx1rlR
|
||||||
PUhDNJSB/r6xNepshZZi642eLlnCRguqjYyNw72QADtYv2B6uehAlXEUY8xtw0lW
|
9fyNAk/0ROJ+5BUtuWgDiyytS5f2T9KGiOHni7UbBIkv0CV2H6VL39Twxf+3OHnx
|
||||||
OGgcSeyF2pH6M3tswWNlgT3lAoGAQ/BttBelOnP7NKgTLH7Usc4wjyAIaszpePZn
|
JJ7OWZ8DRuLM/EJfN3C1+3eDsXOvcdvbo2TFBmCCl4Pa2pm4k3g2NBfxy/zSYWIh
|
||||||
Ykw6dLBP0oixzoCZ7seRYSOgJWkVcEz39Db+KP60mVWTvbIjMHm+vOVy+Pip0JQM
|
ccGPZorFKNMUi29U0Ool6fxeVflbll570pWVBLAB31HdkLSESv9h+2j/IiEJcJXj
|
||||||
xXQwKWU3ZNZSrzPkyWW55ejYQn9nIn5T5mxH3ojBXHcJ9Y8RLQ20zKzwrI77zE3i
|
nzl2RtYB0Uxzk6SjO0z4WXjz/SXg5tQQkm/dx8kM8TvHICFq68AEnw8t9Hagsdxs
|
||||||
mqGK9NkCgYEAq3dzHI0DGAJrR19sWl2LcqI19sj5a91tHx4cl1dJXS/iApOLLieU
|
v5jNyOEeI1I5gPgZmKuboQKCAQEA7Hw6s8Xc3UtNaywMcK1Eb1O+kwRdztgtm0uE
|
||||||
zyUGkwfsqjHPAZ7GacICeBojIn/7KdPdlSKAbGVAU3d4qzvFS0qmWzObplBz3niT
|
uqsHWmGqbBxXN4jiVLh3dILIXFuVbvDSsSZtPLhOj1wqxgsTHg93b4BtvowyNBgo
|
||||||
Xnep2XLaVXqwlFJZZ6AHeKzYmMH0d0raiou2bpEUBqYizy2fi3NI4mA=
|
X4tErMu7/6NRael/hfOEdtpfv2gV+0eQa+8KKqYJPbqpMz/r5L/3RaxS3iXkj3QM
|
||||||
-----END RSA PRIVATE KEY-----
|
6oC4+cRuwy/flPMIpxhDriH5yjfiMOdDsi3ZfMTJu/58DTrKV7WkJxQZmha4EoZn
|
||||||
|
IiXeRhzo+2ukMDWrr3GGPyDfjd/NB7rmY8QBdmhB5NSk+6B66JCNTIbKka/pichS
|
||||||
|
36bwSYFNji4NaHUUlYDUjfKoTNuQMEZknMGhc/433ADO7s17iQKCAQEAyYBYVG7/
|
||||||
|
LE2IkvQy9Nwly5tRCNlSvSkloz7PUwRbzG5uF5mweWEa8YECJe9/vrFXvyBW+NR8
|
||||||
|
XABFn4eG0POTR9nyb4n2nUlqiGugDIPgkrKCkJws5InifITZ/+Viocd4YZL5UwCU
|
||||||
|
R1/kMf0UjK2iJjWEeTPS6RmwRI2Iu7kym9BzphDyNYBQSbUE/f+4hNP6nUT/h09c
|
||||||
|
VH4/sUhubSgVKeK4onOci8bKitAkwVBYCYSyhuBCeCu8fTk2hVRWviRaJPVq2PMB
|
||||||
|
LHw1FCcfJLIPJG6MZpFAPkMQxpiewdggXIgi46ZlZcsNXEJ81ocT4GU2j+ArQXCf
|
||||||
|
lgEycyD3mx4k+wKCAQBGneohmKoVYtEheavVUcgnvkggOqOQirlDsE9YNo4hjRyI
|
||||||
|
4AWjTbrYNaVmI0+VVLvQvxULVUA1a4v5/zm+nbv9s/ykTSN4TQEI0VXtAfdl6gif
|
||||||
|
k7NR/ynXZBpgK2GAFKLLwFj+Agl1JtOHnV+9MA9O5Yv/QDAWqhYQSEU7GWkjHGc+
|
||||||
|
3eLT5ablzrcXHooqunlOxSBP6qURPupGuv1sLewSOOllyfjDLJmW3o+ZgNlY8nUX
|
||||||
|
7tK+mqhD4ZCG9VgMU5I0BrmZfQQ6yXMz09PYV9mb7N5kxbNjwbXpMOqeYolKSdRQ
|
||||||
|
6quST7Pv2OKf6KAdI0txPvP4Y1HFA1rG1W71nGKRAoIBAHlDU+T8J3Rx9I77hu70
|
||||||
|
zYoKnmnE35YW/R+Q3RQIu3X7vyVUyG9DkQNlr/VEfIw2Dahnve9hcLWtNDkdRnTZ
|
||||||
|
IPlMoCmfzVo6pHIU0uy1MKEX7Js6YYnnsPVevhLR6NmTQU73NDRPVOzfOGUc+RDw
|
||||||
|
LXTxIBgQqAy/+ORIiNDwUxSSDgcSi7DG14qD9c0l59WH/HpI276Cc/4lPA9kl4/5
|
||||||
|
X0MlvheFm+BCcgG34Wa1A0Y3JXkl3NqU94oktDro1or3NYioaPTGyR4MYaUPJh7f
|
||||||
|
SV2TacsP/ql5ks7xahkeB9un0ddOfBcWa6PqH1a7U6rnPj63mVB4hpGvhrziSiB/
|
||||||
|
s6ECggEAOp2P4Yd9Vm9/CptxS50HFF4adyLscAtsDd3S2hIAXhDovcPbvRek4pLQ
|
||||||
|
idPhHlRAfqrEztnhaVAmCK9HlhgthtiQGQX62YI4CS4QL2IhzDFo3M1a2snjFEdl
|
||||||
|
QuFk3XI7kQ0Yp8BLLG7T436JUrUkCXc4gQX2uRNut+ff34RIR2CjcQQjChxuHVeG
|
||||||
|
sP/3xFFj8OSs7ZoSPbmDBLrMOl64YHwezQUNAZiRYiaGbFiY0QUV6dHq8qX/qE1h
|
||||||
|
a/0Rq+gTqObDST0TqhMzI8V/i7R8SwVcD5ODHaZp5I2N2P/hV5OWY7ghQXhh89WM
|
||||||
|
o21xtGh0nP2Fq1TC6jFO+9cpbK8jNA==
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
|
@ -16,6 +16,7 @@ use flate2::Compression;
|
||||||
use futures::stream::once;
|
use futures::stream::once;
|
||||||
use rand::{distributions::Alphanumeric, Rng};
|
use rand::{distributions::Alphanumeric, Rng};
|
||||||
|
|
||||||
|
use actix_connect::start_default_resolver;
|
||||||
use actix_web::middleware::{BodyEncoding, Compress};
|
use actix_web::middleware::{BodyEncoding, Compress};
|
||||||
use actix_web::{dev, http, test, web, App, HttpResponse, HttpServer};
|
use actix_web::{dev, http, test, web, App, HttpResponse, HttpServer};
|
||||||
|
|
||||||
|
@ -782,7 +783,7 @@ fn test_brotli_encoding_large() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_reading_deflate_encoding_large_random_ssl() {
|
fn test_reading_deflate_encoding_large_random_ssl() {
|
||||||
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
|
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
|
||||||
use rustls::internal::pemfile::{certs, rsa_private_keys};
|
use rustls::internal::pemfile::{certs, pkcs8_private_keys};
|
||||||
use rustls::{NoClientAuth, ServerConfig};
|
use rustls::{NoClientAuth, ServerConfig};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
@ -803,7 +804,7 @@ fn test_reading_deflate_encoding_large_random_ssl() {
|
||||||
let cert_file = &mut BufReader::new(File::open("tests/cert.pem").unwrap());
|
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 key_file = &mut BufReader::new(File::open("tests/key.pem").unwrap());
|
||||||
let cert_chain = certs(cert_file).unwrap();
|
let cert_chain = certs(cert_file).unwrap();
|
||||||
let mut keys = rsa_private_keys(key_file).unwrap();
|
let mut keys = pkcs8_private_keys(key_file).unwrap();
|
||||||
config.set_single_cert(cert_chain, keys.remove(0)).unwrap();
|
config.set_single_cert(cert_chain, keys.remove(0)).unwrap();
|
||||||
|
|
||||||
let srv = HttpServer::new(|| {
|
let srv = HttpServer::new(|| {
|
||||||
|
@ -823,6 +824,7 @@ fn test_reading_deflate_encoding_large_random_ssl() {
|
||||||
let _ = sys.run();
|
let _ = sys.run();
|
||||||
});
|
});
|
||||||
let (srv, _sys) = rx.recv().unwrap();
|
let (srv, _sys) = rx.recv().unwrap();
|
||||||
|
test::block_on(futures::lazy(|| Ok::<_, ()>(start_default_resolver()))).unwrap();
|
||||||
let client = test::run_on(|| {
|
let client = test::run_on(|| {
|
||||||
let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
|
let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
|
||||||
builder.set_verify(SslVerifyMode::NONE);
|
builder.set_verify(SslVerifyMode::NONE);
|
||||||
|
@ -844,19 +846,18 @@ fn test_reading_deflate_encoding_large_random_ssl() {
|
||||||
let enc = e.finish().unwrap();
|
let enc = e.finish().unwrap();
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let _req = client
|
let req = client
|
||||||
.post(format!("https://{}/", addr))
|
.post(format!("https://localhost:{}/", addr.port()))
|
||||||
.header(http::header::CONTENT_ENCODING, "deflate")
|
.header(http::header::CONTENT_ENCODING, "deflate")
|
||||||
.send_body(enc);
|
.send_body(enc);
|
||||||
|
|
||||||
// TODO: fix
|
let mut response = test::block_on(req).unwrap();
|
||||||
// let response = test::block_on(req).unwrap();
|
assert!(response.status().is_success());
|
||||||
// assert!(response.status().is_success());
|
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
// let bytes = test::block_on(response.body()).unwrap();
|
let bytes = test::block_on(response.body()).unwrap();
|
||||||
// assert_eq!(bytes.len(), data.len());
|
assert_eq!(bytes.len(), data.len());
|
||||||
// assert_eq!(bytes, Bytes::from(data));
|
assert_eq!(bytes, Bytes::from(data));
|
||||||
|
|
||||||
// stop
|
// stop
|
||||||
let _ = srv.stop(false);
|
let _ = srv.stop(false);
|
||||||
|
|
Loading…
Reference in a new issue