1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2025-04-04 09:09:35 +00:00
This commit is contained in:
Marat Safin 2019-07-29 08:53:16 +03:00
parent f387a8ceb8
commit 7f551e6217
18 changed files with 223 additions and 192 deletions

View file

@ -105,8 +105,9 @@ openssl = { version="0.10", optional = true }
rustls = { version = "0.15", optional = true }
[dev-dependencies]
actix = { version = "0.8.3" }
actix-http-test = { version = "0.2.4" }
actix = "0.8.3"
actix-connect = "0.2.2"
actix-http-test = "0.2.4"
rand = "0.7"
env_logger = "0.6"
serde_derive = "1.0"

View file

@ -30,6 +30,3 @@ mime = "0.3"
mime_guess = "2.0.0-alpha"
percent-encoding = "1.0"
v_htmlescape = "0.4"
[dev-dependencies]
actix-web = { version = "1.0.2", features=["ssl"] }

View file

@ -31,8 +31,6 @@ bytes = "0.4"
futures = "0.1.25"
log = "0.4"
[dev-dependencies]
actix-server = { version = "0.6.0", features=["ssl"] }
actix-connect = { version = "0.2.0", features=["ssl"] }
actix-http-test = { version = "0.2.4", features=["ssl"] }
actix-utils = "0.4.4"
# [dev-dependencies]
# actix-http-test = "0.2.4"
# actix-utils = "0.4.4"

View file

@ -45,8 +45,8 @@ fail = ["failure"]
secure-cookies = ["ring"]
# only for tests
dev-ssl = ["ssl", "actix-http-test/ssl", "actix-server/ssl"]
dev-rustls = ["rust-tls", "actix-http-test/rust-tls", "actix-server/rust-tls"]
# dev-ssl = ["ssl", "actix-http-test/ssl", "actix-server/ssl"]
# dev-rust-tls = ["rust-tls", "actix-http-test/rust-tls", "actix-server/rust-tls"]
[dependencies]
actix-service = "0.4.1"
@ -102,10 +102,10 @@ rustls = { version = "0.15.2", optional = true }
webpki-roots = { version = "0.16", optional = true }
chrono = "0.4.6"
[dev-dependencies]
actix-rt = "0.2.2"
actix-server = "0.6.0"
actix-http-test = "0.2.4"
env_logger = "0.6"
serde_derive = "1.0"
openssl = "0.10"
# [dev-dependencies]
# actix-rt = "0.2.2"
# actix-server = "0.6.0"
# actix-http-test = "0.2.4"
# env_logger = "0.6"
# serde_derive = "1.0"
# openssl = "0.10"

View file

