From d6faf23ca3295e4ec691aadc6e5c73f7f9848ae4 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 21 Dec 2012 07:47:32 -0800 Subject: [PATCH] std: modernize net_url This switches over to using structs and send_maps for query string parsing. --- src/libstd/net_url.rs | 680 ++++++++++++++++++++---------------------- 1 file changed, 316 insertions(+), 364 deletions(-) diff --git a/src/libstd/net_url.rs b/src/libstd/net_url.rs index 6b7dc3f1afdb..a6ba728ccbb0 100644 --- a/src/libstd/net_url.rs +++ b/src/libstd/net_url.rs @@ -11,15 +11,10 @@ //! Types/fns concerning URLs (see RFC 3986) #[forbid(deprecated_mode)]; -use core::cmp::Eq; -use map::HashMap; -use io::{Reader, ReaderUtil}; -use dvec::DVec; -use from_str::FromStr; -use result::{Err, Ok}; -use to_str::ToStr; -use to_bytes::IterBytes; +use io::ReaderUtil; +use send_map::linear::LinearMap; +#[deriving_eq] struct Url { scheme: ~str, user: Option, @@ -30,23 +25,40 @@ struct Url { fragment: Option<~str> } -type UserInfo = { +#[deriving_eq] +struct UserInfo { user: ~str, pass: Option<~str> -}; +} pub type Query = ~[(~str, ~str)]; -pub pure fn Url(scheme: ~str, user: Option, host: ~str, - port: Option<~str>, path: ~str, query: Query, - fragment: Option<~str>) -> Url { - Url { scheme: move scheme, user: move user, host: move host, - port: move port, path: move path, query: move query, - fragment: move fragment } +pub impl Url { + static pure fn new( + scheme: ~str, + user: Option, + host: ~str, + port: Option<~str>, + path: ~str, + query: Query, + fragment: Option<~str> + ) -> Url { + Url { + scheme: scheme, + user: user, + host: host, + port: port, + path: path, + query: query, + fragment: fragment, + } + } } -pure fn UserInfo(user: ~str, pass: Option<~str>) -> UserInfo { - {user: move user, pass: move pass} +pub impl UserInfo { + static pure fn new(user: ~str, pass: Option<~str>) -> UserInfo { + UserInfo { user: user, pass: pass } + } } fn encode_inner(s: &str, full_url: bool) -> ~str { @@ -95,7 +107,7 @@ fn encode_inner(s: &str, full_url: bool) -> ~str { * This function is compliant with RFC 3986. */ pub pure fn encode(s: &str) -> ~str { - // unsafe only because encode_inner does (string) IO + // FIXME(#3722): unsafe only because encode_inner does (string) IO unsafe {encode_inner(s, true)} } @@ -107,7 +119,7 @@ pub pure fn encode(s: &str) -> ~str { */ pub pure fn encode_component(s: &str) -> ~str { - // unsafe only because encode_inner does (string) IO + // FIXME(#3722): unsafe only because encode_inner does (string) IO unsafe {encode_inner(s, false)} } @@ -152,10 +164,10 @@ fn decode_inner(s: &str, full_url: bool) -> ~str { /** * Decode a string encoded with percent encoding. * - * This will only decode escape sequences generated by encode_uri. + * This will only decode escape sequences generated by encode. */ pub pure fn decode(s: &str) -> ~str { - // unsafe only because decode_inner does (string) IO + // FIXME(#3722): unsafe only because decode_inner does (string) IO unsafe {decode_inner(s, true)} } @@ -163,7 +175,7 @@ pub pure fn decode(s: &str) -> ~str { * Decode a string encoded with percent encoding. */ pub pure fn decode_component(s: &str) -> ~str { - // unsafe only because decode_inner does (string) IO + // FIXME(#3722): unsafe only because decode_inner does (string) IO unsafe {decode_inner(s, false)} } @@ -189,12 +201,12 @@ fn encode_plus(s: &str) -> ~str { /** * Encode a hashmap to the 'application/x-www-form-urlencoded' media type. */ -pub fn encode_form_urlencoded(m: HashMap<~str, @DVec<@~str>>) -> ~str { +pub fn encode_form_urlencoded(m: &LinearMap<~str, ~[~str]>) -> ~str { let mut out = ~""; let mut first = true; for m.each |key, values| { - let key = encode_plus(key); + let key = encode_plus(*key); for (*values).each |value| { if first { @@ -204,7 +216,7 @@ pub fn encode_form_urlencoded(m: HashMap<~str, @DVec<@~str>>) -> ~str { first = false; } - out += fmt!("%s=%s", key, encode_plus(**value)); + out += fmt!("%s=%s", key, encode_plus(*value)); } } @@ -215,62 +227,60 @@ pub fn encode_form_urlencoded(m: HashMap<~str, @DVec<@~str>>) -> ~str { * Decode a string encoded with the 'application/x-www-form-urlencoded' media * type into a hashmap. */ -pub fn decode_form_urlencoded(s: ~[u8]) -> - map::HashMap<~str, @dvec::DVec<@~str>> { +pub fn decode_form_urlencoded( + s: &[u8] +) -> send_map::linear::LinearMap<~str, ~[~str]> { do io::with_bytes_reader(s) |rdr| { - let m = HashMap(); + let mut m = LinearMap(); let mut key = ~""; let mut value = ~""; let mut parsing_key = true; while !rdr.eof() { match rdr.read_char() { - '&' | ';' => { - if key != ~"" && value != ~"" { - let values = match m.find(key) { - Some(values) => values, - None => { - let values = @DVec(); + '&' | ';' => { + if key != ~"" && value != ~"" { + let mut values = match m.pop(&key) { + Some(move values) => values, + None => ~[], + }; + + values.push(value); m.insert(key, values); - values - } - }; - (*values).push(@value) + } + + parsing_key = true; + key = ~""; + value = ~""; } + '=' => parsing_key = false, + ch => { + let ch = match ch { + '%' => { + let bytes = rdr.read_bytes(2u); + uint::parse_bytes(bytes, 16u).get() as char + } + '+' => ' ', + ch => ch + }; - parsing_key = true; - key = ~""; - value = ~""; - } - '=' => parsing_key = false, - ch => { - let ch = match ch { - '%' => { - uint::parse_bytes(rdr.read_bytes(2u), 16u).get() as char - } - '+' => ' ', - ch => ch - }; - - if parsing_key { - str::push_char(&mut key, ch) - } else { - str::push_char(&mut value, ch) + if parsing_key { + str::push_char(&mut key, ch) + } else { + str::push_char(&mut value, ch) + } } - } } } if key != ~"" && value != ~"" { - let values = match m.find(key) { - Some(values) => values, - None => { - let values = @DVec(); - m.insert(key, values); - values - } + let mut values = match m.pop(&key) { + Some(move values) => values, + None => ~[], }; - (*values).push(@value) + + values.push(value); + m.insert(key, values); } m @@ -282,9 +292,10 @@ pure fn split_char_first(s: &str, c: char) -> (~str, ~str) { let len = str::len(s); let mut index = len; let mut mat = 0; + // FIXME(#3722): unsafe only because decode_inner does (string) IO unsafe { do io::with_str_reader(s) |rdr| { - let mut ch : char; + let mut ch; while !rdr.eof() { ch = rdr.read_byte() as char; if ch == c { @@ -307,107 +318,88 @@ pure fn split_char_first(s: &str, c: char) -> (~str, ~str) { pure fn userinfo_from_str(uinfo: &str) -> UserInfo { let (user, p) = split_char_first(uinfo, ':'); let pass = if str::len(p) == 0 { - option::None + None } else { - option::Some(p) + Some(p) }; - return UserInfo(user, pass); + return UserInfo::new(user, pass); } -pure fn userinfo_to_str(userinfo: UserInfo) -> ~str { - if option::is_some(&userinfo.pass) { - return str::concat(~[copy userinfo.user, ~":", - option::unwrap(copy userinfo.pass), - ~"@"]); - } else { - return str::concat(~[copy userinfo.user, ~"@"]); +pure fn userinfo_to_str(userinfo: &UserInfo) -> ~str { + match userinfo.pass { + Some(ref pass) => fmt!("%s:%s@", userinfo.user, *pass), + None => fmt!("%s@", userinfo.user), } } -impl UserInfo : Eq { - pure fn eq(&self, other: &UserInfo) -> bool { - (*self).user == (*other).user && (*self).pass == (*other).pass - } - pure fn ne(&self, other: &UserInfo) -> bool { !(*self).eq(other) } -} - pure fn query_from_str(rawquery: &str) -> Query { let mut query: Query = ~[]; if str::len(rawquery) != 0 { for str::split_char(rawquery, '&').each |p| { let (k, v) = split_char_first(*p, '='); + // FIXME(#3722): unsafe only because decode_inner does (string) IO unsafe {query.push((decode_component(k), decode_component(v)));} }; } return query; } -pub pure fn query_to_str(query: Query) -> ~str { +pub pure fn query_to_str(query: &Query) -> ~str unsafe { + // FIXME(#3722): unsafe only because decode_inner does (string) IO let mut strvec = ~[]; for query.each |kv| { - let (k, v) = copy *kv; - // This is really safe... - unsafe { - strvec += ~[fmt!("%s=%s", - encode_component(k), encode_component(v))]; + match kv { + &(ref k, ref v) => { + strvec.push(fmt!("%s=%s", + encode_component(*k), + encode_component(*v)) + ); + } } - }; + } return str::connect(strvec, ~"&"); } // returns the scheme and the rest of the url, or a parsing error -pub pure fn get_scheme(rawurl: &str) -> result::Result<(~str, ~str), @~str> { +pub pure fn get_scheme(rawurl: &str) -> Result<(~str, ~str), ~str> { for str::each_chari(rawurl) |i,c| { match c { 'A' .. 'Z' | 'a' .. 'z' => loop, '0' .. '9' | '+' | '-' | '.' => { if i == 0 { - return result::Err(@~"url: Scheme must begin with a letter."); + return Err(~"url: Scheme must begin with a letter."); } loop; } ':' => { if i == 0 { - return result::Err(@~"url: Scheme cannot be empty."); + return Err(~"url: Scheme cannot be empty."); } else { - return result::Ok((rawurl.slice(0,i), + return Ok((rawurl.slice(0,i), rawurl.slice(i+1,str::len(rawurl)))); } } _ => { - return result::Err(@~"url: Invalid character in scheme."); + return Err(~"url: Invalid character in scheme."); } } }; - return result::Err(@~"url: Scheme must be terminated with a colon."); + return Err(~"url: Scheme must be terminated with a colon."); } +#[deriving_eq] enum Input { Digit, // all digits Hex, // digits and letters a-f Unreserved // all other legal characters } -impl Input : Eq { - pure fn eq(&self, other: &Input) -> bool { - match ((*self), (*other)) { - (Digit, Digit) => true, - (Hex, Hex) => true, - (Unreserved, Unreserved) => true, - (Digit, _) => false, - (Hex, _) => false, - (Unreserved, _) => false - } - } - pure fn ne(&self, other: &Input) -> bool { !(*self).eq(other) } -} - // returns userinfo, host, port, and unparsed part, or an error pure fn get_authority(rawurl: &str) -> - result::Result<(Option, ~str, Option<~str>, ~str), @~str> { + Result<(Option, ~str, Option<~str>, ~str), ~str> { if !str::starts_with(rawurl, ~"//") { // there is no authority. - return result::Ok((option::None, ~"", option::None, rawurl.to_str())); + return Ok((None, ~"", None, rawurl.to_str())); } enum State { @@ -419,16 +411,16 @@ pure fn get_authority(rawurl: &str) -> InPort // are in port } - let len = str::len(rawurl); - let mut st : State = Start; - let mut in : Input = Digit; // most restricted, start here. + let len = rawurl.len(); + let mut st = Start; + let mut in = Digit; // most restricted, start here. - let mut userinfo : Option = option::None; - let mut host : ~str = ~""; - let mut port : option::Option<~str> = option::None; + let mut userinfo = None; + let mut host = ~""; + let mut port = None; let mut colon_count = 0; - let mut pos : uint = 0, begin : uint = 2, end : uint = len; + let mut pos = 0, begin = 2, end = len; for str::each_chari(rawurl) |i,c| { if i < 2 { loop; } // ignore the leading // @@ -449,7 +441,7 @@ pure fn get_authority(rawurl: &str) -> // separators, don't change anything } _ => { - return result::Err(@~"Illegal character in authority"); + return Err(~"Illegal character in authority"); } } @@ -465,8 +457,8 @@ pure fn get_authority(rawurl: &str) -> PassHostPort => { // multiple colons means ipv6 address. if in == Unreserved { - return result::Err( - @~"Illegal characters in IPv6 address."); + return Err( + ~"Illegal characters in IPv6 address."); } st = Ip6Host; } @@ -474,13 +466,13 @@ pure fn get_authority(rawurl: &str) -> pos = i; // can't be sure whether this is an ipv6 address or a port if in == Unreserved { - return result::Err(@~"Illegal characters in authority."); + return Err(~"Illegal characters in authority."); } st = Ip6Port; } Ip6Port => { if in == Unreserved { - return result::Err(@~"Illegal characters in authority."); + return Err(~"Illegal characters in authority."); } st = Ip6Host; } @@ -492,7 +484,7 @@ pure fn get_authority(rawurl: &str) -> } } _ => { - return result::Err(@~"Invalid ':' in authority."); + return Err(~"Invalid ':' in authority."); } } in = Digit; // reset input class @@ -504,19 +496,17 @@ pure fn get_authority(rawurl: &str) -> match st { Start => { let user = str::slice(rawurl, begin, i); - userinfo = option::Some({user : user, - pass: option::None}); + userinfo = Some(UserInfo::new(user, None)); st = InHost; } PassHostPort => { let user = str::slice(rawurl, begin, pos); let pass = str::slice(rawurl, pos+1, i); - userinfo = option::Some({user: user, - pass: option::Some(pass)}); + userinfo = Some(UserInfo::new(user, Some(pass))); st = InHost; } _ => { - return result::Err(@~"Invalid '@' in authority."); + return Err(~"Invalid '@' in authority."); } } begin = i+1; @@ -549,31 +539,31 @@ pure fn get_authority(rawurl: &str) -> } PassHostPort | Ip6Port => { if in != Digit { - return result::Err(@~"Non-digit characters in port."); + return Err(~"Non-digit characters in port."); } host = str::slice(rawurl, begin, pos); - port = option::Some(str::slice(rawurl, pos+1, end)); + port = Some(str::slice(rawurl, pos+1, end)); } Ip6Host | InHost => { host = str::slice(rawurl, begin, end); } InPort => { if in != Digit { - return result::Err(@~"Non-digit characters in port."); + return Err(~"Non-digit characters in port."); } - port = option::Some(str::slice(rawurl, pos+1, end)); + port = Some(str::slice(rawurl, pos+1, end)); } } let rest = if host_is_end_plus_one() { ~"" } else { str::slice(rawurl, end, len) }; - return result::Ok((userinfo, host, port, rest)); + return Ok((userinfo, host, port, rest)); } // returns the path and unparsed part of url, or an error -pure fn get_path(rawurl: &str, authority : bool) -> - result::Result<(~str, ~str), @~str> { +pure fn get_path(rawurl: &str, authority: bool) -> + Result<(~str, ~str), ~str> { let len = str::len(rawurl); let mut end = len; for str::each_chari(rawurl) |i,c| { @@ -587,39 +577,39 @@ pure fn get_path(rawurl: &str, authority : bool) -> end = i; break; } - _ => return result::Err(@~"Invalid character in path.") + _ => return Err(~"Invalid character in path.") } } if authority { if end != 0 && !str::starts_with(rawurl, ~"/") { - return result::Err(@~"Non-empty path must begin with\ + return Err(~"Non-empty path must begin with\ '/' in presence of authority."); } } - return result::Ok((decode_component(str::slice(rawurl, 0, end)), + return Ok((decode_component(str::slice(rawurl, 0, end)), str::slice(rawurl, end, len))); } // returns the parsed query and the fragment, if present pure fn get_query_fragment(rawurl: &str) -> - result::Result<(Query, Option<~str>), @~str> { + Result<(Query, Option<~str>), ~str> { if !str::starts_with(rawurl, ~"?") { if str::starts_with(rawurl, ~"#") { let f = decode_component(str::slice(rawurl, 1, str::len(rawurl))); - return result::Ok((~[], option::Some(f))); + return Ok((~[], Some(f))); } else { - return result::Ok((~[], option::None)); + return Ok((~[], None)); } } let (q, r) = split_char_first(str::slice(rawurl, 1, str::len(rawurl)), '#'); let f = if str::len(r) != 0 { - option::Some(decode_component(r)) } else { option::None }; - return result::Ok((query_from_str(q), f)); + Some(decode_component(r)) } else { None }; + return Ok((query_from_str(q), f)); } /** @@ -635,41 +625,36 @@ pure fn get_query_fragment(rawurl: &str) -> * */ -pub pure fn from_str(rawurl: &str) -> result::Result { +pub pure fn from_str(rawurl: &str) -> Result { // scheme - let mut schm = get_scheme(rawurl); - if result::is_err(&schm) { - return result::Err(copy *result::get_err(&schm)); - } - let (scheme, rest) = schm.get(); + let (scheme, rest) = match get_scheme(rawurl) { + Ok(val) => val, + Err(e) => return Err(e), + }; // authority - let mut auth = get_authority(rest); - if result::is_err(&auth) { - return result::Err(copy *result::get_err(&auth)); - } - let (userinfo, host, port, rest) = auth.get(); + let (userinfo, host, port, rest) = match get_authority(rest) { + Ok(val) => val, + Err(e) => return Err(e), + }; // path let has_authority = if host == ~"" { false } else { true }; - let mut pth = get_path(rest, has_authority); - if result::is_err(&pth) { - return result::Err(copy *result::get_err(&pth)); - } - let (path, rest) = pth.get(); + let (path, rest) = match get_path(rest, has_authority) { + Ok(val) => val, + Err(e) => return Err(e), + }; // query and fragment - let mut qry = get_query_fragment(rest); - if result::is_err(&qry) { - return result::Err(copy *result::get_err(&qry)); - } - let (query, fragment) = qry.get(); + let (query, fragment) = match get_query_fragment(rest) { + Ok(val) => val, + Err(e) => return Err(e), + }; - return result::Ok(Url(scheme, userinfo, host, - port, path, query, fragment)); + Ok(Url::new(scheme, userinfo, host, port, path, query, fragment)) } -impl Url : FromStr { +impl Url: from_str::FromStr { static pure fn from_str(s: &str) -> Option { match from_str(s) { Ok(move url) => Some(url), @@ -693,63 +678,41 @@ impl Url : FromStr { * result in just "http://somehost.com". * */ -pub pure fn to_str(url: Url) -> ~str { - let user = if url.user.is_some() { - userinfo_to_str(option::unwrap(copy url.user)) - } else { - ~"" +pub pure fn to_str(url: &Url) -> ~str { + let user = match url.user { + Some(ref user) => userinfo_to_str(user), + None => ~"", }; - let authority = if str::len(url.host) != 0 { - str::concat(~[~"//", user, copy url.host]) - } else { + + let authority = if url.host.is_empty() { ~"" + } else { + fmt!("//%s%s", user, url.host) }; - let query = if url.query.len() == 0 { + + let query = if url.query.is_empty() { ~"" } else { - str::concat(~[~"?", query_to_str(url.query)]) + fmt!("?%s", query_to_str(&url.query)) }; - // ugh, this really is safe - let fragment = if url.fragment.is_some() unsafe { - str::concat(~[~"#", encode_component( - option::unwrap(copy url.fragment))]) - } else { - ~"" + + let fragment = match url.fragment { + Some(ref fragment) => fmt!("#%s", encode_component(*fragment)), + None => ~"", }; - return str::concat(~[copy url.scheme, - ~":", - authority, - copy url.path, - query, - fragment]); + fmt!("%s:%s%s%s%s", url.scheme, authority, url.path, query, fragment) } impl Url: to_str::ToStr { pub pure fn to_str() -> ~str { - to_str(self) + to_str(&self) } } -impl Url : Eq { - pure fn eq(&self, other: &Url) -> bool { - (*self).scheme == (*other).scheme - && (*self).user == (*other).user - && (*self).host == (*other).host - && (*self).port == (*other).port - && (*self).path == (*other).path - && (*self).query == (*other).query - && (*self).fragment == (*other).fragment - } - - pure fn ne(&self, other: &Url) -> bool { - !(*self).eq(other) - } -} - -impl Url: IterBytes { +impl Url: to_bytes::IterBytes { pure fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { - unsafe { self.to_str() }.iter_bytes(lsb0, f) + self.to_str().iter_bytes(lsb0, f) } } @@ -769,81 +732,73 @@ mod tests { #[test] fn test_get_authority() { - let (u, h, p, r) = result::unwrap(get_authority( - ~"//user:pass@rust-lang.org/something")); - assert u == option::Some({user: ~"user", - pass: option::Some(~"pass")}); + let (u, h, p, r) = get_authority( + "//user:pass@rust-lang.org/something").unwrap(); + assert u == Some(UserInfo::new(~"user", Some(~"pass"))); assert h == ~"rust-lang.org"; assert p.is_none(); assert r == ~"/something"; - let (u, h, p, r) = result::unwrap(get_authority( - ~"//rust-lang.org:8000?something")); + let (u, h, p, r) = get_authority( + "//rust-lang.org:8000?something").unwrap(); assert u.is_none(); assert h == ~"rust-lang.org"; - assert p == option::Some(~"8000"); + assert p == Some(~"8000"); assert r == ~"?something"; - let (u, h, p, r) = result::unwrap(get_authority( - ~"//rust-lang.org#blah")); + let (u, h, p, r) = get_authority( + "//rust-lang.org#blah").unwrap(); assert u.is_none(); assert h == ~"rust-lang.org"; assert p.is_none(); assert r == ~"#blah"; // ipv6 tests - let (_, h, _, _) = result::unwrap(get_authority( - ~"//2001:0db8:85a3:0042:0000:8a2e:0370:7334#blah")); + let (_, h, _, _) = get_authority( + "//2001:0db8:85a3:0042:0000:8a2e:0370:7334#blah").unwrap(); assert h == ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334"; - let (_, h, p, _) = result::unwrap(get_authority( - ~"//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah")); + let (_, h, p, _) = get_authority( + "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah").unwrap(); assert h == ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334"; - assert p == option::Some(~"8000"); + assert p == Some(~"8000"); - let (u, h, p, _) = result::unwrap(get_authority( - ~"//us:p@2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah")); - assert u == option::Some({user: ~"us", pass : option::Some(~"p")}); + let (u, h, p, _) = get_authority( + "//us:p@2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah" + ).unwrap(); + assert u == Some(UserInfo::new(~"us", Some(~"p"))); assert h == ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334"; - assert p == option::Some(~"8000"); + assert p == Some(~"8000"); // invalid authorities; - assert result::is_err(&get_authority( - ~"//user:pass@rust-lang:something")); - assert result::is_err(&get_authority( - ~"//user@rust-lang:something:/path")); - assert result::is_err(&get_authority( - ~"//2001:0db8:85a3:0042:0000:8a2e:0370:7334:800a")); - assert result::is_err(&get_authority( - ~"//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000:00")); + assert get_authority("//user:pass@rust-lang:something").is_err(); + assert get_authority("//user@rust-lang:something:/path").is_err(); + assert get_authority( + "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:800a").is_err(); + assert get_authority( + "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000:00").is_err(); // these parse as empty, because they don't start with '//' - let (_, h, _, _) = result::unwrap( - get_authority(~"user:pass@rust-lang")); + let (_, h, _, _) = get_authority(~"user:pass@rust-lang").unwrap(); assert h == ~""; - let (_, h, _, _) = result::unwrap( - get_authority(~"rust-lang.org")); + let (_, h, _, _) = get_authority(~"rust-lang.org").unwrap(); assert h == ~""; - } #[test] fn test_get_path() { - let (p, r) = result::unwrap(get_path( - ~"/something+%20orother", true)); + let (p, r) = get_path("/something+%20orother", true).unwrap(); assert p == ~"/something+ orother"; assert r == ~""; - let (p, r) = result::unwrap(get_path( - ~"test@email.com#fragment", false)); + let (p, r) = get_path("test@email.com#fragment", false).unwrap(); assert p == ~"test@email.com"; assert r == ~"#fragment"; - let (p, r) = result::unwrap(get_path(~"/gen/:addr=?q=v", false)); + let (p, r) = get_path(~"/gen/:addr=?q=v", false).unwrap(); assert p == ~"/gen/:addr="; assert r == ~"?q=v"; //failure cases - assert result::is_err(&get_path(~"something?q", true)); - + assert get_path(~"something?q", true).is_err(); } #[test] @@ -851,22 +806,21 @@ mod tests { let url = ~"http://user:pass@rust-lang.org/doc?s=v#something"; let up = from_str(url); - let u = result::unwrap(up); + let u = up.unwrap(); assert u.scheme == ~"http"; - assert option::unwrap(copy u.user).user == ~"user"; - assert option::unwrap(copy option::unwrap(copy u.user).pass) - == ~"pass"; + let userinfo = u.user.get_ref(); + assert userinfo.user == ~"user"; + assert userinfo.pass.get_ref() == &~"pass"; assert u.host == ~"rust-lang.org"; assert u.path == ~"/doc"; - assert u.query.find(|kv| kv.first() == ~"s").get().second() == ~"v"; - assert option::unwrap(copy u.fragment) == ~"something"; + assert u.query == ~[(~"s", ~"v")]; + assert u.fragment.get_ref() == &~"something"; } #[test] fn test_url_parse_host_slash() { let urlstr = ~"http://0.42.42.42/"; - let url = from_str(urlstr).get(); - debug!("url: %?", url); + let url = from_str(urlstr).unwrap(); assert url.host == ~"0.42.42.42"; assert url.path == ~"/"; } @@ -874,98 +828,95 @@ mod tests { #[test] fn test_url_with_underscores() { let urlstr = ~"http://dotcom.com/file_name.html"; - let url = from_str(urlstr).get(); - debug!("url: %?", url); + let url = from_str(urlstr).unwrap(); assert url.path == ~"/file_name.html"; } #[test] fn test_url_with_dashes() { let urlstr = ~"http://dotcom.com/file-name.html"; - let url = from_str(urlstr).get(); - debug!("url: %?", url); + let url = from_str(urlstr).unwrap(); assert url.path == ~"/file-name.html"; } #[test] fn test_no_scheme() { - assert result::is_err(&get_scheme(~"noschemehere.html")); + assert get_scheme("noschemehere.html").is_err(); } #[test] fn test_invalid_scheme_errors() { - assert result::is_err(&from_str(~"99://something")); - assert result::is_err(&from_str(~"://something")); + assert from_str("99://something").is_err(); + assert from_str("://something").is_err(); } #[test] fn test_full_url_parse_and_format() { let url = ~"http://user:pass@rust-lang.org/doc?s=v#something"; - assert to_str(result::unwrap(from_str(url))) == url; + assert from_str(url).unwrap().to_str() == url; } #[test] fn test_userless_url_parse_and_format() { let url = ~"http://rust-lang.org/doc?s=v#something"; - assert to_str(result::unwrap(from_str(url))) == url; + assert from_str(url).unwrap().to_str() == url; } #[test] fn test_queryless_url_parse_and_format() { let url = ~"http://user:pass@rust-lang.org/doc#something"; - assert to_str(result::unwrap(from_str(url))) == url; + assert from_str(url).unwrap().to_str() == url; } #[test] fn test_empty_query_url_parse_and_format() { let url = ~"http://user:pass@rust-lang.org/doc?#something"; let should_be = ~"http://user:pass@rust-lang.org/doc#something"; - assert to_str(result::unwrap(from_str(url))) == should_be; + assert from_str(url).unwrap().to_str() == should_be; } #[test] fn test_fragmentless_url_parse_and_format() { let url = ~"http://user:pass@rust-lang.org/doc?q=v"; - assert to_str(result::unwrap(from_str(url))) == url; + assert from_str(url).unwrap().to_str() == url; } #[test] fn test_minimal_url_parse_and_format() { let url = ~"http://rust-lang.org/doc"; - assert to_str(result::unwrap(from_str(url))) == url; + assert from_str(url).unwrap().to_str() == url; } #[test] fn test_scheme_host_only_url_parse_and_format() { let url = ~"http://rust-lang.org"; - assert to_str(result::unwrap(from_str(url))) == url; + assert from_str(url).unwrap().to_str() == url; } #[test] fn test_pathless_url_parse_and_format() { let url = ~"http://user:pass@rust-lang.org?q=v#something"; - assert to_str(result::unwrap(from_str(url))) == url; + assert from_str(url).unwrap().to_str() == url; } #[test] fn test_scheme_host_fragment_only_url_parse_and_format() { let url = ~"http://rust-lang.org#something"; - assert to_str(result::unwrap(from_str(url))) == url; + assert from_str(url).unwrap().to_str() == url; } #[test] fn test_url_component_encoding() { let url = ~"http://rust-lang.org/doc%20uments?ba%25d%20=%23%26%2B"; - let u = result::unwrap(from_str(url)); + let u = from_str(url).unwrap(); assert u.path == ~"/doc uments"; - assert u.query.find(|kv| kv.first() == ~"ba%d ") - .get().second() == ~"#&+"; + assert u.query == ~[(~"ba%d ", ~"#&+")]; } #[test] fn test_url_without_authority() { let url = ~"mailto:test@email.com"; - assert to_str(result::unwrap(from_str(url))) == url; + assert from_str(url).unwrap().to_str() == url; } #[test] @@ -998,113 +949,114 @@ mod tests { #[test] fn test_encode_component() { - assert encode_component(~"") == ~""; - assert encode_component(~"http://example.com") == + assert encode_component("") == ~""; + assert encode_component("http://example.com") == ~"http%3A%2F%2Fexample.com"; - assert encode_component(~"foo bar% baz") == ~"foo%20bar%25%20baz"; - assert encode_component(~" ") == ~"%20"; - assert encode_component(~"!") == ~"%21"; - assert encode_component(~"#") == ~"%23"; - assert encode_component(~"$") == ~"%24"; - assert encode_component(~"%") == ~"%25"; - assert encode_component(~"&") == ~"%26"; - assert encode_component(~"'") == ~"%27"; - assert encode_component(~"(") == ~"%28"; - assert encode_component(~")") == ~"%29"; - assert encode_component(~"*") == ~"%2A"; - assert encode_component(~"+") == ~"%2B"; - assert encode_component(~",") == ~"%2C"; - assert encode_component(~"/") == ~"%2F"; - assert encode_component(~":") == ~"%3A"; - assert encode_component(~";") == ~"%3B"; - assert encode_component(~"=") == ~"%3D"; - assert encode_component(~"?") == ~"%3F"; - assert encode_component(~"@") == ~"%40"; - assert encode_component(~"[") == ~"%5B"; - assert encode_component(~"]") == ~"%5D"; + assert encode_component("foo bar% baz") == ~"foo%20bar%25%20baz"; + assert encode_component(" ") == ~"%20"; + assert encode_component("!") == ~"%21"; + assert encode_component("#") == ~"%23"; + assert encode_component("$") == ~"%24"; + assert encode_component("%") == ~"%25"; + assert encode_component("&") == ~"%26"; + assert encode_component("'") == ~"%27"; + assert encode_component("(") == ~"%28"; + assert encode_component(")") == ~"%29"; + assert encode_component("*") == ~"%2A"; + assert encode_component("+") == ~"%2B"; + assert encode_component(",") == ~"%2C"; + assert encode_component("/") == ~"%2F"; + assert encode_component(":") == ~"%3A"; + assert encode_component(";") == ~"%3B"; + assert encode_component("=") == ~"%3D"; + assert encode_component("?") == ~"%3F"; + assert encode_component("@") == ~"%40"; + assert encode_component("[") == ~"%5B"; + assert encode_component("]") == ~"%5D"; } #[test] fn test_decode() { - assert decode(~"") == ~""; - assert decode(~"abc/def 123") == ~"abc/def 123"; - assert decode(~"abc%2Fdef%20123") == ~"abc%2Fdef 123"; - assert decode(~"%20") == ~" "; - assert decode(~"%21") == ~"%21"; - assert decode(~"%22") == ~"%22"; - assert decode(~"%23") == ~"%23"; - assert decode(~"%24") == ~"%24"; - assert decode(~"%25") == ~"%"; - assert decode(~"%26") == ~"%26"; - assert decode(~"%27") == ~"'"; - assert decode(~"%28") == ~"%28"; - assert decode(~"%29") == ~"%29"; - assert decode(~"%2A") == ~"%2A"; - assert decode(~"%2B") == ~"%2B"; - assert decode(~"%2C") == ~"%2C"; - assert decode(~"%2F") == ~"%2F"; - assert decode(~"%3A") == ~"%3A"; - assert decode(~"%3B") == ~"%3B"; - assert decode(~"%3D") == ~"%3D"; - assert decode(~"%3F") == ~"%3F"; - assert decode(~"%40") == ~"%40"; - assert decode(~"%5B") == ~"%5B"; - assert decode(~"%5D") == ~"%5D"; + assert decode("") == ~""; + assert decode("abc/def 123") == ~"abc/def 123"; + assert decode("abc%2Fdef%20123") == ~"abc%2Fdef 123"; + assert decode("%20") == ~" "; + assert decode("%21") == ~"%21"; + assert decode("%22") == ~"%22"; + assert decode("%23") == ~"%23"; + assert decode("%24") == ~"%24"; + assert decode("%25") == ~"%"; + assert decode("%26") == ~"%26"; + assert decode("%27") == ~"'"; + assert decode("%28") == ~"%28"; + assert decode("%29") == ~"%29"; + assert decode("%2A") == ~"%2A"; + assert decode("%2B") == ~"%2B"; + assert decode("%2C") == ~"%2C"; + assert decode("%2F") == ~"%2F"; + assert decode("%3A") == ~"%3A"; + assert decode("%3B") == ~"%3B"; + assert decode("%3D") == ~"%3D"; + assert decode("%3F") == ~"%3F"; + assert decode("%40") == ~"%40"; + assert decode("%5B") == ~"%5B"; + assert decode("%5D") == ~"%5D"; } #[test] fn test_decode_component() { - assert decode_component(~"") == ~""; - assert decode_component(~"abc/def 123") == ~"abc/def 123"; - assert decode_component(~"abc%2Fdef%20123") == ~"abc/def 123"; - assert decode_component(~"%20") == ~" "; - assert decode_component(~"%21") == ~"!"; - assert decode_component(~"%22") == ~"\""; - assert decode_component(~"%23") == ~"#"; - assert decode_component(~"%24") == ~"$"; - assert decode_component(~"%25") == ~"%"; - assert decode_component(~"%26") == ~"&"; - assert decode_component(~"%27") == ~"'"; - assert decode_component(~"%28") == ~"("; - assert decode_component(~"%29") == ~")"; - assert decode_component(~"%2A") == ~"*"; - assert decode_component(~"%2B") == ~"+"; - assert decode_component(~"%2C") == ~","; - assert decode_component(~"%2F") == ~"/"; - assert decode_component(~"%3A") == ~":"; - assert decode_component(~"%3B") == ~";"; - assert decode_component(~"%3D") == ~"="; - assert decode_component(~"%3F") == ~"?"; - assert decode_component(~"%40") == ~"@"; - assert decode_component(~"%5B") == ~"["; - assert decode_component(~"%5D") == ~"]"; + assert decode_component("") == ~""; + assert decode_component("abc/def 123") == ~"abc/def 123"; + assert decode_component("abc%2Fdef%20123") == ~"abc/def 123"; + assert decode_component("%20") == ~" "; + assert decode_component("%21") == ~"!"; + assert decode_component("%22") == ~"\""; + assert decode_component("%23") == ~"#"; + assert decode_component("%24") == ~"$"; + assert decode_component("%25") == ~"%"; + assert decode_component("%26") == ~"&"; + assert decode_component("%27") == ~"'"; + assert decode_component("%28") == ~"("; + assert decode_component("%29") == ~")"; + assert decode_component("%2A") == ~"*"; + assert decode_component("%2B") == ~"+"; + assert decode_component("%2C") == ~","; + assert decode_component("%2F") == ~"/"; + assert decode_component("%3A") == ~":"; + assert decode_component("%3B") == ~";"; + assert decode_component("%3D") == ~"="; + assert decode_component("%3F") == ~"?"; + assert decode_component("%40") == ~"@"; + assert decode_component("%5B") == ~"["; + assert decode_component("%5D") == ~"]"; } #[test] fn test_encode_form_urlencoded() { - let m = HashMap(); - assert encode_form_urlencoded(m) == ~""; + let mut m = LinearMap(); + assert encode_form_urlencoded(&m) == ~""; - m.insert(~"", @DVec()); - m.insert(~"foo", @DVec()); - assert encode_form_urlencoded(m) == ~""; + m.insert(~"", ~[]); + m.insert(~"foo", ~[]); + assert encode_form_urlencoded(&m) == ~""; - let m = HashMap(); - m.insert(~"foo", @dvec::from_vec(~[@~"bar", @~"123"])); - assert encode_form_urlencoded(m) == ~"foo=bar&foo=123"; + let mut m = LinearMap(); + m.insert(~"foo", ~[~"bar", ~"123"]); + assert encode_form_urlencoded(&m) == ~"foo=bar&foo=123"; - let m = HashMap(); - m.insert(~"foo bar", @dvec::from_vec(~[@~"abc", @~"12 = 34"])); - assert encode_form_urlencoded(m) == ~"foo+bar=abc&foo+bar=12+%3D+34"; + let mut m = LinearMap(); + m.insert(~"foo bar", ~[~"abc", ~"12 = 34"]); + assert encode_form_urlencoded(&m) == ~"foo+bar=abc&foo+bar=12+%3D+34"; } #[test] fn test_decode_form_urlencoded() { - assert decode_form_urlencoded(~[]).size() == 0; + assert decode_form_urlencoded(~[]).len() == 0; - let s = str::to_bytes(~"a=1&foo+bar=abc&foo+bar=12+%3D+34"); - assert decode_form_urlencoded(s).size() == 2; + let s = str::to_bytes("a=1&foo+bar=abc&foo+bar=12+%3D+34"); + let form = decode_form_urlencoded(s); + assert form.len() == 2; + assert form.get_ref(&~"a") == &~[~"1"]; + assert form.get_ref(&~"foo bar") == &~[~"abc", ~"12 = 34"]; } - } -