diff --git a/src/application.rs b/src/application.rs index 7eb17899..8c284e71 100644 --- a/src/application.rs +++ b/src/application.rs @@ -231,7 +231,7 @@ impl Application where S: 'static { let mut resource = Resource::default(); f(&mut resource); - let pattern = Pattern::new(resource.get_name(), path); + let pattern = Pattern::new(resource.get_name(), path, "^/"); if parts.resources.contains_key(&pattern) { panic!("Resource {:?} is registered.", path); } @@ -285,7 +285,7 @@ impl Application where S: 'static { panic!("External resource {:?} is registered.", name.as_ref()); } parts.external.insert( - String::from(name.as_ref()), Pattern::new(name.as_ref(), url.as_ref())); + String::from(name.as_ref()), Pattern::new(name.as_ref(), url.as_ref(), "^/")); } self } diff --git a/src/handler.rs b/src/handler.rs index 106fecc8..8f6861e5 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -144,6 +144,7 @@ impl> Responder for Result } impl> From> for Reply { + #[inline] fn from(res: Result) -> Self { match res { Ok(val) => val, @@ -152,6 +153,23 @@ impl> From> for Reply { } } +impl> From> for Reply { + #[inline] + fn from(res: Result) -> Self { + match res { + Ok(val) => Reply(ReplyItem::Message(val)), + Err(err) => Reply(ReplyItem::Message(err.into().into())), + } + } +} + +impl From>> for Reply { + #[inline] + fn from(fut: Box>) -> Reply { + Reply(ReplyItem::Future(fut)) + } +} + impl Responder for Box> where I: Responder + 'static, E: Into + 'static diff --git a/src/httpcodes.rs b/src/httpcodes.rs index e27c5623..c39167dd 100644 --- a/src/httpcodes.rs +++ b/src/httpcodes.rs @@ -93,6 +93,12 @@ impl From for HttpResponse { } } +impl From for Reply { + fn from(st: StaticResponse) -> Self { + HttpResponse::new(st.0, Body::Empty).into() + } +} + macro_rules! STATIC_RESP { ($name:ident, $status:expr) => { #[allow(non_snake_case)] diff --git a/src/httprequest.rs b/src/httprequest.rs index dd8de37d..c39c533d 100644 --- a/src/httprequest.rs +++ b/src/httprequest.rs @@ -137,8 +137,8 @@ impl HttpRequest { #[inline] /// Construct new http request with state. - pub fn change_state(self, state: Rc) -> HttpRequest { - HttpRequest(self.0, Some(state), self.2.clone()) + pub fn change_state(&self, state: Rc) -> HttpRequest { + HttpRequest(self.0.clone(), Some(state), self.2.clone()) } #[inline] @@ -726,7 +726,7 @@ mod tests { let mut resource = Resource::<()>::default(); resource.name("index"); let mut map = HashMap::new(); - map.insert(Pattern::new("index", "/{key}/"), Some(resource)); + map.insert(Pattern::new("index", "/{key}/", "^/"), Some(resource)); let (router, _) = Router::new("", ServerSettings::default(), map); assert!(router.recognize(&mut req).is_some()); @@ -828,7 +828,7 @@ mod tests { let mut resource = Resource::<()>::default(); resource.name("index"); let mut map = HashMap::new(); - map.insert(Pattern::new("index", "/user/{name}.{ext}"), Some(resource)); + map.insert(Pattern::new("index", "/user/{name}.{ext}", "^/"), Some(resource)); let (router, _) = Router::new("/", ServerSettings::default(), map); assert!(router.has_route("/user/test.html")); assert!(!router.has_route("/test/unknown")); @@ -857,7 +857,7 @@ mod tests { let mut resource = Resource::<()>::default(); resource.name("index"); let mut map = HashMap::new(); - map.insert(Pattern::new("index", "/user/{name}.{ext}"), Some(resource)); + map.insert(Pattern::new("index", "/user/{name}.{ext}", "^/"), Some(resource)); let (router, _) = Router::new("/prefix/", ServerSettings::default(), map); assert!(router.has_route("/user/test.html")); assert!(!router.has_route("/prefix/user/test.html")); @@ -876,7 +876,7 @@ mod tests { let mut resource = Resource::<()>::default(); resource.name("index"); let mut map = HashMap::new(); - map.insert(Pattern::new("youtube", "https://youtube.com/watch/{video_id}"), None); + map.insert(Pattern::new("youtube", "https://youtube.com/watch/{video_id}", "^/"), None); let (router, _) = Router::new::<()>("", ServerSettings::default(), map); assert!(!router.has_route("https://youtube.com/watch/unknown")); diff --git a/src/pipeline.rs b/src/pipeline.rs index 3ea1a320..7e2681c5 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -40,6 +40,7 @@ struct PipelineInfo { mws: Rc>>>, context: Option>, error: Option, + disconnected: Option, } impl PipelineInfo { @@ -50,6 +51,7 @@ impl PipelineInfo { mws: Rc::new(Vec::new()), error: None, context: None, + disconnected: None, } } @@ -84,6 +86,7 @@ impl> Pipeline { mws: mws, error: None, context: None, + disconnected: None, }; let state = StartMiddlewares::init(&mut info, handler); @@ -114,9 +117,7 @@ impl Pipeline { impl> HttpHandlerTask for Pipeline { fn disconnected(&mut self) { - if let Some(ref mut context) = self.0.context { - context.disconnected(); - } + self.0.disconnected = Some(true); } fn poll_io(&mut self, io: &mut Writer) -> Poll { @@ -592,10 +593,14 @@ impl ProcessResponse { } }, IOState::Actor(mut ctx) => { + if info.disconnected.take().is_some() { + ctx.disconnected(); + } match ctx.poll() { Ok(Async::Ready(Some(frame))) => { match frame { Frame::Payload(None) => { + println!("ACTOR PAYLOAD EOF"); info.context = Some(ctx); self.iostate = IOState::Done; if let Err(err) = io.write_eof() { @@ -606,6 +611,7 @@ impl ProcessResponse { break }, Frame::Payload(Some(chunk)) => { + println!("ACTOR PAYLOAD"); self.iostate = IOState::Actor(ctx); match io.write(chunk.as_ref()) { Err(err) => { @@ -617,7 +623,9 @@ impl ProcessResponse { } }, Frame::Drain(fut) => { + println!("ACTOR DRAIN"); self.drain = Some(fut); + self.iostate = IOState::Actor(ctx); break } } diff --git a/src/router.rs b/src/router.rs index ebd763bf..ca678341 100644 --- a/src/router.rs +++ b/src/router.rs @@ -88,8 +88,7 @@ impl Router { } if let Some(idx) = idx { - let path: &str = unsafe{ mem::transmute(&req.path()[self.0.prefix_len..]) }; - self.0.patterns[idx].update_match_info(path, req); + self.0.patterns[idx].update_match_info(req, self.0.prefix_len); return Some(idx) } else { None @@ -159,8 +158,8 @@ impl Pattern { /// Parse path pattern and create new `Pattern` instance. /// /// Panics if path pattern is wrong. - pub fn new(name: &str, path: &str) -> Self { - let (pattern, elements) = Pattern::parse(path); + pub fn new(name: &str, path: &str, starts: &str) -> Self { + let (pattern, elements) = Pattern::parse(path, starts); let re = match Regex::new(&pattern) { Ok(re) => re, @@ -190,8 +189,9 @@ impl Pattern { } /// Extract pattern parameters from the text - pub fn update_match_info(&self, text: &str, req: &mut HttpRequest) { + pub fn update_match_info(&self, req: &mut HttpRequest, prefix: usize) { if !self.names.is_empty() { + let text: &str = unsafe{ mem::transmute(&req.path()[prefix..]) }; if let Some(captures) = self.re.captures(text) { let mut idx = 0; for capture in captures.iter() { @@ -207,6 +207,25 @@ impl Pattern { } } + /// Extract pattern parameters from the text + pub fn get_match_info<'a>(&self, text: &'a str) -> HashMap<&str, &'a str> { + let mut info = HashMap::new(); + if !self.names.is_empty() { + if let Some(captures) = self.re.captures(text) { + let mut idx = 0; + for capture in captures.iter() { + if let Some(ref m) = capture { + if idx != 0 { + info.insert(self.names[idx-1].as_str(), m.as_str()); + } + idx += 1; + } + } + }; + } + info + } + /// Build pattern path. pub fn path(&self, prefix: Option<&str>, elements: U) -> Result where U: IntoIterator, @@ -218,7 +237,6 @@ impl Pattern { } else { String::new() }; - println!("TEST: {:?} {:?}", path, prefix); for el in &self.elements { match *el { PatternElement::Str(ref s) => path.push_str(s), @@ -234,10 +252,10 @@ impl Pattern { Ok(path) } - fn parse(pattern: &str) -> (String, Vec) { + fn parse(pattern: &str, starts: &str) -> (String, Vec) { const DEFAULT_PATTERN: &str = "[^/]+"; - let mut re = String::from("^/"); + let mut re = String::from(starts); let mut el = String::new(); let mut in_param = false; let mut in_param_pattern = false; @@ -312,12 +330,14 @@ mod tests { #[test] fn test_recognizer() { let mut routes = HashMap::new(); - routes.insert(Pattern::new("", "/name"), Some(Resource::default())); - routes.insert(Pattern::new("", "/name/{val}"), Some(Resource::default())); - routes.insert(Pattern::new("", "/name/{val}/index.html"), Some(Resource::default())); - routes.insert(Pattern::new("", "/v{val}/{val2}/index.html"), Some(Resource::default())); - routes.insert(Pattern::new("", "/v/{tail:.*}"), Some(Resource::default())); - routes.insert(Pattern::new("", "{test}/index.html"), Some(Resource::default())); + routes.insert(Pattern::new("", "/name", "^/"), Some(Resource::default())); + routes.insert(Pattern::new("", "/name/{val}", "^/"), Some(Resource::default())); + routes.insert(Pattern::new("", "/name/{val}/index.html", "^/"), + Some(Resource::default())); + routes.insert(Pattern::new("", "/v{val}/{val2}/index.html", "^/"), + Some(Resource::default())); + routes.insert(Pattern::new("", "/v/{tail:.*}", "^/"), Some(Resource::default())); + routes.insert(Pattern::new("", "{test}/index.html", "^/"), Some(Resource::default())); let (rec, _) = Router::new::<()>("", ServerSettings::default(), routes); let mut req = TestRequest::with_uri("/name").finish(); @@ -350,8 +370,8 @@ mod tests { #[test] fn test_recognizer_with_prefix() { let mut routes = HashMap::new(); - routes.insert(Pattern::new("", "/name"), Some(Resource::default())); - routes.insert(Pattern::new("", "/name/{val}"), Some(Resource::default())); + routes.insert(Pattern::new("", "/name", "^/"), Some(Resource::default())); + routes.insert(Pattern::new("", "/name/{val}", "^/"), Some(Resource::default())); let (rec, _) = Router::new::<()>("/test", ServerSettings::default(), routes); let mut req = TestRequest::with_uri("/name").finish(); @@ -367,8 +387,8 @@ mod tests { // same patterns let mut routes = HashMap::new(); - routes.insert(Pattern::new("", "/name"), Some(Resource::default())); - routes.insert(Pattern::new("", "/name/{val}"), Some(Resource::default())); + routes.insert(Pattern::new("", "/name", "^/"), Some(Resource::default())); + routes.insert(Pattern::new("", "/name/{val}", "^/"), Some(Resource::default())); let (rec, _) = Router::new::<()>("/test2", ServerSettings::default(), routes); let mut req = TestRequest::with_uri("/name").finish(); @@ -378,7 +398,7 @@ mod tests { } fn assert_parse(pattern: &str, expected_re: &str) -> Regex { - let (re_str, _) = Pattern::parse(pattern); + let (re_str, _) = Pattern::parse(pattern, "^/"); assert_eq!(&*re_str, expected_re); Regex::new(&re_str).unwrap() }