diff options
author | Richard Walters <rwalters@digitalstirling.com> | 2020-10-30 13:42:07 -0700 |
---|---|---|
committer | Richard Walters <rwalters@digitalstirling.com> | 2020-10-30 13:42:07 -0700 |
commit | 9d961981db81d10a7315160fbcb45b1ebaf4c119 (patch) | |
tree | 8f34548cf5152a49ab90e0eb2ffee47392793f42 /src/uri.rs | |
parent | 99a6971893b7d08c1d976e4eb99701e36d80afb8 (diff) |
Add and apply rustfmt configuration
Diffstat (limited to 'src/uri.rs')
-rw-r--r-- | src/uri.rs | 814 |
1 files changed, 550 insertions, 264 deletions
@@ -1,15 +1,20 @@ use std::collections::HashSet; -use super::authority::Authority; -use super::codec::{decode_element, encode_element}; -use super::context::Context; -use super::error::Error; -use super::character_classes::{ - ALPHA, - SCHEME_NOT_FIRST, - PCHAR_NOT_PCT_ENCODED, - QUERY_OR_FRAGMENT_NOT_PCT_ENCODED, - QUERY_NOT_PCT_ENCODED_WITHOUT_PLUS, +use super::{ + authority::Authority, + character_classes::{ + ALPHA, + PCHAR_NOT_PCT_ENCODED, + QUERY_NOT_PCT_ENCODED_WITHOUT_PLUS, + QUERY_OR_FRAGMENT_NOT_PCT_ENCODED, + SCHEME_NOT_FIRST, + }, + codec::{ + decode_element, + encode_element, + }, + context::Context, + error::Error, }; /// This type is used to parse and generate URI strings to and from their @@ -55,7 +60,10 @@ use super::character_classes::{ /// /// ```rust /// # extern crate rhymuri; -/// use rhymuri::{Authority, Uri}; +/// use rhymuri::{ +/// Authority, +/// Uri, +/// }; /// /// let mut uri = Uri::default(); /// assert!(uri.set_scheme(String::from("http")).is_ok()); @@ -96,7 +104,8 @@ impl Uri { } fn can_navigate_path_up_one_level<T>(path: T) -> bool - where T: AsRef<[Vec<u8>]> + where + T: AsRef<[Vec<u8>]>, { let path = path.as_ref(); match path.first() { @@ -107,19 +116,18 @@ impl Uri { // Otherwise, we can navigate up as long as there is at least one // segment. Some(_) => true, - None => false + None => false, } } fn check_scheme<T>(scheme: T) -> Result<T, Error> - where T: AsRef<str> + where + T: AsRef<str>, { match scheme.as_ref() { "" => return Err(Error::EmptyScheme), - scheme => scheme - .chars() - .enumerate() - .try_fold((), |_, (i, c)| { + scheme => { + scheme.chars().enumerate().try_fold((), |_, (i, c)| { let valid_characters: &HashSet<char> = if i == 0 { &ALPHA } else { @@ -130,7 +138,8 @@ impl Uri { } else { Err(Error::IllegalCharacter(Context::Scheme)) } - })?, + })? + }, }; Ok(scheme) } @@ -146,12 +155,13 @@ impl Uri { query_or_fragment: T, context: Context, ) -> Result<Vec<u8>, Error> - where T: AsRef<str> + where + T: AsRef<str>, { decode_element( query_or_fragment, &QUERY_OR_FRAGMENT_NOT_PCT_ENCODED, - context + context, ) } @@ -166,13 +176,13 @@ impl Uri { /// # Errors /// /// Since fragments may contain non-UTF8 byte sequences, this function may - /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant.CannotExpressAsUtf8). + /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant. + /// CannotExpressAsUtf8). #[must_use = "use the fragment return value silly programmer"] pub fn fragment_to_string(&self) -> Result<Option<String>, Error> { self.fragment() .map(|fragment| { - String::from_utf8(fragment.to_vec()) - .map_err(Into::into) + String::from_utf8(fragment.to_vec()).map_err(Into::into) }) .transpose() } @@ -180,9 +190,7 @@ impl Uri { /// Borrow the host portion of the Authority (if any) of the URI. #[must_use = "why u no use host return value?"] pub fn host(&self) -> Option<&[u8]> { - self.authority - .as_ref() - .map(Authority::host) + self.authority.as_ref().map(Authority::host) } /// Convert the host portion of the Authority (if any) into a string. @@ -191,19 +199,18 @@ impl Uri { /// /// Since host names may contain non-UTF8 byte sequences, this function may /// return - /// [`Error::CannotExpressAsUtf8`](enum.Error.html#variant.CannotExpressAsUtf8). + /// [`Error::CannotExpressAsUtf8`](enum.Error.html#variant. + /// CannotExpressAsUtf8). #[must_use = "I made that host field into a string for you; don't you want it?"] pub fn host_to_string(&self) -> Result<Option<String>, Error> { self.host() - .map(|host| { - String::from_utf8(host.to_vec()) - .map_err(Into::into) - }) + .map(|host| String::from_utf8(host.to_vec()).map_err(Into::into)) .transpose() } fn is_path_absolute<T>(path: T) -> bool - where T: AsRef<[Vec<u8>]> + where + T: AsRef<[Vec<u8>]>, { matches!(path.as_ref(), [segment, ..] if segment.is_empty()) } @@ -241,7 +248,8 @@ impl Uri { } fn normalize_path<T>(original_path: T) -> Vec<Vec<u8>> - where T: AsRef<[Vec<u8>]> + where + T: AsRef<[Vec<u8>]>, { // Rebuild the path one segment // at a time, removing and applying special @@ -257,8 +265,7 @@ impl Uri { } else if segment == b".." { // Remove last path element // if we can navigate up a level. - if - !normalized_path.is_empty() + if !normalized_path.is_empty() && Self::can_navigate_path_up_one_level(&normalized_path) { normalized_path.pop(); @@ -286,7 +293,7 @@ impl Uri { (true, Some(segment)) if !segment.is_empty() => { normalized_path.push(vec![]); }, - _ => () + _ => (), } normalized_path } @@ -300,46 +307,45 @@ impl Uri { /// let you know what's up by returning a variant of the /// [`Error`](enum.Error.html) type. pub fn parse<T>(uri_string: T) -> Result<Self, Error> - where T: AsRef<str> + where + T: AsRef<str>, { let (scheme, rest) = Self::parse_scheme(uri_string.as_ref())?; - let path_end = rest - .find(&['?', '#'][..]) - .unwrap_or_else(|| rest.len()); + let path_end = rest.find(&['?', '#'][..]).unwrap_or_else(|| rest.len()); let authority_and_path_string = &rest[0..path_end]; let query_and_or_fragment = &rest[path_end..]; - let (authority, path) = Self::split_authority_from_path_and_parse_them(authority_and_path_string)?; - let (fragment, possible_query) = Self::parse_fragment(query_and_or_fragment)?; + let (authority, path) = Self::split_authority_from_path_and_parse_them( + authority_and_path_string, + )?; + let (fragment, possible_query) = + Self::parse_fragment(query_and_or_fragment)?; let query = Self::parse_query(possible_query)?; - Ok(Self{ + Ok(Self { scheme, authority, path, query, - fragment + fragment, }) } - fn parse_fragment(query_and_or_fragment: &str) -> Result<(Option<Vec<u8>>, &str), Error> { + fn parse_fragment( + query_and_or_fragment: &str + ) -> Result<(Option<Vec<u8>>, &str), Error> { if let Some(fragment_delimiter) = query_and_or_fragment.find('#') { let fragment = Self::decode_query_or_fragment( - &query_and_or_fragment[fragment_delimiter+1..], - Context::Fragment + &query_and_or_fragment[fragment_delimiter + 1..], + Context::Fragment, )?; - Ok(( - Some(fragment), - &query_and_or_fragment[0..fragment_delimiter] - )) + Ok((Some(fragment), &query_and_or_fragment[0..fragment_delimiter])) } else { - Ok(( - None, - query_and_or_fragment - )) + Ok((None, query_and_or_fragment)) } } fn parse_path<T>(path_string: T) -> Result<Vec<Vec<u8>>, Error> - where T: AsRef<str> + where + T: AsRef<str>, { match path_string.as_ref() { "/" => { @@ -355,23 +361,24 @@ impl Uri { Ok(vec![]) }, - path_string => { - path_string - .split('/') - .map(|segment| { - decode_element( - &segment, - &PCHAR_NOT_PCT_ENCODED, - Context::Path - ) - }) - .collect() - } + path_string => path_string + .split('/') + .map(|segment| { + decode_element( + &segment, + &PCHAR_NOT_PCT_ENCODED, + Context::Path, + ) + }) + .collect(), } } - fn parse_query<T>(query_and_or_fragment: T) -> Result<Option<Vec<u8>>, Error> - where T: AsRef<str> + fn parse_query<T>( + query_and_or_fragment: T + ) -> Result<Option<Vec<u8>>, Error> + where + T: AsRef<str>, { let query_and_or_fragment = query_and_or_fragment.as_ref(); if query_and_or_fragment.is_empty() { @@ -379,7 +386,7 @@ impl Uri { } else { let query = Self::decode_query_or_fragment( &query_and_or_fragment[1..], - Context::Query + Context::Query, )?; Ok(Some(query)) } @@ -390,12 +397,14 @@ impl Uri { // or path elements, because these may have the colon // character as well, which we might misinterpret // as the scheme delimiter. - let authority_or_path_delimiter_start = uri_string.find('/') - .unwrap_or_else(|| uri_string.len()); - if let Some(scheme_end) = &uri_string[0..authority_or_path_delimiter_start].find(':') { - let scheme = Self::check_scheme(&uri_string[0..*scheme_end])? - .to_lowercase(); - Ok((Some(scheme), &uri_string[*scheme_end+1..])) + let authority_or_path_delimiter_start = + uri_string.find('/').unwrap_or_else(|| uri_string.len()); + if let Some(scheme_end) = + &uri_string[0..authority_or_path_delimiter_start].find(':') + { + let scheme = + Self::check_scheme(&uri_string[0..*scheme_end])?.to_lowercase(); + Ok((Some(scheme), &uri_string[*scheme_end + 1..])) } else { Ok((None, uri_string)) } @@ -437,17 +446,13 @@ impl Uri { /// /// Since path segments may contain non-UTF8 byte sequences, this function /// may return - /// [`Error::CannotExpressAsUtf8`](enum.Error.html#variant.CannotExpressAsUtf8). + /// [`Error::CannotExpressAsUtf8`](enum.Error.html#variant. + /// CannotExpressAsUtf8). #[must_use = "we went through all that trouble to put the path into a string, and you don't want it?"] pub fn path_to_string(&self) -> Result<String, Error> { match &*self.path { [segment] if segment.is_empty() => Ok("/".to_string()), - path => Ok( - String::from_utf8( - path - .join(&b"/"[..]) - )? - ), + path => Ok(String::from_utf8(path.join(&b"/"[..]))?), } } @@ -468,14 +473,12 @@ impl Uri { /// # Errors /// /// Since queries may contain non-UTF8 byte sequences, this function may - /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant.CannotExpressAsUtf8). + /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant. + /// CannotExpressAsUtf8). #[must_use = "use the query return value silly programmer"] pub fn query_to_string(&self) -> Result<Option<String>, Error> { self.query() - .map(|query| { - String::from_utf8(query.to_vec()) - .map_err(Into::into) - }) + .map(|query| String::from_utf8(query.to_vec()).map_err(Into::into)) .transpose() } @@ -498,75 +501,79 @@ impl Uri { /// # } /// ``` #[must_use = "why go through all that effort to resolve the URI, when you're not going to use it?!"] - pub fn resolve(&self, relative_reference: &Self) -> Self { - let (scheme, authority, path, query) = if relative_reference.scheme.is_some() { - ( - relative_reference.scheme.clone(), - relative_reference.authority.clone(), - Self::normalize_path(&relative_reference.path), - relative_reference.query.clone() - ) - } else { - relative_reference.authority.as_ref().map_or_else( - || { - let scheme = self.scheme.clone(); - let authority = self.authority.clone(); - if relative_reference.path.is_empty() { - let path = self.path.clone(); - let query = if relative_reference.query.is_none() { - self.query.clone() - } else { - relative_reference.query.clone() - }; - ( - scheme, - authority, - path, - query - ) - } else { - let query = relative_reference.query.clone(); - - // RFC describes this as: - // "if (R.path starts-with "/") then" - if Self::is_path_absolute(&relative_reference.path) { - ( - scheme, - authority, - relative_reference.path.clone(), - query - ) + pub fn resolve( + &self, + relative_reference: &Self, + ) -> Self { + let (scheme, authority, path, query) = + if relative_reference.scheme.is_some() { + ( + relative_reference.scheme.clone(), + relative_reference.authority.clone(), + Self::normalize_path(&relative_reference.path), + relative_reference.query.clone(), + ) + } else { + relative_reference.authority.as_ref().map_or_else( + || { + let scheme = self.scheme.clone(); + let authority = self.authority.clone(); + if relative_reference.path.is_empty() { + let path = self.path.clone(); + let query = if relative_reference.query.is_none() { + self.query.clone() + } else { + relative_reference.query.clone() + }; + (scheme, authority, path, query) } else { + let query = relative_reference.query.clone(); + // RFC describes this as: - // "T.path = merge(Base.path, R.path);" - let mut path = self.path.clone(); - if path.len() > 1 { - path.pop(); + // "if (R.path starts-with "/") then" + if Self::is_path_absolute(&relative_reference.path) + { + ( + scheme, + authority, + relative_reference.path.clone(), + query, + ) + } else { + // RFC describes this as: + // "T.path = merge(Base.path, R.path);" + let mut path = self.path.clone(); + if path.len() > 1 { + path.pop(); + } + path.extend( + relative_reference.path.iter().cloned(), + ); + ( + scheme, + authority, + Self::normalize_path(&path), + query, + ) } - path.extend(relative_reference.path.iter().cloned()); - ( - scheme, - authority, - Self::normalize_path(&path), - query - ) } - } - }, - |authority| ( - self.scheme.clone(), - Some(authority.clone()), - Self::normalize_path(&relative_reference.path), - relative_reference.query.clone() + }, + |authority| { + ( + self.scheme.clone(), + Some(authority.clone()), + Self::normalize_path(&relative_reference.path), + relative_reference.query.clone(), + ) + }, ) - ) - }; - Self{ + }; + Self { scheme, authority, path, query, - fragment: relative_reference.fragment.clone() + fragment: relative_reference.fragment.clone(), } } @@ -584,15 +591,21 @@ impl Uri { } /// Change the authority of the URI. - pub fn set_authority<T>(&mut self, authority: T) - where T: Into<Option<Authority>> + pub fn set_authority<T>( + &mut self, + authority: T, + ) where + T: Into<Option<Authority>>, { self.authority = authority.into(); } /// Change the fragment of the URI. - pub fn set_fragment<T>(&mut self, fragment: T) - where T: Into<Option<Vec<u8>>> + pub fn set_fragment<T>( + &mut self, + fragment: T, + ) where + T: Into<Option<Vec<u8>>>, { self.fragment = fragment.into(); } @@ -601,8 +614,11 @@ impl Uri { /// /// Note: See [`path`](#method.path) for special notes about what the /// segments of the path mean. - pub fn set_path<T>(&mut self, path: T) - where T: Into<Vec<Vec<u8>>> + pub fn set_path<T>( + &mut self, + path: T, + ) where + T: Into<Vec<Vec<u8>>>, { self.path = path.into(); } @@ -612,23 +628,28 @@ impl Uri { /// /// Note: See [`path`](#method.path) for special notes about what the /// segments of the path mean. - pub fn set_path_from_str<T>(&mut self, path: T) - where T: AsRef<str> + pub fn set_path_from_str<T>( + &mut self, + path: T, + ) where + T: AsRef<str>, { match path.as_ref() { "" => self.set_path(vec![]), path => self.set_path( - path - .split('/') + path.split('/') .map(|segment| segment.as_bytes().to_vec()) - .collect::<Vec<Vec<u8>>>() + .collect::<Vec<Vec<u8>>>(), ), } } /// Change the query of the URI. - pub fn set_query<T>(&mut self, query: T) - where T: Into<Option<Vec<u8>>> + pub fn set_query<T>( + &mut self, + query: T, + ) where + T: Into<Option<Vec<u8>>>, { self.query = query.into(); } @@ -640,14 +661,18 @@ impl Uri { /// The set of characters allowed in the scheme of a URI is limited. /// [`Error::IllegalCharacter`](enum.Error.html#variant.IllegalCharacter) /// is returned if you try to use a character that isn't allowed. - pub fn set_scheme<T>(&mut self, scheme: T) -> Result<(), Error> - where T: Into<Option<String>> + pub fn set_scheme<T>( + &mut self, + scheme: T, + ) -> Result<(), Error> + where + T: Into<Option<String>>, { self.scheme = match scheme.into() { Some(scheme) => { Self::check_scheme(&scheme)?; Some(scheme) - } + }, None => None, }; Ok(()) @@ -656,7 +681,8 @@ impl Uri { fn split_authority_from_path_and_parse_them<T>( authority_and_path_string: T ) -> Result<(Option<Authority>, Vec<Vec<u8>>), Error> - where T: AsRef<str> + where + T: AsRef<str>, { // Split authority from path. If there is an authority, parse it. let authority_and_path_string = authority_and_path_string.as_ref(); @@ -665,7 +691,8 @@ impl Uri { let authority_and_path_string = &authority_and_path_string[2..]; // First separate the authority from the path. - let authority_end = authority_and_path_string.find('/') + let authority_end = authority_and_path_string + .find('/') .unwrap_or_else(|| authority_and_path_string.len()); let authority_string = &authority_and_path_string[0..authority_end]; let path_string = &authority_and_path_string[authority_end..]; @@ -723,20 +750,23 @@ impl Uri { /// # Errors /// /// Since fragments may contain non-UTF8 byte sequences, this function may - /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant.CannotExpressAsUtf8). + /// return [`Error::CannotExpressAsUtf8`](enum.Error.html#variant. + /// CannotExpressAsUtf8). #[must_use = "come on, you intended to use that userinfo return value, didn't you?"] pub fn userinfo_to_string(&self) -> Result<Option<String>, Error> { self.userinfo() .map(|userinfo| { - String::from_utf8(userinfo.to_vec()) - .map_err(Into::into) + String::from_utf8(userinfo.to_vec()).map_err(Into::into) }) .transpose() } } impl std::fmt::Display for Uri { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt( + &self, + f: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { if let Some(scheme) = &self.scheme { write!(f, "{}:", scheme)?; } @@ -744,10 +774,7 @@ impl std::fmt::Display for Uri { write!(f, "//{}", authority)?; } // Special case: absolute but otherwise empty path. - if - Self::is_path_absolute(&self.path) - && self.path.len() == 1 - { + if Self::is_path_absolute(&self.path) && self.path.len() == 1 { write!(f, "/")?; } for (i, segment) in self.path.iter().enumerate() { @@ -757,10 +784,18 @@ impl std::fmt::Display for Uri { } } if let Some(query) = &self.query { - write!(f, "?{}", encode_element(query, &QUERY_NOT_PCT_ENCODED_WITHOUT_PLUS))?; + write!( + f, + "?{}", + encode_element(query, &QUERY_NOT_PCT_ENCODED_WITHOUT_PLUS) + )?; } if let Some(fragment) = &self.fragment { - write!(f, "#{}", encode_element(fragment, &QUERY_OR_FRAGMENT_NOT_PCT_ENCODED))?; + write!( + f, + "#{}", + encode_element(fragment, &QUERY_OR_FRAGMENT_NOT_PCT_ENCODED) + )?; } Ok(()) } @@ -788,7 +823,10 @@ mod tests { let uri = uri.unwrap(); assert_eq!(Some("http"), uri.scheme()); assert_eq!(Some(&b"www.example.com"[..]), uri.host()); - assert_eq!(Some("www.example.com"), uri.host_to_string().unwrap().as_deref()); + assert_eq!( + Some("www.example.com"), + uri.host_to_string().unwrap().as_deref() + ); assert_eq!(uri.path_to_string().unwrap(), "/foo/bar"); } @@ -835,7 +873,7 @@ mod tests { named_tuple!( struct TestVector { uri_string: &'static str, - is_relative_reference: bool + is_relative_reference: bool, } ); let test_vectors: &[TestVector] = &[ @@ -860,7 +898,7 @@ mod tests { named_tuple!( struct TestVector { uri_string: &'static str, - contains_relative_path: bool + contains_relative_path: bool, } ); let test_vectors: &[TestVector] = &[ @@ -868,7 +906,6 @@ mod tests { ("http://www.example.com", false).into(), ("/", false).into(), ("foo", true).into(), - // This is only a valid test vector if we understand // correctly that an empty string IS a valid // "relative reference" URI with an empty path. @@ -881,7 +918,8 @@ mod tests { assert_eq!( *test_vector.contains_relative_path(), uri.contains_relative_path(), - "{}", test_index + "{}", + test_index ); } } @@ -893,27 +931,56 @@ mod tests { uri_string: &'static str, host: &'static str, query: Option<&'static str>, - fragment: Option<&'static str> + fragment: Option<&'static str>, } ); let test_vectors: &[TestVector] = &[ ("http://www.example.com/", "www.example.com", None, None).into(), ("http://example.com?foo", "example.com", Some("foo"), None).into(), - ("http://www.example.com#foo", "www.example.com", None, Some("foo")).into(), - ("http://www.example.com?foo#bar", "www.example.com", Some("foo"), Some("bar")).into(), - ("http://www.example.com?earth?day#bar", "www.example.com", Some("earth?day"), Some("bar")).into(), - ("http://www.example.com/spam?foo#bar", "www.example.com", Some("foo"), Some("bar")).into(), - ("http://www.example.com/?", "www.example.com", Some(""), None).into(), + ( + "http://www.example.com#foo", + "www.example.com", + None, + Some("foo"), + ) + .into(), + ( + "http://www.example.com?foo#bar", + "www.example.com", + Some("foo"), + Some("bar"), + ) + .into(), + ( + "http://www.example.com?earth?day#bar", + "www.example.com", + Some("earth?day"), + Some("bar"), + ) + .into(), + ( + "http://www.example.com/spam?foo#bar", + "www.example.com", + Some("foo"), + Some("bar"), + ) + .into(), + ("http://www.example.com/?", "www.example.com", Some(""), None) + .into(), ]; for (test_index, test_vector) in test_vectors.iter().enumerate() { let uri = Uri::parse(test_vector.uri_string()); assert!(uri.is_ok()); let uri = uri.unwrap(); - assert_eq!(Some(*test_vector.host()), uri.host_to_string().unwrap().as_deref()); + assert_eq!( + Some(*test_vector.host()), + uri.host_to_string().unwrap().as_deref() + ); assert_eq!( *test_vector.query(), uri.query_to_string().unwrap().as_deref(), - "{}", test_index + "{}", + test_index ); assert_eq!( *test_vector.fragment(), @@ -943,7 +1010,7 @@ mod tests { named_tuple!( struct TestVector { uri_string: &'static str, - scheme: &'static str + scheme: &'static str, } ); let test_vectors: &[TestVector] = &[ @@ -963,7 +1030,7 @@ mod tests { } #[test] - fn scheme_mixed_case () { + fn scheme_mixed_case() { let test_vectors = [ "http://www.example.com/", "hTtp://www.example.com/", @@ -1032,7 +1099,7 @@ mod tests { named_tuple!( struct TestVector { uri_string: &'static str, - path: Vec<&'static [u8]> + path: Vec<&'static [u8]>, } ); let test_vectors: &[TestVector] = &[ @@ -1040,7 +1107,13 @@ mod tests { ("bob@/foo", vec![&b"bob@"[..], &b"foo"[..]]).into(), ("hello!", vec![&b"hello!"[..]]).into(), ("urn:hello,%20w%6Frld", vec![&b"hello, world"[..]]).into(), - ("//example.com/foo/(bar)/", vec![&b""[..], &b"foo"[..], &b"(bar)"[..], &b""[..]]).into(), + ("//example.com/foo/(bar)/", vec![ + &b""[..], + &b"foo"[..], + &b"(bar)"[..], + &b""[..], + ]) + .into(), ]; for test_vector in test_vectors { let uri = Uri::parse(test_vector.uri_string()); @@ -1085,7 +1158,7 @@ mod tests { named_tuple!( struct TestVector { uri_string: &'static str, - query: &'static str + query: &'static str, } ); let test_vectors: &[TestVector] = &[ @@ -1103,7 +1176,8 @@ mod tests { assert_eq!( Some(*test_vector.query()), uri.query_to_string().unwrap().as_deref(), - "{}", test_index + "{}", + test_index ); } } @@ -1143,7 +1217,7 @@ mod tests { named_tuple!( struct TestVector { uri_string: &'static str, - fragment: &'static str + fragment: &'static str, } ); let test_vectors: &[TestVector] = &[ @@ -1170,7 +1244,7 @@ mod tests { named_tuple!( struct TestVector { uri_string: &'static str, - path_first_segment: &'static [u8] + path_first_segment: &'static [u8], } ); let test_vectors: &[TestVector] = &[ @@ -1253,7 +1327,8 @@ mod tests { assert_eq!( *test_vector.normalized_path(), uri.path_to_string().unwrap(), - "{}", test_vector.uri_string() + "{}", + test_vector.uri_string() ); } } @@ -1279,7 +1354,7 @@ mod tests { struct TestVector { base_string: &'static str, relative_reference_string: &'static str, - target_string: &'static str + target_string: &'static str, } ); let test_vectors: &[TestVector] = &[ @@ -1307,7 +1382,6 @@ mod tests { ("http://a/b/c/d;p?q", "../..", "http://a").into(), ("http://a/b/c/d;p?q", "../../", "http://a").into(), ("http://a/b/c/d;p?q", "../../g", "http://a/g").into(), - // Here are some examples of our own. ("http://example.com", "foo", "http://example.com/foo").into(), ("http://example.com/", "foo", "http://example.com/foo").into(), @@ -1322,9 +1396,12 @@ mod tests { ]; for test_vector in test_vectors { let base_uri = Uri::parse(test_vector.base_string()).unwrap(); - let relative_reference_uri = Uri::parse(test_vector.relative_reference_string()).unwrap(); - let expected_target_uri = Uri::parse(test_vector.target_string()).unwrap(); - let actual_target_uri = dbg!(base_uri.resolve(&relative_reference_uri)); + let relative_reference_uri = + Uri::parse(test_vector.relative_reference_string()).unwrap(); + let expected_target_uri = + Uri::parse(test_vector.target_string()).unwrap(); + let actual_target_uri = + dbg!(base_uri.resolve(&relative_reference_uri)); assert_eq!(expected_target_uri, actual_target_uri); } } @@ -1362,56 +1439,278 @@ mod tests { path: &'static str, query: Option<&'static str>, fragment: Option<&'static str>, - expected_uri_string: &'static str + expected_uri_string: &'static str, } ); let test_vectors: &[TestVector] = &[ // general test vectors - // scheme userinfo host port path query fragment expected_uri_string - (Some("http"), Some("bob"), Some("www.example.com"), Some(8080), "/abc/def", Some("foobar"), Some("ch2"), "http://bob@www.example.com:8080/abc/def?foobar#ch2").into(), - (Some("http"), Some("bob"), Some("www.example.com"), Some(0), "", Some("foobar"), Some("ch2"), "http://bob@www.example.com:0?foobar#ch2").into(), - (Some("http"), Some("bob"), Some("www.example.com"), Some(0), "", Some("foobar"), Some(""), "http://bob@www.example.com:0?foobar#").into(), - (None, None, Some("example.com"), None, "", Some("bar"), None, "//example.com?bar").into(), - (None, None, Some("example.com"), None, "", Some(""), None, "//example.com?").into(), - (None, None, Some("example.com"), None, "", None, None, "//example.com").into(), - (None, None, Some("example.com"), None, "/", None, None, "//example.com/").into(), - (None, None, Some("example.com"), None, "/xyz", None, None, "//example.com/xyz").into(), - (None, None, Some("example.com"), None, "/xyz/", None, None, "//example.com/xyz/").into(), - (None, None, None, None, "/", None, None, "/").into(), - (None, None, None, None, "/xyz", None, None, "/xyz").into(), - (None, None, None, None, "/xyz/", None, None, "/xyz/").into(), - (None, None, None, None, "", None, None, "").into(), - (None, None, None, None, "xyz", None, None, "xyz").into(), - (None, None, None, None, "xyz/", None, None, "xyz/").into(), - (None, None, None, None, "", Some("bar"), None, "?bar").into(), - (Some("http"), None, None, None, "", Some("bar"), None, "http:?bar").into(), - (Some("http"), None, None, None, "", None, None, "http:").into(), - (Some("http"), None, Some("::1"), None, "", None, None, "http://[::1]").into(), - (Some("http"), None, Some("::1.2.3.4"), None, "", None, None, "http://[::1.2.3.4]").into(), - (Some("http"), None, Some("1.2.3.4"), None, "", None, None, "http://1.2.3.4").into(), - (None, None, None, None, "", None, None, "").into(), - (Some("http"), Some("bob"), None, None, "", Some("foobar"), None, "http://bob@?foobar").into(), - (None, Some("bob"), None, None, "", Some("foobar"), None, "//bob@?foobar").into(), - (None, Some("bob"), None, None, "", None, None, "//bob@").into(), - + // scheme userinfo host port + // path query fragment expected_uri_string + ( + Some("http"), + Some("bob"), + Some("www.example.com"), + Some(8080), + "/abc/def", + Some("foobar"), + Some("ch2"), + "http://bob@www.example.com:8080/abc/def?foobar#ch2", + ) + .into(), + ( + Some("http"), + Some("bob"), + Some("www.example.com"), + Some(0), + "", + Some("foobar"), + Some("ch2"), + "http://bob@www.example.com:0?foobar#ch2", + ) + .into(), + ( + Some("http"), + Some("bob"), + Some("www.example.com"), + Some(0), + "", + Some("foobar"), + Some(""), + "http://bob@www.example.com:0?foobar#", + ) + .into(), + ( + None, + None, + Some("example.com"), + None, + "", + Some("bar"), + None, + "//example.com?bar", + ) + .into(), + ( + None, + None, + Some("example.com"), + None, + "", + Some(""), + None, + "//example.com?", + ) + .into(), + ( + None, + None, + Some("example.com"), + None, + "", + None, + None, + "//example.com", + ) + .into(), + ( + None, + None, + Some("example.com"), + None, + "/", + None, + None, + "//example.com/", + ) + .into(), + ( + None, + None, + Some("example.com"), + None, + "/xyz", + None, + None, + "//example.com/xyz", + ) + .into(), + ( + None, + None, + Some("example.com"), + None, + "/xyz/", + None, + None, + "//example.com/xyz/", + ) + .into(), + (None, None, None, None, "/", None, None, "/").into(), + (None, None, None, None, "/xyz", None, None, "/xyz").into(), + (None, None, None, None, "/xyz/", None, None, "/xyz/").into(), + (None, None, None, None, "", None, None, "").into(), + (None, None, None, None, "xyz", None, None, "xyz").into(), + (None, None, None, None, "xyz/", None, None, "xyz/").into(), + (None, None, None, None, "", Some("bar"), None, "?bar").into(), + ( + Some("http"), + None, + None, + None, + "", + Some("bar"), + None, + "http:?bar", + ) + .into(), + (Some("http"), None, None, None, "", None, None, "http:").into(), + ( + Some("http"), + None, + Some("::1"), + None, + "", + None, + None, + "http://[::1]", + ) + .into(), + ( + Some("http"), + None, + Some("::1.2.3.4"), + None, + "", + None, + None, + "http://[::1.2.3.4]", + ) + .into(), + ( + Some("http"), + None, + Some("1.2.3.4"), + None, + "", + None, + None, + "http://1.2.3.4", + ) + .into(), + (None, None, None, None, "", None, None, "").into(), + ( + Some("http"), + Some("bob"), + None, + None, + "", + Some("foobar"), + None, + "http://bob@?foobar", + ) + .into(), + ( + None, + Some("bob"), + None, + None, + "", + Some("foobar"), + None, + "//bob@?foobar", + ) + .into(), + (None, Some("bob"), None, None, "", None, None, "//bob@").into(), // percent-encoded character test vectors - // scheme userinfo host port path query fragment expected_uri_string - (Some("http"), Some("b b"), Some("www.example.com"), Some(8080), "/abc/def", Some("foobar"), Some("ch2"), "http://b%20b@www.example.com:8080/abc/def?foobar#ch2").into(), - (Some("http"), Some("bob"), Some("www.e ample.com"), Some(8080), "/abc/def", Some("foobar"), Some("ch2"), "http://bob@www.e%20ample.com:8080/abc/def?foobar#ch2").into(), - (Some("http"), Some("bob"), Some("www.example.com"), Some(8080), "/a c/def", Some("foobar"), Some("ch2"), "http://bob@www.example.com:8080/a%20c/def?foobar#ch2").into(), - (Some("http"), Some("bob"), Some("www.example.com"), Some(8080), "/abc/def", Some("foo ar"), Some("ch2"), "http://bob@www.example.com:8080/abc/def?foo%20ar#ch2").into(), - (Some("http"), Some("bob"), Some("www.example.com"), Some(8080), "/abc/def", Some("foobar"), Some("c 2"), "http://bob@www.example.com:8080/abc/def?foobar#c%202").into(), - (Some("http"), Some("bob"), Some("ሴ.example.com"), Some(8080), "/abc/def", Some("foobar"), None, "http://bob@%E1%88%B4.example.com:8080/abc/def?foobar").into(), - + // scheme userinfo host port + // path query fragment expected_uri_string + ( + Some("http"), + Some("b b"), + Some("www.example.com"), + Some(8080), + "/abc/def", + Some("foobar"), + Some("ch2"), + "http://b%20b@www.example.com:8080/abc/def?foobar#ch2", + ) + .into(), + ( + Some("http"), + Some("bob"), + Some("www.e ample.com"), + Some(8080), + "/abc/def", + Some("foobar"), + Some("ch2"), + "http://bob@www.e%20ample.com:8080/abc/def?foobar#ch2", + ) + .into(), + ( + Some("http"), + Some("bob"), + Some("www.example.com"), + Some(8080), + "/a c/def", + Some("foobar"), + Some("ch2"), + "http://bob@www.example.com:8080/a%20c/def?foobar#ch2", + ) + .into(), + ( + Some("http"), + Some("bob"), + Some("www.example.com"), + Some(8080), + "/abc/def", + Some("foo ar"), + Some("ch2"), + "http://bob@www.example.com:8080/abc/def?foo%20ar#ch2", + ) + .into(), + ( + Some("http"), + Some("bob"), + Some("www.example.com"), + Some(8080), + "/abc/def", + Some("foobar"), + Some("c 2"), + "http://bob@www.example.com:8080/abc/def?foobar#c%202", + ) + .into(), + ( + Some("http"), + Some("bob"), + Some("ሴ.example.com"), + Some(8080), + "/abc/def", + Some("foobar"), + None, + "http://bob@%E1%88%B4.example.com:8080/abc/def?foobar", + ) + .into(), // normalization of IPv6 address hex digits - // scheme userinfo host port path query fragment expected_uri_string - (Some("http"), Some("bob"), Some("fFfF::1"), Some(8080), "/abc/def", Some("foobar"), Some("c 2"), "http://bob@[ffff::1]:8080/abc/def?foobar#c%202").into(), + // scheme userinfo host port path + // query fragment expected_uri_string + ( + Some("http"), + Some("bob"), + Some("fFfF::1"), + Some(8080), + "/abc/def", + Some("foobar"), + Some("c 2"), + "http://bob@[ffff::1]:8080/abc/def?foobar#c%202", + ) + .into(), ]; for test_vector in test_vectors { let mut uri = Uri::default(); - assert!(uri.set_scheme(test_vector.scheme().map(ToString::to_string)).is_ok()); - if - test_vector.userinfo().is_some() + assert!(uri + .set_scheme(test_vector.scheme().map(ToString::to_string)) + .is_ok()); + if test_vector.userinfo().is_some() || test_vector.host().is_some() || test_vector.port().is_some() { @@ -1426,10 +1725,7 @@ mod tests { uri.set_path_from_str(test_vector.path()); uri.set_query(test_vector.query().map(Into::into)); uri.set_fragment(test_vector.fragment().map(Into::into)); - assert_eq!( - *test_vector.expected_uri_string(), - uri.to_string() - ); + assert_eq!(*test_vector.expected_uri_string(), uri.to_string()); } } @@ -1513,23 +1809,13 @@ mod tests { for ci in 0_u8..31_u8 { let mut uri = Uri::default(); uri.set_query(Some(vec![ci])); - assert_eq!( - uri.to_string(), - format!("?%{:02X}", ci) - ); + assert_eq!(uri.to_string(), format!("?%{:02X}", ci)); } } #[test] fn set_illegal_schemes() { - let test_vectors = [ - "ab_de", - "ab/de", - "ab:de", - "", - "&", - "foo&bar", - ]; + let test_vectors = ["ab_de", "ab/de", "ab:de", "", "&", "foo&bar"]; for test_vector in &test_vectors { let mut uri = Uri::default(); assert!(uri.set_scheme(Some((*test_vector).to_string())).is_err()); @@ -1538,7 +1824,8 @@ mod tests { #[test] fn take_parts() { - let mut uri = Uri::parse("https://www.example.com/foo?bar#baz").unwrap(); + let mut uri = + Uri::parse("https://www.example.com/foo?bar#baz").unwrap(); assert_eq!(Some("https"), uri.take_scheme().as_deref()); assert_eq!("//www.example.com/foo?bar#baz", uri.to_string()); assert!(matches!( @@ -1554,5 +1841,4 @@ mod tests { assert_eq!("/foo", uri.to_string()); assert_eq!(None, uri.take_fragment().as_deref()); } - } |