mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-30 18:44:35 +01:00
fix routes registration order
This commit is contained in:
parent
4a9c1ae894
commit
aff43cc8b8
@ -100,7 +100,7 @@ struct ApplicationParts<S> {
|
|||||||
prefix: String,
|
prefix: String,
|
||||||
settings: ServerSettings,
|
settings: ServerSettings,
|
||||||
default: Resource<S>,
|
default: Resource<S>,
|
||||||
resources: HashMap<Pattern, Option<Resource<S>>>,
|
resources: Vec<(Pattern, Option<Resource<S>>)>,
|
||||||
handlers: Vec<(String, Box<RouteHandler<S>>)>,
|
handlers: Vec<(String, Box<RouteHandler<S>>)>,
|
||||||
external: HashMap<String, Pattern>,
|
external: HashMap<String, Pattern>,
|
||||||
encoding: ContentEncoding,
|
encoding: ContentEncoding,
|
||||||
@ -123,7 +123,7 @@ impl Application<()> {
|
|||||||
prefix: "/".to_owned(),
|
prefix: "/".to_owned(),
|
||||||
settings: ServerSettings::default(),
|
settings: ServerSettings::default(),
|
||||||
default: Resource::default_not_found(),
|
default: Resource::default_not_found(),
|
||||||
resources: HashMap::new(),
|
resources: Vec::new(),
|
||||||
handlers: Vec::new(),
|
handlers: Vec::new(),
|
||||||
external: HashMap::new(),
|
external: HashMap::new(),
|
||||||
encoding: ContentEncoding::Auto,
|
encoding: ContentEncoding::Auto,
|
||||||
@ -153,7 +153,7 @@ impl<S> Application<S> where S: 'static {
|
|||||||
prefix: "/".to_owned(),
|
prefix: "/".to_owned(),
|
||||||
settings: ServerSettings::default(),
|
settings: ServerSettings::default(),
|
||||||
default: Resource::default_not_found(),
|
default: Resource::default_not_found(),
|
||||||
resources: HashMap::new(),
|
resources: Vec::new(),
|
||||||
handlers: Vec::new(),
|
handlers: Vec::new(),
|
||||||
external: HashMap::new(),
|
external: HashMap::new(),
|
||||||
middlewares: Vec::new(),
|
middlewares: Vec::new(),
|
||||||
@ -242,11 +242,7 @@ impl<S> Application<S> where S: 'static {
|
|||||||
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) {
|
parts.resources.push((pattern, Some(resource)));
|
||||||
panic!("Resource {:?} is registered.", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
parts.resources.insert(pattern, Some(resource));
|
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -354,7 +350,7 @@ impl<S> Application<S> where S: 'static {
|
|||||||
|
|
||||||
let mut resources = parts.resources;
|
let mut resources = parts.resources;
|
||||||
for (_, pattern) in parts.external {
|
for (_, pattern) in parts.external {
|
||||||
resources.insert(pattern, None);
|
resources.push((pattern, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (router, resources) = Router::new(prefix, parts.settings, resources);
|
let (router, resources) = Router::new(prefix, parts.settings, resources);
|
||||||
|
@ -883,9 +883,9 @@ 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 routes = Vec::new();
|
||||||
map.insert(Pattern::new("index", "/{key}/"), Some(resource));
|
routes.push((Pattern::new("index", "/{key}/"), Some(resource)));
|
||||||
let (router, _) = Router::new("", ServerSettings::default(), map);
|
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
||||||
assert!(router.recognize(&mut req).is_some());
|
assert!(router.recognize(&mut req).is_some());
|
||||||
|
|
||||||
assert_eq!(req.match_info().get("key"), Some("value"));
|
assert_eq!(req.match_info().get("key"), Some("value"));
|
||||||
@ -994,9 +994,8 @@ mod tests {
|
|||||||
|
|
||||||
let mut resource = Resource::<()>::default();
|
let mut resource = Resource::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut map = HashMap::new();
|
let routes = vec!((Pattern::new("index", "/user/{name}.{ext}"), Some(resource)));
|
||||||
map.insert(Pattern::new("index", "/user/{name}.{ext}"), Some(resource));
|
let (router, _) = Router::new("/", ServerSettings::default(), routes);
|
||||||
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"));
|
||||||
|
|
||||||
@ -1019,9 +1018,8 @@ mod tests {
|
|||||||
|
|
||||||
let mut resource = Resource::<()>::default();
|
let mut resource = Resource::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut map = HashMap::new();
|
let routes = vec![(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(), routes);
|
||||||
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"));
|
||||||
|
|
||||||
@ -1036,9 +1034,9 @@ mod tests {
|
|||||||
|
|
||||||
let mut resource = Resource::<()>::default();
|
let mut resource = Resource::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut map = HashMap::new();
|
let routes = vec![
|
||||||
map.insert(Pattern::new("youtube", "https://youtube.com/watch/{video_id}"), None);
|
(Pattern::new("youtube", "https://youtube.com/watch/{video_id}"), None)];
|
||||||
let (router, _) = Router::new::<()>("", ServerSettings::default(), map);
|
let (router, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
assert!(!router.has_route("https://youtube.com/watch/unknown"));
|
assert!(!router.has_route("https://youtube.com/watch/unknown"));
|
||||||
|
|
||||||
let req = req.with_state(Rc::new(()), router);
|
let req = req.with_state(Rc::new(()), router);
|
||||||
|
@ -27,7 +27,7 @@ impl Router {
|
|||||||
/// Create new router
|
/// Create new router
|
||||||
pub fn new<S>(prefix: &str,
|
pub fn new<S>(prefix: &str,
|
||||||
settings: ServerSettings,
|
settings: ServerSettings,
|
||||||
map: HashMap<Pattern, Option<Resource<S>>>) -> (Router, Vec<Resource<S>>)
|
map: Vec<(Pattern, Option<Resource<S>>)>) -> (Router, Vec<Resource<S>>)
|
||||||
{
|
{
|
||||||
let prefix = prefix.trim().trim_right_matches('/').to_owned();
|
let prefix = prefix.trim().trim_right_matches('/').to_owned();
|
||||||
let mut named = HashMap::new();
|
let mut named = HashMap::new();
|
||||||
@ -133,7 +133,7 @@ enum PatternElement {
|
|||||||
Var(String),
|
Var(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
enum PatternType {
|
enum PatternType {
|
||||||
Static(String),
|
Static(String),
|
||||||
Dynamic(Regex, Vec<String>),
|
Dynamic(Regex, Vec<String>),
|
||||||
@ -243,7 +243,8 @@ impl Pattern {
|
|||||||
fn parse(pattern: &str) -> (String, Vec<PatternElement>, bool) {
|
fn parse(pattern: &str) -> (String, Vec<PatternElement>, bool) {
|
||||||
const DEFAULT_PATTERN: &str = "[^/]+";
|
const DEFAULT_PATTERN: &str = "[^/]+";
|
||||||
|
|
||||||
let mut re = String::from("/");
|
let mut re1 = String::from("^/");
|
||||||
|
let mut re2 = String::from("/");
|
||||||
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;
|
||||||
@ -262,7 +263,7 @@ impl Pattern {
|
|||||||
// In parameter segment: `{....}`
|
// In parameter segment: `{....}`
|
||||||
if ch == '}' {
|
if ch == '}' {
|
||||||
elems.push(PatternElement::Var(param_name.clone()));
|
elems.push(PatternElement::Var(param_name.clone()));
|
||||||
re.push_str(&format!(r"(?P<{}>{})", ¶m_name, ¶m_pattern));
|
re1.push_str(&format!(r"(?P<{}>{})", ¶m_name, ¶m_pattern));
|
||||||
|
|
||||||
param_name.clear();
|
param_name.clear();
|
||||||
param_pattern = String::from(DEFAULT_PATTERN);
|
param_pattern = String::from(DEFAULT_PATTERN);
|
||||||
@ -287,15 +288,18 @@ impl Pattern {
|
|||||||
elems.push(PatternElement::Str(el.clone()));
|
elems.push(PatternElement::Str(el.clone()));
|
||||||
el.clear();
|
el.clear();
|
||||||
} else {
|
} else {
|
||||||
re.push_str(escape(&ch.to_string()).as_str());
|
re1.push_str(escape(&ch.to_string()).as_str());
|
||||||
|
re2.push(ch);
|
||||||
el.push(ch);
|
el.push(ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_dynamic {
|
let re = if is_dynamic {
|
||||||
re.insert(0, '^');
|
re1.push('$');
|
||||||
re.push('$');
|
re1
|
||||||
}
|
} else {
|
||||||
|
re2
|
||||||
|
};
|
||||||
(re, elems, is_dynamic)
|
(re, elems, is_dynamic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,78 +325,95 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer() {
|
fn test_recognizer() {
|
||||||
let mut routes = HashMap::new();
|
let routes = vec![
|
||||||
routes.insert(Pattern::new("", "/name"), Some(Resource::default()));
|
(Pattern::new("", "/name"), Some(Resource::default())),
|
||||||
routes.insert(Pattern::new("", "/name/{val}"), Some(Resource::default()));
|
(Pattern::new("", "/name/{val}"), Some(Resource::default())),
|
||||||
routes.insert(Pattern::new("", "/name/{val}/index.html"),
|
(Pattern::new("", "/name/{val}/index.html"), Some(Resource::default())),
|
||||||
Some(Resource::default()));
|
(Pattern::new("", "/file/{file}.{ext}"), Some(Resource::default())),
|
||||||
routes.insert(Pattern::new("", "/file/{file}.{ext}"), Some(Resource::default()));
|
(Pattern::new("", "/v{val}/{val2}/index.html"), Some(Resource::default())),
|
||||||
routes.insert(Pattern::new("", "/v{val}/{val2}/index.html"),
|
(Pattern::new("", "/v/{tail:.*}"), Some(Resource::default())),
|
||||||
Some(Resource::default()));
|
(Pattern::new("", "{test}/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 (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name").finish();
|
let mut req = TestRequest::with_uri("/name").finish();
|
||||||
assert!(rec.recognize(&mut req).is_some());
|
assert_eq!(rec.recognize(&mut req), Some(0));
|
||||||
assert!(req.match_info().is_empty());
|
assert!(req.match_info().is_empty());
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name/value").finish();
|
let mut req = TestRequest::with_uri("/name/value").finish();
|
||||||
assert!(rec.recognize(&mut req).is_some());
|
assert_eq!(rec.recognize(&mut req), Some(1));
|
||||||
assert_eq!(req.match_info().get("val").unwrap(), "value");
|
assert_eq!(req.match_info().get("val").unwrap(), "value");
|
||||||
assert_eq!(&req.match_info()["val"], "value");
|
assert_eq!(&req.match_info()["val"], "value");
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name/value2/index.html").finish();
|
let mut req = TestRequest::with_uri("/name/value2/index.html").finish();
|
||||||
assert!(rec.recognize(&mut req).is_some());
|
assert_eq!(rec.recognize(&mut req), Some(2));
|
||||||
assert_eq!(req.match_info().get("val").unwrap(), "value2");
|
assert_eq!(req.match_info().get("val").unwrap(), "value2");
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/file/file.gz").finish();
|
let mut req = TestRequest::with_uri("/file/file.gz").finish();
|
||||||
assert!(rec.recognize(&mut req).is_some());
|
assert_eq!(rec.recognize(&mut req), Some(3));
|
||||||
assert_eq!(req.match_info().get("file").unwrap(), "file");
|
assert_eq!(req.match_info().get("file").unwrap(), "file");
|
||||||
assert_eq!(req.match_info().get("ext").unwrap(), "gz");
|
assert_eq!(req.match_info().get("ext").unwrap(), "gz");
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/vtest/ttt/index.html").finish();
|
let mut req = TestRequest::with_uri("/vtest/ttt/index.html").finish();
|
||||||
assert!(rec.recognize(&mut req).is_some());
|
assert_eq!(rec.recognize(&mut req), Some(4));
|
||||||
assert_eq!(req.match_info().get("val").unwrap(), "test");
|
assert_eq!(req.match_info().get("val").unwrap(), "test");
|
||||||
assert_eq!(req.match_info().get("val2").unwrap(), "ttt");
|
assert_eq!(req.match_info().get("val2").unwrap(), "ttt");
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/v/blah-blah/index.html").finish();
|
let mut req = TestRequest::with_uri("/v/blah-blah/index.html").finish();
|
||||||
assert!(rec.recognize(&mut req).is_some());
|
assert_eq!(rec.recognize(&mut req), Some(5));
|
||||||
assert_eq!(req.match_info().get("tail").unwrap(), "blah-blah/index.html");
|
assert_eq!(req.match_info().get("tail").unwrap(), "blah-blah/index.html");
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/bbb/index.html").finish();
|
let mut req = TestRequest::with_uri("/bbb/index.html").finish();
|
||||||
assert!(rec.recognize(&mut req).is_some());
|
assert_eq!(rec.recognize(&mut req), Some(6));
|
||||||
assert_eq!(req.match_info().get("test").unwrap(), "bbb");
|
assert_eq!(req.match_info().get("test").unwrap(), "bbb");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_recognizer_2() {
|
||||||
|
let routes = vec![
|
||||||
|
(Pattern::new("", "/index.json"), Some(Resource::default())),
|
||||||
|
(Pattern::new("", "/{source}.json"), Some(Resource::default()))];
|
||||||
|
let (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
|
|
||||||
|
let mut req = TestRequest::with_uri("/index.json").finish();
|
||||||
|
assert_eq!(rec.recognize(&mut req), Some(0));
|
||||||
|
|
||||||
|
let mut req = TestRequest::with_uri("/test.json").finish();
|
||||||
|
assert_eq!(rec.recognize(&mut req), Some(1));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer_with_prefix() {
|
fn test_recognizer_with_prefix() {
|
||||||
let mut routes = HashMap::new();
|
let routes = vec![
|
||||||
routes.insert(Pattern::new("", "/name"), Some(Resource::default()));
|
(Pattern::new("", "/name"), Some(Resource::default())),
|
||||||
routes.insert(Pattern::new("", "/name/{val}"), Some(Resource::default()));
|
(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();
|
||||||
assert!(rec.recognize(&mut req).is_none());
|
assert!(rec.recognize(&mut req).is_none());
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/test/name").finish();
|
let mut req = TestRequest::with_uri("/test/name").finish();
|
||||||
assert!(rec.recognize(&mut req).is_some());
|
assert_eq!(rec.recognize(&mut req), Some(0));
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/test/name/value").finish();
|
let mut req = TestRequest::with_uri("/test/name/value").finish();
|
||||||
assert!(rec.recognize(&mut req).is_some());
|
assert_eq!(rec.recognize(&mut req), Some(1));
|
||||||
assert_eq!(req.match_info().get("val").unwrap(), "value");
|
assert_eq!(req.match_info().get("val").unwrap(), "value");
|
||||||
assert_eq!(&req.match_info()["val"], "value");
|
assert_eq!(&req.match_info()["val"], "value");
|
||||||
|
|
||||||
// same patterns
|
// same patterns
|
||||||
let mut routes = HashMap::new();
|
let routes = vec![
|
||||||
routes.insert(Pattern::new("", "/name"), Some(Resource::default()));
|
(Pattern::new("", "/name"), Some(Resource::default())),
|
||||||
routes.insert(Pattern::new("", "/name/{val}"), Some(Resource::default()));
|
(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();
|
||||||
assert!(rec.recognize(&mut req).is_none());
|
assert!(rec.recognize(&mut req).is_none());
|
||||||
let mut req = TestRequest::with_uri("/test2/name").finish();
|
let mut req = TestRequest::with_uri("/test2/name").finish();
|
||||||
assert!(rec.recognize(&mut req).is_some());
|
assert_eq!(rec.recognize(&mut req), Some(0));
|
||||||
|
let mut req = TestRequest::with_uri("/test2/name-test").finish();
|
||||||
|
assert!(rec.recognize(&mut req).is_none());
|
||||||
|
let mut req = TestRequest::with_uri("/test2/name/ttt").finish();
|
||||||
|
assert_eq!(rec.recognize(&mut req), Some(1));
|
||||||
|
assert_eq!(&req.match_info()["val"], "ttt");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -4,7 +4,6 @@ use std::{net, thread};
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use actix::{Arbiter, Addr, Syn, System, SystemRunner, msgs};
|
use actix::{Arbiter, Addr, Syn, System, SystemRunner, msgs};
|
||||||
use cookie::Cookie;
|
use cookie::Cookie;
|
||||||
@ -411,7 +410,7 @@ impl<S> TestRequest<S> {
|
|||||||
let req = HttpRequest::new(method, uri, version, headers, payload);
|
let req = HttpRequest::new(method, uri, version, headers, payload);
|
||||||
req.as_mut().cookies = cookies;
|
req.as_mut().cookies = cookies;
|
||||||
req.as_mut().params = params;
|
req.as_mut().params = params;
|
||||||
let (router, _) = Router::new::<S>("/", ServerSettings::default(), HashMap::new());
|
let (router, _) = Router::new::<S>("/", ServerSettings::default(), Vec::new());
|
||||||
req.with_state(Rc::new(state), router)
|
req.with_state(Rc::new(state), router)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user