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::{App, Form, Result, http}; /// /// #[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::{App, Form, Path, Result, http}; /// /// #[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> Clone for ExtractorConfig { 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, _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(UnsafeCell::new(f)), _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 hnd: &mut F = unsafe { &mut *self.hnd.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) => Err(err), AsyncResultItem::Ok(resp) => Ok(Async::Ready(resp)), AsyncResultItem::Future(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, _s: PhantomData, } 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(UnsafeCell::new(f)), _s: 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), } }; let hnd: &mut F = unsafe { &mut *self.hnd.get() }; self.fut2 = Some((*hnd)(item)); self.poll() } } pub struct With2 where F: Fn(T1, T2) -> R, T1: FromRequest + 'static, T2: FromRequest + 'static, S: 'static, { hnd: Rc>, cfg1: ExtractorConfig, cfg2: ExtractorConfig, _s: PhantomData, } impl With2 where F: Fn(T1, T2) -> R, T1: FromRequest + 'static, T2: FromRequest + 'static, S: 'static, { pub fn new( f: F, cfg1: ExtractorConfig, cfg2: ExtractorConfig, ) -> Self { With2 { hnd: Rc::new(UnsafeCell::new(f)), cfg1, cfg2, _s: PhantomData, } } } impl Handler for With2 where F: Fn(T1, T2) -> R + 'static, R: Responder + 'static, T1: FromRequest + 'static, T2: FromRequest + 'static, S: 'static, { type Result = AsyncResult; fn handle(&mut self, req: HttpRequest) -> Self::Result { let mut fut = WithHandlerFut2 { req, started: false, hnd: Rc::clone(&self.hnd), cfg1: self.cfg1.clone(), cfg2: self.cfg2.clone(), item: None, 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::ok(e), } } } struct WithHandlerFut2 where F: Fn(T1, T2) -> R + 'static, R: Responder + 'static, T1: FromRequest + 'static, T2: FromRequest + 'static, S: 'static, { started: bool, hnd: Rc>, cfg1: ExtractorConfig, cfg2: ExtractorConfig, req: HttpRequest, item: Option, fut1: Option>>, fut2: Option>>, fut3: Option>>, } impl Future for WithHandlerFut2 where F: Fn(T1, T2) -> R + 'static, R: Responder + 'static, T1: FromRequest + 'static, T2: 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.started { self.started = true; let reply = T1::from_request(&self.req, self.cfg1.as_ref()).into(); let item1 = match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.fut1 = Some(fut); return self.poll(); } }; let reply = T2::from_request(&self.req, self.cfg2.as_ref()).into(); let item2 = match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.item = Some(item1); self.fut2 = Some(fut); return self.poll(); } }; let hnd: &mut F = unsafe { &mut *self.hnd.get() }; match (*hnd)(item1, item2).respond_to(&self.req) { Ok(item) => match item.into().into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(resp) => return Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => { self.fut3 = Some(fut); return self.poll(); } }, Err(e) => return Err(e.into()), } } if self.fut1.is_some() { match self.fut1.as_mut().unwrap().poll()? { Async::Ready(item) => { let reply = T2::from_request(&self.req, self.cfg2.as_ref()).into(); let item2 = match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.item = Some(item); self.fut2 = Some(fut); return self.poll(); } }; let hnd: &mut F = unsafe { &mut *self.hnd.get() }; match (*hnd)(item, item2).respond_to(&self.req) { Ok(item) => match item.into().into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(resp) => return Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => { self.fut3 = Some(fut); return self.poll(); } }, Err(e) => return Err(e.into()), } } Async::NotReady => return Ok(Async::NotReady), } } let item = match self.fut2.as_mut().unwrap().poll()? { Async::Ready(item) => item, Async::NotReady => return Ok(Async::NotReady), }; let hnd: &mut F = unsafe { &mut *self.hnd.get() }; let item = match (*hnd)(self.item.take().unwrap(), item).respond_to(&self.req) { Ok(item) => item.into(), Err(err) => return Err(err.into()), }; match item.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(resp) => return Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => self.fut3 = Some(fut), } self.poll() } } pub struct With3 where F: Fn(T1, T2, T3) -> R, T1: FromRequest + 'static, T2: FromRequest + 'static, T3: FromRequest + 'static, S: 'static, { hnd: Rc>, cfg1: ExtractorConfig, cfg2: ExtractorConfig, cfg3: ExtractorConfig, _s: PhantomData, } impl With3 where F: Fn(T1, T2, T3) -> R, T1: FromRequest + 'static, T2: FromRequest + 'static, T3: FromRequest + 'static, S: 'static, { pub fn new( f: F, cfg1: ExtractorConfig, cfg2: ExtractorConfig, cfg3: ExtractorConfig, ) -> Self { With3 { hnd: Rc::new(UnsafeCell::new(f)), cfg1, cfg2, cfg3, _s: PhantomData, } } } impl Handler for With3 where F: Fn(T1, T2, T3) -> R + 'static, R: Responder + 'static, T1: FromRequest, T2: FromRequest, T3: FromRequest, T1: 'static, T2: 'static, T3: 'static, S: 'static, { type Result = AsyncResult; fn handle(&mut self, req: HttpRequest) -> Self::Result { let mut fut = WithHandlerFut3 { req, hnd: Rc::clone(&self.hnd), cfg1: self.cfg1.clone(), cfg2: self.cfg2.clone(), cfg3: self.cfg3.clone(), started: false, item1: None, item2: None, fut1: None, fut2: None, fut3: None, fut4: 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 WithHandlerFut3 where F: Fn(T1, T2, T3) -> R + 'static, R: Responder + 'static, T1: FromRequest + 'static, T2: FromRequest + 'static, T3: FromRequest + 'static, S: 'static, { hnd: Rc>, req: HttpRequest, cfg1: ExtractorConfig, cfg2: ExtractorConfig, cfg3: ExtractorConfig, started: bool, item1: Option, item2: Option, fut1: Option>>, fut2: Option>>, fut3: Option>>, fut4: Option>>, } impl Future for WithHandlerFut3 where F: Fn(T1, T2, T3) -> R + 'static, R: Responder + 'static, T1: FromRequest + 'static, T2: FromRequest + 'static, T3: FromRequest + 'static, S: 'static, { type Item = HttpResponse; type Error = Error; fn poll(&mut self) -> Poll { if let Some(ref mut fut) = self.fut4 { return fut.poll(); } if !self.started { self.started = true; let reply = T1::from_request(&self.req, self.cfg1.as_ref()).into(); let item1 = match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.fut1 = Some(fut); return self.poll(); } }; let reply = T2::from_request(&self.req, self.cfg2.as_ref()).into(); let item2 = match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.item1 = Some(item1); self.fut2 = Some(fut); return self.poll(); } }; let reply = T3::from_request(&self.req, self.cfg3.as_ref()).into(); let item3 = match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.item1 = Some(item1); self.item2 = Some(item2); self.fut3 = Some(fut); return self.poll(); } }; let hnd: &mut F = unsafe { &mut *self.hnd.get() }; match (*hnd)(item1, item2, item3).respond_to(&self.req) { Ok(item) => match item.into().into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(resp) => return Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => { self.fut4 = Some(fut); return self.poll(); } }, Err(e) => return Err(e.into()), } } if self.fut1.is_some() { match self.fut1.as_mut().unwrap().poll()? { Async::Ready(item) => { self.item1 = Some(item); self.fut1.take(); let reply = T2::from_request(&self.req, self.cfg2.as_ref()).into(); let item2 = match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.fut2 = Some(fut); return self.poll(); } }; let reply = T3::from_request(&self.req, self.cfg3.as_ref()).into(); let item3 = match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.item2 = Some(item2); self.fut3 = Some(fut); return self.poll(); } }; let hnd: &mut F = unsafe { &mut *self.hnd.get() }; match (*hnd)(self.item1.take().unwrap(), item2, item3) .respond_to(&self.req) { Ok(item) => match item.into().into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(resp) => return Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => { self.fut4 = Some(fut); return self.poll(); } }, Err(e) => return Err(e.into()), } } Async::NotReady => return Ok(Async::NotReady), } } if self.fut2.is_some() { match self.fut2.as_mut().unwrap().poll()? { Async::Ready(item) => { self.fut2.take(); let reply = T3::from_request(&self.req, self.cfg3.as_ref()).into(); let item3 = match reply.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(msg) => msg, AsyncResultItem::Future(fut) => { self.item2 = Some(item); self.fut3 = Some(fut); return self.poll(); } }; let hnd: &mut F = unsafe { &mut *self.hnd.get() }; match (*hnd)(self.item1.take().unwrap(), item, item3) .respond_to(&self.req) { Ok(item) => match item.into().into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(resp) => return Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => { self.fut4 = Some(fut); return self.poll(); } }, Err(e) => return Err(e.into()), } } Async::NotReady => return Ok(Async::NotReady), } } let item = match self.fut3.as_mut().unwrap().poll()? { Async::Ready(item) => item, Async::NotReady => return Ok(Async::NotReady), }; let hnd: &mut F = unsafe { &mut *self.hnd.get() }; let item = match (*hnd)(self.item1.take().unwrap(), self.item2.take().unwrap(), item) .respond_to(&self.req) { Ok(item) => item.into(), Err(err) => return Err(err.into()), }; match item.into() { AsyncResultItem::Err(err) => return Err(err), AsyncResultItem::Ok(resp) => return Ok(Async::Ready(resp)), AsyncResultItem::Future(fut) => self.fut4 = Some(fut), } self.poll() } }