@ -17,17 +17,22 @@ use super::pool::{ConnectionPool, Protocol};
use super::Connect;
#[cfg(feature = "ssl")]
use openssl::ssl::SslConnector;
use openssl::ssl::SslConnector as OpensslConnector;
#[cfg(feature = "rust-tls")]
use rustls::ClientConfig;
#[cfg(feature = "rust-tls")]
use std::sync::Arc;
#[cfg(feature = "rust-tls")]
type SslConnector = Arc<ClientConfig>;
#[cfg(any(feature = "ssl", feature = "rust-tls"))]
pub enum SslConnector {
#[cfg(feature = "ssl")]
Openssl(OpensslConnector),
#[cfg(feature = "rust-tls")]
Rustls(Arc<ClientConfig>),
}
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]
type SslConnector = ();
pub type SslConnector = ();
/// Manages http client network connectivity
/// The `Connector` type uses a builder-like combinator pattern for service
@ -53,6 +58,9 @@ pub struct Connector<T, U> {
_t: PhantomData<U>,
}
trait Io: AsyncRead + AsyncWrite {}
impl<T: AsyncRead + AsyncWrite> Io for T {}
impl Connector<(), ()> {
#[allow(clippy::new_ret_no_self)]
pub fn new() -> Connector<
@ -68,13 +76,13 @@ impl Connector<(), ()> {
{
use openssl::ssl::SslMethod;
let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap();
let mut ssl = OpensslConnector::builder(SslMethod::tls()).unwrap();
let _ = ssl
.set_alpn_protos(b"\x02h2\x08http/1.1")
.map_err(|e| error!("Can not set alpn protocol: {:?}", e));
ssl.build()
SslConnector::Openssl(ssl.build())
}
#[cfg(feature = "rust-tls")]
#[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();
@ -82,7 +90,7 @@ impl Connector<(), ()> {
config
.root_store
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
Arc::new(config)
SslConnector::Rustls(Arc::new(config))
}
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]
{}
@ -224,75 +232,15 @@ where
),
}
}
#[cfg(feature = "ssl")]
#[cfg(any(feature = "ssl", feature = "rust-tls"))]
{
const H2: &[u8] = b"h2";
#[cfg(feature = "ssl")]
use actix_connect::ssl::OpensslConnector;
let ssl_service = TimeoutService::new(
self.timeout,
apply_fn(self.connector.clone(), |msg: Connect, srv| {
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
})
.map_err(ConnectError::from)
.and_then(
OpensslConnector::service(self.ssl)
.map_err(ConnectError::from)
.map(|stream| {
let sock = stream.into_parts().0;
let h2 = sock
.get_ref()
.ssl()
.selected_alpn_protocol()
.map(|protos| protos.windows(2).any(|w| w == H2))
.unwrap_or(false);
if h2 {
(sock, Protocol::Http2)
} else {
(sock, Protocol::Http1)
}
}),
),
)
.map_err(|e| match e {
TimeoutError::Service(e) => e,
TimeoutError::Timeout => ConnectError::Timeout,
});
let tcp_service = TimeoutService::new(
self.timeout,
apply_fn(self.connector.clone(), |msg: Connect, srv| {
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
})
.map_err(ConnectError::from)
.map(|stream| (stream.into_parts().0, Protocol::Http1)),
)
.map_err(|e| match e {
TimeoutError::Service(e) => e,
TimeoutError::Timeout => ConnectError::Timeout,
});
connect_impl::InnerConnector {
tcp_pool: ConnectionPool::new(
tcp_service,
self.conn_lifetime,
self.conn_keep_alive,
None,
self.limit,
),
ssl_pool: ConnectionPool::new(
ssl_service,
self.conn_lifetime,
self.conn_keep_alive,
Some(self.disconnect_timeout),
self.limit,
),
}
}
#[cfg(feature = "rust-tls")]
{
const H2: &[u8] = b"h2";
#[cfg(feature = "rustls")]
use actix_connect::ssl::RustlsConnector;
use actix_service::boxed::service;
#[cfg(feature = "rustls")]
use rustls::Session;
let ssl_service = TimeoutService::new(
@ -301,24 +249,46 @@ where
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
})
.map_err(ConnectError::from)
.and_then(
RustlsConnector::service(self.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 {
(sock, Protocol::Http2)
} else {
(sock, Protocol::Http1)
}
}),
),
.and_then(match self.ssl {
#[cfg(feature = "ssl")]
SslConnector::Openssl(ssl) => service(
OpensslConnector::service(ssl)
.map_err(ConnectError::from)
.map(|stream| {
let sock = stream.into_parts().0;
let h2 = sock
.get_ref()
.ssl()
.selected_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)
}
}),
),
#[cfg(feature = "rustls")]
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 {
TimeoutError::Service(e) => e,
@ -355,6 +325,76 @@ where
),
}
}
// #[cfg(feature = "rust-tls")]
// {
// const H2: &[u8] = b"h2";
// use actix_connect::ssl::RustlsConnector;
// use rustls::Session;
// let ssl = match self.ssl {
// SslConnector::Rustls(ssl) => ssl,
// _ => unimplemented!(),
// };
// let ssl_service = TimeoutService::new(
// self.timeout,
// apply_fn(self.connector.clone(), |msg: Connect, srv| {
// srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
// })
// .map_err(ConnectError::from)
// .and_then(
// 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 {
// (sock, Protocol::Http2)
// } else {
// (sock, Protocol::Http1)
// }
// }),
// ),
// )
// .map_err(|e| match e {
// TimeoutError::Service(e) => e,
// TimeoutError::Timeout => ConnectError::Timeout,
// });
// let tcp_service = TimeoutService::new(
// self.timeout,
// apply_fn(self.connector.clone(), |msg: Connect, srv| {
// srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
// })
// .map_err(ConnectError::from)
// .map(|stream| (stream.into_parts().0, Protocol::Http1)),
// )
// .map_err(|e| match e {
// TimeoutError::Service(e) => e,
// TimeoutError::Timeout => ConnectError::Timeout,
// });
// connect_impl::InnerConnector {
// tcp_pool: ConnectionPool::new(
// tcp_service,
// self.conn_lifetime,
// self.conn_keep_alive,
// None,
// self.limit,
// ),
// ssl_pool: Some(ConnectionPool::new(
// ssl_service,
// self.conn_lifetime,
// self.conn_keep_alive,
// Some(self.disconnect_timeout),
// self.limit,
// )),
// }
// }
}
}

View file

@ -9,7 +9,7 @@ mod h2proto;
mod pool;
pub use self::connection::Connection;
pub use self::connector::Connector;
pub use self::connector::{Connector, SslConnector};
pub use self::error::{ConnectError, InvalidUrl, SendRequestError};
pub use self::pool::Protocol;

View file

@ -12,7 +12,7 @@ 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, NoClientAuth};
use rustls::NoClientAuth;
use std::fs::File;
use std::io::{BufReader, Result};
@ -29,22 +29,18 @@ where
}
fn ssl_acceptor<T: AsyncRead + AsyncWrite>() -> Result<RustlsAcceptor<T, ()>> {
use rustls::ServerConfig;
use rustls::{ServerConfig, internal::pemfile::{certs, pkcs8}};
// load ssl keys
let mut key_file = BufReader::new(File::open("tests/key.pem").expect("key file"));
let mut cert_file = BufReader::new(File::open("tests/cert.pem").expect("cert file"));
let key_der = pemfile::pkcs8_private_keys(&mut key_file)
.expect("key der")
.pop()
.expect("key not found");
let cert_chain = pemfile::certs(&mut cert_file).expect("cert chain");
let mut builder = ServerConfig::new(Arc::new(NoClientAuth));
builder
.set_single_cert(cert_chain, key_der)
.expect("set single cert");
let 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()];
builder.set_protocols(&protos);
Ok(RustlsAcceptor::new(builder))
config.set_protocols(&protos);
Ok(RustlsAcceptor::new(config))
}
#[test]
@ -182,9 +178,9 @@ fn test_h2_headers() {
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build().h2(move |_| {
let mut builder = Response::Ok();
let mut config = Response::Ok();
for idx in 0..90 {
builder.header(
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 \
@ -201,7 +197,7 @@ fn test_h2_headers() {
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
);
}
future::ok::<_, ()>(builder.body(data.clone()))
future::ok::<_, ()>(config.body(data.clone()))
}).map_err(|_| ()))
});

View file

@ -24,7 +24,6 @@ serde = "1.0"
serde_json = "1.0"
time = "0.1.42"
[dev-dependencies]
actix-rt = "0.2.2"
actix-http = "0.2.3"
bytes = "0.4"
# [dev-dependencies]
# actix-http = "0.2.3"
# bytes = "0.4"

View file

@ -29,6 +29,5 @@ mime = "0.3"
time = "0.1"
twoway = "0.2"
[dev-dependencies]
actix-rt = "0.2.2"
actix-http = "0.2.4"
# [dev-dependencies]
# actix-http = "0.2.4"

View file

@ -34,5 +34,5 @@ serde = "1.0"
serde_json = "1.0"
time = "0.1.42"
[dev-dependencies]
actix-rt = "0.2.2"
# [dev-dependencies]
# actix-rt = "0.2.2"

View file

