mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-24 07:53:00 +01:00
Merge pull request #503 from uzytkownik/route-regex
Refactor resource route parsing to allow repetition in the regexes
This commit is contained in:
commit
51982b3fec
@ -5,7 +5,7 @@
|
|||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
* Fix system_exit in HttpServer #501
|
* Fix system_exit in HttpServer #501
|
||||||
|
* Fix parsing of route param containin regexes with repetition #500
|
||||||
|
|
||||||
## [0.7.5] - 2018-09-04
|
## [0.7.5] - 2018-09-04
|
||||||
|
|
||||||
|
121
src/router.rs
121
src/router.rs
@ -815,73 +815,56 @@ impl ResourceDef {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(
|
fn parse_param(
|
||||||
pattern: &str, for_prefix: bool,
|
pattern: &str,
|
||||||
) -> (String, Vec<PatternElement>, bool, usize) {
|
) -> (PatternElement, String, &str) {
|
||||||
const DEFAULT_PATTERN: &str = "[^/]+";
|
const DEFAULT_PATTERN: &str = "[^/]+";
|
||||||
|
let mut params_nesting = 0usize;
|
||||||
let mut re1 = String::from("^");
|
let close_idx = pattern.find(|c| match c {
|
||||||
let mut re2 = String::new();
|
'{' => {params_nesting += 1; false},
|
||||||
let mut el = String::new();
|
'}' => {params_nesting -= 1; params_nesting == 0},
|
||||||
let mut in_param = false;
|
_ => false
|
||||||
let mut in_param_pattern = false;
|
}).expect("malformed param");
|
||||||
let mut param_name = String::new();
|
let (mut param, rem) = pattern.split_at(close_idx + 1);
|
||||||
let mut param_pattern = String::from(DEFAULT_PATTERN);
|
param = ¶m[1..param.len() - 1]; // Remove outer brackets
|
||||||
let mut is_dynamic = false;
|
let (name, pattern) = match param.find(":") {
|
||||||
let mut elems = Vec::new();
|
Some(idx) => {
|
||||||
let mut len = 0;
|
let (name, pattern) = param.split_at(idx);
|
||||||
|
(name, &pattern[1..])
|
||||||
for ch in pattern.chars() {
|
|
||||||
if in_param {
|
|
||||||
// In parameter segment: `{....}`
|
|
||||||
if ch == '}' {
|
|
||||||
elems.push(PatternElement::Var(param_name.clone()));
|
|
||||||
re1.push_str(&format!(r"(?P<{}>{})", ¶m_name, ¶m_pattern));
|
|
||||||
|
|
||||||
param_name.clear();
|
|
||||||
param_pattern = String::from(DEFAULT_PATTERN);
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
in_param_pattern = false;
|
|
||||||
in_param = false;
|
|
||||||
} else if ch == ':' {
|
|
||||||
// The parameter name has been determined; custom pattern land
|
|
||||||
in_param_pattern = true;
|
|
||||||
param_pattern.clear();
|
|
||||||
} else if in_param_pattern {
|
|
||||||
// Ignore leading whitespace for pattern
|
|
||||||
if !(ch == ' ' && param_pattern.is_empty()) {
|
|
||||||
param_pattern.push(ch);
|
|
||||||
}
|
}
|
||||||
} else {
|
None => (param, DEFAULT_PATTERN)
|
||||||
param_name.push(ch);
|
|
||||||
}
|
|
||||||
} else if ch == '{' {
|
|
||||||
in_param = true;
|
|
||||||
is_dynamic = true;
|
|
||||||
elems.push(PatternElement::Str(el.clone()));
|
|
||||||
el.clear();
|
|
||||||
} else {
|
|
||||||
re1.push_str(escape(&ch.to_string()).as_str());
|
|
||||||
re2.push(ch);
|
|
||||||
el.push(ch);
|
|
||||||
len += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !el.is_empty() {
|
|
||||||
elems.push(PatternElement::Str(el.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let re = if is_dynamic {
|
|
||||||
if !for_prefix {
|
|
||||||
re1.push('$');
|
|
||||||
}
|
|
||||||
re1
|
|
||||||
} else {
|
|
||||||
re2
|
|
||||||
};
|
};
|
||||||
(re, elems, is_dynamic, len)
|
(PatternElement::Var(name.to_string()), format!(r"(?P<{}>{})", &name, &pattern), rem)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(
|
||||||
|
mut pattern: &str, for_prefix: bool,
|
||||||
|
) -> (String, Vec<PatternElement>, bool, usize) {
|
||||||
|
if pattern.find("{").is_none() {
|
||||||
|
return (String::from(pattern), vec![PatternElement::Str(String::from(pattern))], false, pattern.chars().count())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut elems = Vec::new();
|
||||||
|
let mut re = String::from("^");
|
||||||
|
|
||||||
|
while let Some(idx) = pattern.find("{") {
|
||||||
|
let (prefix, rem) = pattern.split_at(idx);
|
||||||
|
elems.push(PatternElement::Str(String::from(prefix)));
|
||||||
|
re.push_str(&escape(prefix));
|
||||||
|
let (param_pattern, re_part, rem) = Self::parse_param(rem);
|
||||||
|
elems.push(param_pattern);
|
||||||
|
re.push_str(&re_part);
|
||||||
|
pattern = rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
elems.push(PatternElement::Str(String::from(pattern)));
|
||||||
|
re.push_str(&escape(pattern));
|
||||||
|
|
||||||
|
if !for_prefix {
|
||||||
|
re.push_str("$");
|
||||||
|
}
|
||||||
|
|
||||||
|
(re, elems, true, pattern.chars().count())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1072,6 +1055,16 @@ mod tests {
|
|||||||
let info = re.match_with_params(&req, 0).unwrap();
|
let info = re.match_with_params(&req, 0).unwrap();
|
||||||
assert_eq!(info.get("version").unwrap(), "151");
|
assert_eq!(info.get("version").unwrap(), "151");
|
||||||
assert_eq!(info.get("id").unwrap(), "adahg32");
|
assert_eq!(info.get("id").unwrap(), "adahg32");
|
||||||
|
|
||||||
|
let re = ResourceDef::new("/{id:[[:digit:]]{6}}");
|
||||||
|
assert!(re.is_match("/012345"));
|
||||||
|
assert!(!re.is_match("/012"));
|
||||||
|
assert!(!re.is_match("/01234567"));
|
||||||
|
assert!(!re.is_match("/XXXXXX"));
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/012345").finish();
|
||||||
|
let info = re.match_with_params(&req, 0).unwrap();
|
||||||
|
assert_eq!(info.get("id").unwrap(), "012345");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user