std::net::url making scheme parsing compliant with rfc, give appropriate error messages, better split fn
This commit is contained in:
parent
e349201bc2
commit
d60dd6be87
1 changed files with 59 additions and 19 deletions
|
|
@ -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";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue