Skip to content

Commit 661d920

Browse files
authored
Merge pull request #2 from jtgeibel/normalize-paths
Normalize paths
2 parents 7588493 + 0f3a832 commit 661d920

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

src/lib.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod tests;
55

66
use std::io::{Cursor, Read};
77
use std::net::SocketAddr;
8+
use std::path::{Component, Path, PathBuf};
89
use std::sync::Arc;
910

1011
use futures::{future, Future, Stream};
@@ -64,6 +65,7 @@ impl Parts {
6465

6566
struct ConduitRequest {
6667
parts: Parts,
68+
path: String,
6769
body: Cursor<Chunk>,
6870
extensions: conduit::Extensions,
6971
}
@@ -122,7 +124,7 @@ impl conduit::Request for ConduitRequest {
122124
}
123125

124126
fn path(&self) -> &str {
125-
&self.parts.0.uri.path()
127+
&*self.path
126128
}
127129

128130
fn extensions(&self) -> &conduit::Extensions {
@@ -158,8 +160,33 @@ impl conduit::Request for ConduitRequest {
158160

159161
impl ConduitRequest {
160162
fn new(parts: Parts, body: Chunk) -> ConduitRequest {
163+
let path = parts.0.uri.path().to_string();
164+
let path = Path::new(&path);
165+
let path = path
166+
.components()
167+
.fold(PathBuf::new(), |mut result, p| match p {
168+
Component::Normal(x) => {
169+
if x != "" {
170+
result.push(x)
171+
};
172+
result
173+
}
174+
Component::ParentDir => {
175+
result.pop();
176+
result
177+
}
178+
Component::RootDir => {
179+
result.push(Component::RootDir);
180+
result
181+
}
182+
_ => result,
183+
})
184+
.to_string_lossy()
185+
.to_string(); // non-Unicode is replaced with U+FFFD REPLACEMENT CHARACTER
186+
161187
ConduitRequest {
162188
parts,
189+
path,
163190
body: Cursor::new(body),
164191
extensions: conduit::Extensions::new(),
165192
}

src/tests.rs

+32
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ impl Handler for InvalidStatus {
5656
}
5757
}
5858

59+
struct AssertPathNormalized;
60+
impl Handler for AssertPathNormalized {
61+
fn call(&self, req: &mut Request) -> Result<Response, Box<Error + Send>> {
62+
if req.path() == "/normalized" {
63+
OkResult.call(req)
64+
} else {
65+
ErrorResult.call(req)
66+
}
67+
}
68+
}
69+
5970
fn build_headers(msg: &str) -> HashMap<String, Vec<String>> {
6071
let mut headers = HashMap::new();
6172
headers.insert("ok".into(), vec![msg.into()]);
@@ -106,3 +117,24 @@ fn err_responses() {
106117
fn recover_from_panic() {
107118
assert_generic_err(simulate_request(Panic));
108119
}
120+
121+
#[test]
122+
fn normalize_path() {
123+
use hyper::service::{NewService, Service};
124+
125+
let new_service = super::Service::new(AssertPathNormalized, 1);
126+
let mut service = new_service.new_service().wait().unwrap();
127+
let req = hyper::Request::put("//removed/.././.././normalized")
128+
.body(hyper::Body::default())
129+
.unwrap();
130+
let resp = service.call(req).wait().unwrap();
131+
assert_eq!(resp.status(), 200);
132+
assert_eq!(resp.headers().len(), 1);
133+
134+
let req = hyper::Request::put("//normalized")
135+
.body(hyper::Body::default())
136+
.unwrap();
137+
let resp = service.call(req).wait().unwrap();
138+
assert_eq!(resp.status(), 200);
139+
assert_eq!(resp.headers().len(), 1);
140+
}

0 commit comments

Comments
 (0)