Skip to content

Commit 0999baf

Browse files
committed
use set_host + set_port instead of *r.url_mut() =
and also add some tests
1 parent 7ca8f9a commit 0999baf

File tree

1 file changed

+105
-7
lines changed

1 file changed

+105
-7
lines changed

src/server/decode.rs

Lines changed: 105 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,18 @@ where
6464
let version = version.ok_or_else(|| format_err!("No version found"))?;
6565
ensure_eq!(version, HTTP_1_1_VERSION, "Unsupported HTTP version");
6666

67-
let mut req = Request::new(Method::from_str(method)?, url::Url::parse("x:").unwrap());
67+
let mut req = Request::new(
68+
Method::from_str(method)?,
69+
url::Url::parse("http://_").unwrap().join(path)?,
70+
);
6871

6972
for header in httparse_req.headers.iter() {
7073
let name = HeaderName::from_str(header.name)?;
7174
let value = HeaderValue::from_str(std::str::from_utf8(header.value)?)?;
7275
req.insert_header(name, value)?;
7376
}
7477

75-
let host = req
76-
.header(&HOST)
77-
.and_then(|header| header.last())
78-
.ok_or_else(|| format_err!("Mandatory host header missing"))?;
79-
80-
*req.url_mut() = url::Url::parse(&format!("http://{}", host.as_str()))?.join(path)?;
78+
set_url_and_port_from_host_header(&mut req)?;
8179

8280
let content_length = req.header(&CONTENT_LENGTH);
8381
let transfer_encoding = req.header(&TRANSFER_ENCODING);
@@ -106,3 +104,103 @@ where
106104

107105
Ok(Some(req))
108106
}
107+
108+
fn set_url_and_port_from_host_header(req: &mut Request) -> http_types::Result<()> {
109+
let host = req
110+
.header(&HOST)
111+
.and_then(|header| header.last()) // There must only exactly one Host header, so this is permissive
112+
.ok_or_else(|| format_err!("Mandatory Host header missing"))?; // https://tools.ietf.org/html/rfc7230#section-5.4
113+
114+
let host = host.to_string();
115+
if let Some(colon) = host.find(":") {
116+
req.url_mut().set_host(Some(&host[0..colon]))?;
117+
req.url_mut()
118+
.set_port(host[colon + 1..].parse().ok())
119+
.unwrap();
120+
} else {
121+
req.url_mut().set_host(Some(&host))?;
122+
}
123+
124+
Ok(())
125+
}
126+
127+
#[cfg(test)]
128+
mod tests {
129+
use super::*;
130+
131+
fn request_with_host_header(host: &str) -> Request {
132+
let mut req = Request::new(
133+
Method::from_str("GET").unwrap(),
134+
url::Url::parse("http://_")
135+
.unwrap()
136+
.join("/some/path")
137+
.unwrap(),
138+
);
139+
140+
req.insert_header(HOST, host).unwrap();
141+
142+
req
143+
}
144+
145+
#[test]
146+
fn test_setting_host_with_no_port() {
147+
let mut request = request_with_host_header("subdomain.mydomain.tld");
148+
set_url_and_port_from_host_header(&mut request).unwrap();
149+
assert_eq!(
150+
request.url(),
151+
&url::Url::parse("http://subdomain.mydomain.tld/some/path").unwrap()
152+
);
153+
}
154+
155+
#[test]
156+
fn test_setting_host_with_a_port() {
157+
let mut request = request_with_host_header("subdomain.mydomain.tld:8080");
158+
set_url_and_port_from_host_header(&mut request).unwrap();
159+
assert_eq!(
160+
request.url(),
161+
&url::Url::parse("http://subdomain.mydomain.tld:8080/some/path").unwrap()
162+
);
163+
}
164+
165+
#[test]
166+
fn test_setting_host_with_an_ip_and_port() {
167+
let mut request = request_with_host_header("12.34.56.78:90");
168+
set_url_and_port_from_host_header(&mut request).unwrap();
169+
assert_eq!(
170+
request.url(),
171+
&url::Url::parse("http://12.34.56.78:90/some/path").unwrap()
172+
);
173+
}
174+
175+
#[test]
176+
fn test_malformed_nonnumeric_port_is_ignored() {
177+
let mut request = request_with_host_header("hello.world:uh-oh");
178+
set_url_and_port_from_host_header(&mut request).unwrap();
179+
assert_eq!(
180+
request.url(),
181+
&url::Url::parse("http://hello.world/some/path").unwrap()
182+
);
183+
}
184+
185+
#[test]
186+
fn test_malformed_trailing_colon_is_ignored() {
187+
let mut request = request_with_host_header("edge.cases:");
188+
set_url_and_port_from_host_header(&mut request).unwrap();
189+
assert_eq!(
190+
request.url(),
191+
&url::Url::parse("http://edge.cases/some/path").unwrap()
192+
);
193+
}
194+
195+
#[test]
196+
fn test_malformed_leading_colon_is_invalid_host_value() {
197+
let mut request = request_with_host_header(":300");
198+
assert!(set_url_and_port_from_host_header(&mut request).is_err());
199+
}
200+
201+
#[test]
202+
fn test_malformed_invalid_url_host_is_invalid_host_header_value() {
203+
let mut request = request_with_host_header(" ");
204+
assert!(set_url_and_port_from_host_header(&mut request).is_err());
205+
}
206+
}

0 commit comments

Comments
 (0)