#[derive(Debug)]
pub enum RequestTarget<'a> {
Origin(&'a str),
Absolute {
scheme: &'a str,
authority: &'a str,
path: &'a str
},
Authority(&'a str),
Asterisk,
}
fn authority_end_char(&x: &u8) -> bool {
x == b'/' || x == b'?' || x == b'#' || x == b'@'
}
pub fn parse(s: &str) -> Option<RequestTarget> {
use self::RequestTarget::*;
if s.len() == 0 {
return None;
}
if s.starts_with("/") {
return Some(Origin(s));
}
if s.starts_with("http://") {
let auth_end = s[7..].as_bytes().iter()
.position(authority_end_char)
.unwrap_or(s.len()-7);
return Some(Absolute {
scheme: "http",
authority: &s[7..7+auth_end],
path: &s[7+auth_end..],
});
}
if s.starts_with("https://") {
let auth_end = s[8..].as_bytes().iter()
.position(authority_end_char)
.unwrap_or(s.len()-8);
return Some(Absolute {
scheme: "https",
authority: &s[8..8+auth_end],
path: &s[8+auth_end..],
});
}
if s == "*" {
return Some(Asterisk);
}
if s.as_bytes().iter().position(authority_end_char).is_none() {
return Some(Authority(s));
}
return None;
}
#[cfg(test)]
mod test {
use super::RequestTarget::*;
use super::parse;
#[test]
fn test_empty() {
assert_matches!(parse(""), None);
}
#[test]
fn test_path() {
assert_matches!(parse("/hello"),
Some(Origin("/hello")));
}
#[test]
fn test_path_query() {
assert_matches!(parse("/hello?xxx"),
Some(Origin("/hello?xxx")));
}
#[test]
fn test_star() {
assert_matches!(parse("*"), Some(Asterisk));
}
#[test]
fn test_strange_path() {
assert_matches!(parse("/http://x"),
Some(Origin("/http://x")));
}
#[test]
fn test_plain_authority_uri() {
assert_matches!(parse("http://x"),
Some(Absolute { scheme: "http", authority: "x",
path: "" }));
}
#[test]
fn test_uri() {
assert_matches!(parse("http://x/"),
Some(Absolute { scheme: "http", authority: "x",
path: "/" }));
}
#[test]
fn test_bigger_uri() {
assert_matches!(parse("http://x:932/hello?world"),
Some(Absolute { scheme: "http", authority: "x:932",
path: "/hello?world" }));
}
}