diff --git a/examples/multipart/src/main.rs b/examples/multipart/src/main.rs index 1e20aca25..a1f31527d 100644 --- a/examples/multipart/src/main.rs +++ b/examples/multipart/src/main.rs @@ -15,11 +15,10 @@ impl Actor for MyRoute { impl Route for MyRoute { type State = (); - fn request(req: &mut HttpRequest, payload: Payload, - ctx: &mut HttpContext) -> RouteResult { + fn request(mut req: HttpRequest, ctx: &mut HttpContext) -> RouteResult { println!("{:?}", req); - let multipart = req.multipart(payload)?; + let multipart = req.multipart()?; // get Multipart stream WrapStream::::actstream(multipart) diff --git a/examples/tls/src/main.rs b/examples/tls/src/main.rs index 90fd11b1a..07d83b357 100644 --- a/examples/tls/src/main.rs +++ b/examples/tls/src/main.rs @@ -9,7 +9,7 @@ use std::io::Read; use actix_web::*; /// somple handle -fn index(req: &mut HttpRequest, _payload: Payload, state: &()) -> HttpResponse { +fn index(req: HttpRequest) -> HttpResponse { println!("{:?}", req); httpcodes::HTTPOk .builder() @@ -36,7 +36,7 @@ fn main() { // register simple handler, handle all methods .handler("/index.html", index) // with path parameters - .resource("/", |r| r.handler(Method::GET, |req, _, _| { + .resource("/", |r| r.handler(Method::GET, |req| { Ok(httpcodes::HTTPFound .builder() .header("LOCATION", "/index.html") diff --git a/examples/websocket-chat/src/main.rs b/examples/websocket-chat/src/main.rs index 14f93b915..fa9ceaef3 100644 --- a/examples/websocket-chat/src/main.rs +++ b/examples/websocket-chat/src/main.rs @@ -48,13 +48,13 @@ impl Actor for WsChatSession { impl Route for WsChatSession { type State = WsChatSessionState; - fn request(req: &mut HttpRequest, - payload: Payload, ctx: &mut HttpContext) -> RouteResult + fn request(mut req: HttpRequest, + ctx: &mut HttpContext) -> RouteResult { // websocket handshakre, it may fail if request is not websocket request let resp = ws::handshake(&req)?; ctx.start(resp); - ctx.add_stream(ws::WsStream::new(payload)); + ctx.add_stream(ws::WsStream::new(&mut req)); Reply::async( WsChatSession { id: 0, @@ -207,10 +207,10 @@ fn main() { // Create Http server with websocket support HttpServer::new( - Application::builder("/", state) + Application::build("/", state) // redirect to websocket.html .resource("/", |r| - r.handler(Method::GET, |req, payload, state| { + r.handler(Method::GET, |req| { Ok(httpcodes::HTTPFound .builder() .header("LOCATION", "/static/websocket.html") diff --git a/src/context.rs b/src/context.rs index 6aa93e4ae..6f02dccec 100644 --- a/src/context.rs +++ b/src/context.rs @@ -29,6 +29,7 @@ pub struct HttpContext where A: Actor> + Route, address: ActorAddressCell, stream: VecDeque, wait: ActorWaitCell, + app_state: Rc<::State>, disconnected: bool, } @@ -101,9 +102,10 @@ impl AsyncContextApi for HttpContext where A: Actor + Rou } } -impl Default for HttpContext where A: Actor + Route { +impl HttpContext where A: Actor + Route { - fn default() -> HttpContext { + pub fn new(state: Rc<::State>) -> HttpContext + { HttpContext { act: None, state: ActorState::Started, @@ -112,12 +114,10 @@ impl Default for HttpContext where A: Actor + Route { address: ActorAddressCell::default(), wait: ActorWaitCell::default(), stream: VecDeque::new(), + app_state: state, disconnected: false, } } -} - -impl HttpContext where A: Actor + Route { pub(crate) fn set_actor(&mut self, act: A) { self.act = Some(act) @@ -126,6 +126,11 @@ impl HttpContext where A: Actor + Route { impl HttpContext where A: Actor + Route { + /// Shared application state + pub fn state(&self) -> &::State { + &self.app_state + } + /// Start response processing pub fn start>(&mut self, response: R) { self.stream.push_back(Frame::Message(response.into())) diff --git a/src/httprequest.rs b/src/httprequest.rs index 720461151..25abc16c9 100644 --- a/src/httprequest.rs +++ b/src/httprequest.rs @@ -99,6 +99,11 @@ impl HttpRequest { &self.1 } + /// Clone application state + pub(crate) fn clone_state(&self) -> Rc { + Rc::clone(&self.1) + } + /// Protocol extensions. #[inline] pub fn extensions(&mut self) -> &mut Extensions { @@ -287,8 +292,9 @@ impl HttpRequest { /// Return stream to process BODY as multipart. /// /// Content-type: multipart/form-data; - pub fn multipart(&self, payload: Payload) -> Result { - Ok(Multipart::new(Multipart::boundary(&self.0.headers)?, payload)) + pub fn multipart(&mut self) -> Result { + let boundary = Multipart::boundary(&self.0.headers)?; + Ok(Multipart::new(boundary, self.take_payload())) } /// Parse `application/x-www-form-urlencoded` encoded body. diff --git a/src/middlewares/logger.rs b/src/middlewares/logger.rs index 1ab67e806..4b2d386d7 100644 --- a/src/middlewares/logger.rs +++ b/src/middlewares/logger.rs @@ -101,9 +101,9 @@ impl 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())); - Started::Done(req) + Started::Done } fn finish(&self, req: &mut HttpRequest, resp: &HttpResponse) -> Finished { @@ -299,14 +299,14 @@ mod tests { let mut headers = HeaderMap::new(); 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()); let resp = HttpResponse::builder(StatusCode::OK) .header("X-Test", "ttt") .force_close().body(Body::Empty).unwrap(); - let mut req = match logger.start(req) { - Started::Done(req) => req, + match logger.start(&mut req) { + Started::Done => (), _ => panic!(), }; match logger.finish(&mut req, &resp) { diff --git a/src/middlewares/mod.rs b/src/middlewares/mod.rs index 66913fa45..f9720db5c 100644 --- a/src/middlewares/mod.rs +++ b/src/middlewares/mod.rs @@ -16,12 +16,12 @@ pub enum Started { /// Moddleware error Err(Error), /// Execution completed - Done(HttpRequest), + Done, /// New http response got generated. If middleware generates response /// handler execution halts. - Response(HttpRequest, HttpResponse), + Response(HttpResponse), /// Execution completed, runs future to completion. - Future(Box), Error=Error>>), + Future(Box, Error=Error>>), } /// Middleware execution result @@ -48,8 +48,8 @@ pub trait Middleware { /// Method is called when request is ready. It may return /// future, which should resolve before next middleware get called. - fn start(&self, req: HttpRequest) -> Started { - Started::Done(req) + fn start(&self, req: &mut HttpRequest) -> Started { + Started::Done } /// Method is called when handler returns response, diff --git a/src/middlewares/session.rs b/src/middlewares/session.rs index c89817f91..8e7315af9 100644 --- a/src/middlewares/session.rs +++ b/src/middlewares/session.rs @@ -90,14 +90,15 @@ impl SessionStorage { impl Middleware for SessionStorage { - 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) - .then(|res| { + .then(move |res| { match res { Ok(sess) => { req.extensions().insert(Arc::new(SessionImplBox(Box::new(sess)))); - let resp: Option = None; - FutOk((req, resp)) + FutOk(None) }, Err(err) => FutErr(err) } diff --git a/src/pipeline.rs b/src/pipeline.rs index 518a82130..218755ba2 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -146,13 +146,14 @@ impl Pipeline { } } -type Fut = Box), Error=Error>>; +type Fut = Box, Error=Error>>; /// Middlewares start executor struct Start { idx: usize, hnd: *mut Handler, disconnected: bool, + req: HttpRequest, fut: Option, middlewares: Rc>>, } @@ -169,10 +170,11 @@ impl Start { Start { idx: 0, fut: None, + req: req, disconnected: false, hnd: handler as *const _ as *mut _, middlewares: mw, - }.start(req) + }.start() } fn disconnected(&mut self) { @@ -187,43 +189,40 @@ impl Start { task } - fn start(mut self, mut req: HttpRequest) -> Result { + fn start(mut self) -> Result { let len = self.middlewares.len(); loop { if self.idx == len { - let task = (unsafe{&*self.hnd})(req.clone()); + let task = (unsafe{&*self.hnd})(self.req.clone()); 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 { - req = match self.middlewares[self.idx].start(req) { - Started::Done(req) => { - self.idx += 1; - req - } - Started::Response(req, resp) => { + match self.middlewares[self.idx].start(&mut self.req) { + Started::Done => + self.idx += 1, + Started::Response(resp) => return Ok(StartResult::Ready( Box::new(Handle::new( - self.idx, req, self.prepare(Task::reply(resp)), self.middlewares)))) - }, - Started::Future(mut fut) => { + self.idx, self.req.clone(), + self.prepare(Task::reply(resp)), self.middlewares)))), + Started::Future(mut fut) => match fut.poll() { Ok(Async::NotReady) => { self.fut = Some(fut); return Ok(StartResult::NotReady(self)) } - Ok(Async::Ready((req, resp))) => { + Ok(Async::Ready(resp)) => { if let Some(resp) = resp { return Ok(StartResult::Ready( Box::new(Handle::new( - self.idx, req, + self.idx, self.req.clone(), self.prepare(Task::reply(resp)), self.middlewares)))) } self.idx += 1; - req } Err(err) => return Err(err) - } - }, + }, Started::Err(err) => return Err(err), } } @@ -235,28 +234,28 @@ impl Start { 'outer: loop { match self.fut.as_mut().unwrap().poll() { Ok(Async::NotReady) => return Ok(Async::NotReady), - Ok(Async::Ready((mut req, resp))) => { + Ok(Async::Ready(resp)) => { self.idx += 1; if let Some(resp) = resp { 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))))) } 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( - 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 { loop { - req = match self.middlewares[self.idx].start(req) { - Started::Done(req) => { - self.idx += 1; - req - } - Started::Response(req, resp) => { + match self.middlewares[self.idx].start(&mut self.req) { + Started::Done => + self.idx += 1, + Started::Response(resp) => { self.idx += 1; 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))))) }, Started::Future(fut) => { diff --git a/src/route.rs b/src/route.rs index b7289eb55..c591e984d 100644 --- a/src/route.rs +++ b/src/route.rs @@ -96,7 +96,7 @@ impl RouteHandler for RouteFactory S: 'static { fn handle(&self, mut req: HttpRequest) -> Task { - let mut ctx = HttpContext::default(); + let mut ctx = HttpContext::new(req.clone_state()); // handle EXPECT header if req.headers().contains_key(header::EXPECT) { diff --git a/tests/test_server.rs b/tests/test_server.rs index 03a6a4850..83f94ce4b 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -61,9 +61,9 @@ struct 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); - middlewares::Started::Done(req) + middlewares::Started::Done } fn response(&self, _: &mut HttpRequest, resp: HttpResponse) -> middlewares::Response {