1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 16:02:59 +01:00
actix-extras/src/server.rs

296 lines
9.6 KiB
Rust
Raw Normal View History

2017-10-15 23:53:03 +02:00
use std::{io, mem, net};
2017-10-07 06:48:14 +02:00
use std::rc::Rc;
2017-10-14 01:33:23 +02:00
use std::time::Duration;
use std::marker::PhantomData;
2017-10-07 06:48:14 +02:00
use std::collections::VecDeque;
use actix::dev::*;
use futures::{Future, Poll, Async, Stream};
2017-10-14 01:33:23 +02:00
use tokio_core::reactor::Timeout;
2017-10-07 06:48:14 +02:00
use tokio_core::net::{TcpListener, TcpStream};
use tokio_io::{AsyncRead, AsyncWrite};
2017-10-07 06:48:14 +02:00
use task::{Task, RequestInfo};
2017-10-15 23:17:41 +02:00
use router::Router;
2017-10-14 01:33:23 +02:00
use reader::{Reader, ReaderError};
2017-10-07 06:48:14 +02:00
2017-10-08 23:56:51 +02:00
/// An HTTP Server
///
/// `T` - async stream, anything that implements `AsyncRead` + `AsyncWrite`.
///
/// `A` - peer address
pub struct HttpServer<T, A> {
2017-10-07 06:48:14 +02:00
router: Rc<Router>,
io: PhantomData<T>,
addr: PhantomData<A>,
2017-10-07 06:48:14 +02:00
}
impl<T: 'static, A: 'static> Actor for HttpServer<T, A> {
2017-10-07 06:48:14 +02:00
type Context = Context<Self>;
}
impl<T, A> HttpServer<T, A> {
2017-10-07 08:14:13 +02:00
/// Create new http server with specified `RoutingMap`
2017-10-15 23:17:41 +02:00
pub fn new(router: Router) -> Self {
HttpServer {router: Rc::new(router), io: PhantomData, addr: PhantomData}
2017-10-07 06:48:14 +02:00
}
}
impl<T, A> HttpServer<T, A>
where T: AsyncRead + AsyncWrite + 'static,
A: 'static
{
/// Start listening for incomming connections from stream.
pub fn serve_incoming<S, Addr>(self, stream: S) -> io::Result<Addr>
where Self: ActorAddress<Self, Addr>,
S: Stream<Item=(T, A), Error=io::Error> + 'static
{
Ok(HttpServer::create(move |ctx| {
ctx.add_stream(stream);
self
}))
}
}
impl HttpServer<TcpStream, net::SocketAddr> {
2017-10-07 06:48:14 +02:00
2017-10-07 08:14:13 +02:00
/// Start listening for incomming connections.
///
/// This methods converts address to list of `SocketAddr`
/// then binds to all available addresses.
2017-10-15 23:53:03 +02:00
pub fn serve<S, Addr>(self, addr: S) -> io::Result<Addr>
where Self: ActorAddress<Self, Addr>,
S: net::ToSocketAddrs,
2017-10-07 06:48:14 +02:00
{
2017-10-15 23:53:03 +02:00
let mut err = None;
let mut addrs = Vec::new();
2017-10-16 10:19:23 +02:00
if let Ok(iter) = addr.to_socket_addrs() {
2017-10-15 23:53:03 +02:00
for addr in iter {
match TcpListener::bind(&addr, Arbiter::handle()) {
Ok(tcp) => addrs.push(tcp),
Err(e) => err = Some(e),
}
}
}
if addrs.is_empty() {
if let Some(e) = err.take() {
Err(e)
} else {
Err(io::Error::new(io::ErrorKind::Other, "Can not bind to address."))
}
} else {
Ok(HttpServer::create(move |ctx| {
for tcp in addrs {
ctx.add_stream(tcp.incoming());
}
self
}))
}
2017-10-07 06:48:14 +02:00
}
}
impl<T, A> ResponseType<(T, A)> for HttpServer<T, A>
where T: AsyncRead + AsyncWrite + 'static,
A: 'static
{
2017-10-07 06:48:14 +02:00
type Item = ();
type Error = ();
}
impl<T, A> StreamHandler<(T, A), io::Error> for HttpServer<T, A>
where T: AsyncRead + AsyncWrite + 'static,
A: 'static {
}
2017-10-07 06:48:14 +02:00
impl<T, A> Handler<(T, A), io::Error> for HttpServer<T, A>
where T: AsyncRead + AsyncWrite + 'static,
A: 'static
{
fn handle(&mut self, msg: (T, A), _: &mut Context<Self>) -> Response<Self, (T, A)>
2017-10-07 06:48:14 +02:00
{
Arbiter::handle().spawn(
HttpChannel{router: Rc::clone(&self.router),
addr: msg.1,
stream: msg.0,
reader: Reader::new(),
error: false,
2017-10-07 06:48:14 +02:00
items: VecDeque::new(),
inactive: Vec::new(),
2017-10-14 01:33:23 +02:00
keepalive: true,
keepalive_timer: None,
2017-10-07 06:48:14 +02:00
});
2017-10-07 09:22:09 +02:00
Self::empty()
2017-10-07 06:48:14 +02:00
}
}
struct Entry {
task: Task,
req: RequestInfo,
2017-10-07 06:48:14 +02:00
eof: bool,
error: bool,
finished: bool,
}
2017-10-14 01:33:23 +02:00
const KEEPALIVE_PERIOD: u64 = 15; // seconds
const MAX_PIPELINED_MESSAGES: usize = 16;
pub struct HttpChannel<T: 'static, A: 'static> {
2017-10-07 06:48:14 +02:00
router: Rc<Router>,
#[allow(dead_code)]
addr: A,
stream: T,
2017-10-07 06:48:14 +02:00
reader: Reader,
error: bool,
2017-10-07 06:48:14 +02:00
items: VecDeque<Entry>,
inactive: Vec<Entry>,
2017-10-14 01:33:23 +02:00
keepalive: bool,
keepalive_timer: Option<Timeout>,
}
2017-10-21 06:08:38 +02:00
/*impl<T: 'static, A: 'static> Drop for HttpChannel<T, A> {
2017-10-14 01:33:23 +02:00
fn drop(&mut self) {
println!("Drop http channel");
}
2017-10-21 06:08:38 +02:00
}*/
2017-10-07 06:48:14 +02:00
impl<T, A> Actor for HttpChannel<T, A>
where T: AsyncRead + AsyncWrite + 'static, A: 'static
{
2017-10-07 06:48:14 +02:00
type Context = Context<Self>;
}
impl<T, A> Future for HttpChannel<T, A>
where T: AsyncRead + AsyncWrite + 'static, A: 'static
{
2017-10-07 06:48:14 +02:00
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
2017-10-14 01:33:23 +02:00
// keep-alive timer
if let Some(ref mut timeout) = self.keepalive_timer {
match timeout.poll() {
Ok(Async::Ready(_)) =>
return Ok(Async::Ready(())),
Ok(Async::NotReady) => (),
Err(_) => unreachable!(),
}
}
2017-10-07 06:48:14 +02:00
loop {
// check in-flight messages
let mut idx = 0;
while idx < self.items.len() {
if idx == 0 {
if self.items[idx].error {
return Err(())
}
// this is anoying
let req: &RequestInfo = unsafe {
mem::transmute(&self.items[idx].req)
};
match self.items[idx].task.poll_io(&mut self.stream, req)
{
2017-10-07 06:48:14 +02:00
Ok(Async::Ready(val)) => {
let mut item = self.items.pop_front().unwrap();
2017-10-14 01:33:23 +02:00
// overide keep-alive state
if self.keepalive {
self.keepalive = item.task.keepalive();
}
2017-10-07 06:48:14 +02:00
if !val {
item.eof = true;
self.inactive.push(item);
}
2017-10-14 01:33:23 +02:00
// no keep-alive
if !self.keepalive && self.items.is_empty() {
return Ok(Async::Ready(()))
}
2017-10-07 06:48:14 +02:00
continue
},
Ok(Async::NotReady) => (),
Err(_) => {
// it is not possible to recover from error
// during task handling, so just drop connection
return Err(())
}
2017-10-07 06:48:14 +02:00
}
} else if !self.items[idx].finished {
match self.items[idx].task.poll() {
Ok(Async::Ready(_)) =>
self.items[idx].finished = true,
Ok(Async::NotReady) => (),
Err(_) =>
self.items[idx].error = true,
}
}
idx += 1;
}
// read incoming data
2017-10-14 01:33:23 +02:00
if !self.error && self.items.len() < MAX_PIPELINED_MESSAGES {
match self.reader.parse(&mut self.stream) {
Ok(Async::Ready((req, payload))) => {
2017-10-14 01:33:23 +02:00
// stop keepalive timer
self.keepalive_timer.take();
// start request processing
let info = RequestInfo::new(&req);
self.items.push_back(
Entry {task: self.router.call(req, payload),
req: info,
eof: false,
error: false,
finished: false});
}
2017-10-14 01:33:23 +02:00
Err(err) => {
// kill keepalive
self.keepalive = false;
self.keepalive_timer.take();
// on parse error, stop reading stream but
// complete tasks
self.error = true;
if let ReaderError::Error(err) = err {
self.items.push_back(
Entry {task: Task::reply(err),
req: RequestInfo::for_error(),
eof: false,
error: false,
finished: false});
}
}
Ok(Async::NotReady) => {
// start keep-alive timer, this is also slow request timeout
if self.items.is_empty() {
if self.keepalive {
if self.keepalive_timer.is_none() {
trace!("Start keep-alive timer");
let mut timeout = Timeout::new(
Duration::new(KEEPALIVE_PERIOD, 0),
Arbiter::handle()).unwrap();
// register timeout
let _ = timeout.poll();
self.keepalive_timer = Some(timeout);
}
} else {
// keep-alive disable, drop connection
return Ok(Async::Ready(()))
}
}
return Ok(Async::NotReady)
}
}
2017-10-07 06:48:14 +02:00
}
2017-10-14 01:33:23 +02:00
// check for parse error
if self.items.is_empty() && self.error {
return Ok(Async::Ready(()))
}
2017-10-07 06:48:14 +02:00
}
}
}