@ -25,6 +25,6 @@ actix-codec = "0.1.2"
bytes = "0.4"
futures = "0.1.25"
[dev-dependencies]
env_logger = "0.6"
actix-http-test = { version = "0.2.4", features=["ssl"] }
# [dev-dependencies]
# env_logger = "0.6"
# actix-http-test = { version = "0.2.4", features=["ssl"] }

View file

@ -15,8 +15,8 @@ proc-macro = true
quote = "0.6.12"
syn = { version = "0.15.34", features = ["full", "parsing", "extra-traits"] }
[dev-dependencies]
actix-web = { version = "1.0.0" }
actix-http = { version = "0.2.4", features=["ssl"] }
actix-http-test = { version = "0.2.0", features=["ssl"] }
futures = { version = "0.1" }
# [dev-dependencies]
# actix-web = { version = "1.0.0" }
# actix-http = { version = "0.2.4", features=["ssl"] }
# actix-http-test = { version = "0.2.0", features=["ssl"] }
# futures = { version = "0.1" }

View file

@ -42,8 +42,8 @@ flate2-zlib = ["actix-http/flate2-zlib"]
flate2-rust = ["actix-http/flate2-rust"]
# only for tests
dev-ssl = ["ssl", "actix-http-test/ssl", "actix-server/ssl", "actix-http/ssl"]
dev-rustls = ["rust-tls", "actix-http-test/rust-tls", "actix-server/rust-tls", "actix-http/rust-tls"]
# dev-ssl = ["ssl", "actix-http-test/ssl", "actix-server/ssl", "actix-http/ssl"]
# dev-rust-tls = ["rust-tls", "actix-http-test/rust-tls", "actix-server/rust-tls", "actix-http/rust-tls"]
[dependencies]
actix-codec = "0.1.2"
@ -64,15 +64,15 @@ tokio-timer = "0.2.8"
openssl = { version="0.10", optional = true }
rustls = { version = "0.15.2", optional = true }
[dev-dependencies]
actix-rt = "0.2.2"
actix-web = "1.0.0"
actix-http-test = "0.2.0"
actix-utils = "0.4.1"
actix-server = "0.5.1"
brotli2 = "0.3.2"
flate2 = "1.0.2"
env_logger = "0.6"
rand = "0.7"
tokio-tcp = "0.1"
webpki = "0.19"
# [dev-dependencies]
# actix-rt = "0.2.2"
# actix-web = "1.0.0"
# actix-http-test = "0.2.0"
# actix-utils = "0.4.1"
# actix-server = "0.5.1"
# brotli2 = "0.3.2"
# flate2 = "1.0.2"
# env_logger = "0.6"
# rand = "0.7"
# tokio-tcp = "0.1"
# webpki = "0.19"

View file

