Repository: seanmonstar/warp (language: rust)

Issue:
Panic on invalid path
Hello,
I'm building a service and I'm using warp to for the http stack and at some point I had a malformed request and warp just panicked instead of returning an error for me to handle somehow...

The malformed request was
```
GET foo.txt HTTP/1.1


```
as you can see there's a missing slash at the start of the path, if I add it everything works fine...

This is the warp server code:
```
let warp = warp::get().and(warp::fs::dir(path)).with(warp::log::log("static webserver");
warp::serve(webserver).run(ADDR).await;
```

Backtrace [here](http://ix.io/2ll6).
This is the line just before the panic:
```
15: warp::filters::path::path_and_query
             at /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.2/src/filters/path.rs:465
```
Panic on invalid path
Hello,
I'm building a service and I'm using warp to for the http stack and at some point I had a malformed request and warp just panicked instead of returning an error for me to handle somehow...

The malformed request was
```
GET foo.txt HTTP/1.1


```
as you can see there's a missing slash at the start of the path, if I add it everything works fine...

This is the warp server code:
```
let warp = warp::get().and(warp::fs::dir(path)).with(warp::log::log("static webserver");
warp::serve(webserver).run(ADDR).await;
```

Backtrace [here](http://ix.io/2ll6).
This is the line just before the panic:
```
15: warp::filters::path::path_and_query
             at /home/karrq/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.2/src/filters/path.rs:465
```


Discussion / hints:
Ya I think this is assuming a slash, which will fail when receiving a URI in authority-form.
Ya I think this is assuming a slash, which will fail when receiving a URI in authority-form.

Fix patch:
diff --git a/examples/handlebars_template.rs b/examples/handlebars_template.rs
index 5b0268f5a..ed1e52bb0 100644
--- a/examples/handlebars_template.rs
+++ b/examples/handlebars_template.rs
@@ -6,7 +6,6 @@ extern crate warp;
 extern crate serde_json;
 extern crate serde;
 
-use std::error::Error;
 use std::sync::Arc;
 
 use handlebars::Handlebars;
@@ -23,7 +22,7 @@ where
     T: Serialize,
 {
     hbs.render(template.name, &template.value)
-        .unwrap_or_else(|err| err.description().to_owned())
+        .unwrap_or_else(|err| err.to_string().to_owned())
 }
 
 fn main() {
diff --git a/src/filters/path.rs b/src/filters/path.rs
index 9346451ab..e8c4b8d58 100644
--- a/src/filters/path.rs
+++ b/src/filters/path.rs
@@ -460,8 +460,9 @@ fn path_and_query(route: &Route) -> PathAndQuery {
     route
         .uri()
         .path_and_query()
-        .expect("server URIs should always have path_and_query")
-        .clone()
+        .cloned()
+        .unwrap_or_else(|| PathAndQuery::from_static(""))
+
 }
 
 /// Convenient way to chain multiple path filters together.
diff --git a/src/route.rs b/src/route.rs
index af6803891..4704f8c2e 100644
--- a/src/route.rs
+++ b/src/route.rs
@@ -92,14 +92,14 @@ impl Route {
 
     pub(crate) fn set_unmatched_path(&mut self, index: usize) {
         let index = self.segments_index + index;
-
         let path = self.req.uri().path();
-
-        if path.len() == index {
+        if path.is_empty() {
+            // malformed path
+            return;
+        } else if path.len() == index {
             self.segments_index = index;
         } else {
             debug_assert_eq!(path.as_bytes()[index], b'/');
-
             self.segments_index = index + 1;
         }
     }


Test patch:
diff --git a/tests/fs.rs b/tests/fs.rs
index 33959f60e..c0b2945e8 100644
--- a/tests/fs.rs
+++ b/tests/fs.rs
@@ -46,6 +46,9 @@ fn dir() {
     assert_eq!(res.headers()["accept-ranges"], "bytes");
 
     assert_eq!(res.body(), &*contents);
+
+    let malformed_req = warp::test::request().path("todos.rs");
+    assert_eq!(malformed_req.reply(&file).status(), 404);
 }
 
 #[test]
diff --git a/tests/path.rs b/tests/path.rs
index 5d80f18b6..c088ba1a1 100644
--- a/tests/path.rs
+++ b/tests/path.rs
@@ -155,6 +155,12 @@ fn tail() {
     assert!(warp::test::request()
         .path("/foo/bar")
         .matches(&tail.and(warp::path::end())));
+
+    let ex = warp::test::request()
+        .path("localhost")
+        .filter(&tail)
+        .unwrap();
+    assert_eq!(ex.as_str(), "/");
 }
 
 #[test]