std::net::url making scheme parsing compliant with rfc, give appropriate error messages, better split fn

This commit is contained in:
Daniel Patterson 2012-07-25 22:40:31 -04:00 committed by Brian Anderson
parent e349201bc2
commit d60dd6be87

View file

@ -263,11 +263,25 @@ fn decode_form_urlencoded(s: ~[u8]) -> hashmap<~str, @dvec<@~str>> {
fn split_char_first(s: ~str, c: char) -> (~str, ~str) {
let mut v = str::splitn_char(s, c, 1);
if v.len() == 1 {
return (s, ~"");
let len = str::len(s);
let mut index = len;
let mut match_ = 0;
do io::with_str_reader(s) |rdr| {
let mut ch : char;
while !rdr.eof() {
ch = rdr.read_byte() as char;
if ch == c {
// found a match, adjust markers
index = rdr.tell()-1;
match_ = 1;
break;
}
}
}
if index+match_ == len {
return (str::slice(s, 0, index), ~"");
} else {
return (vec::shift(v), vec::pop(v));
return (str::slice(s, 0, index), str::slice(s, index + match_, str::len(s)));
}
}
@ -311,18 +325,30 @@ fn query_to_str(query: query) -> ~str {
return str::connect(strvec, ~"&");
}
fn get_scheme(rawurl: ~str) -> option::option<(~str, ~str)> {
fn get_scheme(rawurl: ~str) -> result::result<(~str, ~str), @~str> {
for str::each_chari(rawurl) |i,c| {
if char::is_alphabetic(c) {
alt c {
'A' to 'Z' | 'a' to 'z' { again; }
'0' to '9' | '+' | '-' | '.' {
if i == 0 {
return result::err(@~"url: Scheme must begin with a letter.");
}
again;
} else if c == ':' && i != 0 {
return option::some((rawurl.slice(0,i),
rawurl.slice(i+3,str::len(rawurl))));
} else {
return option::none;
}
':' {
if i == 0 {
return result::err(@~"url: Scheme cannot be empty.");
} else {
return result::ok((rawurl.slice(0,i),
rawurl.slice(i+3,str::len(rawurl))));
}
}
_ {
return result::err(@~"url: Invalid character in scheme.");
}
}
};
return option::none;
return result::ok((copy rawurl, ~""));
}
/**
@ -340,10 +366,10 @@ fn get_scheme(rawurl: ~str) -> option::option<(~str, ~str)> {
fn from_str(rawurl: ~str) -> result::result<url, ~str> {
let mut schm = get_scheme(rawurl);
if option::is_none(schm) {
return result::err(~"invalid scheme");
if result::is_err(schm) {
return result::err(copy *result::get_err(schm));
}
let (scheme, rest) = option::unwrap(schm);
let (scheme, rest) = result::unwrap(schm);
let (u, rest) = split_char_first(rest, '@');
let user = if str::len(rest) == 0 {
option::none
@ -421,18 +447,32 @@ impl of to_str::to_str for url {
#[cfg(test)]
mod tests {
#[test]
fn test_split_char_first() {
let (u,v) = split_char_first(~"hello, sweet world", ',');
assert u == ~"hello";
assert v == ~" sweet world";
}
#[test]
fn test_url_parse() {
let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
let u = result::unwrap(from_str(url));
assert u.scheme == ~"http";
assert option::unwrap(u.user).user == ~"user";
assert option::unwrap(option::unwrap(u.user).pass) == ~"pass";
assert option::unwrap(copy u.user).user == ~"user";
assert option::unwrap(copy option::unwrap(copy u.user).pass) == ~"pass";
assert u.host == ~"rust-lang.org";
assert u.path == ~"/doc";
assert u.query.get(~"s") == ~"v";
assert option::unwrap(u.fragment) == "something";
assert u.query.find(|kv| kv.first() == ~"s").get().second() == ~"v";
assert option::unwrap(copy u.fragment) == ~"something";
}
#[test]
fn test_invalid_scheme_errors() {
assert result::is_err(from_str(~"99://something"));
assert result::is_err(from_str(~"://something"));
}
#[test]
fn test_full_url_parse_and_format() {
let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";