@ -15,23 +15,17 @@ use actix_web::http::Version;
use actix_web::{web, App, HttpResponse};
fn ssl_acceptor<T: AsyncRead + AsyncWrite>() -> Result<RustlsAcceptor<T, ()>> {
use rustls::ServerConfig;
use rustls::{ServerConfig, internal::pemfile::{certs, pkcs8}};
// load ssl keys
let mut key_file = BufReader::new(File::open("../tests/key.pem").expect("key file"));
let mut cert_file =
BufReader::new(File::open("../tests/cert.pem").expect("cert file"));
let key_der = pemfile::pkcs8_private_keys(&mut key_file)
.expect("key der")
.pop()
.expect("key not found");
let cert_chain = pemfile::certs(&mut cert_file).expect("cert chain");
let mut builder = ServerConfig::new(Arc::new(NoClientAuth));
builder
.set_single_cert(cert_chain, key_der)
.expect("set single cert");
let 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()];
builder.set_protocols(&protos);
Ok(RustlsAcceptor::new(builder))
config.set_protocols(&protos);
Ok(RustlsAcceptor::new(config))
}
mod danger {

View file

@ -27,8 +27,8 @@ path = "src/lib.rs"
default = []
# openssl
ssl = ["openssl", "actix-server/ssl", "awc/ssl"]
rust-tls = ["rustls", "webpki", "actix-server/rust-tls", "awc/rust-tls"]
ssl = ["openssl", "actix-server/ssl", "awc/ssl", "actix-http/ssl"]
rust-tls = ["rustls", "webpki", "actix-server/rust-tls", "awc/rust-tls", "actix-http/rust-tls"]
[dependencies]
actix-codec = "0.1.2"
@ -37,6 +37,7 @@ actix-rt = "0.2.2"
actix-service = "0.4.1"
actix-server = "0.6.0"
actix-utils = "0.4.1"
actix-http = "0.2.7"
awc = "0.2.2"
base64 = "0.10"

View file

@ -154,6 +154,7 @@ impl TestServer {
let connector = {
#[cfg(feature = "ssl")]
{
use actix_http::client::SslConnector::Openssl;
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
let mut builder =
@ -165,11 +166,12 @@ impl TestServer {
Connector::new()
.conn_lifetime(time::Duration::from_secs(0))
.timeout(time::Duration::from_millis(500))
.ssl(builder.build())
.ssl(Openssl(builder.build()))
.finish()
}
#[cfg(feature = "rust-tls")]
#[cfg(all(not(feature = "ssl"), feature = "rust-tls"))]
{
use actix_http::client::SslConnector::Rustls;
use rustls::ClientConfig;
use std::sync::Arc;
@ -183,7 +185,7 @@ impl TestServer {
Connector::new()
.conn_lifetime(time::Duration::from_secs(0))
.timeout(time::Duration::from_millis(500))
.ssl(Arc::new(config))
.ssl(Rustls(Arc::new(config)))
.finish()
}
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]

View file

@ -124,6 +124,7 @@ fn test_start_ssl() {
let client = test::run_on(|| {
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
use actix_http::client::SslConnector::Openssl;
let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
builder.set_verify(SslVerifyMode::NONE);
let _ = builder
@ -134,7 +135,7 @@ fn test_start_ssl() {
awc::Client::build()
.connector(
awc::Connector::new()
.ssl(builder.build())
.ssl(Openssl(builder.build()))
.timeout(Duration::from_millis(100))
.finish(),
)

View file

@ -782,10 +782,11 @@ fn test_brotli_encoding_large() {
#[test]
fn test_reading_deflate_encoding_large_random_ssl() {
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 std::fs::File;
use std::io::BufReader;
use actix_http::client::SslConnector::Openssl;
let addr = TestServer::unused_addr();
let (tx, rx) = mpsc::channel();
@ -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 key_file = &mut BufReader::new(File::open("tests/key.pem").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();
let srv = HttpServer::new(|| {
@ -823,6 +824,9 @@ fn test_reading_deflate_encoding_large_random_ssl() {
let _ = sys.run();
});
let (srv, _sys) = rx.recv().unwrap();
test::block_on(futures::lazy(
|| Ok::<_, ()>(actix_connect::start_default_resolver()),
)).unwrap();
let client = test::run_on(|| {
let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
builder.set_verify(SslVerifyMode::NONE);
@ -832,7 +836,7 @@ fn test_reading_deflate_encoding_large_random_ssl() {
.connector(
awc::Connector::new()
.timeout(std::time::Duration::from_millis(500))
.ssl(builder.build())
.ssl(Openssl(builder.build()))
.finish(),
)
.finish()
@ -844,19 +848,18 @@ fn test_reading_deflate_encoding_large_random_ssl() {
let enc = e.finish().unwrap();
// client request
let _req = client
.post(format!("https://{}/", addr))
let req = client
.post(format!("https://localhost:{}/", addr.port()))
.header(http::header::CONTENT_ENCODING, "deflate")
.send_body(enc);
// TODO: fix
// let response = test::block_on(req).unwrap();
// assert!(response.status().is_success());
let mut response = test::block_on(req).unwrap();
assert!(response.status().is_success());
// read response
// let bytes = test::block_on(response.body()).unwrap();
// assert_eq!(bytes.len(), data.len());
// assert_eq!(bytes, Bytes::from(data));
let bytes = test::block_on(response.body()).unwrap();
assert_eq!(bytes.len(), data.len());
assert_eq!(bytes, Bytes::from(data));
// stop
let _ = srv.stop(false);