refactor(headers): errors for parse_header
Header::parse_header() returns now a hyper Result instead of an option this will enable more precise Error messages in the future, currently most failures are reported as ::Error::Header. BREAKING CHANGE: parse_header returns Result instead of Option, related code did also change
This commit is contained in:
@@ -52,8 +52,8 @@ pub enum RangeUnit {
|
||||
|
||||
|
||||
impl FromStr for RangeUnit {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Self, ()> {
|
||||
type Err = ::Error;
|
||||
fn from_str(s: &str) -> ::Result<Self> {
|
||||
match s {
|
||||
"bytes" => Ok(RangeUnit::Bytes),
|
||||
"none" => Ok(RangeUnit::None),
|
||||
|
||||
@@ -35,16 +35,14 @@ impl Header for AccessControlAllowOrigin {
|
||||
"Access-Control-Allow-Origin"
|
||||
}
|
||||
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<AccessControlAllowOrigin> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<AccessControlAllowOrigin> {
|
||||
if raw.len() == 1 {
|
||||
match unsafe { &raw.get_unchecked(0)[..] } {
|
||||
b"*" => Some(AccessControlAllowOrigin::Any),
|
||||
b"null" => Some(AccessControlAllowOrigin::Null),
|
||||
r => if let Ok(s) = str::from_utf8(r) {
|
||||
Url::parse(s).ok().map(AccessControlAllowOrigin::Value)
|
||||
} else { None }
|
||||
b"*" => Ok(AccessControlAllowOrigin::Any),
|
||||
b"null" => Ok(AccessControlAllowOrigin::Null),
|
||||
r => Ok(AccessControlAllowOrigin::Value(try!(Url::parse(try!(str::from_utf8(r))))))
|
||||
}
|
||||
} else { None }
|
||||
} else { Err(::Error::Header) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,18 +42,25 @@ impl<S: Scheme + Any> Header for Authorization<S> where <S as FromStr>::Err: 'st
|
||||
"Authorization"
|
||||
}
|
||||
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<Authorization<S>> {
|
||||
if raw.len() == 1 {
|
||||
match (from_utf8(unsafe { &raw.get_unchecked(0)[..] }), <S as Scheme>::scheme()) {
|
||||
(Ok(header), Some(scheme))
|
||||
if header.starts_with(scheme) && header.len() > scheme.len() + 1 => {
|
||||
header[scheme.len() + 1..].parse::<S>().map(Authorization).ok()
|
||||
},
|
||||
(Ok(header), None) => header.parse::<S>().map(Authorization).ok(),
|
||||
_ => None
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Authorization<S>> {
|
||||
if raw.len() != 1 {
|
||||
return Err(::Error::Header);
|
||||
}
|
||||
let header = try!(from_utf8(unsafe { &raw.get_unchecked(0)[..] }));
|
||||
return if let Some(scheme) = <S as Scheme>::scheme() {
|
||||
if header.starts_with(scheme) && header.len() > scheme.len() + 1 {
|
||||
match header[scheme.len() + 1..].parse::<S>().map(Authorization) {
|
||||
Ok(h) => Ok(h),
|
||||
Err(_) => Err(::Error::Header)
|
||||
}
|
||||
} else {
|
||||
Err(::Error::Header)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
match header.parse::<S>().map(Authorization) {
|
||||
Ok(h) => Ok(h),
|
||||
Err(_) => Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,15 +128,15 @@ impl Scheme for Basic {
|
||||
}
|
||||
|
||||
impl FromStr for Basic {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Basic, ()> {
|
||||
type Err = ::Error;
|
||||
fn from_str(s: &str) -> ::Result<Basic> {
|
||||
match s.from_base64() {
|
||||
Ok(decoded) => match String::from_utf8(decoded) {
|
||||
Ok(text) => {
|
||||
let mut parts = &mut text.split(':');
|
||||
let user = match parts.next() {
|
||||
Some(part) => part.to_owned(),
|
||||
None => return Err(())
|
||||
None => return Err(::Error::Header)
|
||||
};
|
||||
let password = match parts.next() {
|
||||
Some(part) => Some(part.to_owned()),
|
||||
@@ -142,12 +149,12 @@ impl FromStr for Basic {
|
||||
},
|
||||
Err(e) => {
|
||||
debug!("Basic::from_utf8 error={:?}", e);
|
||||
Err(())
|
||||
Err(::Error::Header)
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
debug!("Basic::from_base64 error={:?}", e);
|
||||
Err(())
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,15 +30,15 @@ impl Header for CacheControl {
|
||||
"Cache-Control"
|
||||
}
|
||||
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<CacheControl> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<CacheControl> {
|
||||
let directives = raw.iter()
|
||||
.filter_map(|line| from_one_comma_delimited(&line[..]))
|
||||
.filter_map(|line| from_one_comma_delimited(&line[..]).ok())
|
||||
.collect::<Vec<Vec<CacheDirective>>>()
|
||||
.concat();
|
||||
if !directives.is_empty() {
|
||||
Some(CacheControl(directives))
|
||||
Ok(CacheControl(directives))
|
||||
} else {
|
||||
None
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,35 +148,35 @@ mod tests {
|
||||
#[test]
|
||||
fn test_parse_multiple_headers() {
|
||||
let cache = Header::parse_header(&[b"no-cache".to_vec(), b"private".to_vec()]);
|
||||
assert_eq!(cache, Some(CacheControl(vec![CacheDirective::NoCache,
|
||||
assert_eq!(cache.ok(), Some(CacheControl(vec![CacheDirective::NoCache,
|
||||
CacheDirective::Private])))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_argument() {
|
||||
let cache = Header::parse_header(&[b"max-age=100, private".to_vec()]);
|
||||
assert_eq!(cache, Some(CacheControl(vec![CacheDirective::MaxAge(100),
|
||||
assert_eq!(cache.ok(), Some(CacheControl(vec![CacheDirective::MaxAge(100),
|
||||
CacheDirective::Private])))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_quote_form() {
|
||||
let cache = Header::parse_header(&[b"max-age=\"200\"".to_vec()]);
|
||||
assert_eq!(cache, Some(CacheControl(vec![CacheDirective::MaxAge(200)])))
|
||||
assert_eq!(cache.ok(), Some(CacheControl(vec![CacheDirective::MaxAge(200)])))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_extension() {
|
||||
let cache = Header::parse_header(&[b"foo, bar=baz".to_vec()]);
|
||||
assert_eq!(cache, Some(CacheControl(vec![
|
||||
assert_eq!(cache.ok(), Some(CacheControl(vec![
|
||||
CacheDirective::Extension("foo".to_owned(), None),
|
||||
CacheDirective::Extension("bar".to_owned(), Some("baz".to_owned()))])))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_bad_syntax() {
|
||||
let cache: Option<CacheControl> = Header::parse_header(&[b"foo=".to_vec()]);
|
||||
assert_eq!(cache, None)
|
||||
let cache: ::Result<CacheControl> = Header::parse_header(&[b"foo=".to_vec()]);
|
||||
assert_eq!(cache.ok(), None)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,26 +27,23 @@ impl Header for Cookie {
|
||||
"Cookie"
|
||||
}
|
||||
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<Cookie> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Cookie> {
|
||||
let mut cookies = Vec::with_capacity(raw.len());
|
||||
for cookies_raw in raw.iter() {
|
||||
match from_utf8(&cookies_raw[..]) {
|
||||
Ok(cookies_str) => {
|
||||
for cookie_str in cookies_str.split(';') {
|
||||
match cookie_str.trim().parse() {
|
||||
Ok(cookie) => cookies.push(cookie),
|
||||
Err(_) => return None
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(_) => return None
|
||||
};
|
||||
let cookies_str = try!(from_utf8(&cookies_raw[..]));
|
||||
for cookie_str in cookies_str.split(';') {
|
||||
if let Ok(cookie) = cookie_str.trim().parse() {
|
||||
cookies.push(cookie);
|
||||
} else {
|
||||
return Err(::Error::Header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !cookies.is_empty() {
|
||||
Some(Cookie(cookies))
|
||||
Ok(Cookie(cookies))
|
||||
} else {
|
||||
None
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,7 +85,7 @@ fn test_parse() {
|
||||
let h = Header::parse_header(&[b"foo=bar; baz=quux".to_vec()][..]);
|
||||
let c1 = CookiePair::new("foo".to_owned(), "bar".to_owned());
|
||||
let c2 = CookiePair::new("baz".to_owned(), "quux".to_owned());
|
||||
assert_eq!(h, Some(Cookie(vec![c1, c2])));
|
||||
assert_eq!(h.ok(), Some(Cookie(vec![c1, c2])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -26,7 +26,7 @@ impl Header for Expect {
|
||||
"Expect"
|
||||
}
|
||||
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<Expect> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Expect> {
|
||||
if raw.len() == 1 {
|
||||
let text = unsafe {
|
||||
// safe because:
|
||||
@@ -38,12 +38,12 @@ impl Header for Expect {
|
||||
str::from_utf8_unchecked(raw.get_unchecked(0))
|
||||
};
|
||||
if UniCase(text) == EXPECT_CONTINUE {
|
||||
Some(Expect::Continue)
|
||||
Ok(Expect::Continue)
|
||||
} else {
|
||||
None
|
||||
Err(::Error::Header)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ impl Header for Host {
|
||||
"Host"
|
||||
}
|
||||
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<Host> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Host> {
|
||||
from_one_raw_str(raw).and_then(|mut s: String| {
|
||||
// FIXME: use rust-url to parse this
|
||||
// https://github.com/servo/rust-url/issues/42
|
||||
@@ -39,7 +39,7 @@ impl Header for Host {
|
||||
None
|
||||
}
|
||||
}
|
||||
None => return None // this is a bad ipv6 address...
|
||||
None => return Err(::Error::Header) // this is a bad ipv6 address...
|
||||
}
|
||||
} else {
|
||||
slice.rfind(':')
|
||||
@@ -56,7 +56,7 @@ impl Header for Host {
|
||||
None => ()
|
||||
}
|
||||
|
||||
Some(Host {
|
||||
Ok(Host {
|
||||
hostname: s,
|
||||
port: port
|
||||
})
|
||||
@@ -82,14 +82,14 @@ mod tests {
|
||||
#[test]
|
||||
fn test_host() {
|
||||
let host = Header::parse_header([b"foo.com".to_vec()].as_ref());
|
||||
assert_eq!(host, Some(Host {
|
||||
assert_eq!(host.ok(), Some(Host {
|
||||
hostname: "foo.com".to_owned(),
|
||||
port: None
|
||||
}));
|
||||
|
||||
|
||||
let host = Header::parse_header([b"foo.com:8080".to_vec()].as_ref());
|
||||
assert_eq!(host, Some(Host {
|
||||
assert_eq!(host.ok(), Some(Host {
|
||||
hostname: "foo.com".to_owned(),
|
||||
port: Some(8080)
|
||||
}));
|
||||
|
||||
@@ -45,10 +45,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_if_none_match() {
|
||||
let mut if_none_match: Option<IfNoneMatch>;
|
||||
let mut if_none_match: ::Result<IfNoneMatch>;
|
||||
|
||||
if_none_match = Header::parse_header([b"*".to_vec()].as_ref());
|
||||
assert_eq!(if_none_match, Some(IfNoneMatch::Any));
|
||||
assert_eq!(if_none_match.ok(), Some(IfNoneMatch::Any));
|
||||
|
||||
if_none_match = Header::parse_header([b"\"foobar\", W/\"weak-etag\"".to_vec()].as_ref());
|
||||
let mut entities: Vec<EntityTag> = Vec::new();
|
||||
@@ -56,7 +56,7 @@ mod tests {
|
||||
let weak_etag = EntityTag::new(true, "weak-etag".to_owned());
|
||||
entities.push(foobar_etag);
|
||||
entities.push(weak_etag);
|
||||
assert_eq!(if_none_match, Some(IfNoneMatch::Items(entities)));
|
||||
assert_eq!(if_none_match.ok(), Some(IfNoneMatch::Items(entities)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,16 +36,16 @@ impl Header for IfRange {
|
||||
fn header_name() -> &'static str {
|
||||
"If-Range"
|
||||
}
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<IfRange> {
|
||||
let etag: Option<EntityTag> = header::parsing::from_one_raw_str(raw);
|
||||
if etag != None {
|
||||
return Some(IfRange::EntityTag(etag.unwrap()));
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<IfRange> {
|
||||
let etag: ::Result<EntityTag> = header::parsing::from_one_raw_str(raw);
|
||||
if etag.is_ok() {
|
||||
return Ok(IfRange::EntityTag(etag.unwrap()));
|
||||
}
|
||||
let date: Option<HttpDate> = header::parsing::from_one_raw_str(raw);
|
||||
if date != None {
|
||||
return Some(IfRange::Date(date.unwrap()));
|
||||
let date: ::Result<HttpDate> = header::parsing::from_one_raw_str(raw);
|
||||
if date.is_ok() {
|
||||
return Ok(IfRange::Date(date.unwrap()));
|
||||
}
|
||||
None
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ macro_rules! test_header {
|
||||
let a: Vec<Vec<u8>> = $raw.iter().map(|x| x.to_vec()).collect();
|
||||
let val = HeaderField::parse_header(&a[..]);
|
||||
// Test parsing
|
||||
assert_eq!(val, $typed);
|
||||
assert_eq!(val.ok(), $typed);
|
||||
// Test formatting
|
||||
if $typed != None {
|
||||
let res: &str = str::from_utf8($raw[0]).unwrap();
|
||||
@@ -171,7 +171,7 @@ macro_rules! header {
|
||||
fn header_name() -> &'static str {
|
||||
$n
|
||||
}
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
|
||||
$crate::header::parsing::from_comma_delimited(raw).map($id)
|
||||
}
|
||||
}
|
||||
@@ -197,7 +197,7 @@ macro_rules! header {
|
||||
fn header_name() -> &'static str {
|
||||
$n
|
||||
}
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
|
||||
$crate::header::parsing::from_comma_delimited(raw).map($id)
|
||||
}
|
||||
}
|
||||
@@ -223,7 +223,7 @@ macro_rules! header {
|
||||
fn header_name() -> &'static str {
|
||||
$n
|
||||
}
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
|
||||
$crate::header::parsing::from_one_raw_str(raw).map($id)
|
||||
}
|
||||
}
|
||||
@@ -252,11 +252,11 @@ macro_rules! header {
|
||||
fn header_name() -> &'static str {
|
||||
$n
|
||||
}
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<Self> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
|
||||
// FIXME: Return None if no item is in $id::Only
|
||||
if raw.len() == 1 {
|
||||
if raw[0] == b"*" {
|
||||
return Some($id::Any)
|
||||
return Ok($id::Any)
|
||||
}
|
||||
}
|
||||
$crate::header::parsing::from_comma_delimited(raw).map(|vec| $id::Items(vec))
|
||||
|
||||
@@ -29,12 +29,12 @@ impl Header for Pragma {
|
||||
"Pragma"
|
||||
}
|
||||
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<Pragma> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Pragma> {
|
||||
parsing::from_one_raw_str(raw).and_then(|s: String| {
|
||||
let slice = &s.to_ascii_lowercase()[..];
|
||||
match slice {
|
||||
"no-cache" => Some(Pragma::NoCache),
|
||||
_ => Some(Pragma::Ext(s)),
|
||||
"no-cache" => Ok(Pragma::NoCache),
|
||||
_ => Ok(Pragma::Ext(s)),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -57,6 +57,6 @@ fn test_parse_header() {
|
||||
let c: Pragma = Header::parse_header([b"FoObar".to_vec()].as_ref()).unwrap();
|
||||
let d = Pragma::Ext("FoObar".to_owned());
|
||||
assert_eq!(c, d);
|
||||
let e: Option<Pragma> = Header::parse_header([b"".to_vec()].as_ref());
|
||||
assert_eq!(e, None);
|
||||
let e: ::Result<Pragma> = Header::parse_header([b"".to_vec()].as_ref());
|
||||
assert_eq!(e.ok(), None);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ impl Header for SetCookie {
|
||||
"Set-Cookie"
|
||||
}
|
||||
|
||||
fn parse_header(raw: &[Vec<u8>]) -> Option<SetCookie> {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<SetCookie> {
|
||||
let mut set_cookies = Vec::with_capacity(raw.len());
|
||||
for set_cookies_raw in raw {
|
||||
if let Ok(s) = from_utf8(&set_cookies_raw[..]) {
|
||||
@@ -75,9 +75,9 @@ impl Header for SetCookie {
|
||||
}
|
||||
|
||||
if !set_cookies.is_empty() {
|
||||
Some(SetCookie(set_cookies))
|
||||
Ok(SetCookie(set_cookies))
|
||||
} else {
|
||||
None
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ fn test_parse() {
|
||||
let mut c1 = Cookie::new("foo".to_owned(), "bar".to_owned());
|
||||
c1.httponly = true;
|
||||
|
||||
assert_eq!(h, Some(SetCookie(vec![c1])));
|
||||
assert_eq!(h.ok(), Some(SetCookie(vec![c1])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -45,8 +45,8 @@ header! {
|
||||
Some(Upgrade(vec![Protocol::new(ProtocolName::WebSocket, None)])));
|
||||
#[test]
|
||||
fn test3() {
|
||||
let x: Option<Upgrade> = Header::parse_header(&[b"WEbSOCKet".to_vec()]);
|
||||
assert_eq!(x, Some(Upgrade(vec![Protocol::new(ProtocolName::WebSocket, None)])));
|
||||
let x: ::Result<Upgrade> = Header::parse_header(&[b"WEbSOCKet".to_vec()]);
|
||||
assert_eq!(x.ok(), Some(Upgrade(vec![Protocol::new(ProtocolName::WebSocket, None)])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,15 +24,15 @@ header! {
|
||||
|
||||
#[test]
|
||||
fn test2() {
|
||||
let mut vary: Option<Vary>;
|
||||
let mut vary: ::Result<Vary>;
|
||||
|
||||
vary = Header::parse_header([b"*".to_vec()].as_ref());
|
||||
assert_eq!(vary, Some(Vary::Any));
|
||||
assert_eq!(vary.ok(), Some(Vary::Any));
|
||||
|
||||
vary = Header::parse_header([b"etag,cookie,allow".to_vec()].as_ref());
|
||||
assert_eq!(vary, Some(Vary::Items(vec!["eTag".parse().unwrap(),
|
||||
"cookIE".parse().unwrap(),
|
||||
"AlLOw".parse().unwrap(),])));
|
||||
assert_eq!(vary.ok(), Some(Vary::Items(vec!["eTag".parse().unwrap(),
|
||||
"cookIE".parse().unwrap(),
|
||||
"AlLOw".parse().unwrap(),])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user