Skip to content

Commit 23b1f63

Browse files
authored
router: handle newline char '\n' in url (#360)
1 parent 3aa037d commit 23b1f63

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

actix-router/CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
* `Path::add` and `add_static` takes `impl Into<Cow<'static, str>>` [#345]
55
* When matching URL parameters, `%25` is kept in the percent-encoded form - no longer decoded to `%`. [#357]
66
* Fixed a bug where the `Path` extractor returns unsafe malformed string due to malformed URL. [#359]
7+
* Path tail patterns now match `'\n'` in request URL. [#360]
78

89
[#345]: https://github.com/actix/actix-net/pull/345
910
[#357]: https://github.com/actix/actix-net/pull/357
1011
[#359]: https://github.com/actix/actix-net/pull/359
12+
[#360]: https://github.com/actix/actix-net/pull/360
1113

1214

1315
## 0.2.7 - 2021-02-06

actix-router/src/resource.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ use crate::{IntoPattern, Resource, ResourcePath};
1010

1111
const MAX_DYNAMIC_SEGMENTS: usize = 16;
1212

13+
/// Regex flags to allow '.' in regex to match '\n'
14+
///
15+
/// See the docs under: https://docs.rs/regex/1.5.4/regex/#grouping-and-flags
16+
const REGEX_FLAGS: &str = "(?s-m)";
17+
1318
/// ResourceDef describes an entry in resources table
1419
///
1520
/// Resource definition can contain only 16 dynamic segments
@@ -571,7 +576,7 @@ impl ResourceDef {
571576
) -> (String, Vec<PatternElement>, bool, usize) {
572577
if pattern.find('{').is_none() {
573578
return if let Some(path) = pattern.strip_suffix('*') {
574-
let re = String::from("^") + path + "(.*)";
579+
let re = format!("{}^{}(.*)", REGEX_FLAGS, path);
575580
(re, vec![PatternElement::Str(String::from(path))], true, 0)
576581
} else {
577582
(
@@ -584,7 +589,7 @@ impl ResourceDef {
584589
}
585590

586591
let mut elements = Vec::new();
587-
let mut re = String::from("^");
592+
let mut re = format!("{}^", REGEX_FLAGS);
588593
let mut dyn_elements = 0;
589594

590595
while let Some(idx) = pattern.find('{') {
@@ -817,6 +822,32 @@ mod tests {
817822
assert!(re.is_match("/user/2345/sdg"));
818823
}
819824

825+
#[test]
826+
fn test_newline() {
827+
let re = ResourceDef::new("/user/a\nb");
828+
assert!(re.is_match("/user/a\nb"));
829+
assert!(!re.is_match("/user/a\nb/profile"));
830+
831+
let re = ResourceDef::new("/a{x}b/test/a{y}b");
832+
let mut path = Path::new("/a\nb/test/a\nb");
833+
assert!(re.match_path(&mut path));
834+
assert_eq!(path.get("x").unwrap(), "\n");
835+
assert_eq!(path.get("y").unwrap(), "\n");
836+
837+
let re = ResourceDef::new("/user/*");
838+
assert!(re.is_match("/user/a\nb/"));
839+
840+
let re = ResourceDef::new("/user/{id}*");
841+
let mut path = Path::new("/user/a\nb/a\nb");
842+
assert!(re.match_path(&mut path));
843+
assert_eq!(path.get("id").unwrap(), "a\nb/a\nb");
844+
845+
let re = ResourceDef::new("/user/{id:.*}");
846+
let mut path = Path::new("/user/a\nb/a\nb");
847+
assert!(re.match_path(&mut path));
848+
assert_eq!(path.get("id").unwrap(), "a\nb/a\nb");
849+
}
850+
820851
#[cfg(feature = "http")]
821852
#[test]
822853
fn test_parse_urlencoded_param() {

0 commit comments

Comments
 (0)