use futures::{Async, Future, Poll}; use std::cell::UnsafeCell; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use error::Error; use handler::{AsyncResult, AsyncResultItem, FromRequest, Handler, Responder}; use httprequest::HttpRequest; use httpresponse::HttpResponse; /// Extractor configuration /// /// `Route::with()` and `Route::with_async()` returns instance /// of the `ExtractorConfig` type. It could be used for extractor configuration. /// /// In this example `Form` configured. /// /// ```rust /// # extern crate actix_web; /// #[macro_use] extern crate serde_derive; /// use actix_web::{http, App, Form, Result}; /// /// #[derive(Deserialize)] /// struct FormData { /// username: String, /// } /// /// fn index(form: Form) -> Result { /// Ok(format!("Welcome {}!", form.username)) /// } /// /// fn main() { /// let app = App::new().resource( /// "/index.html", /// |r| { /// r.method(http::Method::GET).with(index).limit(4096); /// }, // <- change form extractor configuration /// ); /// } /// ``` /// /// Same could be donce with multiple extractors /// /// ```rust /// # extern crate actix_web; /// #[macro_use] extern crate serde_derive; /// use actix_web::{http, App, Form, Path, Result}; /// /// #[derive(Deserialize)] /// struct FormData { /// username: String, /// } /// /// fn index(data: (Path<(String,)>, Form)) -> Result { /// Ok(format!("Welcome {}!", data.1.username)) /// } /// /// fn main() { /// let app = App::new().resource( /// "/index.html", /// |r| { /// r.method(http::Method::GET).with(index).1.limit(4096); /// }, // <- change form extractor configuration /// ); /// } /// ``` pub struct ExtractorConfig> { cfg: Rc>, } impl> Default for ExtractorConfig { fn default() -> Self { ExtractorConfig { cfg: Rc::new(UnsafeCell::new(T::Config::default())), } } } impl> ExtractorConfig { pub(crate) fn clone(&self) -> Self { ExtractorConfig { cfg: Rc::clone(&self.cfg), } } } impl> AsRef for ExtractorConfig { fn as_ref(&self) -> &T::Config { unsafe { &*self.cfg.get() } } } impl> Deref for ExtractorConfig { type Target = T::Config; fn deref(&self) -> &T::Config { unsafe { &*self.cfg.get() } } } impl> DerefMut for ExtractorConfig { fn deref_mut(&mut self) -> &mut T::Config { unsafe { &mut *self.cfg.get() } } } pub struct With where F: Fn(T) -> R, T: FromRequest, S: 'static, { hnd: Rc>, cfg: ExtractorConfig, } pub struct WithHnd where F: Fn(T) -> R, T: FromRequest, S: 'static, { hnd: Rc>, _t: PhantomData, _s: PhantomData, } impl With where F: Fn(T) -> R, T: FromRequest, S: 'static, { pub fn new(f: F, cfg: ExtractorConfig) -> Self { With { cfg, hnd: Rc::new(WithHnd { hnd: Rc::new(UnsafeCell::new(f)), _t: PhantomData, _s: PhantomData, }), } } } impl Handler for With where F: Fn(T) -> R + 'static, R: Responder + 'static, T: FromRequest + 'static, S: 'static, { type Result = AsyncResult; fn handle(&mut self, req: HttpRequest) -> Self::Result { let mut fut = WithHandlerFut { req, started: false, hnd: Rc::clone(&self.hnd), cfg: self.cfg.clone(), fut1: None, fut2: None, }; match fut.poll() { Ok(Async::Ready(resp)) => AsyncResult::ok(resp), Ok(Async::NotReady) => AsyncResult::async(Box::new(fut)), Err(e) => AsyncResult::err(e), } } } struct WithHandlerFut where F: Fn(T) -> R, R: Responder, T: FromRequest + 'static, S: 'static, { started: bool, hnd: Rc>, cfg: ExtractorConfig, req: HttpRequest, fut1: Option>>, fut2: Option>>, } impl Future for WithHandlerFut where F: Fn(T) -> R, R: Responder + 'static, T: FromRequest + 'static, S: 'static, { type Item = HttpResponse; type Error = Error; fn poll(&mut self) -> Poll { if let Some(ref mut fut) = self.fut2 { return fut.poll(); } let item = if !self.started { self.started = true; let reply = T::from_request(&self.req, self.cfg.as_ref()).into(); match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.fut1 = Some(fut); return self.poll(); } } } else { match self.fut1.as_mut().unwrap().poll()? { Async::Ready(item) => item, Async::NotReady => return Ok(Async::NotReady), } }; let fut = { // clone handler, inicrease ref counter let h = self.hnd.as_ref().hnd.clone(); // Enforce invariants before entering unsafe code. // Only two references could exists With struct owns one, and line above if Rc::weak_count(&h) != 0 || Rc::strong_count(&h) != 2 { panic!("Multiple copies of handler are in use") } let hnd: &mut F = unsafe { &mut *h.as_ref().get() }; let item = match (*hnd)(item).respond_to(&self.req) { Ok(item) => item.into(), Err(e) => return Err(e.into()), }; match item.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(resp) => return Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => fut, } }; self.fut2 = Some(fut); self.poll() } } pub struct WithAsync where F: Fn(T) -> R, R: Future, I: Responder, E: Into, T: FromRequest, S: 'static, { hnd: Rc>, cfg: ExtractorConfig, } impl WithAsync where F: Fn(T) -> R, R: Future, I: Responder, E: Into, T: FromRequest, S: 'static, { pub fn new(f: F, cfg: ExtractorConfig) -> Self { WithAsync { cfg, hnd: Rc::new(WithHnd { hnd: Rc::new(UnsafeCell::new(f)), _s: PhantomData, _t: PhantomData, }), } } } impl Handler for WithAsync where F: Fn(T) -> R + 'static, R: Future + 'static, I: Responder + 'static, E: Into + 'static, T: FromRequest + 'static, S: 'static, { type Result = AsyncResult; fn handle(&mut self, req: HttpRequest) -> Self::Result { let mut fut = WithAsyncHandlerFut { req, started: false, hnd: Rc::clone(&self.hnd), cfg: self.cfg.clone(), fut1: None, fut2: None, fut3: None, }; match fut.poll() { Ok(Async::Ready(resp)) => AsyncResult::ok(resp), Ok(Async::NotReady) => AsyncResult::async(Box::new(fut)), Err(e) => AsyncResult::err(e), } } } struct WithAsyncHandlerFut where F: Fn(T) -> R, R: Future + 'static, I: Responder + 'static, E: Into + 'static, T: FromRequest + 'static, S: 'static, { started: bool, hnd: Rc>, cfg: ExtractorConfig, req: HttpRequest, fut1: Option>>, fut2: Option, fut3: Option>>, } impl Future for WithAsyncHandlerFut where F: Fn(T) -> R, R: Future + 'static, I: Responder + 'static, E: Into + 'static, T: FromRequest + 'static, S: 'static, { type Item = HttpResponse; type Error = Error; fn poll(&mut self) -> Poll { if let Some(ref mut fut) = self.fut3 { return fut.poll(); } if self.fut2.is_some() { return match self.fut2.as_mut().unwrap().poll() { Ok(Async::NotReady) => Ok(Async::NotReady), Ok(Async::Ready(r)) => match r.respond_to(&self.req) { Ok(r) => match r.into().into() { AsyncResultItem::Err(err) => Err(err), AsyncResultItem::Ok(resp) => Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => { self.fut3 = Some(fut); self.poll() } }, Err(e) => Err(e.into()), }, Err(e) => Err(e.into()), }; } let item = if !self.started { self.started = true; let reply = T::from_request(&self.req, self.cfg.as_ref()).into(); match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.fut1 = Some(fut); return self.poll(); } } } else { match self.fut1.as_mut().unwrap().poll()? { Async::Ready(item) => item, Async::NotReady => return Ok(Async::NotReady), } }; self.fut2 = { // clone handler, inicrease ref counter let h = self.hnd.as_ref().hnd.clone(); // Enforce invariants before entering unsafe code. // Only two references could exists With struct owns one, and line above if Rc::weak_count(&h) != 0 || Rc::strong_count(&h) != 2 { panic!("Multiple copies of handler are in use") } let hnd: &mut F = unsafe { &mut *h.as_ref().get() }; Some((*hnd)(item)) }; self.poll() } }