diff --git a/src/uri/mod.rs b/src/uri/mod.rs index 5233aece..cce376a5 100644 --- a/src/uri/mod.rs +++ b/src/uri/mod.rs @@ -137,6 +137,7 @@ enum ErrorKind { SchemeMissing, AuthorityMissing, PathAndQueryMissing, + SlashInPathMissing, TooLong, Empty, SchemeTooLong, @@ -192,6 +193,14 @@ impl Uri { } } + if let (&Some(_), &Some(ref path_and_query)) = (&src.authority, &src.path_and_query) { + let path = path_and_query.path(); + if !path.is_empty() && !path.starts_with('/') { + // As per RFC3986 sections 3 and 3.3 + return Err(ErrorKind::SlashInPathMissing.into()); + } + } + let scheme = match src.scheme { Some(scheme) => scheme, None => Scheme { inner: Scheme2::None }, @@ -991,6 +1000,7 @@ impl Error for InvalidUri { ErrorKind::SchemeMissing => "scheme missing", ErrorKind::AuthorityMissing => "authority missing", ErrorKind::PathAndQueryMissing => "path missing", + ErrorKind::SlashInPathMissing => "slash in path missing", ErrorKind::TooLong => "uri too long", ErrorKind::Empty => "empty string", ErrorKind::SchemeTooLong => "scheme too long", diff --git a/src/uri/tests.rs b/src/uri/tests.rs index 08b32ead..3ee2347d 100644 --- a/src/uri/tests.rs +++ b/src/uri/tests.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use super::{ErrorKind, InvalidUri, Uri, URI_CHARS}; +use super::*; #[test] fn test_char_table() { @@ -445,3 +445,30 @@ fn test_authority_uri_parts_round_trip() { assert_eq!(uri2, s); assert_eq!(uri2.to_string(), s); } + +#[test] +/// As per RFC3986 sections 3 and 3.3 +fn test_authority_slash_path() { + fn parse_from_parts(a: &str, p: &str) -> Result { + let mut parts = Parts::default(); + parts.scheme = Some(Scheme::HTTP); + parts.authority = Some(Authority::from_str(a).expect("first parse")); + parts.path_and_query = Some(PathAndQuery::from_str(p).expect("second parse")); + Uri::from_parts(parts) + } + + match parse_from_parts("hyper.rs", "foo") { + Err(InvalidUriParts(InvalidUri(ErrorKind::SlashInPathMissing))) => (), + bad => panic!("Unexpected result of first from_parts call: {:#?}", bad), + } + + match parse_from_parts("hyper.rs", "/foo") { + Ok(_) => (), + bad => panic!("Unexpected result of second from_parts call: {:#?}", bad), + } + + match parse_from_parts("hyper.rs", "") { + Ok(_) => (), + bad => panic!("Unexpected result of third from_parts call: {:#?}", bad), + } +}