mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-24 16:02:59 +01:00
fix drain support for actor; make pattern more reusable
This commit is contained in:
parent
9e6d090fd0
commit
70ea43b3c0
@ -231,7 +231,7 @@ impl<S> Application<S> where S: 'static {
|
|||||||
let mut resource = Resource::default();
|
let mut resource = Resource::default();
|
||||||
f(&mut resource);
|
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) {
|
if parts.resources.contains_key(&pattern) {
|
||||||
panic!("Resource {:?} is registered.", path);
|
panic!("Resource {:?} is registered.", path);
|
||||||
}
|
}
|
||||||
@ -285,7 +285,7 @@ impl<S> Application<S> where S: 'static {
|
|||||||
panic!("External resource {:?} is registered.", name.as_ref());
|
panic!("External resource {:?} is registered.", name.as_ref());
|
||||||
}
|
}
|
||||||
parts.external.insert(
|
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
|
self
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,7 @@ impl<T: Responder, E: Into<Error>> Responder for Result<T, E>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Into<Error>> From<Result<Reply, E>> for Reply {
|
impl<E: Into<Error>> From<Result<Reply, E>> for Reply {
|
||||||
|
#[inline]
|
||||||
fn from(res: Result<Reply, E>) -> Self {
|
fn from(res: Result<Reply, E>) -> Self {
|
||||||
match res {
|
match res {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
@ -152,6 +153,23 @@ impl<E: Into<Error>> From<Result<Reply, E>> for Reply {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: Into<Error>> From<Result<HttpResponse, E>> for Reply {
|
||||||
|
#[inline]
|
||||||
|
fn from(res: Result<HttpResponse, E>) -> Self {
|
||||||
|
match res {
|
||||||
|
Ok(val) => Reply(ReplyItem::Message(val)),
|
||||||
|
Err(err) => Reply(ReplyItem::Message(err.into().into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<Future<Item=HttpResponse, Error=Error>>> for Reply {
|
||||||
|
#[inline]
|
||||||
|
fn from(fut: Box<Future<Item=HttpResponse, Error=Error>>) -> Reply {
|
||||||
|
Reply(ReplyItem::Future(fut))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<I, E> Responder for Box<Future<Item=I, Error=E>>
|
impl<I, E> Responder for Box<Future<Item=I, Error=E>>
|
||||||
where I: Responder + 'static,
|
where I: Responder + 'static,
|
||||||
E: Into<Error> + 'static
|
E: Into<Error> + 'static
|
||||||
|
@ -93,6 +93,12 @@ impl From<StaticResponse> for HttpResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<StaticResponse> for Reply {
|
||||||
|
fn from(st: StaticResponse) -> Self {
|
||||||
|
HttpResponse::new(st.0, Body::Empty).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! STATIC_RESP {
|
macro_rules! STATIC_RESP {
|
||||||
($name:ident, $status:expr) => {
|
($name:ident, $status:expr) => {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -137,8 +137,8 @@ impl<S> HttpRequest<S> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Construct new http request with state.
|
/// Construct new http request with state.
|
||||||
pub fn change_state<NS>(self, state: Rc<NS>) -> HttpRequest<NS> {
|
pub fn change_state<NS>(&self, state: Rc<NS>) -> HttpRequest<NS> {
|
||||||
HttpRequest(self.0, Some(state), self.2.clone())
|
HttpRequest(self.0.clone(), Some(state), self.2.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -726,7 +726,7 @@ mod tests {
|
|||||||
let mut resource = Resource::<()>::default();
|
let mut resource = Resource::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut map = HashMap::new();
|
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);
|
let (router, _) = Router::new("", ServerSettings::default(), map);
|
||||||
assert!(router.recognize(&mut req).is_some());
|
assert!(router.recognize(&mut req).is_some());
|
||||||
|
|
||||||
@ -828,7 +828,7 @@ mod tests {
|
|||||||
let mut resource = Resource::<()>::default();
|
let mut resource = Resource::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut map = HashMap::new();
|
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);
|
let (router, _) = Router::new("/", ServerSettings::default(), map);
|
||||||
assert!(router.has_route("/user/test.html"));
|
assert!(router.has_route("/user/test.html"));
|
||||||
assert!(!router.has_route("/test/unknown"));
|
assert!(!router.has_route("/test/unknown"));
|
||||||
@ -857,7 +857,7 @@ mod tests {
|
|||||||
let mut resource = Resource::<()>::default();
|
let mut resource = Resource::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut map = HashMap::new();
|
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);
|
let (router, _) = Router::new("/prefix/", ServerSettings::default(), map);
|
||||||
assert!(router.has_route("/user/test.html"));
|
assert!(router.has_route("/user/test.html"));
|
||||||
assert!(!router.has_route("/prefix/user/test.html"));
|
assert!(!router.has_route("/prefix/user/test.html"));
|
||||||
@ -876,7 +876,7 @@ mod tests {
|
|||||||
let mut resource = Resource::<()>::default();
|
let mut resource = Resource::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut map = HashMap::new();
|
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);
|
let (router, _) = Router::new::<()>("", ServerSettings::default(), map);
|
||||||
assert!(!router.has_route("https://youtube.com/watch/unknown"));
|
assert!(!router.has_route("https://youtube.com/watch/unknown"));
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ struct PipelineInfo<S> {
|
|||||||
mws: Rc<Vec<Box<Middleware<S>>>>,
|
mws: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
context: Option<Box<ActorHttpContext>>,
|
context: Option<Box<ActorHttpContext>>,
|
||||||
error: Option<Error>,
|
error: Option<Error>,
|
||||||
|
disconnected: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> PipelineInfo<S> {
|
impl<S> PipelineInfo<S> {
|
||||||
@ -50,6 +51,7 @@ impl<S> PipelineInfo<S> {
|
|||||||
mws: Rc::new(Vec::new()),
|
mws: Rc::new(Vec::new()),
|
||||||
error: None,
|
error: None,
|
||||||
context: None,
|
context: None,
|
||||||
|
disconnected: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +86,7 @@ impl<S, H: PipelineHandler<S>> Pipeline<S, H> {
|
|||||||
mws: mws,
|
mws: mws,
|
||||||
error: None,
|
error: None,
|
||||||
context: None,
|
context: None,
|
||||||
|
disconnected: None,
|
||||||
};
|
};
|
||||||
let state = StartMiddlewares::init(&mut info, handler);
|
let state = StartMiddlewares::init(&mut info, handler);
|
||||||
|
|
||||||
@ -114,9 +117,7 @@ impl<S, H> Pipeline<S, H> {
|
|||||||
impl<S, H: PipelineHandler<S>> HttpHandlerTask for Pipeline<S, H> {
|
impl<S, H: PipelineHandler<S>> HttpHandlerTask for Pipeline<S, H> {
|
||||||
|
|
||||||
fn disconnected(&mut self) {
|
fn disconnected(&mut self) {
|
||||||
if let Some(ref mut context) = self.0.context {
|
self.0.disconnected = Some(true);
|
||||||
context.disconnected();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
||||||
@ -592,10 +593,14 @@ impl<S, H> ProcessResponse<S, H> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
IOState::Actor(mut ctx) => {
|
IOState::Actor(mut ctx) => {
|
||||||
|
if info.disconnected.take().is_some() {
|
||||||
|
ctx.disconnected();
|
||||||
|
}
|
||||||
match ctx.poll() {
|
match ctx.poll() {
|
||||||
Ok(Async::Ready(Some(frame))) => {
|
Ok(Async::Ready(Some(frame))) => {
|
||||||
match frame {
|
match frame {
|
||||||
Frame::Payload(None) => {
|
Frame::Payload(None) => {
|
||||||
|
println!("ACTOR PAYLOAD EOF");
|
||||||
info.context = Some(ctx);
|
info.context = Some(ctx);
|
||||||
self.iostate = IOState::Done;
|
self.iostate = IOState::Done;
|
||||||
if let Err(err) = io.write_eof() {
|
if let Err(err) = io.write_eof() {
|
||||||
@ -606,6 +611,7 @@ impl<S, H> ProcessResponse<S, H> {
|
|||||||
break
|
break
|
||||||
},
|
},
|
||||||
Frame::Payload(Some(chunk)) => {
|
Frame::Payload(Some(chunk)) => {
|
||||||
|
println!("ACTOR PAYLOAD");
|
||||||
self.iostate = IOState::Actor(ctx);
|
self.iostate = IOState::Actor(ctx);
|
||||||
match io.write(chunk.as_ref()) {
|
match io.write(chunk.as_ref()) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -617,7 +623,9 @@ impl<S, H> ProcessResponse<S, H> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Frame::Drain(fut) => {
|
Frame::Drain(fut) => {
|
||||||
|
println!("ACTOR DRAIN");
|
||||||
self.drain = Some(fut);
|
self.drain = Some(fut);
|
||||||
|
self.iostate = IOState::Actor(ctx);
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,8 +88,7 @@ impl Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(idx) = idx {
|
if let Some(idx) = idx {
|
||||||
let path: &str = unsafe{ mem::transmute(&req.path()[self.0.prefix_len..]) };
|
self.0.patterns[idx].update_match_info(req, self.0.prefix_len);
|
||||||
self.0.patterns[idx].update_match_info(path, req);
|
|
||||||
return Some(idx)
|
return Some(idx)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -159,8 +158,8 @@ impl Pattern {
|
|||||||
/// Parse path pattern and create new `Pattern` instance.
|
/// Parse path pattern and create new `Pattern` instance.
|
||||||
///
|
///
|
||||||
/// Panics if path pattern is wrong.
|
/// Panics if path pattern is wrong.
|
||||||
pub fn new(name: &str, path: &str) -> Self {
|
pub fn new(name: &str, path: &str, starts: &str) -> Self {
|
||||||
let (pattern, elements) = Pattern::parse(path);
|
let (pattern, elements) = Pattern::parse(path, starts);
|
||||||
|
|
||||||
let re = match Regex::new(&pattern) {
|
let re = match Regex::new(&pattern) {
|
||||||
Ok(re) => re,
|
Ok(re) => re,
|
||||||
@ -190,8 +189,9 @@ impl Pattern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Extract pattern parameters from the text
|
/// Extract pattern parameters from the text
|
||||||
pub fn update_match_info<S>(&self, text: &str, req: &mut HttpRequest<S>) {
|
pub fn update_match_info<S>(&self, req: &mut HttpRequest<S>, prefix: usize) {
|
||||||
if !self.names.is_empty() {
|
if !self.names.is_empty() {
|
||||||
|
let text: &str = unsafe{ mem::transmute(&req.path()[prefix..]) };
|
||||||
if let Some(captures) = self.re.captures(text) {
|
if let Some(captures) = self.re.captures(text) {
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
for capture in captures.iter() {
|
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.
|
/// Build pattern path.
|
||||||
pub fn path<U, I>(&self, prefix: Option<&str>, elements: U) -> Result<String, UrlGenerationError>
|
pub fn path<U, I>(&self, prefix: Option<&str>, elements: U) -> Result<String, UrlGenerationError>
|
||||||
where U: IntoIterator<Item=I>,
|
where U: IntoIterator<Item=I>,
|
||||||
@ -218,7 +237,6 @@ impl Pattern {
|
|||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
println!("TEST: {:?} {:?}", path, prefix);
|
|
||||||
for el in &self.elements {
|
for el in &self.elements {
|
||||||
match *el {
|
match *el {
|
||||||
PatternElement::Str(ref s) => path.push_str(s),
|
PatternElement::Str(ref s) => path.push_str(s),
|
||||||
@ -234,10 +252,10 @@ impl Pattern {
|
|||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(pattern: &str) -> (String, Vec<PatternElement>) {
|
fn parse(pattern: &str, starts: &str) -> (String, Vec<PatternElement>) {
|
||||||
const DEFAULT_PATTERN: &str = "[^/]+";
|
const DEFAULT_PATTERN: &str = "[^/]+";
|
||||||
|
|
||||||
let mut re = String::from("^/");
|
let mut re = String::from(starts);
|
||||||
let mut el = String::new();
|
let mut el = String::new();
|
||||||
let mut in_param = false;
|
let mut in_param = false;
|
||||||
let mut in_param_pattern = false;
|
let mut in_param_pattern = false;
|
||||||
@ -312,12 +330,14 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer() {
|
fn test_recognizer() {
|
||||||
let mut routes = HashMap::new();
|
let mut routes = HashMap::new();
|
||||||
routes.insert(Pattern::new("", "/name"), 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}", "^/"), Some(Resource::default()));
|
||||||
routes.insert(Pattern::new("", "/name/{val}/index.html"), Some(Resource::default()));
|
routes.insert(Pattern::new("", "/name/{val}/index.html", "^/"),
|
||||||
routes.insert(Pattern::new("", "/v{val}/{val2}/index.html"), Some(Resource::default()));
|
Some(Resource::default()));
|
||||||
routes.insert(Pattern::new("", "/v/{tail:.*}"), Some(Resource::default()));
|
routes.insert(Pattern::new("", "/v{val}/{val2}/index.html", "^/"),
|
||||||
routes.insert(Pattern::new("", "{test}/index.html"), Some(Resource::default()));
|
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 (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name").finish();
|
let mut req = TestRequest::with_uri("/name").finish();
|
||||||
@ -350,8 +370,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer_with_prefix() {
|
fn test_recognizer_with_prefix() {
|
||||||
let mut routes = HashMap::new();
|
let mut routes = HashMap::new();
|
||||||
routes.insert(Pattern::new("", "/name"), 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}", "^/"), Some(Resource::default()));
|
||||||
let (rec, _) = Router::new::<()>("/test", ServerSettings::default(), routes);
|
let (rec, _) = Router::new::<()>("/test", ServerSettings::default(), routes);
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name").finish();
|
let mut req = TestRequest::with_uri("/name").finish();
|
||||||
@ -367,8 +387,8 @@ mod tests {
|
|||||||
|
|
||||||
// same patterns
|
// same patterns
|
||||||
let mut routes = HashMap::new();
|
let mut routes = HashMap::new();
|
||||||
routes.insert(Pattern::new("", "/name"), 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}", "^/"), Some(Resource::default()));
|
||||||
let (rec, _) = Router::new::<()>("/test2", ServerSettings::default(), routes);
|
let (rec, _) = Router::new::<()>("/test2", ServerSettings::default(), routes);
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name").finish();
|
let mut req = TestRequest::with_uri("/name").finish();
|
||||||
@ -378,7 +398,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn assert_parse(pattern: &str, expected_re: &str) -> Regex {
|
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);
|
assert_eq!(&*re_str, expected_re);
|
||||||
Regex::new(&re_str).unwrap()
|
Regex::new(&re_str).unwrap()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user