forked from seanmonstar/warp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a feature to ignore empty path segments (// in path).
When the new `ignore-empty-path-segments` feature is enabled, multiple leading slashes at the start of the path are ignored (the first segment starts after them), and multiple slashes at the end of any matched segment are ignored (so the next segment starts after them). In addition, the `end` filter will ignore multiple slashes that follow the final segment. Both the `fullpath` and `tail` filters will still return any multiple slashes in their matched text, but their `segments` iterator will ignore the empty segments (in fact it does this today even without this feature being set). This change does _not_ include this feature in the list of default features. This change includes path filter testing on paths with multiple slashes in them. This change fixes seanmonstar#738.
- Loading branch information
1 parent
3cf1783
commit 3ab39ff
Showing
4 changed files
with
318 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,293 @@ | ||
#![deny(warnings)] | ||
extern crate warp; | ||
|
||
use warp::Filter; | ||
|
||
#[tokio::test] | ||
async fn path() { | ||
let _ = pretty_env_logger::try_init(); | ||
|
||
let foo = warp::path("foo"); | ||
let bar = warp::path(String::from("bar")); | ||
let foo_bar = foo.and(bar.clone()); | ||
let foo_bar_end = foo.and(bar.clone()).and(warp::path::end()); | ||
|
||
// /foo | ||
let fffoo_req = || warp::test::request().path("///foo"); | ||
|
||
assert!(fffoo_req().matches(&foo).await); | ||
assert!(!fffoo_req().matches(&bar).await); | ||
assert!(!fffoo_req().matches(&foo_bar).await); | ||
|
||
// /foo/bar | ||
let ffoo_bar_req = || warp::test::request().path("//foo/bar"); | ||
let foo_bbar_req= || warp::test::request().path("/foo//bar"); | ||
let foo_bar_reqq= || warp::test::request().path("/foo/bar//"); | ||
|
||
assert!(ffoo_bar_req().matches(&foo).await); | ||
assert!(!ffoo_bar_req().matches(&bar).await); | ||
assert!(ffoo_bar_req().matches(&foo_bar).await); | ||
assert!(foo_bbar_req().matches(&foo).await); | ||
assert!(foo_bbar_req().matches(&foo_bar).await); | ||
assert!(foo_bar_reqq().matches(&foo).await); | ||
assert!(foo_bar_reqq().matches(&foo_bar).await); | ||
assert!(foo_bar_reqq().matches(&foo_bar_end).await); | ||
} | ||
|
||
#[tokio::test] | ||
async fn end() { | ||
let _ = pretty_env_logger::try_init(); | ||
|
||
let foo = warp::path("foo"); | ||
let end = warp::path::end(); | ||
let foo_end = foo.and(end); | ||
|
||
assert!( | ||
warp::test::request().path("///").matches(&end).await, | ||
"end() matches ///" | ||
); | ||
|
||
assert!( | ||
warp::test::request() | ||
.path("http://localhost:1234") | ||
.matches(&end) | ||
.await, | ||
"end() matches /" | ||
); | ||
|
||
assert!( | ||
warp::test::request() | ||
.path("http://localhost:1234?q=2") | ||
.matches(&end) | ||
.await, | ||
"end() matches empty path" | ||
); | ||
|
||
assert!( | ||
warp::test::request() | ||
.path("localhost:1234") | ||
.matches(&end) | ||
.await, | ||
"end() matches authority-form" | ||
); | ||
|
||
assert!( | ||
!warp::test::request().path("///foo").matches(&end).await, | ||
"end() doesn't match ///foo" | ||
); | ||
|
||
assert!( | ||
warp::test::request().path("///foo").matches(&foo_end).await, | ||
"path().and(end()) matches ///foo" | ||
); | ||
|
||
assert!( | ||
warp::test::request().path("///foo/").matches(&foo_end).await, | ||
"path().and(end()) matches ///foo/" | ||
); | ||
|
||
assert!( | ||
warp::test::request().path("///foo///").matches(&foo_end).await, | ||
"path().and(end()) matches ///foo///" | ||
) | ||
} | ||
|
||
#[tokio::test] | ||
async fn tail() { | ||
let tail = warp::path::tail(); | ||
|
||
// matches full path | ||
let ex = warp::test::request() | ||
.path("///42//vroom") | ||
.filter(&tail) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "42//vroom"); | ||
|
||
// matches index | ||
let ex = warp::test::request().path("///").filter(&tail).await.unwrap(); | ||
assert_eq!(ex.as_str(), ""); | ||
|
||
// doesn't include query | ||
let ex = warp::test::request() | ||
.path("//foo/bar//?baz=quux") | ||
.filter(&tail) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "foo/bar//"); | ||
|
||
// doesn't include previously matched prefix | ||
let and = warp::path("foo").and(tail); | ||
let ex = warp::test::request() | ||
.path("///foo///bar//") | ||
.filter(&and) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "bar//"); | ||
|
||
// sets unmatched path index to end | ||
let m = tail.and(warp::path("foo")); | ||
assert!(!warp::test::request().path("//foo//bar//").matches(&m).await); | ||
|
||
let m = tail.and(warp::path::end()); | ||
assert!(warp::test::request().path("//foo/bar//").matches(&m).await); | ||
|
||
let ex = warp::test::request() | ||
.path("localhost") | ||
.filter(&tail) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "/"); | ||
} | ||
|
||
#[tokio::test] | ||
async fn full_path() { | ||
let full_path = warp::path::full(); | ||
|
||
let foo = warp::path("foo"); | ||
let bar = warp::path("bar"); | ||
let param = warp::path::param::<u32>(); | ||
|
||
// matches full request path | ||
let ex = warp::test::request() | ||
.path("///42//vroom///") | ||
.filter(&full_path) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "///42//vroom///"); | ||
|
||
// matches index | ||
let ex = warp::test::request() | ||
.path("//") | ||
.filter(&full_path) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "//"); | ||
|
||
// does not include query | ||
let ex = warp::test::request() | ||
.path("////foo///bar//?baz=quux") | ||
.filter(&full_path) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "////foo///bar//"); | ||
|
||
// includes previously matched prefix | ||
let and = foo.and(full_path); | ||
let ex = warp::test::request() | ||
.path("///foo///bar//") | ||
.filter(&and) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "///foo///bar//"); | ||
|
||
// includes following matches | ||
let and = full_path.and(foo); | ||
let ex = warp::test::request() | ||
.path("//foo///bar//") | ||
.filter(&and) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "//foo///bar//"); | ||
|
||
// includes previously matched param | ||
let and = foo.and(param).and(full_path); | ||
let (_, ex) = warp::test::request() | ||
.path("///foo///123") | ||
.filter(&and) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "///foo///123"); | ||
|
||
// does not modify matching | ||
let m = full_path.and(foo).and(bar); | ||
assert!(warp::test::request().path("///foo///bar//").matches(&m).await); | ||
|
||
// doesn't panic on authority-form | ||
let ex = warp::test::request() | ||
.path("localhost:1234") | ||
.filter(&full_path) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "/"); | ||
} | ||
|
||
#[tokio::test] | ||
async fn peek() { | ||
let peek = warp::path::peek(); | ||
|
||
let foo = warp::path("foo"); | ||
let bar = warp::path("bar"); | ||
let param = warp::path::param::<u32>(); | ||
|
||
// matches full request path | ||
let ex = warp::test::request() | ||
.path("///42///vroom//") | ||
.filter(&peek) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "42///vroom//"); | ||
|
||
// matches index | ||
let ex = warp::test::request().path("///").filter(&peek).await.unwrap(); | ||
assert_eq!(ex.as_str(), ""); | ||
|
||
// does not include query | ||
let ex = warp::test::request() | ||
.path("///foo///bar//?baz=quux") | ||
.filter(&peek) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "foo///bar//"); | ||
|
||
// does not include previously matched prefix | ||
let and = foo.and(peek); | ||
let ex = warp::test::request() | ||
.path("///foo///bar//") | ||
.filter(&and) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "bar//"); | ||
|
||
// includes following matches | ||
let and = peek.and(foo); | ||
let ex = warp::test::request() | ||
.path("///foo///bar//") | ||
.filter(&and) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), "foo///bar//"); | ||
|
||
// does not include previously matched param | ||
let and = foo.and(param).and(peek); | ||
let (_, ex) = warp::test::request() | ||
.path("///foo///123//") | ||
.filter(&and) | ||
.await | ||
.unwrap(); | ||
assert_eq!(ex.as_str(), ""); | ||
|
||
// does not modify matching | ||
let and = peek.and(foo).and(bar); | ||
assert!(warp::test::request().path("///foo///bar//").matches(&and).await); | ||
} | ||
|
||
#[tokio::test] | ||
async fn peek_segments() { | ||
let peek = warp::path::peek(); | ||
|
||
// matches full request path | ||
let ex = warp::test::request() | ||
.path("///42///vroom//") | ||
.filter(&peek) | ||
.await | ||
.unwrap(); | ||
|
||
assert_eq!(ex.segments().collect::<Vec<_>>(), &["42", "vroom"]); | ||
|
||
// matches index | ||
let ex = warp::test::request().path("/").filter(&peek).await.unwrap(); | ||
|
||
let segs = ex.segments().collect::<Vec<_>>(); | ||
assert_eq!(segs, Vec::<&str>::new()); | ||
} |