mirror of
https://github.com/actix/actix-web.git
synced 2024-12-17 21:56:38 +00:00
simplify middleware api; fix examples
This commit is contained in:
parent
5a3b6638a7
commit
fdafb0c848
11 changed files with 74 additions and 64 deletions
|
@ -15,11 +15,10 @@ impl Actor for MyRoute {
|
||||||
impl Route for MyRoute {
|
impl Route for MyRoute {
|
||||||
type State = ();
|
type State = ();
|
||||||
|
|
||||||
fn request(req: &mut HttpRequest, payload: Payload,
|
fn request(mut req: HttpRequest, ctx: &mut HttpContext<Self>) -> RouteResult<Self> {
|
||||||
ctx: &mut HttpContext<Self>) -> RouteResult<Self> {
|
|
||||||
println!("{:?}", req);
|
println!("{:?}", req);
|
||||||
|
|
||||||
let multipart = req.multipart(payload)?;
|
let multipart = req.multipart()?;
|
||||||
|
|
||||||
// get Multipart stream
|
// get Multipart stream
|
||||||
WrapStream::<MyRoute>::actstream(multipart)
|
WrapStream::<MyRoute>::actstream(multipart)
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::io::Read;
|
||||||
use actix_web::*;
|
use actix_web::*;
|
||||||
|
|
||||||
/// somple handle
|
/// somple handle
|
||||||
fn index(req: &mut HttpRequest, _payload: Payload, state: &()) -> HttpResponse {
|
fn index(req: HttpRequest) -> HttpResponse {
|
||||||
println!("{:?}", req);
|
println!("{:?}", req);
|
||||||
httpcodes::HTTPOk
|
httpcodes::HTTPOk
|
||||||
.builder()
|
.builder()
|
||||||
|
@ -36,7 +36,7 @@ fn main() {
|
||||||
// register simple handler, handle all methods
|
// register simple handler, handle all methods
|
||||||
.handler("/index.html", index)
|
.handler("/index.html", index)
|
||||||
// with path parameters
|
// with path parameters
|
||||||
.resource("/", |r| r.handler(Method::GET, |req, _, _| {
|
.resource("/", |r| r.handler(Method::GET, |req| {
|
||||||
Ok(httpcodes::HTTPFound
|
Ok(httpcodes::HTTPFound
|
||||||
.builder()
|
.builder()
|
||||||
.header("LOCATION", "/index.html")
|
.header("LOCATION", "/index.html")
|
||||||
|
|
|
@ -48,13 +48,13 @@ impl Actor for WsChatSession {
|
||||||
impl Route for WsChatSession {
|
impl Route for WsChatSession {
|
||||||
type State = WsChatSessionState;
|
type State = WsChatSessionState;
|
||||||
|
|
||||||
fn request(req: &mut HttpRequest,
|
fn request(mut req: HttpRequest<WsChatSessionState>,
|
||||||
payload: Payload, ctx: &mut HttpContext<Self>) -> RouteResult<Self>
|
ctx: &mut HttpContext<Self>) -> RouteResult<Self>
|
||||||
{
|
{
|
||||||
// websocket handshakre, it may fail if request is not websocket request
|
// websocket handshakre, it may fail if request is not websocket request
|
||||||
let resp = ws::handshake(&req)?;
|
let resp = ws::handshake(&req)?;
|
||||||
ctx.start(resp);
|
ctx.start(resp);
|
||||||
ctx.add_stream(ws::WsStream::new(payload));
|
ctx.add_stream(ws::WsStream::new(&mut req));
|
||||||
Reply::async(
|
Reply::async(
|
||||||
WsChatSession {
|
WsChatSession {
|
||||||
id: 0,
|
id: 0,
|
||||||
|
@ -207,10 +207,10 @@ fn main() {
|
||||||
|
|
||||||
// Create Http server with websocket support
|
// Create Http server with websocket support
|
||||||
HttpServer::new(
|
HttpServer::new(
|
||||||
Application::builder("/", state)
|
Application::build("/", state)
|
||||||
// redirect to websocket.html
|
// redirect to websocket.html
|
||||||
.resource("/", |r|
|
.resource("/", |r|
|
||||||
r.handler(Method::GET, |req, payload, state| {
|
r.handler(Method::GET, |req| {
|
||||||
Ok(httpcodes::HTTPFound
|
Ok(httpcodes::HTTPFound
|
||||||
.builder()
|
.builder()
|
||||||
.header("LOCATION", "/static/websocket.html")
|
.header("LOCATION", "/static/websocket.html")
|
||||||
|
|
|
@ -29,6 +29,7 @@ pub struct HttpContext<A> where A: Actor<Context=HttpContext<A>> + Route,
|
||||||
address: ActorAddressCell<A>,
|
address: ActorAddressCell<A>,
|
||||||
stream: VecDeque<Frame>,
|
stream: VecDeque<Frame>,
|
||||||
wait: ActorWaitCell<A>,
|
wait: ActorWaitCell<A>,
|
||||||
|
app_state: Rc<<A as Route>::State>,
|
||||||
disconnected: bool,
|
disconnected: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,9 +102,10 @@ impl<A> AsyncContextApi<A> for HttpContext<A> where A: Actor<Context=Self> + Rou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> Default for HttpContext<A> where A: Actor<Context=Self> + Route {
|
impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
|
||||||
|
|
||||||
fn default() -> HttpContext<A> {
|
pub fn new(state: Rc<<A as Route>::State>) -> HttpContext<A>
|
||||||
|
{
|
||||||
HttpContext {
|
HttpContext {
|
||||||
act: None,
|
act: None,
|
||||||
state: ActorState::Started,
|
state: ActorState::Started,
|
||||||
|
@ -112,12 +114,10 @@ impl<A> Default for HttpContext<A> where A: Actor<Context=Self> + Route {
|
||||||
address: ActorAddressCell::default(),
|
address: ActorAddressCell::default(),
|
||||||
wait: ActorWaitCell::default(),
|
wait: ActorWaitCell::default(),
|
||||||
stream: VecDeque::new(),
|
stream: VecDeque::new(),
|
||||||
|
app_state: state,
|
||||||
disconnected: false,
|
disconnected: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
|
|
||||||
|
|
||||||
pub(crate) fn set_actor(&mut self, act: A) {
|
pub(crate) fn set_actor(&mut self, act: A) {
|
||||||
self.act = Some(act)
|
self.act = Some(act)
|
||||||
|
@ -126,6 +126,11 @@ impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
|
||||||
|
|
||||||
impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
|
impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
|
||||||
|
|
||||||
|
/// Shared application state
|
||||||
|
pub fn state(&self) -> &<A as Route>::State {
|
||||||
|
&self.app_state
|
||||||
|
}
|
||||||
|
|
||||||
/// Start response processing
|
/// Start response processing
|
||||||
pub fn start<R: Into<HttpResponse>>(&mut self, response: R) {
|
pub fn start<R: Into<HttpResponse>>(&mut self, response: R) {
|
||||||
self.stream.push_back(Frame::Message(response.into()))
|
self.stream.push_back(Frame::Message(response.into()))
|
||||||
|
|
|
@ -99,6 +99,11 @@ impl<S> HttpRequest<S> {
|
||||||
&self.1
|
&self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clone application state
|
||||||
|
pub(crate) fn clone_state(&self) -> Rc<S> {
|
||||||
|
Rc::clone(&self.1)
|
||||||
|
}
|
||||||
|
|
||||||
/// Protocol extensions.
|
/// Protocol extensions.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extensions(&mut self) -> &mut Extensions {
|
pub fn extensions(&mut self) -> &mut Extensions {
|
||||||
|
@ -287,8 +292,9 @@ impl<S> HttpRequest<S> {
|
||||||
/// Return stream to process BODY as multipart.
|
/// Return stream to process BODY as multipart.
|
||||||
///
|
///
|
||||||
/// Content-type: multipart/form-data;
|
/// Content-type: multipart/form-data;
|
||||||
pub fn multipart(&self, payload: Payload) -> Result<Multipart, MultipartError> {
|
pub fn multipart(&mut self) -> Result<Multipart, MultipartError> {
|
||||||
Ok(Multipart::new(Multipart::boundary(&self.0.headers)?, payload))
|
let boundary = Multipart::boundary(&self.0.headers)?;
|
||||||
|
Ok(Multipart::new(boundary, self.take_payload()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse `application/x-www-form-urlencoded` encoded body.
|
/// Parse `application/x-www-form-urlencoded` encoded body.
|
||||||
|
|
|
@ -101,9 +101,9 @@ impl Logger {
|
||||||
|
|
||||||
impl Middleware for Logger {
|
impl Middleware for Logger {
|
||||||
|
|
||||||
fn start(&self, mut req: HttpRequest) -> Started {
|
fn start(&self, req: &mut HttpRequest) -> Started {
|
||||||
req.extensions().insert(StartTime(time::now()));
|
req.extensions().insert(StartTime(time::now()));
|
||||||
Started::Done(req)
|
Started::Done
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&self, req: &mut HttpRequest, resp: &HttpResponse) -> Finished {
|
fn finish(&self, req: &mut HttpRequest, resp: &HttpResponse) -> Finished {
|
||||||
|
@ -299,14 +299,14 @@ mod tests {
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(header::USER_AGENT, header::HeaderValue::from_static("ACTIX-WEB"));
|
headers.insert(header::USER_AGENT, header::HeaderValue::from_static("ACTIX-WEB"));
|
||||||
let req = HttpRequest::new(
|
let mut req = HttpRequest::new(
|
||||||
Method::GET, "/".to_owned(), Version::HTTP_11, headers, String::new(), Payload::empty());
|
Method::GET, "/".to_owned(), Version::HTTP_11, headers, String::new(), Payload::empty());
|
||||||
let resp = HttpResponse::builder(StatusCode::OK)
|
let resp = HttpResponse::builder(StatusCode::OK)
|
||||||
.header("X-Test", "ttt")
|
.header("X-Test", "ttt")
|
||||||
.force_close().body(Body::Empty).unwrap();
|
.force_close().body(Body::Empty).unwrap();
|
||||||
|
|
||||||
let mut req = match logger.start(req) {
|
match logger.start(&mut req) {
|
||||||
Started::Done(req) => req,
|
Started::Done => (),
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
};
|
};
|
||||||
match logger.finish(&mut req, &resp) {
|
match logger.finish(&mut req, &resp) {
|
||||||
|
|
|
@ -16,12 +16,12 @@ pub enum Started {
|
||||||
/// Moddleware error
|
/// Moddleware error
|
||||||
Err(Error),
|
Err(Error),
|
||||||
/// Execution completed
|
/// Execution completed
|
||||||
Done(HttpRequest),
|
Done,
|
||||||
/// New http response got generated. If middleware generates response
|
/// New http response got generated. If middleware generates response
|
||||||
/// handler execution halts.
|
/// handler execution halts.
|
||||||
Response(HttpRequest, HttpResponse),
|
Response(HttpResponse),
|
||||||
/// Execution completed, runs future to completion.
|
/// Execution completed, runs future to completion.
|
||||||
Future(Box<Future<Item=(HttpRequest, Option<HttpResponse>), Error=Error>>),
|
Future(Box<Future<Item=Option<HttpResponse>, Error=Error>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Middleware execution result
|
/// Middleware execution result
|
||||||
|
@ -48,8 +48,8 @@ pub trait Middleware {
|
||||||
|
|
||||||
/// Method is called when request is ready. It may return
|
/// Method is called when request is ready. It may return
|
||||||
/// future, which should resolve before next middleware get called.
|
/// future, which should resolve before next middleware get called.
|
||||||
fn start(&self, req: HttpRequest) -> Started {
|
fn start(&self, req: &mut HttpRequest) -> Started {
|
||||||
Started::Done(req)
|
Started::Done
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method is called when handler returns response,
|
/// Method is called when handler returns response,
|
||||||
|
|
|
@ -90,14 +90,15 @@ impl<T: SessionBackend> SessionStorage<T> {
|
||||||
|
|
||||||
impl<T: SessionBackend> Middleware for SessionStorage<T> {
|
impl<T: SessionBackend> Middleware for SessionStorage<T> {
|
||||||
|
|
||||||
fn start(&self, mut req: HttpRequest) -> Started {
|
fn start(&self, req: &mut HttpRequest) -> Started {
|
||||||
|
let mut req = req.clone();
|
||||||
|
|
||||||
let fut = self.0.from_request(&mut req)
|
let fut = self.0.from_request(&mut req)
|
||||||
.then(|res| {
|
.then(move |res| {
|
||||||
match res {
|
match res {
|
||||||
Ok(sess) => {
|
Ok(sess) => {
|
||||||
req.extensions().insert(Arc::new(SessionImplBox(Box::new(sess))));
|
req.extensions().insert(Arc::new(SessionImplBox(Box::new(sess))));
|
||||||
let resp: Option<HttpResponse> = None;
|
FutOk(None)
|
||||||
FutOk((req, resp))
|
|
||||||
},
|
},
|
||||||
Err(err) => FutErr(err)
|
Err(err) => FutErr(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,13 +146,14 @@ impl Pipeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Fut = Box<Future<Item=(HttpRequest, Option<HttpResponse>), Error=Error>>;
|
type Fut = Box<Future<Item=Option<HttpResponse>, Error=Error>>;
|
||||||
|
|
||||||
/// Middlewares start executor
|
/// Middlewares start executor
|
||||||
struct Start {
|
struct Start {
|
||||||
idx: usize,
|
idx: usize,
|
||||||
hnd: *mut Handler,
|
hnd: *mut Handler,
|
||||||
disconnected: bool,
|
disconnected: bool,
|
||||||
|
req: HttpRequest,
|
||||||
fut: Option<Fut>,
|
fut: Option<Fut>,
|
||||||
middlewares: Rc<Vec<Box<Middleware>>>,
|
middlewares: Rc<Vec<Box<Middleware>>>,
|
||||||
}
|
}
|
||||||
|
@ -169,10 +170,11 @@ impl Start {
|
||||||
Start {
|
Start {
|
||||||
idx: 0,
|
idx: 0,
|
||||||
fut: None,
|
fut: None,
|
||||||
|
req: req,
|
||||||
disconnected: false,
|
disconnected: false,
|
||||||
hnd: handler as *const _ as *mut _,
|
hnd: handler as *const _ as *mut _,
|
||||||
middlewares: mw,
|
middlewares: mw,
|
||||||
}.start(req)
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disconnected(&mut self) {
|
fn disconnected(&mut self) {
|
||||||
|
@ -187,43 +189,40 @@ impl Start {
|
||||||
task
|
task
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(mut self, mut req: HttpRequest) -> Result<StartResult, Error> {
|
fn start(mut self) -> Result<StartResult, Error> {
|
||||||
let len = self.middlewares.len();
|
let len = self.middlewares.len();
|
||||||
loop {
|
loop {
|
||||||
if self.idx == len {
|
if self.idx == len {
|
||||||
let task = (unsafe{&*self.hnd})(req.clone());
|
let task = (unsafe{&*self.hnd})(self.req.clone());
|
||||||
return Ok(StartResult::Ready(
|
return Ok(StartResult::Ready(
|
||||||
Box::new(Handle::new(self.idx-1, req, self.prepare(task), self.middlewares))))
|
Box::new(Handle::new(self.idx-1, self.req.clone(),
|
||||||
|
self.prepare(task), self.middlewares))))
|
||||||
} else {
|
} else {
|
||||||
req = match self.middlewares[self.idx].start(req) {
|
match self.middlewares[self.idx].start(&mut self.req) {
|
||||||
Started::Done(req) => {
|
Started::Done =>
|
||||||
self.idx += 1;
|
self.idx += 1,
|
||||||
req
|
Started::Response(resp) =>
|
||||||
}
|
|
||||||
Started::Response(req, resp) => {
|
|
||||||
return Ok(StartResult::Ready(
|
return Ok(StartResult::Ready(
|
||||||
Box::new(Handle::new(
|
Box::new(Handle::new(
|
||||||
self.idx, req, self.prepare(Task::reply(resp)), self.middlewares))))
|
self.idx, self.req.clone(),
|
||||||
},
|
self.prepare(Task::reply(resp)), self.middlewares)))),
|
||||||
Started::Future(mut fut) => {
|
Started::Future(mut fut) =>
|
||||||
match fut.poll() {
|
match fut.poll() {
|
||||||
Ok(Async::NotReady) => {
|
Ok(Async::NotReady) => {
|
||||||
self.fut = Some(fut);
|
self.fut = Some(fut);
|
||||||
return Ok(StartResult::NotReady(self))
|
return Ok(StartResult::NotReady(self))
|
||||||
}
|
}
|
||||||
Ok(Async::Ready((req, resp))) => {
|
Ok(Async::Ready(resp)) => {
|
||||||
if let Some(resp) = resp {
|
if let Some(resp) = resp {
|
||||||
return Ok(StartResult::Ready(
|
return Ok(StartResult::Ready(
|
||||||
Box::new(Handle::new(
|
Box::new(Handle::new(
|
||||||
self.idx, req,
|
self.idx, self.req.clone(),
|
||||||
self.prepare(Task::reply(resp)), self.middlewares))))
|
self.prepare(Task::reply(resp)), self.middlewares))))
|
||||||
}
|
}
|
||||||
self.idx += 1;
|
self.idx += 1;
|
||||||
req
|
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err)
|
Err(err) => return Err(err)
|
||||||
}
|
},
|
||||||
},
|
|
||||||
Started::Err(err) => return Err(err),
|
Started::Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,28 +234,28 @@ impl Start {
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
match self.fut.as_mut().unwrap().poll() {
|
match self.fut.as_mut().unwrap().poll() {
|
||||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||||
Ok(Async::Ready((mut req, resp))) => {
|
Ok(Async::Ready(resp)) => {
|
||||||
self.idx += 1;
|
self.idx += 1;
|
||||||
if let Some(resp) = resp {
|
if let Some(resp) = resp {
|
||||||
return Ok(Async::Ready(Box::new(Handle::new(
|
return Ok(Async::Ready(Box::new(Handle::new(
|
||||||
self.idx-1, req,
|
self.idx-1, self.req.clone(),
|
||||||
self.prepare(Task::reply(resp)), Rc::clone(&self.middlewares)))))
|
self.prepare(Task::reply(resp)), Rc::clone(&self.middlewares)))))
|
||||||
}
|
}
|
||||||
if self.idx == len {
|
if self.idx == len {
|
||||||
let task = (unsafe{&*self.hnd})(req.clone());
|
let task = (unsafe{&*self.hnd})(self.req.clone());
|
||||||
return Ok(Async::Ready(Box::new(Handle::new(
|
return Ok(Async::Ready(Box::new(Handle::new(
|
||||||
self.idx-1, req, self.prepare(task), Rc::clone(&self.middlewares)))))
|
self.idx-1, self.req.clone(),
|
||||||
|
self.prepare(task), Rc::clone(&self.middlewares)))))
|
||||||
} else {
|
} else {
|
||||||
loop {
|
loop {
|
||||||
req = match self.middlewares[self.idx].start(req) {
|
match self.middlewares[self.idx].start(&mut self.req) {
|
||||||
Started::Done(req) => {
|
Started::Done =>
|
||||||
self.idx += 1;
|
self.idx += 1,
|
||||||
req
|
Started::Response(resp) => {
|
||||||
}
|
|
||||||
Started::Response(req, resp) => {
|
|
||||||
self.idx += 1;
|
self.idx += 1;
|
||||||
return Ok(Async::Ready(Box::new(Handle::new(
|
return Ok(Async::Ready(Box::new(Handle::new(
|
||||||
self.idx-1, req, self.prepare(Task::reply(resp)),
|
self.idx-1, self.req.clone(),
|
||||||
|
self.prepare(Task::reply(resp)),
|
||||||
Rc::clone(&self.middlewares)))))
|
Rc::clone(&self.middlewares)))))
|
||||||
},
|
},
|
||||||
Started::Future(fut) => {
|
Started::Future(fut) => {
|
||||||
|
|
|
@ -96,7 +96,7 @@ impl<A, S> RouteHandler<S> for RouteFactory<A, S>
|
||||||
S: 'static
|
S: 'static
|
||||||
{
|
{
|
||||||
fn handle(&self, mut req: HttpRequest<A::State>) -> Task {
|
fn handle(&self, mut req: HttpRequest<A::State>) -> Task {
|
||||||
let mut ctx = HttpContext::default();
|
let mut ctx = HttpContext::new(req.clone_state());
|
||||||
|
|
||||||
// handle EXPECT header
|
// handle EXPECT header
|
||||||
if req.headers().contains_key(header::EXPECT) {
|
if req.headers().contains_key(header::EXPECT) {
|
||||||
|
|
|
@ -61,9 +61,9 @@ struct MiddlewareTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl middlewares::Middleware for MiddlewareTest {
|
impl middlewares::Middleware for MiddlewareTest {
|
||||||
fn start(&self, req: HttpRequest) -> middlewares::Started {
|
fn start(&self, _: &mut HttpRequest) -> middlewares::Started {
|
||||||
self.start.store(self.start.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
self.start.store(self.start.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
||||||
middlewares::Started::Done(req)
|
middlewares::Started::Done
|
||||||
}
|
}
|
||||||
|
|
||||||
fn response(&self, _: &mut HttpRequest, resp: HttpResponse) -> middlewares::Response {
|
fn response(&self, _: &mut HttpRequest, resp: HttpResponse) -> middlewares::Response {
|
||||||
|
|
Loading…
Reference in a new issue