2018-01-12 03:35:05 +01:00
|
|
|
//! Http server
|
|
|
|
use std::net::Shutdown;
|
2018-04-14 01:02:01 +02:00
|
|
|
use std::{io, time};
|
2018-01-12 03:35:05 +01:00
|
|
|
|
2018-06-22 05:01:20 +02:00
|
|
|
use bytes::{BufMut, BytesMut};
|
2018-05-21 05:37:19 +02:00
|
|
|
use futures::{Async, Poll};
|
2018-04-14 01:02:01 +02:00
|
|
|
use tokio_io::{AsyncRead, AsyncWrite};
|
2018-05-25 06:03:16 +02:00
|
|
|
use tokio_tcp::TcpStream;
|
2018-01-12 03:35:05 +01:00
|
|
|
|
|
|
|
mod channel;
|
2018-01-28 07:03:03 +01:00
|
|
|
pub(crate) mod encoding;
|
|
|
|
pub(crate) mod h1;
|
2018-04-29 07:20:32 +02:00
|
|
|
pub(crate) mod h1decoder;
|
2018-01-12 03:35:05 +01:00
|
|
|
mod h1writer;
|
2018-04-14 01:02:01 +02:00
|
|
|
mod h2;
|
2018-01-12 03:35:05 +01:00
|
|
|
mod h2writer;
|
2018-03-29 19:44:26 +02:00
|
|
|
pub(crate) mod helpers;
|
2018-06-18 00:56:18 +02:00
|
|
|
pub(crate) mod settings;
|
2018-01-28 07:03:03 +01:00
|
|
|
pub(crate) mod shared;
|
2018-04-14 01:02:01 +02:00
|
|
|
mod srv;
|
|
|
|
mod worker;
|
2018-01-12 03:35:05 +01:00
|
|
|
|
|
|
|
pub use self::settings::ServerSettings;
|
2018-04-14 01:02:01 +02:00
|
|
|
pub use self::srv::HttpServer;
|
2018-01-12 03:35:05 +01:00
|
|
|
|
2018-05-21 05:37:19 +02:00
|
|
|
#[doc(hidden)]
|
|
|
|
pub use self::helpers::write_content_length;
|
|
|
|
|
2018-06-01 18:36:16 +02:00
|
|
|
use actix::Message;
|
2018-01-14 22:50:38 +01:00
|
|
|
use body::Binary;
|
2018-01-12 03:35:05 +01:00
|
|
|
use error::Error;
|
2018-03-29 20:06:44 +02:00
|
|
|
use header::ContentEncoding;
|
2018-02-28 00:03:28 +01:00
|
|
|
use httprequest::{HttpInnerMessage, HttpRequest};
|
2018-01-12 03:35:05 +01:00
|
|
|
use httpresponse::HttpResponse;
|
|
|
|
|
|
|
|
/// max buffer size 64k
|
|
|
|
pub(crate) const MAX_WRITE_BUFFER_SIZE: usize = 65_536;
|
|
|
|
|
2018-06-22 05:01:20 +02:00
|
|
|
const LW_BUFFER_SIZE: usize = 4096;
|
|
|
|
const HW_BUFFER_SIZE: usize = 32_768;
|
|
|
|
|
2018-04-06 17:40:11 +02:00
|
|
|
/// Create new http server with application factory.
|
|
|
|
///
|
|
|
|
/// This is shortcut for `server::HttpServer::new()` method.
|
2018-03-31 08:07:33 +02:00
|
|
|
///
|
|
|
|
/// ```rust
|
2018-06-01 19:27:23 +02:00
|
|
|
/// # extern crate actix_web;
|
2018-06-01 18:36:16 +02:00
|
|
|
/// use actix_web::{actix, server, App, HttpResponse};
|
2018-03-31 08:07:33 +02:00
|
|
|
///
|
|
|
|
/// fn main() {
|
2018-06-17 00:09:07 +02:00
|
|
|
/// let sys = actix::System::new("example"); // <- create Actix system
|
2018-03-31 08:07:33 +02:00
|
|
|
///
|
2018-06-17 00:09:07 +02:00
|
|
|
/// server::new(
|
|
|
|
/// || App::new()
|
|
|
|
/// .resource("/", |r| r.f(|_| HttpResponse::Ok())))
|
|
|
|
/// .bind("127.0.0.1:59090").unwrap()
|
|
|
|
/// .start();
|
2018-03-31 08:07:33 +02:00
|
|
|
///
|
2018-06-14 08:37:19 +02:00
|
|
|
/// # actix::System::current().stop();
|
2018-06-17 00:09:07 +02:00
|
|
|
/// sys.run();
|
2018-03-31 08:07:33 +02:00
|
|
|
/// }
|
|
|
|
/// ```
|
2018-03-31 03:54:38 +02:00
|
|
|
pub fn new<F, U, H>(factory: F) -> HttpServer<H>
|
2018-04-14 01:02:01 +02:00
|
|
|
where
|
|
|
|
F: Fn() -> U + Sync + Send + 'static,
|
|
|
|
U: IntoIterator<Item = H> + 'static,
|
|
|
|
H: IntoHttpHandler + 'static,
|
2018-03-31 03:54:38 +02:00
|
|
|
{
|
|
|
|
HttpServer::new(factory)
|
|
|
|
}
|
|
|
|
|
2018-03-10 01:21:14 +01:00
|
|
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
|
|
|
/// Server keep-alive setting
|
|
|
|
pub enum KeepAlive {
|
|
|
|
/// Keep alive in seconds
|
|
|
|
Timeout(usize),
|
|
|
|
/// Use `SO_KEEPALIVE` socket option, value in seconds
|
|
|
|
Tcp(usize),
|
|
|
|
/// Relay on OS to shutdown tcp connection
|
|
|
|
Os,
|
|
|
|
/// Disabled
|
|
|
|
Disabled,
|
|
|
|
}
|
|
|
|
|
2018-03-10 10:40:36 +01:00
|
|
|
impl From<usize> for KeepAlive {
|
|
|
|
fn from(keepalive: usize) -> Self {
|
|
|
|
KeepAlive::Timeout(keepalive)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Option<usize>> for KeepAlive {
|
|
|
|
fn from(keepalive: Option<usize>) -> Self {
|
|
|
|
if let Some(keepalive) = keepalive {
|
|
|
|
KeepAlive::Timeout(keepalive)
|
|
|
|
} else {
|
|
|
|
KeepAlive::Disabled
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-12 03:35:05 +01:00
|
|
|
/// Pause accepting incoming connections
|
|
|
|
///
|
|
|
|
/// If socket contains some pending connection, they might be dropped.
|
|
|
|
/// All opened connection remains active.
|
|
|
|
#[derive(Message)]
|
|
|
|
pub struct PauseServer;
|
|
|
|
|
|
|
|
/// Resume accepting incoming connections
|
|
|
|
#[derive(Message)]
|
|
|
|
pub struct ResumeServer;
|
|
|
|
|
|
|
|
/// Stop incoming connection processing, stop all workers and exit.
|
|
|
|
///
|
|
|
|
/// If server starts with `spawn()` method, then spawned thread get terminated.
|
|
|
|
pub struct StopServer {
|
2018-06-02 15:51:58 +02:00
|
|
|
/// Whether to try and shut down gracefully
|
2018-04-14 01:02:01 +02:00
|
|
|
pub graceful: bool,
|
2018-01-12 03:35:05 +01:00
|
|
|
}
|
|
|
|
|
2018-06-01 18:36:16 +02:00
|
|
|
impl Message for StopServer {
|
2018-02-12 21:17:30 +01:00
|
|
|
type Result = Result<(), ()>;
|
|
|
|
}
|
|
|
|
|
2018-01-12 03:35:05 +01:00
|
|
|
/// Low level http request handler
|
|
|
|
#[allow(unused_variables)]
|
|
|
|
pub trait HttpHandler: 'static {
|
2018-06-18 01:45:54 +02:00
|
|
|
/// Request handling task
|
|
|
|
type Task: HttpHandlerTask;
|
|
|
|
|
2018-01-12 03:35:05 +01:00
|
|
|
/// Handle request
|
2018-06-21 13:07:54 +02:00
|
|
|
fn handle(&self, req: HttpRequest) -> Result<Self::Task, HttpRequest>;
|
2018-01-12 03:35:05 +01:00
|
|
|
}
|
|
|
|
|
2018-06-18 01:45:54 +02:00
|
|
|
impl HttpHandler for Box<HttpHandler<Task = Box<HttpHandlerTask>>> {
|
|
|
|
type Task = Box<HttpHandlerTask>;
|
|
|
|
|
2018-06-21 13:07:54 +02:00
|
|
|
fn handle(&self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest> {
|
|
|
|
self.as_ref().handle(req)
|
2018-01-14 03:58:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-18 01:45:54 +02:00
|
|
|
/// Low level http request handler
|
2018-01-12 03:35:05 +01:00
|
|
|
pub trait HttpHandlerTask {
|
2018-03-31 18:18:25 +02:00
|
|
|
/// Poll task, this method is used before or after *io* object is available
|
2018-06-18 01:45:54 +02:00
|
|
|
fn poll_completed(&mut self) -> Poll<(), Error> {
|
2018-05-21 05:37:19 +02:00
|
|
|
Ok(Async::Ready(()))
|
|
|
|
}
|
2018-01-12 03:35:05 +01:00
|
|
|
|
2018-03-31 18:18:25 +02:00
|
|
|
/// Poll task when *io* object is available
|
2018-01-12 07:06:06 +01:00
|
|
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error>;
|
|
|
|
|
2018-03-31 18:18:25 +02:00
|
|
|
/// Connection is disconnected
|
2018-05-21 05:37:19 +02:00
|
|
|
fn disconnected(&mut self) {}
|
2018-01-12 03:35:05 +01:00
|
|
|
}
|
|
|
|
|
2018-06-18 01:45:54 +02:00
|
|
|
impl HttpHandlerTask for Box<HttpHandlerTask> {
|
|
|
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
|
|
|
self.as_mut().poll_io(io)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-12 03:35:05 +01:00
|
|
|
/// Conversion helper trait
|
|
|
|
pub trait IntoHttpHandler {
|
|
|
|
/// The associated type which is result of conversion.
|
|
|
|
type Handler: HttpHandler;
|
|
|
|
|
|
|
|
/// Convert into `HttpHandler` object.
|
|
|
|
fn into_handler(self, settings: ServerSettings) -> Self::Handler;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: HttpHandler> IntoHttpHandler for T {
|
|
|
|
type Handler = T;
|
|
|
|
|
|
|
|
fn into_handler(self, _: ServerSettings) -> Self::Handler {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-31 18:18:25 +02:00
|
|
|
#[doc(hidden)]
|
2018-01-12 03:35:05 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum WriterState {
|
|
|
|
Done,
|
|
|
|
Pause,
|
|
|
|
}
|
|
|
|
|
2018-03-31 18:18:25 +02:00
|
|
|
#[doc(hidden)]
|
2018-01-12 03:35:05 +01:00
|
|
|
/// Stream writer
|
|
|
|
pub trait Writer {
|
2018-05-21 05:37:19 +02:00
|
|
|
/// number of bytes written to the stream
|
2018-01-12 03:35:05 +01:00
|
|
|
fn written(&self) -> u64;
|
|
|
|
|
2018-05-21 05:37:19 +02:00
|
|
|
#[doc(hidden)]
|
|
|
|
fn set_date(&self, st: &mut BytesMut);
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
2018-06-19 03:44:01 +02:00
|
|
|
fn buffer(&mut self) -> &mut BytesMut;
|
2018-05-21 05:37:19 +02:00
|
|
|
|
2018-04-14 01:02:01 +02:00
|
|
|
fn start(
|
|
|
|
&mut self, req: &mut HttpInnerMessage, resp: &mut HttpResponse,
|
|
|
|
encoding: ContentEncoding,
|
|
|
|
) -> io::Result<WriterState>;
|
2018-01-12 03:35:05 +01:00
|
|
|
|
2018-06-19 03:44:01 +02:00
|
|
|
fn write(&mut self, payload: &Binary) -> io::Result<WriterState>;
|
2018-01-12 03:35:05 +01:00
|
|
|
|
2018-01-14 22:50:38 +01:00
|
|
|
fn write_eof(&mut self) -> io::Result<WriterState>;
|
2018-01-12 03:35:05 +01:00
|
|
|
|
|
|
|
fn poll_completed(&mut self, shutdown: bool) -> Poll<(), io::Error>;
|
|
|
|
}
|
2018-01-12 07:06:06 +01:00
|
|
|
|
2018-03-31 18:18:25 +02:00
|
|
|
#[doc(hidden)]
|
2018-01-12 07:06:06 +01:00
|
|
|
/// Low-level io stream operations
|
|
|
|
pub trait IoStream: AsyncRead + AsyncWrite + 'static {
|
|
|
|
fn shutdown(&mut self, how: Shutdown) -> io::Result<()>;
|
|
|
|
|
|
|
|
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()>;
|
|
|
|
|
|
|
|
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()>;
|
2018-06-22 05:01:20 +02:00
|
|
|
|
|
|
|
fn read_available(&mut self, buf: &mut BytesMut) -> Poll<usize, io::Error> {
|
|
|
|
unsafe {
|
|
|
|
if buf.remaining_mut() < LW_BUFFER_SIZE {
|
|
|
|
buf.reserve(HW_BUFFER_SIZE);
|
|
|
|
}
|
|
|
|
match self.read(buf.bytes_mut()) {
|
|
|
|
Ok(n) => {
|
|
|
|
buf.advance_mut(n);
|
|
|
|
Ok(Async::Ready(n))
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
if e.kind() == io::ErrorKind::WouldBlock {
|
|
|
|
Ok(Async::NotReady)
|
|
|
|
} else {
|
|
|
|
Err(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-01-12 07:06:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl IoStream for TcpStream {
|
|
|
|
#[inline]
|
|
|
|
fn shutdown(&mut self, how: Shutdown) -> io::Result<()> {
|
|
|
|
TcpStream::shutdown(self, how)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
|
|
|
|
TcpStream::set_nodelay(self, nodelay)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
|
|
|
|
TcpStream::set_linger(self, dur)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-14 01:02:01 +02:00
|
|
|
#[cfg(feature = "alpn")]
|
2018-01-12 07:06:06 +01:00
|
|
|
use tokio_openssl::SslStream;
|
|
|
|
|
2018-04-14 01:02:01 +02:00
|
|
|
#[cfg(feature = "alpn")]
|
2018-01-12 07:06:06 +01:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-14 01:02:01 +02:00
|
|
|
#[cfg(feature = "tls")]
|
2018-01-12 07:06:06 +01:00
|
|
|
use tokio_tls::TlsStream;
|
|
|
|
|
2018-04-14 01:02:01 +02:00
|
|
|
#[cfg(feature = "tls")]
|
2018-01-12 07:06:06 +01:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|