mirror of
https://github.com/actix/actix-extras.git
synced 2025-06-30 03:44:27 +02:00
refactor HttpHandlerTask trait
This commit is contained in:
@ -11,7 +11,7 @@ use super::{h1, h2, utils, HttpHandler, IoStream};
|
||||
|
||||
const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0";
|
||||
|
||||
enum HttpProtocol<T: IoStream, H: 'static> {
|
||||
enum HttpProtocol<T: IoStream, H: HttpHandler + 'static> {
|
||||
H1(h1::Http1<T, H>),
|
||||
H2(h2::Http2<T, H>),
|
||||
Unknown(Rc<WorkerSettings<H>>, Option<SocketAddr>, T, BytesMut),
|
||||
|
@ -8,7 +8,7 @@ use bytes::{BufMut, BytesMut};
|
||||
use futures::{Async, Future, Poll};
|
||||
use tokio_timer::Delay;
|
||||
|
||||
use error::PayloadError;
|
||||
use error::{Error, PayloadError};
|
||||
use httprequest::HttpRequest;
|
||||
use httpresponse::HttpResponse;
|
||||
use payload::{Payload, PayloadStatus, PayloadWriter};
|
||||
@ -43,7 +43,7 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Http1<T: IoStream, H: 'static> {
|
||||
pub(crate) struct Http1<T: IoStream, H: HttpHandler + 'static> {
|
||||
flags: Flags,
|
||||
settings: Rc<WorkerSettings<H>>,
|
||||
addr: Option<SocketAddr>,
|
||||
@ -51,12 +51,38 @@ pub(crate) struct Http1<T: IoStream, H: 'static> {
|
||||
decoder: H1Decoder,
|
||||
payload: Option<PayloadType>,
|
||||
buf: BytesMut,
|
||||
tasks: VecDeque<Entry>,
|
||||
tasks: VecDeque<Entry<H>>,
|
||||
keepalive_timer: Option<Delay>,
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
pipe: Box<HttpHandlerTask>,
|
||||
enum EntryPipe<H: HttpHandler> {
|
||||
Task(H::Task),
|
||||
Error(Box<HttpHandlerTask>),
|
||||
}
|
||||
|
||||
impl<H: HttpHandler> EntryPipe<H> {
|
||||
fn disconnected(&mut self) {
|
||||
match *self {
|
||||
EntryPipe::Task(ref mut task) => task.disconnected(),
|
||||
EntryPipe::Error(ref mut task) => task.disconnected(),
|
||||
}
|
||||
}
|
||||
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
||||
match *self {
|
||||
EntryPipe::Task(ref mut task) => task.poll_io(io),
|
||||
EntryPipe::Error(ref mut task) => task.poll_io(io),
|
||||
}
|
||||
}
|
||||
fn poll_completed(&mut self) -> Poll<(), Error> {
|
||||
match *self {
|
||||
EntryPipe::Task(ref mut task) => task.poll_completed(),
|
||||
EntryPipe::Error(ref mut task) => task.poll_completed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Entry<H: HttpHandler> {
|
||||
pipe: EntryPipe<H>,
|
||||
flags: EntryFlags,
|
||||
}
|
||||
|
||||
@ -181,7 +207,7 @@ where
|
||||
let mut io = false;
|
||||
let mut idx = 0;
|
||||
while idx < self.tasks.len() {
|
||||
let item: &mut Entry = unsafe { &mut *(&mut self.tasks[idx] as *mut _) };
|
||||
let item: &mut Entry<H> = unsafe { &mut *(&mut self.tasks[idx] as *mut _) };
|
||||
|
||||
// only one task can do io operation in http/1
|
||||
if !io && !item.flags.contains(EntryFlags::EOF) {
|
||||
@ -232,7 +258,7 @@ where
|
||||
}
|
||||
}
|
||||
} else if !item.flags.contains(EntryFlags::FINISHED) {
|
||||
match item.pipe.poll() {
|
||||
match item.pipe.poll_completed() {
|
||||
Ok(Async::NotReady) => (),
|
||||
Ok(Async::Ready(_)) => item.flags.insert(EntryFlags::FINISHED),
|
||||
Err(err) => {
|
||||
@ -342,7 +368,7 @@ where
|
||||
|
||||
if !ready {
|
||||
let item = Entry {
|
||||
pipe,
|
||||
pipe: EntryPipe::Task(pipe),
|
||||
flags: EntryFlags::EOF,
|
||||
};
|
||||
self.tasks.push_back(item);
|
||||
@ -358,7 +384,7 @@ where
|
||||
}
|
||||
}
|
||||
self.tasks.push_back(Entry {
|
||||
pipe,
|
||||
pipe: EntryPipe::Task(pipe),
|
||||
flags: EntryFlags::empty(),
|
||||
});
|
||||
continue 'outer;
|
||||
@ -369,7 +395,9 @@ where
|
||||
|
||||
// handler is not found
|
||||
self.tasks.push_back(Entry {
|
||||
pipe: Pipeline::error(HttpResponse::NotFound()),
|
||||
pipe: EntryPipe::Error(
|
||||
Pipeline::error(HttpResponse::NotFound()),
|
||||
),
|
||||
flags: EntryFlags::empty(),
|
||||
});
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use modhttp::request::Parts;
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use tokio_timer::Delay;
|
||||
|
||||
use error::PayloadError;
|
||||
use error::{Error, PayloadError};
|
||||
use httpmessage::HttpMessage;
|
||||
use httprequest::HttpRequest;
|
||||
use httpresponse::HttpResponse;
|
||||
@ -38,7 +38,7 @@ bitflags! {
|
||||
pub(crate) struct Http2<T, H>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + 'static,
|
||||
H: 'static,
|
||||
H: HttpHandler + 'static,
|
||||
{
|
||||
flags: Flags,
|
||||
settings: Rc<WorkerSettings<H>>,
|
||||
@ -142,7 +142,7 @@ where
|
||||
break;
|
||||
}
|
||||
} else if !item.flags.contains(EntryFlags::FINISHED) {
|
||||
match item.task.poll() {
|
||||
match item.task.poll_completed() {
|
||||
Ok(Async::NotReady) => (),
|
||||
Ok(Async::Ready(_)) => {
|
||||
not_ready = false;
|
||||
@ -288,15 +288,41 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
struct Entry<H: 'static> {
|
||||
task: Box<HttpHandlerTask>,
|
||||
enum EntryPipe<H: HttpHandler> {
|
||||
Task(H::Task),
|
||||
Error(Box<HttpHandlerTask>),
|
||||
}
|
||||
|
||||
impl<H: HttpHandler> EntryPipe<H> {
|
||||
fn disconnected(&mut self) {
|
||||
match *self {
|
||||
EntryPipe::Task(ref mut task) => task.disconnected(),
|
||||
EntryPipe::Error(ref mut task) => task.disconnected(),
|
||||
}
|
||||
}
|
||||
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
||||
match *self {
|
||||
EntryPipe::Task(ref mut task) => task.poll_io(io),
|
||||
EntryPipe::Error(ref mut task) => task.poll_io(io),
|
||||
}
|
||||
}
|
||||
fn poll_completed(&mut self) -> Poll<(), Error> {
|
||||
match *self {
|
||||
EntryPipe::Task(ref mut task) => task.poll_completed(),
|
||||
EntryPipe::Error(ref mut task) => task.poll_completed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Entry<H: HttpHandler + 'static> {
|
||||
task: EntryPipe<H>,
|
||||
payload: PayloadType,
|
||||
recv: RecvStream,
|
||||
stream: H2Writer<H>,
|
||||
flags: EntryFlags,
|
||||
}
|
||||
|
||||
impl<H: 'static> Entry<H> {
|
||||
impl<H: HttpHandler + 'static> Entry<H> {
|
||||
fn new(
|
||||
parts: Parts, recv: RecvStream, resp: SendResponse<Bytes>,
|
||||
addr: Option<SocketAddr>, settings: &Rc<WorkerSettings<H>>,
|
||||
@ -333,7 +359,9 @@ impl<H: 'static> Entry<H> {
|
||||
}
|
||||
|
||||
Entry {
|
||||
task: task.unwrap_or_else(|| Pipeline::error(HttpResponse::NotFound())),
|
||||
task: task.map(EntryPipe::Task).unwrap_or_else(|| {
|
||||
EntryPipe::Error(Pipeline::error(HttpResponse::NotFound()))
|
||||
}),
|
||||
payload: psender,
|
||||
stream: H2Writer::new(
|
||||
resp,
|
||||
|
@ -122,20 +122,25 @@ impl Message for StopServer {
|
||||
/// Low level http request handler
|
||||
#[allow(unused_variables)]
|
||||
pub trait HttpHandler: 'static {
|
||||
/// Request handling task
|
||||
type Task: HttpHandlerTask;
|
||||
|
||||
/// Handle request
|
||||
fn handle(&mut self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest>;
|
||||
fn handle(&mut self, req: HttpRequest) -> Result<Self::Task, HttpRequest>;
|
||||
}
|
||||
|
||||
impl HttpHandler for Box<HttpHandler> {
|
||||
impl HttpHandler for Box<HttpHandler<Task = Box<HttpHandlerTask>>> {
|
||||
type Task = Box<HttpHandlerTask>;
|
||||
|
||||
fn handle(&mut self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest> {
|
||||
self.as_mut().handle(req)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Low level http request handler
|
||||
pub trait HttpHandlerTask {
|
||||
/// Poll task, this method is used before or after *io* object is available
|
||||
fn poll(&mut self) -> Poll<(), Error> {
|
||||
fn poll_completed(&mut self) -> Poll<(), Error> {
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
|
||||
@ -146,6 +151,12 @@ pub trait HttpHandlerTask {
|
||||
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.
|
||||
|
Reference in New Issue
Block a user