diff --git a/examples/basic.rs b/examples/basic.rs index f91048371..256a990d9 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -12,7 +12,7 @@ use actix_web::middlewares::RequestSession; use futures::stream::{once, Once}; /// somple handle -fn index(mut req: HttpRequest, state: &()) -> Result { +fn index(mut req: HttpRequest) -> Result { println!("{:?}", req); if let Ok(ch) = req.payload_mut().readany() { if let futures::Async::Ready(Some(d)) = ch { @@ -32,7 +32,7 @@ fn index(mut req: HttpRequest, state: &()) -> Result { } /// somple handle -fn index_async(req: HttpRequest, state: &()) -> Once +fn index_async(req: HttpRequest) -> Once { println!("{:?}", req); @@ -44,7 +44,7 @@ fn index_async(req: HttpRequest, state: &()) -> Once } /// handle with path parameters like `/user/{name}/` -fn with_param(req: HttpRequest, state: &()) -> Result +fn with_param(req: HttpRequest) -> Result { println!("{:?}", req); @@ -75,7 +75,7 @@ fn main() { // async handler .resource("/async/{name}", |r| r.async(Method::GET, index_async)) // redirect - .resource("/", |r| r.handler(Method::GET, |req, _| { + .resource("/", |r| r.handler(Method::GET, |req| { println!("{:?}", req); Ok(httpcodes::HTTPFound diff --git a/examples/state.rs b/examples/state.rs index 22550a568..6b33a933f 100644 --- a/examples/state.rs +++ b/examples/state.rs @@ -1,3 +1,4 @@ +#![cfg_attr(feature="cargo-clippy", allow(needless_pass_by_value))] //! There are two level of statfulness in actix-web. Application has state //! that is shared across all handlers within same Application. //! And individual handler can have state. @@ -15,11 +16,11 @@ struct AppState { } /// somple handle -fn index(req: HttpRequest, state: &AppState) -> HttpResponse { +fn index(req: HttpRequest) -> HttpResponse { println!("{:?}", req); - state.counter.set(state.counter.get() + 1); + req.state().counter.set(req.state().counter.get() + 1); httpcodes::HTTPOk.with_body( - format!("Num of requests: {}", state.counter.get())) + format!("Num of requests: {}", req.state().counter.get())) } /// `MyWebSocket` counts how many messages it receives from peer, @@ -36,7 +37,7 @@ impl Route for MyWebSocket { /// Shared application state type State = AppState; - fn request(mut req: HttpRequest, ctx: &mut HttpContext) -> RouteResult + fn request(mut req: HttpRequest, ctx: &mut HttpContext) -> RouteResult { let resp = ws::handshake(&req)?; ctx.start(resp); @@ -44,6 +45,7 @@ impl Route for MyWebSocket { Reply::async(MyWebSocket{counter: 0}) } } + impl StreamHandler for MyWebSocket {} impl Handler for MyWebSocket { fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext) @@ -64,7 +66,6 @@ impl Handler for MyWebSocket { } } - fn main() { ::std::env::set_var("RUST_LOG", "actix_web=info"); let _ = env_logger::init(); diff --git a/src/application.rs b/src/application.rs index 399cac8dc..8912438c2 100644 --- a/src/application.rs +++ b/src/application.rs @@ -24,19 +24,21 @@ pub struct Application { impl Application { - fn run(&self, mut req: HttpRequest) -> Task { + fn run(&self, req: HttpRequest) -> Task { + let mut req = req.with_state(Rc::clone(&self.state)); + if let Some((params, h)) = self.router.recognize(req.path()) { if let Some(params) = params { req.set_match_info(params); } - h.handle(req, Rc::clone(&self.state)) + h.handle(req) } else { for (prefix, handler) in &self.handlers { if req.path().starts_with(prefix) { - return handler.handle(req, Rc::clone(&self.state)) + return handler.handle(req) } } - self.default.handle(req, Rc::clone(&self.state)) + self.default.handle(req) } } } @@ -146,7 +148,7 @@ impl ApplicationBuilder where S: 'static { /// let app = Application::default("/") /// .resource("/test", |r| { /// r.get::(); - /// r.handler(Method::HEAD, |req, state| { + /// r.handler(Method::HEAD, |req| { /// Ok(httpcodes::HTTPMethodNotAllowed) /// }); /// }) @@ -190,7 +192,7 @@ impl ApplicationBuilder where S: 'static { /// /// fn main() { /// let app = Application::default("/") - /// .handler("/test", |req, state| { + /// .handler("/test", |req| { /// match *req.method() { /// Method::GET => httpcodes::HTTPOk, /// Method::POST => httpcodes::HTTPMethodNotAllowed, @@ -201,7 +203,7 @@ impl ApplicationBuilder where S: 'static { /// } /// ``` pub fn handler(&mut self, path: P, handler: F) -> &mut Self - where F: Fn(HttpRequest, &S) -> R + 'static, + where F: Fn(HttpRequest) -> R + 'static, R: Into + 'static, P: Into, { diff --git a/src/context.rs b/src/context.rs index 89a145b81..6aa93e4ae 100644 --- a/src/context.rs +++ b/src/context.rs @@ -29,7 +29,6 @@ pub struct HttpContext where A: Actor> + Route, address: ActorAddressCell, stream: VecDeque, wait: ActorWaitCell, - app_state: Rc<::State>, disconnected: bool, } @@ -102,10 +101,9 @@ impl AsyncContextApi for HttpContext where A: Actor + Rou } } -impl HttpContext where A: Actor + Route { +impl Default for HttpContext where A: Actor + Route { - pub fn new(state: Rc<::State>) -> HttpContext - { + fn default() -> HttpContext { HttpContext { act: None, state: ActorState::Started, @@ -114,10 +112,12 @@ impl 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,11 +126,6 @@ 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/h1.rs b/src/h1.rs index 3eaa5d0f2..335660d95 100644 --- a/src/h1.rs +++ b/src/h1.rs @@ -35,9 +35,14 @@ pub(crate) enum Http1Result { Switch, } +#[derive(Debug)] +enum Item { + Http1(HttpRequest), + Http2, +} + pub(crate) struct Http1 { router: Rc>, - #[allow(dead_code)] addr: Option, stream: H1Writer, reader: Reader, @@ -268,12 +273,6 @@ impl Http1 } } -#[derive(Debug)] -enum Item { - Http1(HttpRequest), - Http2, -} - struct Reader { h1: bool, payload: Option, diff --git a/src/httpcodes.rs b/src/httpcodes.rs index bb5905aaf..5cf6b50ed 100644 --- a/src/httpcodes.rs +++ b/src/httpcodes.rs @@ -1,6 +1,5 @@ //! Basic http responses #![allow(non_upper_case_globals)] -use std::rc::Rc; use http::StatusCode; use body::Body; @@ -70,7 +69,7 @@ impl StaticResponse { } impl RouteHandler for StaticResponse { - fn handle(&self, _: HttpRequest, _: Rc) -> Task { + fn handle(&self, _: HttpRequest) -> Task { Task::reply(HttpResponse::new(self.0, Body::Empty)) } } diff --git a/src/httprequest.rs b/src/httprequest.rs index 75db9b939..720461151 100644 --- a/src/httprequest.rs +++ b/src/httprequest.rs @@ -48,9 +48,9 @@ impl Default for HttpMessage { } /// An HTTP Request -pub struct HttpRequest(Rc); +pub struct HttpRequest(Rc, Rc); -impl HttpRequest { +impl HttpRequest<()> { /// Construct a new Request. #[inline] pub fn new(method: Method, path: String, version: Version, @@ -69,20 +69,36 @@ impl HttpRequest { addr: None, payload: payload, extensions: Extensions::new(), - }) + }), + Rc::new(()) ) } + /// Construct request for error response. pub(crate) fn for_error() -> HttpRequest { - HttpRequest(Rc::new(HttpMessage::default())) + HttpRequest(Rc::new(HttpMessage::default()), Rc::new(())) } + /// Construct new http request with state. + pub(crate) fn with_state(self, state: Rc) -> HttpRequest { + HttpRequest(self.0, state) + } +} + +impl HttpRequest { + + /// get mutable reference for inner message fn as_mut(&mut self) -> &mut HttpMessage { let r: &HttpMessage = self.0.as_ref(); #[allow(mutable_transmutes)] unsafe{mem::transmute(r)} } + /// Shared application state + pub fn state(&self) -> &S { + &self.1 + } + /// Protocol extensions. #[inline] pub fn extensions(&mut self) -> &mut Extensions { @@ -317,13 +333,13 @@ impl HttpRequest { } } -impl Clone for HttpRequest { - fn clone(&self) -> HttpRequest { - HttpRequest(Rc::clone(&self.0)) +impl Clone for HttpRequest { + fn clone(&self) -> HttpRequest { + HttpRequest(Rc::clone(&self.0), Rc::clone(&self.1)) } } -impl fmt::Debug for HttpRequest { +impl fmt::Debug for HttpRequest { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let res = write!(f, "\nHttpRequest {:?} {}:{}\n", self.0.version, self.0.method, self.0.path); diff --git a/src/resource.rs b/src/resource.rs index 54f7c43b1..ceb275b76 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -1,4 +1,3 @@ -use std::rc::Rc; use std::marker::PhantomData; use std::collections::HashMap; @@ -64,7 +63,7 @@ impl Resource where S: 'static { /// Register handler for specified method. pub fn handler(&mut self, method: Method, handler: F) - where F: Fn(HttpRequest, &S) -> Result + 'static, + where F: Fn(HttpRequest) -> Result + 'static, R: Into + 'static, { self.routes.insert(method, Box::new(FnHandler::new(handler))); @@ -72,7 +71,7 @@ impl Resource where S: 'static { /// Register async handler for specified method. pub fn async(&mut self, method: Method, handler: F) - where F: Fn(HttpRequest, &S) -> R + 'static, + where F: Fn(HttpRequest) -> R + 'static, R: Stream + 'static, { self.routes.insert(method, Box::new(StreamHandler::new(handler))); @@ -125,11 +124,11 @@ impl Resource where S: 'static { impl RouteHandler for Resource { - fn handle(&self, req: HttpRequest, state: Rc) -> Task { + fn handle(&self, req: HttpRequest) -> Task { if let Some(handler) = self.routes.get(req.method()) { - handler.handle(req, state) + handler.handle(req) } else { - self.default.handle(req, state) + self.default.handle(req) } } } diff --git a/src/route.rs b/src/route.rs index 3a1ccfd8f..b7289eb55 100644 --- a/src/route.rs +++ b/src/route.rs @@ -33,7 +33,7 @@ impl Frame { #[allow(unused_variables)] pub trait RouteHandler: 'static { /// Handle request - fn handle(&self, req: HttpRequest, state: Rc) -> Task; + fn handle(&self, req: HttpRequest) -> Task; /// Set route prefix fn set_prefix(&mut self, prefix: String) {} @@ -46,11 +46,11 @@ pub type RouteResult = Result, Error>; #[allow(unused_variables)] pub trait Route: Actor { /// Shared state. State is shared with all routes within same application - /// and could be accessed with `HttpContext::state()` method. + /// and could be accessed with `HttpRequest::state()` method. type State; /// Handle `EXPECT` header. By default respones with `HTTP/1.1 100 Continue` - fn expect(req: &mut HttpRequest, ctx: &mut Self::Context) -> Result<(), Error> + fn expect(req: &mut HttpRequest, ctx: &mut Self::Context) -> Result<(), Error> where Self: Actor> { // handle expect header only for HTTP/1.1 @@ -80,7 +80,7 @@ pub trait Route: Actor { /// request/response or websocket connection. /// In that case `HttpContext::start` and `HttpContext::write` has to be used /// for writing response. - fn request(req: HttpRequest, ctx: &mut Self::Context) -> RouteResult; + fn request(req: HttpRequest, ctx: &mut Self::Context) -> RouteResult; /// This method creates `RouteFactory` for this actor. fn factory() -> RouteFactory { @@ -95,8 +95,8 @@ impl RouteHandler for RouteFactory where A: Actor> + Route, S: 'static { - fn handle(&self, mut req: HttpRequest, state: Rc) -> Task { - let mut ctx = HttpContext::new(state); + fn handle(&self, mut req: HttpRequest) -> Task { + let mut ctx = HttpContext::default(); // handle EXPECT header if req.headers().contains_key(header::EXPECT) { @@ -114,7 +114,7 @@ impl RouteHandler for RouteFactory /// Fn() route handler pub(crate) struct FnHandler - where F: Fn(HttpRequest, &S) -> R + 'static, + where F: Fn(HttpRequest) -> R + 'static, R: Into, S: 'static, { @@ -123,7 +123,7 @@ struct FnHandler } impl FnHandler - where F: Fn(HttpRequest, &S) -> R + 'static, + where F: Fn(HttpRequest) -> R + 'static, R: Into + 'static, S: 'static, { @@ -133,19 +133,19 @@ impl FnHandler } impl RouteHandler for FnHandler - where F: Fn(HttpRequest, &S) -> R + 'static, + where F: Fn(HttpRequest) -> R + 'static, R: Into + 'static, S: 'static, { - fn handle(&self, req: HttpRequest, state: Rc) -> Task { - Task::reply((self.f)(req, &state).into()) + fn handle(&self, req: HttpRequest) -> Task { + Task::reply((self.f)(req).into()) } } /// Async route handler pub(crate) struct StreamHandler - where F: Fn(HttpRequest, &S) -> R + 'static, + where F: Fn(HttpRequest) -> R + 'static, R: Stream + 'static, S: 'static, { @@ -154,7 +154,7 @@ struct StreamHandler } impl StreamHandler - where F: Fn(HttpRequest, &S) -> R + 'static, + where F: Fn(HttpRequest) -> R + 'static, R: Stream + 'static, S: 'static, { @@ -164,11 +164,11 @@ impl StreamHandler } impl RouteHandler for StreamHandler - where F: Fn(HttpRequest, &S) -> R + 'static, + where F: Fn(HttpRequest) -> R + 'static, R: Stream + 'static, S: 'static, { - fn handle(&self, req: HttpRequest, state: Rc) -> Task { - Task::with_stream((self.f)(req, &state)) + fn handle(&self, req: HttpRequest) -> Task { + Task::with_stream((self.f)(req)) } } diff --git a/src/staticfiles.rs b/src/staticfiles.rs index 97cd44070..d19b93a55 100644 --- a/src/staticfiles.rs +++ b/src/staticfiles.rs @@ -3,7 +3,6 @@ //! TODO: needs to re-implement actual files handling, current impl blocks use std::io; use std::io::Read; -use std::rc::Rc; use std::fmt::Write; use std::fs::{File, DirEntry}; use std::path::PathBuf; @@ -137,7 +136,7 @@ impl RouteHandler for StaticFiles { } } - fn handle(&self, req: HttpRequest, _: Rc) -> Task { + fn handle(&self, req: HttpRequest) -> Task { if !self.accessible { Task::reply(HTTPNotFound) } else { diff --git a/src/ws.rs b/src/ws.rs index 910248192..3d9e65058 100644 --- a/src/ws.rs +++ b/src/ws.rs @@ -108,7 +108,7 @@ impl ResponseType for Message { // /// `protocols` is a sequence of known protocols. On successful handshake, // /// the returned response headers contain the first protocol in this list // /// which the server also knows. -pub fn handshake(req: &HttpRequest) -> Result { +pub fn handshake(req: &HttpRequest) -> Result { // WebSocket accepts only GET if *req.method() != Method::GET { return Err(WsHandshakeError::GetMethodRequired) @@ -176,7 +176,7 @@ pub struct WsStream { } impl WsStream { - pub fn new(req: &mut HttpRequest) -> WsStream { + pub fn new(req: &mut HttpRequest) -> WsStream { WsStream { rx: req.take_payload(), buf: BytesMut::new(), closed: false, error_sent: false } } } diff --git a/tests/test_server.rs b/tests/test_server.rs index da506b26d..03a6a4850 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -16,7 +16,7 @@ fn create_server() -> HttpServer> { HttpServer::new( vec![Application::default("/") .resource("/", |r| - r.handler(Method::GET, |_, _| { + r.handler(Method::GET, |_| { Ok(httpcodes::HTTPOk) })) .finish()]) @@ -96,7 +96,7 @@ fn test_middlewares() { response: act_num2, finish: act_num3}) .resource("/", |r| - r.handler(Method::GET, |_, _| { + r.handler(Method::GET, |_| { Ok(httpcodes::HTTPOk) })) .finish()])