1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-28 09:42:40 +01:00

separate mod for HttpHandler; add HttpHandler impl for Vec<H>

This commit is contained in:
Nikolay Kim 2018-09-09 18:06:00 -07:00
parent 6f3e70a92a
commit dbb4fab4f7
6 changed files with 204 additions and 93 deletions

View File

@ -447,7 +447,7 @@ where
}); });
continue 'outer; continue 'outer;
} }
Err(msg) => { Err(_) => {
// handler is not found // handler is not found
self.tasks.push_back(Entry { self.tasks.push_back(Entry {
pipe: EntryPipe::Error(ServerError::err( pipe: EntryPipe::Error(ServerError::err(
@ -516,19 +516,22 @@ mod tests {
use std::{cmp, io, time}; use std::{cmp, io, time};
use bytes::{Buf, Bytes, BytesMut}; use bytes::{Buf, Bytes, BytesMut};
use futures::future;
use http::{Method, Version}; use http::{Method, Version};
use tokio::runtime::current_thread;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use super::*; use super::*;
use application::HttpApplication; use application::{App, HttpApplication};
use httpmessage::HttpMessage; use httpmessage::HttpMessage;
use server::h1decoder::Message; use server::h1decoder::Message;
use server::handler::IntoHttpHandler;
use server::settings::{ServerSettings, WorkerSettings}; use server::settings::{ServerSettings, WorkerSettings};
use server::{KeepAlive, Request}; use server::{KeepAlive, Request};
fn wrk_settings() -> WorkerSettings<HttpApplication> { fn wrk_settings() -> WorkerSettings<HttpApplication> {
WorkerSettings::<HttpApplication>::new( WorkerSettings::<HttpApplication>::new(
Vec::new(), App::new().into_handler(),
KeepAlive::Os, KeepAlive::Os,
ServerSettings::default(), ServerSettings::default(),
) )
@ -646,30 +649,6 @@ mod tests {
} }
} }
#[test]
fn test_req_parse1() {
let buf = Buffer::new("GET /test HTTP/1.1\r\n\r\n");
let readbuf = BytesMut::new();
let settings = wrk_settings();
let mut h1 = Http1::new(settings.clone(), buf, None, readbuf, false, None);
h1.poll_io();
h1.poll_io();
assert_eq!(h1.tasks.len(), 1);
}
#[test]
fn test_req_parse2() {
let buf = Buffer::new("");
let readbuf =
BytesMut::from(Vec::<u8>::from(&b"GET /test HTTP/1.1\r\n\r\n"[..]));
let settings = wrk_settings();
let mut h1 = Http1::new(settings.clone(), buf, None, readbuf, true, None);
h1.poll_io();
assert_eq!(h1.tasks.len(), 1);
}
#[test] #[test]
fn test_req_parse_err() { fn test_req_parse_err() {
let buf = Buffer::new("GET /test HTTP/1\r\n\r\n"); let buf = Buffer::new("GET /test HTTP/1\r\n\r\n");

View File

@ -370,7 +370,7 @@ impl<H: HttpHandler + 'static> Entry<H> {
// start request processing // start request processing
let task = match settings.handler().handle(msg) { let task = match settings.handler().handle(msg) {
Ok(task) => EntryPipe::Task(task), Ok(task) => EntryPipe::Task(task),
Err(msg) => EntryPipe::Error(ServerError::err( Err(_) => EntryPipe::Error(ServerError::err(
Version::HTTP_2, Version::HTTP_2,
StatusCode::NOT_FOUND, StatusCode::NOT_FOUND,
)), )),

189
src/server/handler.rs Normal file
View File

@ -0,0 +1,189 @@
use futures::{Async, Poll};
use super::message::Request;
use super::Writer;
use error::Error;
/// Low level http request handler
#[allow(unused_variables)]
pub trait HttpHandler: 'static {
/// Request handling task
type Task: HttpHandlerTask;
/// Handle request
fn handle(&self, req: Request) -> Result<Self::Task, Request>;
}
impl HttpHandler for Box<HttpHandler<Task = Box<HttpHandlerTask>>> {
type Task = Box<HttpHandlerTask>;
fn handle(&self, req: Request) -> Result<Box<HttpHandlerTask>, Request> {
self.as_ref().handle(req)
}
}
/// Low level http request handler
pub trait HttpHandlerTask {
/// Poll task, this method is used before or after *io* object is available
fn poll_completed(&mut self) -> Poll<(), Error> {
Ok(Async::Ready(()))
}
/// Poll task when *io* object is available
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error>;
/// Connection is disconnected
fn disconnected(&mut self) {}
}
impl HttpHandlerTask for Box<HttpHandlerTask> {
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
self.as_mut().poll_io(io)
}
}
/// 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) -> Self::Handler;
}
impl<T: HttpHandler> IntoHttpHandler for T {
type Handler = T;
fn into_handler(self) -> Self::Handler {
self
}
}
impl<T: IntoHttpHandler> IntoHttpHandler for Vec<T> {
type Handler = VecHttpHandler<T::Handler>;
fn into_handler(self) -> Self::Handler {
VecHttpHandler(self.into_iter().map(|item| item.into_handler()).collect())
}
}
#[doc(hidden)]
pub struct VecHttpHandler<H: HttpHandler>(Vec<H>);
impl<H: HttpHandler> HttpHandler for VecHttpHandler<H> {
type Task = H::Task;
fn handle(&self, mut req: Request) -> Result<Self::Task, Request> {
for h in &self.0 {
req = match h.handle(req) {
Ok(task) => return Ok(task),
Err(e) => e,
};
}
Err(req)
}
}
macro_rules! http_handler ({$EN:ident, $(($n:tt, $T:ident)),+} => {
impl<$($T: HttpHandler,)+> HttpHandler for ($($T,)+) {
type Task = $EN<$($T,)+>;
fn handle(&self, mut req: Request) -> Result<Self::Task, Request> {
$(
req = match self.$n.handle(req) {
Ok(task) => return Ok($EN::$T(task)),
Err(e) => e,
};
)+
Err(req)
}
}
#[doc(hidden)]
pub enum $EN<$($T: HttpHandler,)+> {
$($T ($T::Task),)+
}
impl<$($T: HttpHandler,)+> HttpHandlerTask for $EN<$($T,)+>
{
fn poll_completed(&mut self) -> Poll<(), Error> {
match self {
$($EN :: $T(ref mut task) => task.poll_completed(),)+
}
}
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
match self {
$($EN::$T(ref mut task) => task.poll_io(io),)+
}
}
/// Connection is disconnected
fn disconnected(&mut self) {
match self {
$($EN::$T(ref mut task) => task.disconnected(),)+
}
}
}
});
http_handler!(HttpHandlerTask1, (0, A));
http_handler!(HttpHandlerTask2, (0, A), (1, B));
http_handler!(HttpHandlerTask3, (0, A), (1, B), (2, C));
http_handler!(HttpHandlerTask4, (0, A), (1, B), (2, C), (3, D));
http_handler!(HttpHandlerTask5, (0, A), (1, B), (2, C), (3, D), (4, E));
http_handler!(
HttpHandlerTask6,
(0, A),
(1, B),
(2, C),
(3, D),
(4, E),
(5, F)
);
http_handler!(
HttpHandlerTask7,
(0, A),
(1, B),
(2, C),
(3, D),
(4, E),
(5, F),
(6, G)
);
http_handler!(
HttpHandlerTask8,
(0, A),
(1, B),
(2, C),
(3, D),
(4, E),
(5, F),
(6, G),
(7, H)
);
http_handler!(
HttpHandlerTask9,
(0, A),
(1, B),
(2, C),
(3, D),
(4, E),
(5, F),
(6, G),
(7, H),
(8, I)
);
http_handler!(
HttpHandlerTask10,
(0, A),
(1, B),
(2, C),
(3, D),
(4, E),
(5, F),
(6, G),
(7, H),
(8, I),
(9, J)
);

View File

@ -3,7 +3,8 @@ use std::{io, mem, net, time};
use actix::{Actor, Addr, AsyncContext, Context, Handler, System}; use actix::{Actor, Addr, AsyncContext, Context, Handler, System};
use actix_net::server::{Server, ServerServiceFactory}; use actix_net::server::{Server, ServerServiceFactory};
use actix_net::{ssl, NewService, NewServiceExt, Service}; use actix_net::service::{NewService, NewServiceExt, Service};
use actix_net::ssl;
use futures::future::{ok, FutureResult}; use futures::future::{ok, FutureResult};
use futures::{Async, Poll, Stream}; use futures::{Async, Poll, Stream};

View File

@ -115,7 +115,7 @@ use futures::{Async, Poll};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use tokio_tcp::TcpStream; use tokio_tcp::TcpStream;
pub use actix_net::{PauseServer, ResumeServer, StopServer}; pub use actix_net::server::{PauseServer, ResumeServer, StopServer};
mod channel; mod channel;
mod error; mod error;
@ -124,25 +124,25 @@ pub(crate) mod h1decoder;
mod h1writer; mod h1writer;
mod h2; mod h2;
mod h2writer; mod h2writer;
mod handler;
pub(crate) mod helpers; pub(crate) mod helpers;
mod http; mod http;
pub(crate) mod input; pub(crate) mod input;
pub(crate) mod message; pub(crate) mod message;
pub(crate) mod output; pub(crate) mod output;
pub(crate) mod settings; pub(crate) mod settings;
mod ssl; mod ssl;
pub use self::ssl::*;
pub use self::handler::*;
pub use self::http::HttpServer; pub use self::http::HttpServer;
pub use self::message::Request; pub use self::message::Request;
pub use self::settings::ServerSettings; pub use self::settings::ServerSettings;
pub use self::ssl::*;
#[doc(hidden)] #[doc(hidden)]
pub use self::helpers::write_content_length; pub use self::helpers::write_content_length;
use body::Binary; use body::Binary;
use error::Error;
use extensions::Extensions; use extensions::Extensions;
use header::ContentEncoding; use header::ContentEncoding;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
@ -222,61 +222,6 @@ impl From<Option<usize>> for KeepAlive {
} }
} }
/// Low level http request handler
#[allow(unused_variables)]
pub trait HttpHandler: 'static {
/// Request handling task
type Task: HttpHandlerTask;
/// Handle request
fn handle(&self, req: Request) -> Result<Self::Task, Request>;
}
impl HttpHandler for Box<HttpHandler<Task = Box<HttpHandlerTask>>> {
type Task = Box<HttpHandlerTask>;
fn handle(&self, req: Request) -> Result<Box<HttpHandlerTask>, Request> {
self.as_ref().handle(req)
}
}
/// Low level http request handler
pub trait HttpHandlerTask {
/// Poll task, this method is used before or after *io* object is available
fn poll_completed(&mut self) -> Poll<(), Error> {
Ok(Async::Ready(()))
}
/// Poll task when *io* object is available
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error>;
/// Connection is disconnected
fn disconnected(&mut self) {}
}
impl HttpHandlerTask for Box<HttpHandlerTask> {
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
self.as_mut().poll_io(io)
}
}
/// 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) -> Self::Handler;
}
impl<T: HttpHandler> IntoHttpHandler for T {
type Handler = T;
fn into_handler(self) -> Self::Handler {
self
}
}
#[doc(hidden)] #[doc(hidden)]
#[derive(Debug)] #[derive(Debug)]
pub enum WriterState { pub enum WriterState {

View File

@ -316,11 +316,8 @@ mod tests {
let mut rt = current_thread::Runtime::new().unwrap(); let mut rt = current_thread::Runtime::new().unwrap();
let _ = rt.block_on(future::lazy(|| { let _ = rt.block_on(future::lazy(|| {
let settings = WorkerSettings::<()>::new( let settings =
Vec::new(), WorkerSettings::<()>::new((), KeepAlive::Os, ServerSettings::default());
KeepAlive::Os,
ServerSettings::default(),
);
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10); let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
settings.set_date(&mut buf1, true); settings.set_date(&mut buf1, true);
let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10); let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);