mirror of
https://github.com/fafhrd91/actix-web
synced 2025-01-18 05:41:50 +01:00
move state to request object
This commit is contained in:
parent
8e0a7f44d4
commit
5a3b6638a7
@ -12,7 +12,7 @@ use actix_web::middlewares::RequestSession;
|
||||
use futures::stream::{once, Once};
|
||||
|
||||
/// somple handle
|
||||
fn index(mut req: HttpRequest, state: &()) -> Result<HttpResponse> {
|
||||
fn index(mut req: HttpRequest) -> Result<HttpResponse> {
|
||||
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<HttpResponse> {
|
||||
}
|
||||
|
||||
/// somple handle
|
||||
fn index_async(req: HttpRequest, state: &()) -> Once<actix_web::Frame, Error>
|
||||
fn index_async(req: HttpRequest) -> Once<actix_web::Frame, Error>
|
||||
{
|
||||
println!("{:?}", req);
|
||||
|
||||
@ -44,7 +44,7 @@ fn index_async(req: HttpRequest, state: &()) -> Once<actix_web::Frame, Error>
|
||||
}
|
||||
|
||||
/// handle with path parameters like `/user/{name}/`
|
||||
fn with_param(req: HttpRequest, state: &()) -> Result<HttpResponse>
|
||||
fn with_param(req: HttpRequest) -> Result<HttpResponse>
|
||||
{
|
||||
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
|
||||
|
@ -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<AppState>) -> 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<Self>) -> RouteResult<Self>
|
||||
fn request(mut req: HttpRequest<AppState>, ctx: &mut HttpContext<Self>) -> RouteResult<Self>
|
||||
{
|
||||
let resp = ws::handshake(&req)?;
|
||||
ctx.start(resp);
|
||||
@ -44,6 +45,7 @@ impl Route for MyWebSocket {
|
||||
Reply::async(MyWebSocket{counter: 0})
|
||||
}
|
||||
}
|
||||
|
||||
impl StreamHandler<ws::Message> for MyWebSocket {}
|
||||
impl Handler<ws::Message> for MyWebSocket {
|
||||
fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext<Self>)
|
||||
@ -64,7 +66,6 @@ impl Handler<ws::Message> for MyWebSocket {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
::std::env::set_var("RUST_LOG", "actix_web=info");
|
||||
let _ = env_logger::init();
|
||||
|
@ -24,19 +24,21 @@ pub struct Application<S> {
|
||||
|
||||
impl<S: 'static> Application<S> {
|
||||
|
||||
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<S> ApplicationBuilder<S> where S: 'static {
|
||||
/// let app = Application::default("/")
|
||||
/// .resource("/test", |r| {
|
||||
/// r.get::<MyRoute>();
|
||||
/// r.handler(Method::HEAD, |req, state| {
|
||||
/// r.handler(Method::HEAD, |req| {
|
||||
/// Ok(httpcodes::HTTPMethodNotAllowed)
|
||||
/// });
|
||||
/// })
|
||||
@ -190,7 +192,7 @@ impl<S> ApplicationBuilder<S> 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<S> ApplicationBuilder<S> where S: 'static {
|
||||
/// }
|
||||
/// ```
|
||||
pub fn handler<P, F, R>(&mut self, path: P, handler: F) -> &mut Self
|
||||
where F: Fn(HttpRequest, &S) -> R + 'static,
|
||||
where F: Fn(HttpRequest<S>) -> R + 'static,
|
||||
R: Into<HttpResponse> + 'static,
|
||||
P: Into<String>,
|
||||
{
|
||||
|
@ -29,7 +29,6 @@ pub struct HttpContext<A> where A: Actor<Context=HttpContext<A>> + Route,
|
||||
address: ActorAddressCell<A>,
|
||||
stream: VecDeque<Frame>,
|
||||
wait: ActorWaitCell<A>,
|
||||
app_state: Rc<<A as Route>::State>,
|
||||
disconnected: bool,
|
||||
}
|
||||
|
||||
@ -102,10 +101,9 @@ impl<A> AsyncContextApi<A> for HttpContext<A> where A: Actor<Context=Self> + Rou
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
|
||||
impl<A> Default for HttpContext<A> where A: Actor<Context=Self> + Route {
|
||||
|
||||
pub fn new(state: Rc<<A as Route>::State>) -> HttpContext<A>
|
||||
{
|
||||
fn default() -> HttpContext<A> {
|
||||
HttpContext {
|
||||
act: None,
|
||||
state: ActorState::Started,
|
||||
@ -114,10 +112,12 @@ impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
|
||||
address: ActorAddressCell::default(),
|
||||
wait: ActorWaitCell::default(),
|
||||
stream: VecDeque::new(),
|
||||
app_state: state,
|
||||
disconnected: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> HttpContext<A> where A: Actor<Context=Self> + Route {
|
||||
|
||||
pub(crate) fn set_actor(&mut self, act: A) {
|
||||
self.act = Some(act)
|
||||
@ -126,11 +126,6 @@ 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
|
||||
pub fn start<R: Into<HttpResponse>>(&mut self, response: R) {
|
||||
self.stream.push_back(Frame::Message(response.into()))
|
||||
|
13
src/h1.rs
13
src/h1.rs
@ -35,9 +35,14 @@ pub(crate) enum Http1Result {
|
||||
Switch,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Item {
|
||||
Http1(HttpRequest),
|
||||
Http2,
|
||||
}
|
||||
|
||||
pub(crate) struct Http1<T: AsyncWrite + 'static, H: 'static> {
|
||||
router: Rc<Vec<H>>,
|
||||
#[allow(dead_code)]
|
||||
addr: Option<SocketAddr>,
|
||||
stream: H1Writer<T>,
|
||||
reader: Reader,
|
||||
@ -268,12 +273,6 @@ impl<T, H> Http1<T, H>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Item {
|
||||
Http1(HttpRequest),
|
||||
Http2,
|
||||
}
|
||||
|
||||
struct Reader {
|
||||
h1: bool,
|
||||
payload: Option<PayloadInfo>,
|
||||
|
@ -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<S> RouteHandler<S> for StaticResponse {
|
||||
fn handle(&self, _: HttpRequest, _: Rc<S>) -> Task {
|
||||
fn handle(&self, _: HttpRequest<S>) -> Task {
|
||||
Task::reply(HttpResponse::new(self.0, Body::Empty))
|
||||
}
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ impl Default for HttpMessage {
|
||||
}
|
||||
|
||||
/// An HTTP Request
|
||||
pub struct HttpRequest(Rc<HttpMessage>);
|
||||
pub struct HttpRequest<S=()>(Rc<HttpMessage>, Rc<S>);
|
||||
|
||||
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<S>(self, state: Rc<S>) -> HttpRequest<S> {
|
||||
HttpRequest(self.0, state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> HttpRequest<S> {
|
||||
|
||||
/// 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<S> Clone for HttpRequest<S> {
|
||||
fn clone(&self) -> HttpRequest<S> {
|
||||
HttpRequest(Rc::clone(&self.0), Rc::clone(&self.1))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for HttpRequest {
|
||||
impl<S> fmt::Debug for HttpRequest<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let res = write!(f, "\nHttpRequest {:?} {}:{}\n",
|
||||
self.0.version, self.0.method, self.0.path);
|
||||
|
@ -1,4 +1,3 @@
|
||||
use std::rc::Rc;
|
||||
use std::marker::PhantomData;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -64,7 +63,7 @@ impl<S> Resource<S> where S: 'static {
|
||||
|
||||
/// Register handler for specified method.
|
||||
pub fn handler<F, R>(&mut self, method: Method, handler: F)
|
||||
where F: Fn(HttpRequest, &S) -> Result<R> + 'static,
|
||||
where F: Fn(HttpRequest<S>) -> Result<R> + 'static,
|
||||
R: Into<HttpResponse> + 'static,
|
||||
{
|
||||
self.routes.insert(method, Box::new(FnHandler::new(handler)));
|
||||
@ -72,7 +71,7 @@ impl<S> Resource<S> where S: 'static {
|
||||
|
||||
/// Register async handler for specified method.
|
||||
pub fn async<F, R>(&mut self, method: Method, handler: F)
|
||||
where F: Fn(HttpRequest, &S) -> R + 'static,
|
||||
where F: Fn(HttpRequest<S>) -> R + 'static,
|
||||
R: Stream<Item=Frame, Error=Error> + 'static,
|
||||
{
|
||||
self.routes.insert(method, Box::new(StreamHandler::new(handler)));
|
||||
@ -125,11 +124,11 @@ impl<S> Resource<S> where S: 'static {
|
||||
|
||||
impl<S: 'static> RouteHandler<S> for Resource<S> {
|
||||
|
||||
fn handle(&self, req: HttpRequest, state: Rc<S>) -> Task {
|
||||
fn handle(&self, req: HttpRequest<S>) -> 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
32
src/route.rs
32
src/route.rs
@ -33,7 +33,7 @@ impl Frame {
|
||||
#[allow(unused_variables)]
|
||||
pub trait RouteHandler<S>: 'static {
|
||||
/// Handle request
|
||||
fn handle(&self, req: HttpRequest, state: Rc<S>) -> Task;
|
||||
fn handle(&self, req: HttpRequest<S>) -> Task;
|
||||
|
||||
/// Set route prefix
|
||||
fn set_prefix(&mut self, prefix: String) {}
|
||||
@ -46,11 +46,11 @@ pub type RouteResult<T> = Result<Reply<T>, 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<Self::State>, ctx: &mut Self::Context) -> Result<(), Error>
|
||||
where Self: Actor<Context=HttpContext<Self>>
|
||||
{
|
||||
// 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<Self>;
|
||||
fn request(req: HttpRequest<Self::State>, ctx: &mut Self::Context) -> RouteResult<Self>;
|
||||
|
||||
/// This method creates `RouteFactory` for this actor.
|
||||
fn factory() -> RouteFactory<Self, Self::State> {
|
||||
@ -95,8 +95,8 @@ impl<A, S> RouteHandler<S> for RouteFactory<A, S>
|
||||
where A: Actor<Context=HttpContext<A>> + Route<State=S>,
|
||||
S: 'static
|
||||
{
|
||||
fn handle(&self, mut req: HttpRequest, state: Rc<A::State>) -> Task {
|
||||
let mut ctx = HttpContext::new(state);
|
||||
fn handle(&self, mut req: HttpRequest<A::State>) -> Task {
|
||||
let mut ctx = HttpContext::default();
|
||||
|
||||
// handle EXPECT header
|
||||
if req.headers().contains_key(header::EXPECT) {
|
||||
@ -114,7 +114,7 @@ impl<A, S> RouteHandler<S> for RouteFactory<A, S>
|
||||
/// Fn() route handler
|
||||
pub(crate)
|
||||
struct FnHandler<S, R, F>
|
||||
where F: Fn(HttpRequest, &S) -> R + 'static,
|
||||
where F: Fn(HttpRequest<S>) -> R + 'static,
|
||||
R: Into<HttpResponse>,
|
||||
S: 'static,
|
||||
{
|
||||
@ -123,7 +123,7 @@ struct FnHandler<S, R, F>
|
||||
}
|
||||
|
||||
impl<S, R, F> FnHandler<S, R, F>
|
||||
where F: Fn(HttpRequest, &S) -> R + 'static,
|
||||
where F: Fn(HttpRequest<S>) -> R + 'static,
|
||||
R: Into<HttpResponse> + 'static,
|
||||
S: 'static,
|
||||
{
|
||||
@ -133,19 +133,19 @@ impl<S, R, F> FnHandler<S, R, F>
|
||||
}
|
||||
|
||||
impl<S, R, F> RouteHandler<S> for FnHandler<S, R, F>
|
||||
where F: Fn(HttpRequest, &S) -> R + 'static,
|
||||
where F: Fn(HttpRequest<S>) -> R + 'static,
|
||||
R: Into<HttpResponse> + 'static,
|
||||
S: 'static,
|
||||
{
|
||||
fn handle(&self, req: HttpRequest, state: Rc<S>) -> Task {
|
||||
Task::reply((self.f)(req, &state).into())
|
||||
fn handle(&self, req: HttpRequest<S>) -> Task {
|
||||
Task::reply((self.f)(req).into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Async route handler
|
||||
pub(crate)
|
||||
struct StreamHandler<S, R, F>
|
||||
where F: Fn(HttpRequest, &S) -> R + 'static,
|
||||
where F: Fn(HttpRequest<S>) -> R + 'static,
|
||||
R: Stream<Item=Frame, Error=Error> + 'static,
|
||||
S: 'static,
|
||||
{
|
||||
@ -154,7 +154,7 @@ struct StreamHandler<S, R, F>
|
||||
}
|
||||
|
||||
impl<S, R, F> StreamHandler<S, R, F>
|
||||
where F: Fn(HttpRequest, &S) -> R + 'static,
|
||||
where F: Fn(HttpRequest<S>) -> R + 'static,
|
||||
R: Stream<Item=Frame, Error=Error> + 'static,
|
||||
S: 'static,
|
||||
{
|
||||
@ -164,11 +164,11 @@ impl<S, R, F> StreamHandler<S, R, F>
|
||||
}
|
||||
|
||||
impl<S, R, F> RouteHandler<S> for StreamHandler<S, R, F>
|
||||
where F: Fn(HttpRequest, &S) -> R + 'static,
|
||||
where F: Fn(HttpRequest<S>) -> R + 'static,
|
||||
R: Stream<Item=Frame, Error=Error> + 'static,
|
||||
S: 'static,
|
||||
{
|
||||
fn handle(&self, req: HttpRequest, state: Rc<S>) -> Task {
|
||||
Task::with_stream((self.f)(req, &state))
|
||||
fn handle(&self, req: HttpRequest<S>) -> Task {
|
||||
Task::with_stream((self.f)(req))
|
||||
}
|
||||
}
|
||||
|
@ -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<S: 'static> RouteHandler<S> for StaticFiles {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(&self, req: HttpRequest, _: Rc<S>) -> Task {
|
||||
fn handle(&self, req: HttpRequest<S>) -> Task {
|
||||
if !self.accessible {
|
||||
Task::reply(HTTPNotFound)
|
||||
} else {
|
||||
|
@ -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<HttpResponse, WsHandshakeError> {
|
||||
pub fn handshake<S>(req: &HttpRequest<S>) -> Result<HttpResponse, WsHandshakeError> {
|
||||
// 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<S>(req: &mut HttpRequest<S>) -> WsStream {
|
||||
WsStream { rx: req.take_payload(), buf: BytesMut::new(), closed: false, error_sent: false }
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ fn create_server<T, A>() -> HttpServer<T, A, Application<()>> {
|
||||
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()])
|
||||
|
Loading…
x
Reference in New Issue
Block a user