mirror of
https://github.com/actix/actix-extras.git
synced 2024-12-02 19:12:24 +01:00
refactor ssl support
This commit is contained in:
parent
036cf5e867
commit
f3f1e04853
@ -4,9 +4,12 @@
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
* Added `HttpServer::max_connections()` and `HttpServer::max_sslrate()`,
|
* Added `HttpServer::maxconn()` and `HttpServer::maxconnrate()`,
|
||||||
accept backpressure #250
|
accept backpressure #250
|
||||||
|
|
||||||
|
* Allow to customize connection handshake process via `HttpServer::listen_with()`
|
||||||
|
and `HttpServer::bind_with()` methods
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
* Use zlib instead of raw deflate for decoding and encoding payloads with
|
* Use zlib instead of raw deflate for decoding and encoding payloads with
|
||||||
|
@ -9,8 +9,8 @@ use tokio_timer::Delay;
|
|||||||
|
|
||||||
use actix::{msgs::Execute, Arbiter, System};
|
use actix::{msgs::Execute, Arbiter, System};
|
||||||
|
|
||||||
use super::srv::{ServerCommand, Socket};
|
use super::srv::ServerCommand;
|
||||||
use super::worker::{Conn, WorkerClient};
|
use super::worker::{Conn, Socket, Token, WorkerClient};
|
||||||
|
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
Pause,
|
Pause,
|
||||||
@ -21,7 +21,7 @@ pub(crate) enum Command {
|
|||||||
|
|
||||||
struct ServerSocketInfo {
|
struct ServerSocketInfo {
|
||||||
addr: net::SocketAddr,
|
addr: net::SocketAddr,
|
||||||
token: usize,
|
token: Token,
|
||||||
sock: mio::net::TcpListener,
|
sock: mio::net::TcpListener,
|
||||||
timeout: Option<Instant>,
|
timeout: Option<Instant>,
|
||||||
}
|
}
|
||||||
@ -31,20 +31,24 @@ pub(crate) struct AcceptNotify {
|
|||||||
ready: mio::SetReadiness,
|
ready: mio::SetReadiness,
|
||||||
maxconn: usize,
|
maxconn: usize,
|
||||||
maxconn_low: usize,
|
maxconn_low: usize,
|
||||||
maxsslrate: usize,
|
maxconnrate: usize,
|
||||||
maxsslrate_low: usize,
|
maxconnrate_low: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AcceptNotify {
|
impl AcceptNotify {
|
||||||
pub fn new(ready: mio::SetReadiness, maxconn: usize, maxsslrate: usize) -> Self {
|
pub fn new(ready: mio::SetReadiness, maxconn: usize, maxconnrate: usize) -> Self {
|
||||||
let maxconn_low = if maxconn > 10 { maxconn - 10 } else { 0 };
|
let maxconn_low = if maxconn > 10 { maxconn - 10 } else { 0 };
|
||||||
let maxsslrate_low = if maxsslrate > 10 { maxsslrate - 10 } else { 0 };
|
let maxconnrate_low = if maxconnrate > 10 {
|
||||||
|
maxconnrate - 10
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
AcceptNotify {
|
AcceptNotify {
|
||||||
ready,
|
ready,
|
||||||
maxconn,
|
maxconn,
|
||||||
maxconn_low,
|
maxconn_low,
|
||||||
maxsslrate,
|
maxconnrate,
|
||||||
maxsslrate_low,
|
maxconnrate_low,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,8 +57,8 @@ impl AcceptNotify {
|
|||||||
let _ = self.ready.set_readiness(mio::Ready::readable());
|
let _ = self.ready.set_readiness(mio::Ready::readable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn notify_maxsslrate(&self, sslrate: usize) {
|
pub fn notify_maxconnrate(&self, connrate: usize) {
|
||||||
if sslrate > self.maxsslrate_low && sslrate <= self.maxsslrate {
|
if connrate > self.maxconnrate_low && connrate <= self.maxconnrate {
|
||||||
let _ = self.ready.set_readiness(mio::Ready::readable());
|
let _ = self.ready.set_readiness(mio::Ready::readable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,7 +82,7 @@ pub(crate) struct AcceptLoop {
|
|||||||
mpsc::UnboundedReceiver<ServerCommand>,
|
mpsc::UnboundedReceiver<ServerCommand>,
|
||||||
)>,
|
)>,
|
||||||
maxconn: usize,
|
maxconn: usize,
|
||||||
maxsslrate: usize,
|
maxconnrate: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AcceptLoop {
|
impl AcceptLoop {
|
||||||
@ -94,7 +98,7 @@ impl AcceptLoop {
|
|||||||
notify_ready,
|
notify_ready,
|
||||||
notify_reg: Some(notify_reg),
|
notify_reg: Some(notify_reg),
|
||||||
maxconn: 102_400,
|
maxconn: 102_400,
|
||||||
maxsslrate: 256,
|
maxconnrate: 256,
|
||||||
rx: Some(rx),
|
rx: Some(rx),
|
||||||
srv: Some(mpsc::unbounded()),
|
srv: Some(mpsc::unbounded()),
|
||||||
}
|
}
|
||||||
@ -106,19 +110,19 @@ impl AcceptLoop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_notify(&self) -> AcceptNotify {
|
pub fn get_notify(&self) -> AcceptNotify {
|
||||||
AcceptNotify::new(self.notify_ready.clone(), self.maxconn, self.maxsslrate)
|
AcceptNotify::new(self.notify_ready.clone(), self.maxconn, self.maxconnrate)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_connections(&mut self, num: usize) {
|
pub fn maxconn(&mut self, num: usize) {
|
||||||
self.maxconn = num;
|
self.maxconn = num;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_sslrate(&mut self, num: usize) {
|
pub fn maxconnrate(&mut self, num: usize) {
|
||||||
self.maxsslrate = num;
|
self.maxconnrate = num;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn start(
|
pub(crate) fn start(
|
||||||
&mut self, socks: Vec<(usize, Socket)>, workers: Vec<WorkerClient>,
|
&mut self, socks: Vec<Socket>, workers: Vec<WorkerClient>,
|
||||||
) -> mpsc::UnboundedReceiver<ServerCommand> {
|
) -> mpsc::UnboundedReceiver<ServerCommand> {
|
||||||
let (tx, rx) = self.srv.take().expect("Can not re-use AcceptInfo");
|
let (tx, rx) = self.srv.take().expect("Can not re-use AcceptInfo");
|
||||||
|
|
||||||
@ -127,7 +131,7 @@ impl AcceptLoop {
|
|||||||
self.cmd_reg.take().expect("Can not re-use AcceptInfo"),
|
self.cmd_reg.take().expect("Can not re-use AcceptInfo"),
|
||||||
self.notify_reg.take().expect("Can not re-use AcceptInfo"),
|
self.notify_reg.take().expect("Can not re-use AcceptInfo"),
|
||||||
self.maxconn,
|
self.maxconn,
|
||||||
self.maxsslrate,
|
self.maxconnrate,
|
||||||
socks,
|
socks,
|
||||||
tx,
|
tx,
|
||||||
workers,
|
workers,
|
||||||
@ -145,7 +149,7 @@ struct Accept {
|
|||||||
timer: (mio::Registration, mio::SetReadiness),
|
timer: (mio::Registration, mio::SetReadiness),
|
||||||
next: usize,
|
next: usize,
|
||||||
maxconn: usize,
|
maxconn: usize,
|
||||||
maxsslrate: usize,
|
maxconnrate: usize,
|
||||||
backpressure: bool,
|
backpressure: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,8 +175,8 @@ impl Accept {
|
|||||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||||
pub(crate) fn start(
|
pub(crate) fn start(
|
||||||
rx: sync_mpsc::Receiver<Command>, cmd_reg: mio::Registration,
|
rx: sync_mpsc::Receiver<Command>, cmd_reg: mio::Registration,
|
||||||
notify_reg: mio::Registration, maxconn: usize, maxsslrate: usize,
|
notify_reg: mio::Registration, maxconn: usize, maxconnrate: usize,
|
||||||
socks: Vec<(usize, Socket)>, srv: mpsc::UnboundedSender<ServerCommand>,
|
socks: Vec<Socket>, srv: mpsc::UnboundedSender<ServerCommand>,
|
||||||
workers: Vec<WorkerClient>,
|
workers: Vec<WorkerClient>,
|
||||||
) {
|
) {
|
||||||
let sys = System::current();
|
let sys = System::current();
|
||||||
@ -184,7 +188,7 @@ impl Accept {
|
|||||||
System::set_current(sys);
|
System::set_current(sys);
|
||||||
let mut accept = Accept::new(rx, socks, workers, srv);
|
let mut accept = Accept::new(rx, socks, workers, srv);
|
||||||
accept.maxconn = maxconn;
|
accept.maxconn = maxconn;
|
||||||
accept.maxsslrate = maxsslrate;
|
accept.maxconnrate = maxconnrate;
|
||||||
|
|
||||||
// Start listening for incoming commands
|
// Start listening for incoming commands
|
||||||
if let Err(err) = accept.poll.register(
|
if let Err(err) = accept.poll.register(
|
||||||
@ -211,7 +215,7 @@ impl Accept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
rx: sync_mpsc::Receiver<Command>, socks: Vec<(usize, Socket)>,
|
rx: sync_mpsc::Receiver<Command>, socks: Vec<Socket>,
|
||||||
workers: Vec<WorkerClient>, srv: mpsc::UnboundedSender<ServerCommand>,
|
workers: Vec<WorkerClient>, srv: mpsc::UnboundedSender<ServerCommand>,
|
||||||
) -> Accept {
|
) -> Accept {
|
||||||
// Create a poll instance
|
// Create a poll instance
|
||||||
@ -222,7 +226,7 @@ impl Accept {
|
|||||||
|
|
||||||
// Start accept
|
// Start accept
|
||||||
let mut sockets = Slab::new();
|
let mut sockets = Slab::new();
|
||||||
for (stoken, sock) in socks {
|
for sock in socks {
|
||||||
let server = mio::net::TcpListener::from_std(sock.lst)
|
let server = mio::net::TcpListener::from_std(sock.lst)
|
||||||
.expect("Can not create mio::net::TcpListener");
|
.expect("Can not create mio::net::TcpListener");
|
||||||
|
|
||||||
@ -240,7 +244,7 @@ impl Accept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entry.insert(ServerSocketInfo {
|
entry.insert(ServerSocketInfo {
|
||||||
token: stoken,
|
token: sock.token,
|
||||||
addr: sock.addr,
|
addr: sock.addr,
|
||||||
sock: server,
|
sock: server,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
@ -264,7 +268,7 @@ impl Accept {
|
|||||||
next: 0,
|
next: 0,
|
||||||
timer: (tm, tmr),
|
timer: (tm, tmr),
|
||||||
maxconn: 102_400,
|
maxconn: 102_400,
|
||||||
maxsslrate: 256,
|
maxconnrate: 256,
|
||||||
backpressure: false,
|
backpressure: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -427,7 +431,7 @@ impl Accept {
|
|||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
while idx < self.workers.len() {
|
while idx < self.workers.len() {
|
||||||
idx += 1;
|
idx += 1;
|
||||||
if self.workers[self.next].available(self.maxconn, self.maxsslrate) {
|
if self.workers[self.next].available(self.maxconn, self.maxconnrate) {
|
||||||
match self.workers[self.next].send(msg) {
|
match self.workers[self.next].send(msg) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.next = (self.next + 1) % self.workers.len();
|
self.next = (self.next + 1) % self.workers.len();
|
||||||
|
@ -375,7 +375,7 @@ where
|
|||||||
self.keepalive_timer.take();
|
self.keepalive_timer.take();
|
||||||
|
|
||||||
// search handler for request
|
// search handler for request
|
||||||
for h in self.settings.handlers().iter_mut() {
|
for h in self.settings.handlers().iter() {
|
||||||
msg = match h.handle(msg) {
|
msg = match h.handle(msg) {
|
||||||
Ok(mut pipe) => {
|
Ok(mut pipe) => {
|
||||||
if self.tasks.is_empty() {
|
if self.tasks.is_empty() {
|
||||||
|
@ -347,7 +347,7 @@ impl<H: HttpHandler + 'static> Entry<H> {
|
|||||||
|
|
||||||
// start request processing
|
// start request processing
|
||||||
let mut task = None;
|
let mut task = None;
|
||||||
for h in settings.handlers().iter_mut() {
|
for h in settings.handlers().iter() {
|
||||||
msg = match h.handle(msg) {
|
msg = match h.handle(msg) {
|
||||||
Ok(t) => {
|
Ok(t) => {
|
||||||
task = Some(t);
|
task = Some(t);
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
//! Http server
|
//! Http server
|
||||||
use std::net::Shutdown;
|
use std::net::Shutdown;
|
||||||
use std::{io, time};
|
use std::{io, net, time};
|
||||||
|
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use futures::{Async, Poll};
|
use futures::{Async, Future, Poll};
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
use tokio_reactor::Handle;
|
||||||
use tokio_tcp::TcpStream;
|
use tokio_tcp::TcpStream;
|
||||||
|
|
||||||
pub(crate) mod accept;
|
pub(crate) mod accept;
|
||||||
@ -21,11 +22,13 @@ pub(crate) mod message;
|
|||||||
pub(crate) mod output;
|
pub(crate) mod output;
|
||||||
pub(crate) mod settings;
|
pub(crate) mod settings;
|
||||||
mod srv;
|
mod srv;
|
||||||
|
mod ssl;
|
||||||
mod worker;
|
mod worker;
|
||||||
|
|
||||||
pub use self::message::Request;
|
pub use self::message::Request;
|
||||||
pub use self::settings::ServerSettings;
|
pub use self::settings::ServerSettings;
|
||||||
pub use self::srv::HttpServer;
|
pub use self::srv::HttpServer;
|
||||||
|
pub use self::ssl::*;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use self::helpers::write_content_length;
|
pub use self::helpers::write_content_length;
|
||||||
@ -72,6 +75,13 @@ where
|
|||||||
HttpServer::new(factory)
|
HttpServer::new(factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct ServerFlags: u8 {
|
||||||
|
const HTTP1 = 0b0000_0001;
|
||||||
|
const HTTP2 = 0b0000_0010;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
/// Server keep-alive setting
|
/// Server keep-alive setting
|
||||||
pub enum KeepAlive {
|
pub enum KeepAlive {
|
||||||
@ -179,6 +189,34 @@ impl<T: HttpHandler> IntoHttpHandler for T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) trait IntoAsyncIo {
|
||||||
|
type Io: AsyncRead + AsyncWrite;
|
||||||
|
|
||||||
|
fn into_async_io(self) -> Result<Self::Io, io::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoAsyncIo for net::TcpStream {
|
||||||
|
type Io = TcpStream;
|
||||||
|
|
||||||
|
fn into_async_io(self) -> Result<Self::Io, io::Error> {
|
||||||
|
TcpStream::from_std(self, &Handle::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait implemented by types that could accept incomming socket connections.
|
||||||
|
pub trait AcceptorService<Io: AsyncRead + AsyncWrite>: Clone {
|
||||||
|
/// Established connection type
|
||||||
|
type Accepted: IoStream;
|
||||||
|
/// Future describes async accept process.
|
||||||
|
type Future: Future<Item = Self::Accepted, Error = io::Error> + 'static;
|
||||||
|
|
||||||
|
/// Establish new connection
|
||||||
|
fn accept(&self, io: Io) -> Self::Future;
|
||||||
|
|
||||||
|
/// Scheme
|
||||||
|
fn scheme(&self) -> &'static str;
|
||||||
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum WriterState {
|
pub enum WriterState {
|
||||||
@ -267,90 +305,3 @@ impl IoStream for TcpStream {
|
|||||||
TcpStream::set_linger(self, dur)
|
TcpStream::set_linger(self, dur)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alpn")]
|
|
||||||
use tokio_openssl::SslStream;
|
|
||||||
|
|
||||||
#[cfg(feature = "alpn")]
|
|
||||||
impl IoStream for SslStream<TcpStream> {
|
|
||||||
#[inline]
|
|
||||||
fn shutdown(&mut self, _how: Shutdown) -> io::Result<()> {
|
|
||||||
let _ = self.get_mut().shutdown();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
|
|
||||||
self.get_mut().get_mut().set_nodelay(nodelay)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
|
|
||||||
self.get_mut().get_mut().set_linger(dur)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
|
||||||
use tokio_tls::TlsStream;
|
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
|
||||||
impl IoStream for TlsStream<TcpStream> {
|
|
||||||
#[inline]
|
|
||||||
fn shutdown(&mut self, _how: Shutdown) -> io::Result<()> {
|
|
||||||
let _ = self.get_mut().shutdown();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
|
|
||||||
self.get_mut().get_mut().set_nodelay(nodelay)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
|
|
||||||
self.get_mut().get_mut().set_linger(dur)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
use rustls::{ClientSession, ServerSession};
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
use tokio_rustls::TlsStream as RustlsStream;
|
|
||||||
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
impl IoStream for RustlsStream<TcpStream, ClientSession> {
|
|
||||||
#[inline]
|
|
||||||
fn shutdown(&mut self, _how: Shutdown) -> io::Result<()> {
|
|
||||||
let _ = <Self as AsyncWrite>::shutdown(self);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
|
|
||||||
self.get_mut().0.set_nodelay(nodelay)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
|
|
||||||
self.get_mut().0.set_linger(dur)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
impl IoStream for RustlsStream<TcpStream, ServerSession> {
|
|
||||||
#[inline]
|
|
||||||
fn shutdown(&mut self, _how: Shutdown) -> io::Result<()> {
|
|
||||||
let _ = <Self as AsyncWrite>::shutdown(self);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
|
|
||||||
self.get_mut().0.set_nodelay(nodelay)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
|
|
||||||
self.get_mut().0.set_linger(dur)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -132,7 +132,7 @@ impl ServerSettings {
|
|||||||
const DATE_VALUE_LENGTH: usize = 29;
|
const DATE_VALUE_LENGTH: usize = 29;
|
||||||
|
|
||||||
pub(crate) struct WorkerSettings<H> {
|
pub(crate) struct WorkerSettings<H> {
|
||||||
h: RefCell<Vec<H>>,
|
h: Vec<H>,
|
||||||
keep_alive: u64,
|
keep_alive: u64,
|
||||||
ka_enabled: bool,
|
ka_enabled: bool,
|
||||||
bytes: Rc<SharedBytesPool>,
|
bytes: Rc<SharedBytesPool>,
|
||||||
@ -140,14 +140,14 @@ pub(crate) struct WorkerSettings<H> {
|
|||||||
channels: Arc<AtomicUsize>,
|
channels: Arc<AtomicUsize>,
|
||||||
node: RefCell<Node<()>>,
|
node: RefCell<Node<()>>,
|
||||||
date: UnsafeCell<Date>,
|
date: UnsafeCell<Date>,
|
||||||
sslrate: Arc<AtomicUsize>,
|
connrate: Arc<AtomicUsize>,
|
||||||
notify: AcceptNotify,
|
notify: AcceptNotify,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H> WorkerSettings<H> {
|
impl<H> WorkerSettings<H> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
h: Vec<H>, keep_alive: KeepAlive, settings: ServerSettings,
|
h: Vec<H>, keep_alive: KeepAlive, settings: ServerSettings,
|
||||||
notify: AcceptNotify, channels: Arc<AtomicUsize>, sslrate: Arc<AtomicUsize>,
|
notify: AcceptNotify, channels: Arc<AtomicUsize>, connrate: Arc<AtomicUsize>,
|
||||||
) -> WorkerSettings<H> {
|
) -> WorkerSettings<H> {
|
||||||
let (keep_alive, ka_enabled) = match keep_alive {
|
let (keep_alive, ka_enabled) = match keep_alive {
|
||||||
KeepAlive::Timeout(val) => (val as u64, true),
|
KeepAlive::Timeout(val) => (val as u64, true),
|
||||||
@ -156,7 +156,7 @@ impl<H> WorkerSettings<H> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
WorkerSettings {
|
WorkerSettings {
|
||||||
h: RefCell::new(h),
|
h,
|
||||||
bytes: Rc::new(SharedBytesPool::new()),
|
bytes: Rc::new(SharedBytesPool::new()),
|
||||||
messages: RequestPool::pool(settings),
|
messages: RequestPool::pool(settings),
|
||||||
node: RefCell::new(Node::head()),
|
node: RefCell::new(Node::head()),
|
||||||
@ -164,7 +164,7 @@ impl<H> WorkerSettings<H> {
|
|||||||
keep_alive,
|
keep_alive,
|
||||||
ka_enabled,
|
ka_enabled,
|
||||||
channels,
|
channels,
|
||||||
sslrate,
|
connrate,
|
||||||
notify,
|
notify,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,8 +177,8 @@ impl<H> WorkerSettings<H> {
|
|||||||
self.node.borrow_mut()
|
self.node.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handlers(&self) -> RefMut<Vec<H>> {
|
pub fn handlers(&self) -> &Vec<H> {
|
||||||
self.h.borrow_mut()
|
&self.h
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keep_alive(&self) -> u64 {
|
pub fn keep_alive(&self) -> u64 {
|
||||||
@ -230,13 +230,13 @@ impl<H> WorkerSettings<H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn ssl_conn_add(&self) {
|
pub(crate) fn conn_rate_add(&self) {
|
||||||
self.sslrate.fetch_add(1, Ordering::Relaxed);
|
self.connrate.fetch_add(1, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn ssl_conn_del(&self) {
|
pub(crate) fn conn_rate_del(&self) {
|
||||||
let val = self.sslrate.fetch_sub(1, Ordering::Relaxed);
|
let val = self.connrate.fetch_sub(1, Ordering::Relaxed);
|
||||||
self.notify.notify_maxsslrate(val);
|
self.notify.notify_maxconnrate(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,15 +10,15 @@ use actix::{
|
|||||||
|
|
||||||
use futures::sync::mpsc;
|
use futures::sync::mpsc;
|
||||||
use futures::{Future, Sink, Stream};
|
use futures::{Future, Sink, Stream};
|
||||||
use net2::TcpBuilder;
|
|
||||||
use num_cpus;
|
use num_cpus;
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
use tokio_tcp::TcpStream;
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
use native_tls::TlsAcceptor;
|
use native_tls::TlsAcceptor;
|
||||||
|
|
||||||
#[cfg(feature = "alpn")]
|
#[cfg(feature = "alpn")]
|
||||||
use openssl::ssl::{AlpnError, SslAcceptorBuilder};
|
use openssl::ssl::SslAcceptorBuilder;
|
||||||
|
|
||||||
#[cfg(feature = "rust-tls")]
|
#[cfg(feature = "rust-tls")]
|
||||||
use rustls::ServerConfig;
|
use rustls::ServerConfig;
|
||||||
@ -26,43 +26,25 @@ use rustls::ServerConfig;
|
|||||||
use super::accept::{AcceptLoop, AcceptNotify, Command};
|
use super::accept::{AcceptLoop, AcceptNotify, Command};
|
||||||
use super::channel::{HttpChannel, WrapperStream};
|
use super::channel::{HttpChannel, WrapperStream};
|
||||||
use super::settings::{ServerSettings, WorkerSettings};
|
use super::settings::{ServerSettings, WorkerSettings};
|
||||||
use super::worker::{
|
use super::worker::{Conn, StopWorker, Token, Worker, WorkerClient, WorkerFactory};
|
||||||
Conn, StopWorker, StreamHandlerType, Worker, WorkerClient, WorkersPool,
|
use super::{AcceptorService, IntoHttpHandler, IoStream, KeepAlive};
|
||||||
};
|
|
||||||
use super::{IntoHttpHandler, IoStream, KeepAlive};
|
|
||||||
use super::{PauseServer, ResumeServer, StopServer};
|
use super::{PauseServer, ResumeServer, StopServer};
|
||||||
|
|
||||||
#[cfg(feature = "alpn")]
|
|
||||||
fn configure_alpn(builder: &mut SslAcceptorBuilder) -> io::Result<()> {
|
|
||||||
builder.set_alpn_protos(b"\x02h2\x08http/1.1")?;
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An HTTP Server
|
/// An HTTP Server
|
||||||
pub struct HttpServer<H>
|
pub struct HttpServer<H>
|
||||||
where
|
where
|
||||||
H: IntoHttpHandler + 'static,
|
H: IntoHttpHandler + 'static,
|
||||||
{
|
{
|
||||||
h: Option<Rc<WorkerSettings<H::Handler>>>,
|
|
||||||
threads: usize,
|
threads: usize,
|
||||||
backlog: i32,
|
factory: WorkerFactory<H>,
|
||||||
sockets: Vec<Socket>,
|
workers: Vec<(usize, Addr<Worker>)>,
|
||||||
pool: WorkersPool<H>,
|
|
||||||
workers: Vec<(usize, Addr<Worker<H::Handler>>)>,
|
|
||||||
accept: AcceptLoop,
|
accept: AcceptLoop,
|
||||||
exit: bool,
|
exit: bool,
|
||||||
shutdown_timeout: u16,
|
shutdown_timeout: u16,
|
||||||
signals: Option<Addr<signal::ProcessSignals>>,
|
signals: Option<Addr<signal::ProcessSignals>>,
|
||||||
no_http2: bool,
|
no_http2: bool,
|
||||||
no_signals: bool,
|
no_signals: bool,
|
||||||
|
settings: Option<Rc<WorkerSettings<H::Handler>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum ServerCommand {
|
pub(crate) enum ServerCommand {
|
||||||
@ -76,12 +58,6 @@ where
|
|||||||
type Context = Context<Self>;
|
type Context = Context<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Socket {
|
|
||||||
pub lst: net::TcpListener,
|
|
||||||
pub addr: net::SocketAddr,
|
|
||||||
pub tp: StreamHandlerType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H> HttpServer<H>
|
impl<H> HttpServer<H>
|
||||||
where
|
where
|
||||||
H: IntoHttpHandler + 'static,
|
H: IntoHttpHandler + 'static,
|
||||||
@ -95,18 +71,16 @@ where
|
|||||||
let f = move || (factory)().into_iter().collect();
|
let f = move || (factory)().into_iter().collect();
|
||||||
|
|
||||||
HttpServer {
|
HttpServer {
|
||||||
h: None,
|
|
||||||
threads: num_cpus::get(),
|
threads: num_cpus::get(),
|
||||||
backlog: 2048,
|
factory: WorkerFactory::new(f),
|
||||||
pool: WorkersPool::new(f),
|
|
||||||
workers: Vec::new(),
|
workers: Vec::new(),
|
||||||
sockets: Vec::new(),
|
|
||||||
accept: AcceptLoop::new(),
|
accept: AcceptLoop::new(),
|
||||||
exit: false,
|
exit: false,
|
||||||
shutdown_timeout: 30,
|
shutdown_timeout: 30,
|
||||||
signals: None,
|
signals: None,
|
||||||
no_http2: false,
|
no_http2: false,
|
||||||
no_signals: false,
|
no_signals: false,
|
||||||
|
settings: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +104,7 @@ where
|
|||||||
///
|
///
|
||||||
/// This method should be called before `bind()` method call.
|
/// This method should be called before `bind()` method call.
|
||||||
pub fn backlog(mut self, num: i32) -> Self {
|
pub fn backlog(mut self, num: i32) -> Self {
|
||||||
self.backlog = num;
|
self.factory.backlog = num;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,20 +114,19 @@ where
|
|||||||
/// for each worker.
|
/// for each worker.
|
||||||
///
|
///
|
||||||
/// By default max connections is set to a 100k.
|
/// By default max connections is set to a 100k.
|
||||||
pub fn max_connections(mut self, num: usize) -> Self {
|
pub fn maxconn(mut self, num: usize) -> Self {
|
||||||
self.accept.max_connections(num);
|
self.accept.maxconn(num);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the maximum concurrent per-worker number of SSL handshakes.
|
/// Sets the maximum per-worker concurrent connection establish process.
|
||||||
///
|
///
|
||||||
/// All listeners will stop accepting connections when this limit is reached. It
|
/// All listeners will stop accepting connections when this limit is reached. It
|
||||||
/// can be used to limit the global SSL CPU usage regardless of each worker
|
/// can be used to limit the global SSL CPU usage.
|
||||||
/// capacity.
|
|
||||||
///
|
///
|
||||||
/// By default max connections is set to a 256.
|
/// By default max connections is set to a 256.
|
||||||
pub fn max_sslrate(mut self, num: usize) -> Self {
|
pub fn maxconnrate(mut self, num: usize) -> Self {
|
||||||
self.accept.max_sslrate(num);
|
self.accept.maxconnrate(num);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +134,7 @@ where
|
|||||||
///
|
///
|
||||||
/// By default keep alive is set to a `Os`.
|
/// By default keep alive is set to a `Os`.
|
||||||
pub fn keep_alive<T: Into<KeepAlive>>(mut self, val: T) -> Self {
|
pub fn keep_alive<T: Into<KeepAlive>>(mut self, val: T) -> Self {
|
||||||
self.pool.keep_alive = val.into();
|
self.factory.keep_alive = val.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +144,7 @@ where
|
|||||||
/// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo.
|
/// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo.
|
||||||
/// html#method.host) documentation for more information.
|
/// html#method.host) documentation for more information.
|
||||||
pub fn server_hostname(mut self, val: String) -> Self {
|
pub fn server_hostname(mut self, val: String) -> Self {
|
||||||
self.pool.host = Some(val);
|
self.factory.host = Some(val);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +188,7 @@ where
|
|||||||
|
|
||||||
/// Get addresses of bound sockets.
|
/// Get addresses of bound sockets.
|
||||||
pub fn addrs(&self) -> Vec<net::SocketAddr> {
|
pub fn addrs(&self) -> Vec<net::SocketAddr> {
|
||||||
self.sockets.iter().map(|s| s.addr).collect()
|
self.factory.addrs()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get addresses of bound sockets and the scheme for it.
|
/// Get addresses of bound sockets and the scheme for it.
|
||||||
@ -225,10 +198,7 @@ where
|
|||||||
/// and the user should be presented with an enumeration of which
|
/// and the user should be presented with an enumeration of which
|
||||||
/// socket requires which protocol.
|
/// socket requires which protocol.
|
||||||
pub fn addrs_with_scheme(&self) -> Vec<(net::SocketAddr, &str)> {
|
pub fn addrs_with_scheme(&self) -> Vec<(net::SocketAddr, &str)> {
|
||||||
self.sockets
|
self.factory.addrs_with_scheme()
|
||||||
.iter()
|
|
||||||
.map(|s| (s.addr, s.tp.scheme()))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use listener for accepting incoming connection requests
|
/// Use listener for accepting incoming connection requests
|
||||||
@ -236,175 +206,177 @@ where
|
|||||||
/// HttpServer does not change any configuration for TcpListener,
|
/// HttpServer does not change any configuration for TcpListener,
|
||||||
/// it needs to be configured before passing it to listen() method.
|
/// it needs to be configured before passing it to listen() method.
|
||||||
pub fn listen(mut self, lst: net::TcpListener) -> Self {
|
pub fn listen(mut self, lst: net::TcpListener) -> Self {
|
||||||
let addr = lst.local_addr().unwrap();
|
self.factory.listen(lst);
|
||||||
self.sockets.push(Socket {
|
|
||||||
addr,
|
|
||||||
lst,
|
|
||||||
tp: StreamHandlerType::Normal,
|
|
||||||
});
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Use listener for accepting incoming connection requests
|
||||||
|
pub fn listen_with<A>(
|
||||||
|
mut self, lst: net::TcpListener, acceptor: A,
|
||||||
|
) -> io::Result<Self>
|
||||||
|
where
|
||||||
|
A: AcceptorService<TcpStream> + Send + 'static,
|
||||||
|
{
|
||||||
|
self.factory.listen_with(lst, acceptor);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.7.4",
|
||||||
|
note = "please use `actix_web::HttpServer::listen_with()` and `actix_web::server::NativeTlsAcceptor` instead"
|
||||||
|
)]
|
||||||
/// Use listener for accepting incoming tls connection requests
|
/// Use listener for accepting incoming tls connection requests
|
||||||
///
|
///
|
||||||
/// HttpServer does not change any configuration for TcpListener,
|
/// HttpServer does not change any configuration for TcpListener,
|
||||||
/// it needs to be configured before passing it to listen() method.
|
/// it needs to be configured before passing it to listen() method.
|
||||||
pub fn listen_tls(mut self, lst: net::TcpListener, acceptor: TlsAcceptor) -> Self {
|
pub fn listen_tls(
|
||||||
let addr = lst.local_addr().unwrap();
|
self, lst: net::TcpListener, acceptor: TlsAcceptor,
|
||||||
self.sockets.push(Socket {
|
) -> io::Result<Self> {
|
||||||
addr,
|
use super::NativeTlsAcceptor;
|
||||||
lst,
|
|
||||||
tp: StreamHandlerType::Tls(acceptor.clone()),
|
self.listen_with(lst, NativeTlsAcceptor::new(acceptor))
|
||||||
});
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alpn")]
|
#[cfg(feature = "alpn")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.7.4",
|
||||||
|
note = "please use `actix_web::HttpServer::listen_with()` and `actix_web::server::OpensslAcceptor` instead"
|
||||||
|
)]
|
||||||
/// Use listener for accepting incoming tls connection requests
|
/// Use listener for accepting incoming tls connection requests
|
||||||
///
|
///
|
||||||
/// This method sets alpn protocols to "h2" and "http/1.1"
|
/// This method sets alpn protocols to "h2" and "http/1.1"
|
||||||
pub fn listen_ssl(
|
pub fn listen_ssl(
|
||||||
mut self, lst: net::TcpListener, mut builder: SslAcceptorBuilder,
|
self, lst: net::TcpListener, builder: SslAcceptorBuilder,
|
||||||
) -> io::Result<Self> {
|
) -> io::Result<Self> {
|
||||||
|
use super::{OpensslAcceptor, ServerFlags};
|
||||||
|
|
||||||
// alpn support
|
// alpn support
|
||||||
if !self.no_http2 {
|
let flags = if !self.no_http2 {
|
||||||
configure_alpn(&mut builder)?;
|
ServerFlags::HTTP1
|
||||||
}
|
} else {
|
||||||
let acceptor = builder.build();
|
ServerFlags::HTTP1 | ServerFlags::HTTP2
|
||||||
let addr = lst.local_addr().unwrap();
|
};
|
||||||
self.sockets.push(Socket {
|
|
||||||
addr,
|
self.listen_with(lst, OpensslAcceptor::with_flags(builder, flags)?)
|
||||||
lst,
|
|
||||||
tp: StreamHandlerType::Alpn(acceptor.clone()),
|
|
||||||
});
|
|
||||||
Ok(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rust-tls")]
|
#[cfg(feature = "rust-tls")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.7.4",
|
||||||
|
note = "please use `actix_web::HttpServer::listen_with()` and `actix_web::server::RustlsAcceptor` instead"
|
||||||
|
)]
|
||||||
/// Use listener for accepting incoming tls connection requests
|
/// Use listener for accepting incoming tls connection requests
|
||||||
///
|
///
|
||||||
/// This method sets alpn protocols to "h2" and "http/1.1"
|
/// This method sets alpn protocols to "h2" and "http/1.1"
|
||||||
pub fn listen_rustls(
|
pub fn listen_rustls(
|
||||||
mut self, lst: net::TcpListener, mut builder: ServerConfig,
|
self, lst: net::TcpListener, builder: ServerConfig,
|
||||||
) -> io::Result<Self> {
|
) -> io::Result<Self> {
|
||||||
|
use super::{RustlsAcceptor, ServerFlags};
|
||||||
|
|
||||||
// alpn support
|
// alpn support
|
||||||
if !self.no_http2 {
|
let flags = if !self.no_http2 {
|
||||||
builder.set_protocols(&vec!["h2".to_string(), "http/1.1".to_string()]);
|
ServerFlags::HTTP1
|
||||||
}
|
|
||||||
let addr = lst.local_addr().unwrap();
|
|
||||||
self.sockets.push(Socket {
|
|
||||||
addr,
|
|
||||||
lst,
|
|
||||||
tp: StreamHandlerType::Rustls(Arc::new(builder)),
|
|
||||||
});
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bind2<S: net::ToSocketAddrs>(&mut self, addr: S) -> io::Result<Vec<Socket>> {
|
|
||||||
let mut err = None;
|
|
||||||
let mut succ = false;
|
|
||||||
let mut sockets = Vec::new();
|
|
||||||
for addr in addr.to_socket_addrs()? {
|
|
||||||
match create_tcp_listener(addr, self.backlog) {
|
|
||||||
Ok(lst) => {
|
|
||||||
succ = true;
|
|
||||||
let addr = lst.local_addr().unwrap();
|
|
||||||
sockets.push(Socket {
|
|
||||||
lst,
|
|
||||||
addr,
|
|
||||||
tp: StreamHandlerType::Normal,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Err(e) => err = Some(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !succ {
|
|
||||||
if let Some(e) = err.take() {
|
|
||||||
Err(e)
|
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::new(
|
ServerFlags::HTTP1 | ServerFlags::HTTP2
|
||||||
io::ErrorKind::Other,
|
};
|
||||||
"Can not bind to address.",
|
|
||||||
))
|
self.listen_with(lst, RustlsAcceptor::with_flags(builder, flags))
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(sockets)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The socket address to bind
|
/// The socket address to bind
|
||||||
///
|
///
|
||||||
/// To bind multiple addresses this method can be called multiple times.
|
/// To bind multiple addresses this method can be called multiple times.
|
||||||
pub fn bind<S: net::ToSocketAddrs>(mut self, addr: S) -> io::Result<Self> {
|
pub fn bind<S: net::ToSocketAddrs>(mut self, addr: S) -> io::Result<Self> {
|
||||||
let sockets = self.bind2(addr)?;
|
self.factory.bind(addr)?;
|
||||||
self.sockets.extend(sockets);
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start listening for incoming connections with supplied acceptor.
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
|
||||||
|
pub fn bind_with<S, A>(mut self, addr: S, acceptor: A) -> io::Result<Self>
|
||||||
|
where
|
||||||
|
S: net::ToSocketAddrs,
|
||||||
|
A: AcceptorService<TcpStream> + Send + 'static,
|
||||||
|
{
|
||||||
|
self.factory.bind_with(addr, &acceptor)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.7.4",
|
||||||
|
note = "please use `actix_web::HttpServer::bind_with()` and `actix_web::server::NativeTlsAcceptor` instead"
|
||||||
|
)]
|
||||||
/// The ssl socket address to bind
|
/// The ssl socket address to bind
|
||||||
///
|
///
|
||||||
/// To bind multiple addresses this method can be called multiple times.
|
/// To bind multiple addresses this method can be called multiple times.
|
||||||
pub fn bind_tls<S: net::ToSocketAddrs>(
|
pub fn bind_tls<S: net::ToSocketAddrs>(
|
||||||
mut self, addr: S, acceptor: TlsAcceptor,
|
self, addr: S, acceptor: TlsAcceptor,
|
||||||
) -> io::Result<Self> {
|
) -> io::Result<Self> {
|
||||||
let sockets = self.bind2(addr)?;
|
use super::NativeTlsAcceptor;
|
||||||
self.sockets.extend(sockets.into_iter().map(|mut s| {
|
|
||||||
s.tp = StreamHandlerType::Tls(acceptor.clone());
|
self.bind_with(addr, NativeTlsAcceptor::new(acceptor))
|
||||||
s
|
|
||||||
}));
|
|
||||||
Ok(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alpn")]
|
#[cfg(feature = "alpn")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.7.4",
|
||||||
|
note = "please use `actix_web::HttpServer::bind_with()` and `actix_web::server::OpensslAcceptor` instead"
|
||||||
|
)]
|
||||||
/// Start listening for incoming tls connections.
|
/// Start listening for incoming tls connections.
|
||||||
///
|
///
|
||||||
/// This method sets alpn protocols to "h2" and "http/1.1"
|
/// This method sets alpn protocols to "h2" and "http/1.1"
|
||||||
pub fn bind_ssl<S: net::ToSocketAddrs>(
|
pub fn bind_ssl<S>(self, addr: S, builder: SslAcceptorBuilder) -> io::Result<Self>
|
||||||
mut self, addr: S, mut builder: SslAcceptorBuilder,
|
where
|
||||||
) -> io::Result<Self> {
|
S: net::ToSocketAddrs,
|
||||||
// alpn support
|
{
|
||||||
if !self.no_http2 {
|
use super::{OpensslAcceptor, ServerFlags};
|
||||||
configure_alpn(&mut builder)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let acceptor = builder.build();
|
// alpn support
|
||||||
let sockets = self.bind2(addr)?;
|
let flags = if !self.no_http2 {
|
||||||
self.sockets.extend(sockets.into_iter().map(|mut s| {
|
ServerFlags::HTTP1
|
||||||
s.tp = StreamHandlerType::Alpn(acceptor.clone());
|
} else {
|
||||||
s
|
ServerFlags::HTTP1 | ServerFlags::HTTP2
|
||||||
}));
|
};
|
||||||
Ok(self)
|
|
||||||
|
self.bind_with(addr, OpensslAcceptor::with_flags(builder, flags)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rust-tls")]
|
#[cfg(feature = "rust-tls")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.7.4",
|
||||||
|
note = "please use `actix_web::HttpServer::bind_with()` and `actix_web::server::RustlsAcceptor` instead"
|
||||||
|
)]
|
||||||
/// Start listening for incoming tls connections.
|
/// Start listening for incoming tls connections.
|
||||||
///
|
///
|
||||||
/// This method sets alpn protocols to "h2" and "http/1.1"
|
/// This method sets alpn protocols to "h2" and "http/1.1"
|
||||||
pub fn bind_rustls<S: net::ToSocketAddrs>(
|
pub fn bind_rustls<S: net::ToSocketAddrs>(
|
||||||
mut self, addr: S, mut builder: ServerConfig,
|
self, addr: S, builder: ServerConfig,
|
||||||
) -> io::Result<Self> {
|
) -> io::Result<Self> {
|
||||||
// alpn support
|
use super::{RustlsAcceptor, ServerFlags};
|
||||||
if !self.no_http2 {
|
|
||||||
builder.set_protocols(&vec!["h2".to_string(), "http/1.1".to_string()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let builder = Arc::new(builder);
|
// alpn support
|
||||||
let sockets = self.bind2(addr)?;
|
let flags = if !self.no_http2 {
|
||||||
self.sockets.extend(sockets.into_iter().map(move |mut s| {
|
ServerFlags::HTTP1
|
||||||
s.tp = StreamHandlerType::Rustls(builder.clone());
|
} else {
|
||||||
s
|
ServerFlags::HTTP1 | ServerFlags::HTTP2
|
||||||
}));
|
};
|
||||||
Ok(self)
|
|
||||||
|
self.bind_with(addr, RustlsAcceptor::with_flags(builder, flags))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_workers(&mut self, notify: &AcceptNotify) -> Vec<WorkerClient> {
|
fn start_workers(&mut self, notify: &AcceptNotify) -> Vec<WorkerClient> {
|
||||||
// start workers
|
// start workers
|
||||||
let mut workers = Vec::new();
|
let mut workers = Vec::new();
|
||||||
for idx in 0..self.threads {
|
for idx in 0..self.threads {
|
||||||
let (worker, addr) = self.pool.start(idx, notify.clone());
|
let (worker, addr) = self.factory.start(idx, notify.clone());
|
||||||
workers.push(worker);
|
workers.push(worker);
|
||||||
self.workers.push((idx, addr));
|
self.workers.push((idx, addr));
|
||||||
}
|
}
|
||||||
@ -453,23 +425,18 @@ impl<H: IntoHttpHandler> HttpServer<H> {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn start(mut self) -> Addr<Self> {
|
pub fn start(mut self) -> Addr<Self> {
|
||||||
if self.sockets.is_empty() {
|
let sockets = self.factory.take_sockets();
|
||||||
|
if sockets.is_empty() {
|
||||||
panic!("HttpServer::bind() has to be called before start()");
|
panic!("HttpServer::bind() has to be called before start()");
|
||||||
} else {
|
} else {
|
||||||
let mut addrs: Vec<(usize, Socket)> = Vec::new();
|
|
||||||
|
|
||||||
for socket in self.sockets.drain(..) {
|
|
||||||
let token = self.pool.insert(socket.addr, socket.tp.clone());
|
|
||||||
addrs.push((token, socket));
|
|
||||||
}
|
|
||||||
let notify = self.accept.get_notify();
|
let notify = self.accept.get_notify();
|
||||||
let workers = self.start_workers(¬ify);
|
let workers = self.start_workers(¬ify);
|
||||||
|
|
||||||
// start accept thread
|
// start accept thread
|
||||||
for (_, sock) in &addrs {
|
for sock in &sockets {
|
||||||
info!("Starting server on http://{}", sock.addr);
|
info!("Starting server on http://{}", sock.addr);
|
||||||
}
|
}
|
||||||
let rx = self.accept.start(addrs, workers.clone());
|
let rx = self.accept.start(sockets, workers.clone());
|
||||||
|
|
||||||
// start http server actor
|
// start http server actor
|
||||||
let signals = self.subscribe_to_signals();
|
let signals = self.subscribe_to_signals();
|
||||||
@ -511,64 +478,6 @@ impl<H: IntoHttpHandler> HttpServer<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[cfg(feature = "tls")]
|
|
||||||
#[deprecated(
|
|
||||||
since = "0.6.0",
|
|
||||||
note = "please use `actix_web::HttpServer::bind_tls` instead"
|
|
||||||
)]
|
|
||||||
impl<H: IntoHttpHandler> HttpServer<H> {
|
|
||||||
/// Start listening for incoming tls connections.
|
|
||||||
pub fn start_tls(mut self, acceptor: TlsAcceptor) -> io::Result<Addr<Self>> {
|
|
||||||
for sock in &mut self.sockets {
|
|
||||||
match sock.tp {
|
|
||||||
StreamHandlerType::Normal => (),
|
|
||||||
_ => continue,
|
|
||||||
}
|
|
||||||
sock.tp = StreamHandlerType::Tls(acceptor.clone());
|
|
||||||
}
|
|
||||||
Ok(self.start())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[cfg(feature = "alpn")]
|
|
||||||
#[deprecated(
|
|
||||||
since = "0.6.0",
|
|
||||||
note = "please use `actix_web::HttpServer::bind_ssl` instead"
|
|
||||||
)]
|
|
||||||
impl<H: IntoHttpHandler> HttpServer<H> {
|
|
||||||
/// Start listening for incoming tls connections.
|
|
||||||
///
|
|
||||||
/// This method sets alpn protocols to "h2" and "http/1.1"
|
|
||||||
pub fn start_ssl(
|
|
||||||
mut self, mut builder: SslAcceptorBuilder,
|
|
||||||
) -> io::Result<Addr<Self>> {
|
|
||||||
// alpn support
|
|
||||||
if !self.no_http2 {
|
|
||||||
builder.set_alpn_protos(b"\x02h2\x08http/1.1")?;
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let acceptor = builder.build();
|
|
||||||
for sock in &mut self.sockets {
|
|
||||||
match sock.tp {
|
|
||||||
StreamHandlerType::Normal => (),
|
|
||||||
_ => continue,
|
|
||||||
}
|
|
||||||
sock.tp = StreamHandlerType::Alpn(acceptor.clone());
|
|
||||||
}
|
|
||||||
Ok(self.start())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H: IntoHttpHandler> HttpServer<H> {
|
impl<H: IntoHttpHandler> HttpServer<H> {
|
||||||
/// Start listening for incoming connections from a stream.
|
/// Start listening for incoming connections from a stream.
|
||||||
///
|
///
|
||||||
@ -580,14 +489,14 @@ impl<H: IntoHttpHandler> HttpServer<H> {
|
|||||||
{
|
{
|
||||||
// set server settings
|
// set server settings
|
||||||
let addr: net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
|
let addr: net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
|
||||||
let settings = ServerSettings::new(Some(addr), &self.pool.host, secure);
|
let settings = ServerSettings::new(Some(addr), &self.factory.host, secure);
|
||||||
let apps: Vec<_> = (*self.pool.factory)()
|
let apps: Vec<_> = (*self.factory.factory)()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|h| h.into_handler())
|
.map(|h| h.into_handler())
|
||||||
.collect();
|
.collect();
|
||||||
self.h = Some(Rc::new(WorkerSettings::new(
|
self.settings = Some(Rc::new(WorkerSettings::new(
|
||||||
apps,
|
apps,
|
||||||
self.pool.keep_alive,
|
self.factory.keep_alive,
|
||||||
settings,
|
settings,
|
||||||
AcceptNotify::default(),
|
AcceptNotify::default(),
|
||||||
Arc::new(AtomicUsize::new(0)),
|
Arc::new(AtomicUsize::new(0)),
|
||||||
@ -599,7 +508,7 @@ impl<H: IntoHttpHandler> HttpServer<H> {
|
|||||||
let addr = HttpServer::create(move |ctx| {
|
let addr = HttpServer::create(move |ctx| {
|
||||||
ctx.add_message_stream(stream.map_err(|_| ()).map(move |t| Conn {
|
ctx.add_message_stream(stream.map_err(|_| ()).map(move |t| Conn {
|
||||||
io: WrapperStream::new(t),
|
io: WrapperStream::new(t),
|
||||||
token: 0,
|
token: Token::new(0),
|
||||||
peer: None,
|
peer: None,
|
||||||
http2: false,
|
http2: false,
|
||||||
}));
|
}));
|
||||||
@ -672,7 +581,7 @@ impl<H: IntoHttpHandler> StreamHandler<ServerCommand, ()> for HttpServer<H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (worker, addr) =
|
let (worker, addr) =
|
||||||
self.pool.start(new_idx, self.accept.get_notify());
|
self.factory.start(new_idx, self.accept.get_notify());
|
||||||
self.workers.push((new_idx, addr));
|
self.workers.push((new_idx, addr));
|
||||||
self.accept.send(Command::Worker(worker));
|
self.accept.send(Command::Worker(worker));
|
||||||
}
|
}
|
||||||
@ -690,7 +599,7 @@ where
|
|||||||
|
|
||||||
fn handle(&mut self, msg: Conn<T>, _: &mut Context<Self>) -> Self::Result {
|
fn handle(&mut self, msg: Conn<T>, _: &mut Context<Self>) -> Self::Result {
|
||||||
Arbiter::spawn(HttpChannel::new(
|
Arbiter::spawn(HttpChannel::new(
|
||||||
Rc::clone(self.h.as_ref().unwrap()),
|
Rc::clone(self.settings.as_ref().unwrap()),
|
||||||
msg.io,
|
msg.io,
|
||||||
msg.peer,
|
msg.peer,
|
||||||
msg.http2,
|
msg.http2,
|
||||||
@ -766,15 +675,3 @@ impl<H: IntoHttpHandler> Handler<StopServer> for HttpServer<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_tcp_listener(
|
|
||||||
addr: net::SocketAddr, backlog: i32,
|
|
||||||
) -> io::Result<net::TcpListener> {
|
|
||||||
let builder = match addr {
|
|
||||||
net::SocketAddr::V4(_) => TcpBuilder::new_v4()?,
|
|
||||||
net::SocketAddr::V6(_) => TcpBuilder::new_v6()?,
|
|
||||||
};
|
|
||||||
builder.reuse_address(true)?;
|
|
||||||
builder.bind(addr)?;
|
|
||||||
Ok(builder.listen(backlog)?)
|
|
||||||
}
|
|
||||||
|
14
src/server/ssl/mod.rs
Normal file
14
src/server/ssl/mod.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#[cfg(feature = "alpn")]
|
||||||
|
mod openssl;
|
||||||
|
#[cfg(feature = "alpn")]
|
||||||
|
pub use self::openssl::OpensslAcceptor;
|
||||||
|
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
|
mod nativetls;
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
|
pub use self::nativetls::NativeTlsAcceptor;
|
||||||
|
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
mod rustls;
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
pub use self::rustls::RustlsAcceptor;
|
67
src/server/ssl/nativetls.rs
Normal file
67
src/server/ssl/nativetls.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
use std::net::Shutdown;
|
||||||
|
use std::{io, time};
|
||||||
|
|
||||||
|
use futures::{Future, Poll};
|
||||||
|
use native_tls::TlsAcceptor;
|
||||||
|
use tokio_tls::{AcceptAsync, TlsAcceptorExt, TlsStream};
|
||||||
|
|
||||||
|
use server::{AcceptorService, IoStream};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
/// Support `SSL` connections via native-tls package
|
||||||
|
///
|
||||||
|
/// `tls` feature enables `NativeTlsAcceptor` type
|
||||||
|
pub struct NativeTlsAcceptor {
|
||||||
|
acceptor: TlsAcceptor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NativeTlsAcceptor {
|
||||||
|
/// Create `NativeTlsAcceptor` instance
|
||||||
|
pub fn new(acceptor: TlsAcceptor) -> Self {
|
||||||
|
NativeTlsAcceptor { acceptor }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AcceptorFut<Io>(AcceptAsync<Io>);
|
||||||
|
|
||||||
|
impl<Io: IoStream> Future for AcceptorFut<Io> {
|
||||||
|
type Item = TlsStream<Io>;
|
||||||
|
type Error = io::Error;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
|
self.0
|
||||||
|
.poll()
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Io: IoStream> AcceptorService<Io> for NativeTlsAcceptor {
|
||||||
|
type Accepted = TlsStream<Io>;
|
||||||
|
type Future = AcceptorFut<Io>;
|
||||||
|
|
||||||
|
fn scheme(&self) -> &'static str {
|
||||||
|
"https"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accept(&self, io: Io) -> Self::Future {
|
||||||
|
AcceptorFut(TlsAcceptorExt::accept_async(&self.acceptor, io))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Io: IoStream> IoStream for TlsStream<Io> {
|
||||||
|
#[inline]
|
||||||
|
fn shutdown(&mut self, _how: Shutdown) -> io::Result<()> {
|
||||||
|
let _ = self.get_mut().shutdown();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
|
||||||
|
self.get_mut().get_mut().set_nodelay(nodelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
|
||||||
|
self.get_mut().get_mut().set_linger(dur)
|
||||||
|
}
|
||||||
|
}
|
96
src/server/ssl/openssl.rs
Normal file
96
src/server/ssl/openssl.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
use std::net::Shutdown;
|
||||||
|
use std::{io, time};
|
||||||
|
|
||||||
|
use futures::{Future, Poll};
|
||||||
|
use openssl::ssl::{AlpnError, SslAcceptor, SslAcceptorBuilder};
|
||||||
|
use tokio_openssl::{AcceptAsync, SslAcceptorExt, SslStream};
|
||||||
|
|
||||||
|
use server::{AcceptorService, IoStream, ServerFlags};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
/// Support `SSL` connections via openssl package
|
||||||
|
///
|
||||||
|
/// `alpn` feature enables `OpensslAcceptor` type
|
||||||
|
pub struct OpensslAcceptor {
|
||||||
|
acceptor: SslAcceptor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpensslAcceptor {
|
||||||
|
/// Create `OpensslAcceptor` with enabled `HTTP/2` and `HTTP1.1` support.
|
||||||
|
pub fn new(builder: SslAcceptorBuilder) -> io::Result<Self> {
|
||||||
|
OpensslAcceptor::with_flags(builder, ServerFlags::HTTP1 | ServerFlags::HTTP2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create `OpensslAcceptor` with custom server flags.
|
||||||
|
pub fn with_flags(
|
||||||
|
mut builder: SslAcceptorBuilder, flags: ServerFlags,
|
||||||
|
) -> io::Result<Self> {
|
||||||
|
let mut protos = Vec::new();
|
||||||
|
if flags.contains(ServerFlags::HTTP1) {
|
||||||
|
protos.extend(b"\x08http/1.1");
|
||||||
|
}
|
||||||
|
if flags.contains(ServerFlags::HTTP2) {
|
||||||
|
protos.extend(b"\x02h2");
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if !protos.is_empty() {
|
||||||
|
builder.set_alpn_protos(&protos)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(OpensslAcceptor {
|
||||||
|
acceptor: builder.build(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AcceptorFut<Io>(AcceptAsync<Io>);
|
||||||
|
|
||||||
|
impl<Io: IoStream> Future for AcceptorFut<Io> {
|
||||||
|
type Item = SslStream<Io>;
|
||||||
|
type Error = io::Error;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
|
self.0
|
||||||
|
.poll()
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Io: IoStream> AcceptorService<Io> for OpensslAcceptor {
|
||||||
|
type Accepted = SslStream<Io>;
|
||||||
|
type Future = AcceptorFut<Io>;
|
||||||
|
|
||||||
|
fn scheme(&self) -> &'static str {
|
||||||
|
"https"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accept(&self, io: Io) -> Self::Future {
|
||||||
|
AcceptorFut(SslAcceptorExt::accept_async(&self.acceptor, io))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: IoStream> IoStream for SslStream<T> {
|
||||||
|
#[inline]
|
||||||
|
fn shutdown(&mut self, _how: Shutdown) -> io::Result<()> {
|
||||||
|
let _ = self.get_mut().shutdown();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
|
||||||
|
self.get_mut().get_mut().set_nodelay(nodelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
|
||||||
|
self.get_mut().get_mut().set_linger(dur)
|
||||||
|
}
|
||||||
|
}
|
92
src/server/ssl/rustls.rs
Normal file
92
src/server/ssl/rustls.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
use std::net::Shutdown;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::{io, time};
|
||||||
|
|
||||||
|
use rustls::{ClientSession, ServerConfig, ServerSession};
|
||||||
|
use tokio_io::AsyncWrite;
|
||||||
|
use tokio_rustls::{AcceptAsync, ServerConfigExt, TlsStream};
|
||||||
|
|
||||||
|
use server::{AcceptorService, IoStream, ServerFlags};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
/// Support `SSL` connections via rustls package
|
||||||
|
///
|
||||||
|
/// `rust-tls` feature enables `RustlsAcceptor` type
|
||||||
|
pub struct RustlsAcceptor {
|
||||||
|
config: Arc<ServerConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RustlsAcceptor {
|
||||||
|
/// Create `OpensslAcceptor` with enabled `HTTP/2` and `HTTP1.1` support.
|
||||||
|
pub fn new(config: ServerConfig) -> Self {
|
||||||
|
RustlsAcceptor::with_flags(config, ServerFlags::HTTP1 | ServerFlags::HTTP2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create `OpensslAcceptor` with custom server flags.
|
||||||
|
pub fn with_flags(mut config: ServerConfig, flags: ServerFlags) -> Self {
|
||||||
|
let mut protos = Vec::new();
|
||||||
|
if flags.contains(ServerFlags::HTTP1) {
|
||||||
|
protos.push("http/1.1".to_string());
|
||||||
|
}
|
||||||
|
if flags.contains(ServerFlags::HTTP2) {
|
||||||
|
protos.push("h2".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if !protos.is_empty() {
|
||||||
|
config.set_protocols(&protos);
|
||||||
|
}
|
||||||
|
|
||||||
|
RustlsAcceptor {
|
||||||
|
config: Arc::new(config),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Io: IoStream> AcceptorService<Io> for RustlsAcceptor {
|
||||||
|
type Accepted = TlsStream<Io, ServerSession>;
|
||||||
|
type Future = AcceptAsync<Io>;
|
||||||
|
|
||||||
|
fn scheme(&self) -> &'static str {
|
||||||
|
"https"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accept(&self, io: Io) -> Self::Future {
|
||||||
|
ServerConfigExt::accept_async(&self.config, io)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Io: IoStream> IoStream for TlsStream<Io, ClientSession> {
|
||||||
|
#[inline]
|
||||||
|
fn shutdown(&mut self, _how: Shutdown) -> io::Result<()> {
|
||||||
|
let _ = <Self as AsyncWrite>::shutdown(self);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
|
||||||
|
self.get_mut().0.set_nodelay(nodelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
|
||||||
|
self.get_mut().0.set_linger(dur)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Io: IoStream> IoStream for TlsStream<Io, ServerSession> {
|
||||||
|
#[inline]
|
||||||
|
fn shutdown(&mut self, _how: Shutdown) -> io::Result<()> {
|
||||||
|
let _ = <Self as AsyncWrite>::shutdown(self);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
|
||||||
|
self.get_mut().0.set_nodelay(nodelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
|
||||||
|
self.get_mut().0.set_linger(dur)
|
||||||
|
}
|
||||||
|
}
|
@ -1,102 +1,195 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{atomic::AtomicUsize, atomic::Ordering, Arc};
|
use std::sync::{atomic::AtomicUsize, atomic::Ordering, Arc};
|
||||||
use std::{net, time};
|
use std::{io, mem, net, time};
|
||||||
|
|
||||||
use futures::sync::mpsc::{unbounded, SendError, UnboundedSender};
|
use futures::sync::mpsc::{unbounded, SendError, UnboundedSender};
|
||||||
use futures::sync::oneshot;
|
use futures::sync::oneshot;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use net2::TcpStreamExt;
|
use net2::{TcpBuilder, TcpStreamExt};
|
||||||
use slab::Slab;
|
|
||||||
use tokio::executor::current_thread;
|
use tokio::executor::current_thread;
|
||||||
use tokio_reactor::Handle;
|
|
||||||
use tokio_tcp::TcpStream;
|
use tokio_tcp::TcpStream;
|
||||||
|
|
||||||
#[cfg(any(feature = "tls", feature = "alpn", feature = "rust-tls"))]
|
|
||||||
use futures::future;
|
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
|
||||||
use native_tls::TlsAcceptor;
|
|
||||||
#[cfg(feature = "tls")]
|
|
||||||
use tokio_tls::TlsAcceptorExt;
|
|
||||||
|
|
||||||
#[cfg(feature = "alpn")]
|
|
||||||
use openssl::ssl::SslAcceptor;
|
|
||||||
#[cfg(feature = "alpn")]
|
|
||||||
use tokio_openssl::SslAcceptorExt;
|
|
||||||
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
use rustls::{ServerConfig, Session};
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
use tokio_rustls::ServerConfigExt;
|
|
||||||
|
|
||||||
use actix::msgs::StopArbiter;
|
use actix::msgs::StopArbiter;
|
||||||
use actix::{Actor, Addr, Arbiter, AsyncContext, Context, Handler, Message, Response};
|
use actix::{Actor, Addr, Arbiter, AsyncContext, Context, Handler, Message, Response};
|
||||||
|
|
||||||
use super::accept::AcceptNotify;
|
use super::accept::AcceptNotify;
|
||||||
use super::channel::HttpChannel;
|
use super::channel::HttpChannel;
|
||||||
use super::settings::{ServerSettings, WorkerSettings};
|
use super::settings::{ServerSettings, WorkerSettings};
|
||||||
use super::{HttpHandler, IntoHttpHandler, KeepAlive};
|
use super::{
|
||||||
|
AcceptorService, HttpHandler, IntoAsyncIo, IntoHttpHandler, IoStream, KeepAlive,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub(crate) struct Conn<T> {
|
pub(crate) struct Conn<T> {
|
||||||
pub io: T,
|
pub io: T,
|
||||||
pub token: usize,
|
pub token: Token,
|
||||||
pub peer: Option<net::SocketAddr>,
|
pub peer: Option<net::SocketAddr>,
|
||||||
pub http2: bool,
|
pub http2: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Copy)]
|
||||||
pub(crate) struct SocketInfo {
|
pub struct Token(usize);
|
||||||
pub addr: net::SocketAddr,
|
|
||||||
pub htype: StreamHandlerType,
|
impl Token {
|
||||||
|
pub(crate) fn new(val: usize) -> Token {
|
||||||
|
Token(val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct WorkersPool<H: IntoHttpHandler + 'static> {
|
pub(crate) struct Socket {
|
||||||
sockets: Slab<SocketInfo>,
|
pub lst: net::TcpListener,
|
||||||
|
pub addr: net::SocketAddr,
|
||||||
|
pub token: Token,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct WorkerFactory<H: IntoHttpHandler + 'static> {
|
||||||
pub factory: Arc<Fn() -> Vec<H> + Send + Sync>,
|
pub factory: Arc<Fn() -> Vec<H> + Send + Sync>,
|
||||||
pub host: Option<String>,
|
pub host: Option<String>,
|
||||||
pub keep_alive: KeepAlive,
|
pub keep_alive: KeepAlive,
|
||||||
|
pub backlog: i32,
|
||||||
|
sockets: Vec<Socket>,
|
||||||
|
handlers: Vec<Box<IoStreamHandler<H::Handler, net::TcpStream>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: IntoHttpHandler + 'static> WorkersPool<H> {
|
impl<H: IntoHttpHandler + 'static> WorkerFactory<H> {
|
||||||
pub fn new<F>(factory: F) -> Self
|
pub fn new<F>(factory: F) -> Self
|
||||||
where
|
where
|
||||||
F: Fn() -> Vec<H> + Send + Sync + 'static,
|
F: Fn() -> Vec<H> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
WorkersPool {
|
WorkerFactory {
|
||||||
factory: Arc::new(factory),
|
factory: Arc::new(factory),
|
||||||
host: None,
|
host: None,
|
||||||
|
backlog: 2048,
|
||||||
keep_alive: KeepAlive::Os,
|
keep_alive: KeepAlive::Os,
|
||||||
sockets: Slab::new(),
|
sockets: Vec::new(),
|
||||||
|
handlers: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, addr: net::SocketAddr, htype: StreamHandlerType) -> usize {
|
pub fn addrs(&self) -> Vec<net::SocketAddr> {
|
||||||
let entry = self.sockets.vacant_entry();
|
self.sockets.iter().map(|s| s.addr).collect()
|
||||||
let token = entry.key();
|
}
|
||||||
entry.insert(SocketInfo { addr, htype });
|
|
||||||
token
|
pub fn addrs_with_scheme(&self) -> Vec<(net::SocketAddr, &str)> {
|
||||||
|
self.handlers
|
||||||
|
.iter()
|
||||||
|
.map(|s| (s.addr(), s.scheme()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_sockets(&mut self) -> Vec<Socket> {
|
||||||
|
mem::replace(&mut self.sockets, Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen(&mut self, lst: net::TcpListener) {
|
||||||
|
let token = Token(self.handlers.len());
|
||||||
|
let addr = lst.local_addr().unwrap();
|
||||||
|
self.handlers
|
||||||
|
.push(Box::new(SimpleHandler::new(lst.local_addr().unwrap())));
|
||||||
|
self.sockets.push(Socket { lst, addr, token })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen_with<A>(&mut self, lst: net::TcpListener, acceptor: A)
|
||||||
|
where
|
||||||
|
A: AcceptorService<TcpStream> + Send + 'static,
|
||||||
|
{
|
||||||
|
let token = Token(self.handlers.len());
|
||||||
|
let addr = lst.local_addr().unwrap();
|
||||||
|
self.handlers.push(Box::new(StreamHandler::new(
|
||||||
|
lst.local_addr().unwrap(),
|
||||||
|
acceptor,
|
||||||
|
)));
|
||||||
|
self.sockets.push(Socket { lst, addr, token })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind<S>(&mut self, addr: S) -> io::Result<()>
|
||||||
|
where
|
||||||
|
S: net::ToSocketAddrs,
|
||||||
|
{
|
||||||
|
let sockets = self.bind2(addr)?;
|
||||||
|
|
||||||
|
for lst in sockets {
|
||||||
|
let token = Token(self.handlers.len());
|
||||||
|
let addr = lst.local_addr().unwrap();
|
||||||
|
self.handlers
|
||||||
|
.push(Box::new(SimpleHandler::new(lst.local_addr().unwrap())));
|
||||||
|
self.sockets.push(Socket { lst, addr, token })
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind_with<S, A>(&mut self, addr: S, acceptor: &A) -> io::Result<()>
|
||||||
|
where
|
||||||
|
S: net::ToSocketAddrs,
|
||||||
|
A: AcceptorService<TcpStream> + Send + 'static,
|
||||||
|
{
|
||||||
|
let sockets = self.bind2(addr)?;
|
||||||
|
|
||||||
|
for lst in sockets {
|
||||||
|
let token = Token(self.handlers.len());
|
||||||
|
let addr = lst.local_addr().unwrap();
|
||||||
|
self.handlers.push(Box::new(StreamHandler::new(
|
||||||
|
lst.local_addr().unwrap(),
|
||||||
|
acceptor.clone(),
|
||||||
|
)));
|
||||||
|
self.sockets.push(Socket { lst, addr, token })
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind2<S: net::ToSocketAddrs>(
|
||||||
|
&self, addr: S,
|
||||||
|
) -> io::Result<Vec<net::TcpListener>> {
|
||||||
|
let mut err = None;
|
||||||
|
let mut succ = false;
|
||||||
|
let mut sockets = Vec::new();
|
||||||
|
for addr in addr.to_socket_addrs()? {
|
||||||
|
match create_tcp_listener(addr, self.backlog) {
|
||||||
|
Ok(lst) => {
|
||||||
|
succ = true;
|
||||||
|
sockets.push(lst);
|
||||||
|
}
|
||||||
|
Err(e) => err = Some(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !succ {
|
||||||
|
if let Some(e) = err.take() {
|
||||||
|
Err(e)
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
"Can not bind to address.",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(sockets)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(
|
pub fn start(
|
||||||
&mut self, idx: usize, notify: AcceptNotify,
|
&mut self, idx: usize, notify: AcceptNotify,
|
||||||
) -> (WorkerClient, Addr<Worker<H::Handler>>) {
|
) -> (WorkerClient, Addr<Worker>) {
|
||||||
let host = self.host.clone();
|
let host = self.host.clone();
|
||||||
let addr = self.sockets[0].addr;
|
let addr = self.handlers[0].addr();
|
||||||
let factory = Arc::clone(&self.factory);
|
let factory = Arc::clone(&self.factory);
|
||||||
let socks = self.sockets.clone();
|
|
||||||
let ka = self.keep_alive;
|
let ka = self.keep_alive;
|
||||||
let (tx, rx) = unbounded::<Conn<net::TcpStream>>();
|
let (tx, rx) = unbounded::<Conn<net::TcpStream>>();
|
||||||
let client = WorkerClient::new(idx, tx, self.sockets.clone());
|
let client = WorkerClient::new(idx, tx);
|
||||||
let conn = client.conn.clone();
|
let conn = client.conn.clone();
|
||||||
let sslrate = client.sslrate.clone();
|
let sslrate = client.sslrate.clone();
|
||||||
|
let handlers: Vec<_> = self.handlers.iter().map(|v| v.clone()).collect();
|
||||||
|
|
||||||
let addr = Arbiter::start(move |ctx: &mut Context<_>| {
|
let addr = Arbiter::start(move |ctx: &mut Context<_>| {
|
||||||
let s = ServerSettings::new(Some(addr), &host, false);
|
let s = ServerSettings::new(Some(addr), &host, false);
|
||||||
let apps: Vec<_> =
|
let apps: Vec<_> =
|
||||||
(*factory)().into_iter().map(|h| h.into_handler()).collect();
|
(*factory)().into_iter().map(|h| h.into_handler()).collect();
|
||||||
ctx.add_message_stream(rx);
|
ctx.add_message_stream(rx);
|
||||||
Worker::new(apps, socks, ka, s, conn, sslrate, notify)
|
let inner = WorkerInner::new(apps, handlers, ka, s, conn, sslrate, notify);
|
||||||
|
Worker {
|
||||||
|
inner: Box::new(inner),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
(client, addr)
|
(client, addr)
|
||||||
@ -107,19 +200,15 @@ impl<H: IntoHttpHandler + 'static> WorkersPool<H> {
|
|||||||
pub(crate) struct WorkerClient {
|
pub(crate) struct WorkerClient {
|
||||||
pub idx: usize,
|
pub idx: usize,
|
||||||
tx: UnboundedSender<Conn<net::TcpStream>>,
|
tx: UnboundedSender<Conn<net::TcpStream>>,
|
||||||
info: Slab<SocketInfo>,
|
|
||||||
pub conn: Arc<AtomicUsize>,
|
pub conn: Arc<AtomicUsize>,
|
||||||
pub sslrate: Arc<AtomicUsize>,
|
pub sslrate: Arc<AtomicUsize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkerClient {
|
impl WorkerClient {
|
||||||
fn new(
|
fn new(idx: usize, tx: UnboundedSender<Conn<net::TcpStream>>) -> Self {
|
||||||
idx: usize, tx: UnboundedSender<Conn<net::TcpStream>>, info: Slab<SocketInfo>,
|
|
||||||
) -> Self {
|
|
||||||
WorkerClient {
|
WorkerClient {
|
||||||
idx,
|
idx,
|
||||||
tx,
|
tx,
|
||||||
info,
|
|
||||||
conn: Arc::new(AtomicUsize::new(0)),
|
conn: Arc::new(AtomicUsize::new(0)),
|
||||||
sslrate: Arc::new(AtomicUsize::new(0)),
|
sslrate: Arc::new(AtomicUsize::new(0)),
|
||||||
}
|
}
|
||||||
@ -154,47 +243,30 @@ impl Message for StopWorker {
|
|||||||
///
|
///
|
||||||
/// Worker accepts Socket objects via unbounded channel and start requests
|
/// Worker accepts Socket objects via unbounded channel and start requests
|
||||||
/// processing.
|
/// processing.
|
||||||
pub(crate) struct Worker<H>
|
pub(crate) struct Worker {
|
||||||
where
|
inner: Box<WorkerHandler>,
|
||||||
H: HttpHandler + 'static,
|
|
||||||
{
|
|
||||||
settings: Rc<WorkerSettings<H>>,
|
|
||||||
socks: Slab<SocketInfo>,
|
|
||||||
tcp_ka: Option<time::Duration>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: HttpHandler + 'static> Worker<H> {
|
impl Actor for Worker {
|
||||||
pub(crate) fn new(
|
type Context = Context<Self>;
|
||||||
h: Vec<H>, socks: Slab<SocketInfo>, keep_alive: KeepAlive,
|
|
||||||
settings: ServerSettings, conn: Arc<AtomicUsize>, sslrate: Arc<AtomicUsize>,
|
|
||||||
notify: AcceptNotify,
|
|
||||||
) -> Worker<H> {
|
|
||||||
let tcp_ka = if let KeepAlive::Tcp(val) = keep_alive {
|
|
||||||
Some(time::Duration::new(val as u64, 0))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Worker {
|
fn started(&mut self, ctx: &mut Self::Context) {
|
||||||
settings: Rc::new(WorkerSettings::new(
|
self.update_date(ctx);
|
||||||
h, keep_alive, settings, notify, conn, sslrate,
|
|
||||||
)),
|
|
||||||
socks,
|
|
||||||
tcp_ka,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_time(&self, ctx: &mut Context<Self>) {
|
impl Worker {
|
||||||
self.settings.update_date();
|
fn update_date(&self, ctx: &mut Context<Self>) {
|
||||||
ctx.run_later(time::Duration::new(1, 0), |slf, ctx| slf.update_time(ctx));
|
self.inner.update_date();
|
||||||
|
ctx.run_later(time::Duration::new(1, 0), |slf, ctx| slf.update_date(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shutdown_timeout(
|
fn shutdown_timeout(
|
||||||
&self, ctx: &mut Context<Self>, tx: oneshot::Sender<bool>, dur: time::Duration,
|
&self, ctx: &mut Context<Worker>, tx: oneshot::Sender<bool>, dur: time::Duration,
|
||||||
) {
|
) {
|
||||||
// sleep for 1 second and then check again
|
// sleep for 1 second and then check again
|
||||||
ctx.run_later(time::Duration::new(1, 0), move |slf, ctx| {
|
ctx.run_later(time::Duration::new(1, 0), move |slf, ctx| {
|
||||||
let num = slf.settings.num_channels();
|
let num = slf.inner.num_channels();
|
||||||
if num == 0 {
|
if num == 0 {
|
||||||
let _ = tx.send(true);
|
let _ = tx.send(true);
|
||||||
Arbiter::current().do_send(StopArbiter(0));
|
Arbiter::current().do_send(StopArbiter(0));
|
||||||
@ -202,7 +274,7 @@ impl<H: HttpHandler + 'static> Worker<H> {
|
|||||||
slf.shutdown_timeout(ctx, tx, d);
|
slf.shutdown_timeout(ctx, tx, d);
|
||||||
} else {
|
} else {
|
||||||
info!("Force shutdown http worker, {} connections", num);
|
info!("Force shutdown http worker, {} connections", num);
|
||||||
slf.settings.head().traverse::<TcpStream, H>();
|
slf.inner.force_shutdown();
|
||||||
let _ = tx.send(false);
|
let _ = tx.send(false);
|
||||||
Arbiter::current().do_send(StopArbiter(0));
|
Arbiter::current().do_send(StopArbiter(0));
|
||||||
}
|
}
|
||||||
@ -210,44 +282,20 @@ impl<H: HttpHandler + 'static> Worker<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: 'static> Actor for Worker<H>
|
impl Handler<Conn<net::TcpStream>> for Worker {
|
||||||
where
|
|
||||||
H: HttpHandler + 'static,
|
|
||||||
{
|
|
||||||
type Context = Context<Self>;
|
|
||||||
|
|
||||||
fn started(&mut self, ctx: &mut Self::Context) {
|
|
||||||
self.update_time(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H> Handler<Conn<net::TcpStream>> for Worker<H>
|
|
||||||
where
|
|
||||||
H: HttpHandler + 'static,
|
|
||||||
{
|
|
||||||
type Result = ();
|
type Result = ();
|
||||||
|
|
||||||
fn handle(&mut self, msg: Conn<net::TcpStream>, _: &mut Context<Self>) {
|
fn handle(&mut self, msg: Conn<net::TcpStream>, _: &mut Context<Self>) {
|
||||||
if self.tcp_ka.is_some() && msg.io.set_keepalive(self.tcp_ka).is_err() {
|
self.inner.handle_connect(msg)
|
||||||
error!("Can not set socket keep-alive option");
|
|
||||||
}
|
|
||||||
self.socks
|
|
||||||
.get_mut(msg.token)
|
|
||||||
.unwrap()
|
|
||||||
.htype
|
|
||||||
.handle(Rc::clone(&self.settings), msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `StopWorker` message handler
|
/// `StopWorker` message handler
|
||||||
impl<H> Handler<StopWorker> for Worker<H>
|
impl Handler<StopWorker> for Worker {
|
||||||
where
|
|
||||||
H: HttpHandler + 'static,
|
|
||||||
{
|
|
||||||
type Result = Response<bool, ()>;
|
type Result = Response<bool, ()>;
|
||||||
|
|
||||||
fn handle(&mut self, msg: StopWorker, ctx: &mut Context<Self>) -> Self::Result {
|
fn handle(&mut self, msg: StopWorker, ctx: &mut Context<Self>) -> Self::Result {
|
||||||
let num = self.settings.num_channels();
|
let num = self.inner.num_channels();
|
||||||
if num == 0 {
|
if num == 0 {
|
||||||
info!("Shutting down http worker, 0 connections");
|
info!("Shutting down http worker, 0 connections");
|
||||||
Response::reply(Ok(true))
|
Response::reply(Ok(true))
|
||||||
@ -258,148 +306,242 @@ where
|
|||||||
Response::async(rx.map_err(|_| ()))
|
Response::async(rx.map_err(|_| ()))
|
||||||
} else {
|
} else {
|
||||||
info!("Force shutdown http worker, {} connections", num);
|
info!("Force shutdown http worker, {} connections", num);
|
||||||
self.settings.head().traverse::<TcpStream, H>();
|
self.inner.force_shutdown();
|
||||||
Response::reply(Ok(false))
|
Response::reply(Ok(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
trait WorkerHandler {
|
||||||
pub(crate) enum StreamHandlerType {
|
fn update_date(&self);
|
||||||
Normal,
|
|
||||||
#[cfg(feature = "tls")]
|
fn handle_connect(&mut self, Conn<net::TcpStream>);
|
||||||
Tls(TlsAcceptor),
|
|
||||||
#[cfg(feature = "alpn")]
|
fn force_shutdown(&self);
|
||||||
Alpn(SslAcceptor),
|
|
||||||
#[cfg(feature = "rust-tls")]
|
fn num_channels(&self) -> usize;
|
||||||
Rustls(Arc<ServerConfig>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StreamHandlerType {
|
struct WorkerInner<H>
|
||||||
pub fn is_ssl(&self) -> bool {
|
where
|
||||||
match *self {
|
H: HttpHandler + 'static,
|
||||||
StreamHandlerType::Normal => false,
|
{
|
||||||
#[cfg(feature = "tls")]
|
settings: Rc<WorkerSettings<H>>,
|
||||||
StreamHandlerType::Tls(_) => true,
|
socks: Vec<Box<IoStreamHandler<H, net::TcpStream>>>,
|
||||||
#[cfg(feature = "alpn")]
|
tcp_ka: Option<time::Duration>,
|
||||||
StreamHandlerType::Alpn(_) => true,
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
StreamHandlerType::Rustls(_) => true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle<H: HttpHandler>(
|
impl<H: HttpHandler + 'static> WorkerInner<H> {
|
||||||
&mut self, h: Rc<WorkerSettings<H>>, msg: Conn<net::TcpStream>,
|
pub(crate) fn new(
|
||||||
) {
|
h: Vec<H>, socks: Vec<Box<IoStreamHandler<H, net::TcpStream>>>,
|
||||||
match *self {
|
keep_alive: KeepAlive, settings: ServerSettings, conn: Arc<AtomicUsize>,
|
||||||
StreamHandlerType::Normal => {
|
sslrate: Arc<AtomicUsize>, notify: AcceptNotify,
|
||||||
let _ = msg.io.set_nodelay(true);
|
) -> WorkerInner<H> {
|
||||||
let io = TcpStream::from_std(msg.io, &Handle::default())
|
let tcp_ka = if let KeepAlive::Tcp(val) = keep_alive {
|
||||||
.expect("failed to associate TCP stream");
|
Some(time::Duration::new(val as u64, 0))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
current_thread::spawn(HttpChannel::new(h, io, msg.peer, msg.http2));
|
WorkerInner {
|
||||||
}
|
settings: Rc::new(WorkerSettings::new(
|
||||||
#[cfg(feature = "tls")]
|
h, keep_alive, settings, notify, conn, sslrate,
|
||||||
StreamHandlerType::Tls(ref acceptor) => {
|
|
||||||
let Conn {
|
|
||||||
io, peer, http2, ..
|
|
||||||
} = msg;
|
|
||||||
let _ = io.set_nodelay(true);
|
|
||||||
let io = TcpStream::from_std(io, &Handle::default())
|
|
||||||
.expect("failed to associate TCP stream");
|
|
||||||
h.ssl_conn_add();
|
|
||||||
|
|
||||||
current_thread::spawn(TlsAcceptorExt::accept_async(acceptor, io).then(
|
|
||||||
move |res| {
|
|
||||||
h.ssl_conn_del();
|
|
||||||
match res {
|
|
||||||
Ok(io) => current_thread::spawn(HttpChannel::new(
|
|
||||||
h, io, peer, http2,
|
|
||||||
)),
|
)),
|
||||||
Err(err) => {
|
socks,
|
||||||
trace!("Error during handling tls connection: {}", err)
|
tcp_ka,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
future::result(Ok(()))
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "alpn")]
|
|
||||||
StreamHandlerType::Alpn(ref acceptor) => {
|
|
||||||
let Conn { io, peer, .. } = msg;
|
|
||||||
let _ = io.set_nodelay(true);
|
|
||||||
let io = TcpStream::from_std(io, &Handle::default())
|
|
||||||
.expect("failed to associate TCP stream");
|
|
||||||
h.ssl_conn_add();
|
|
||||||
|
|
||||||
current_thread::spawn(SslAcceptorExt::accept_async(acceptor, io).then(
|
impl<H> WorkerHandler for WorkerInner<H>
|
||||||
move |res| {
|
where
|
||||||
h.ssl_conn_del();
|
H: HttpHandler + 'static,
|
||||||
match res {
|
|
||||||
Ok(io) => {
|
|
||||||
let http2 = if let Some(p) =
|
|
||||||
io.get_ref().ssl().selected_alpn_protocol()
|
|
||||||
{
|
{
|
||||||
p.len() == 2 && &p == b"h2"
|
fn update_date(&self) {
|
||||||
} else {
|
self.settings.update_date();
|
||||||
false
|
|
||||||
};
|
|
||||||
current_thread::spawn(HttpChannel::new(
|
|
||||||
h, io, peer, http2,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Err(err) => {
|
|
||||||
trace!("Error during handling tls connection: {}", err)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
future::result(Ok(()))
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
StreamHandlerType::Rustls(ref acceptor) => {
|
|
||||||
let Conn { io, peer, .. } = msg;
|
|
||||||
let _ = io.set_nodelay(true);
|
|
||||||
let io = TcpStream::from_std(io, &Handle::default())
|
|
||||||
.expect("failed to associate TCP stream");
|
|
||||||
h.ssl_conn_add();
|
|
||||||
|
|
||||||
current_thread::spawn(ServerConfigExt::accept_async(acceptor, io).then(
|
fn handle_connect(&mut self, msg: Conn<net::TcpStream>) {
|
||||||
move |res| {
|
if self.tcp_ka.is_some() && msg.io.set_keepalive(self.tcp_ka).is_err() {
|
||||||
h.ssl_conn_del();
|
error!("Can not set socket keep-alive option");
|
||||||
match res {
|
}
|
||||||
Ok(io) => {
|
self.socks[msg.token.0].handle(Rc::clone(&self.settings), msg.io, msg.peer);
|
||||||
let http2 = if let Some(p) =
|
}
|
||||||
io.get_ref().1.get_alpn_protocol()
|
|
||||||
|
fn num_channels(&self) -> usize {
|
||||||
|
self.settings.num_channels()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn force_shutdown(&self) {
|
||||||
|
self.settings.head().traverse::<TcpStream, H>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SimpleHandler<Io> {
|
||||||
|
addr: net::SocketAddr,
|
||||||
|
io: PhantomData<Io>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Io: IntoAsyncIo> Clone for SimpleHandler<Io> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
SimpleHandler {
|
||||||
|
addr: self.addr,
|
||||||
|
io: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Io: IntoAsyncIo> SimpleHandler<Io> {
|
||||||
|
fn new(addr: net::SocketAddr) -> Self {
|
||||||
|
SimpleHandler {
|
||||||
|
addr,
|
||||||
|
io: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H, Io> IoStreamHandler<H, Io> for SimpleHandler<Io>
|
||||||
|
where
|
||||||
|
H: HttpHandler,
|
||||||
|
Io: IntoAsyncIo + Send + 'static,
|
||||||
|
Io::Io: IoStream,
|
||||||
{
|
{
|
||||||
p.len() == 2 && &p == &"h2"
|
fn addr(&self) -> net::SocketAddr {
|
||||||
} else {
|
self.addr
|
||||||
false
|
|
||||||
};
|
|
||||||
current_thread::spawn(HttpChannel::new(
|
|
||||||
h, io, peer, http2,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clone(&self) -> Box<IoStreamHandler<H, Io>> {
|
||||||
|
Box::new(Clone::clone(self))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scheme(&self) -> &'static str {
|
||||||
|
"http"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle(&self, h: Rc<WorkerSettings<H>>, io: Io, peer: Option<net::SocketAddr>) {
|
||||||
|
let mut io = match io.into_async_io() {
|
||||||
|
Ok(io) => io,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
trace!("Error during handling tls connection: {}", err)
|
trace!("Failed to create async io: {}", err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
future::result(Ok(()))
|
let _ = io.set_nodelay(true);
|
||||||
},
|
|
||||||
));
|
current_thread::spawn(HttpChannel::new(h, io, peer, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StreamHandler<A, Io> {
|
||||||
|
acceptor: A,
|
||||||
|
addr: net::SocketAddr,
|
||||||
|
io: PhantomData<Io>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Io: IntoAsyncIo, A: AcceptorService<Io::Io>> StreamHandler<A, Io> {
|
||||||
|
fn new(addr: net::SocketAddr, acceptor: A) -> Self {
|
||||||
|
StreamHandler {
|
||||||
|
addr,
|
||||||
|
acceptor,
|
||||||
|
io: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn scheme(&self) -> &'static str {
|
impl<Io: IntoAsyncIo, A: AcceptorService<Io::Io>> Clone for StreamHandler<A, Io> {
|
||||||
match *self {
|
fn clone(&self) -> Self {
|
||||||
StreamHandlerType::Normal => "http",
|
StreamHandler {
|
||||||
#[cfg(feature = "tls")]
|
addr: self.addr,
|
||||||
StreamHandlerType::Tls(_) => "https",
|
acceptor: self.acceptor.clone(),
|
||||||
#[cfg(feature = "alpn")]
|
io: PhantomData,
|
||||||
StreamHandlerType::Alpn(_) => "https",
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
StreamHandlerType::Rustls(_) => "https",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<H, Io, A> IoStreamHandler<H, Io> for StreamHandler<A, Io>
|
||||||
|
where
|
||||||
|
H: HttpHandler,
|
||||||
|
Io: IntoAsyncIo + Send + 'static,
|
||||||
|
Io::Io: IoStream,
|
||||||
|
A: AcceptorService<Io::Io> + Send + 'static,
|
||||||
|
{
|
||||||
|
fn addr(&self) -> net::SocketAddr {
|
||||||
|
self.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone(&self) -> Box<IoStreamHandler<H, Io>> {
|
||||||
|
Box::new(Clone::clone(self))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scheme(&self) -> &'static str {
|
||||||
|
self.acceptor.scheme()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle(&self, h: Rc<WorkerSettings<H>>, io: Io, peer: Option<net::SocketAddr>) {
|
||||||
|
let mut io = match io.into_async_io() {
|
||||||
|
Ok(io) => io,
|
||||||
|
Err(err) => {
|
||||||
|
trace!("Failed to create async io: {}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let _ = io.set_nodelay(true);
|
||||||
|
|
||||||
|
h.conn_rate_add();
|
||||||
|
current_thread::spawn(self.acceptor.accept(io).then(move |res| {
|
||||||
|
h.conn_rate_del();
|
||||||
|
match res {
|
||||||
|
Ok(io) => current_thread::spawn(HttpChannel::new(h, io, peer, false)),
|
||||||
|
Err(err) => trace!("Can not establish connection: {}", err),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H, Io: 'static> IoStreamHandler<H, Io> for Box<IoStreamHandler<H, Io>>
|
||||||
|
where
|
||||||
|
H: HttpHandler,
|
||||||
|
Io: IntoAsyncIo,
|
||||||
|
{
|
||||||
|
fn addr(&self) -> net::SocketAddr {
|
||||||
|
self.as_ref().addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone(&self) -> Box<IoStreamHandler<H, Io>> {
|
||||||
|
self.as_ref().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scheme(&self) -> &'static str {
|
||||||
|
self.as_ref().scheme()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle(&self, h: Rc<WorkerSettings<H>>, io: Io, peer: Option<net::SocketAddr>) {
|
||||||
|
self.as_ref().handle(h, io, peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait IoStreamHandler<H, Io>: Send
|
||||||
|
where
|
||||||
|
H: HttpHandler,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Box<IoStreamHandler<H, Io>>;
|
||||||
|
|
||||||
|
fn addr(&self) -> net::SocketAddr;
|
||||||
|
|
||||||
|
fn scheme(&self) -> &'static str;
|
||||||
|
|
||||||
|
fn handle(&self, h: Rc<WorkerSettings<H>>, io: Io, peer: Option<net::SocketAddr>);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_tcp_listener(
|
||||||
|
addr: net::SocketAddr, backlog: i32,
|
||||||
|
) -> io::Result<net::TcpListener> {
|
||||||
|
let builder = match addr {
|
||||||
|
net::SocketAddr::V4(_) => TcpBuilder::new_v4()?,
|
||||||
|
net::SocketAddr::V6(_) => TcpBuilder::new_v6()?,
|
||||||
|
};
|
||||||
|
builder.reuse_address(true)?;
|
||||||
|
builder.bind(addr)?;
|
||||||
|
Ok(builder.listen(backlog)?)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user