Skip to content

Commit

Permalink
feat(headers): return hyper::Error instead of () from header components
Browse files Browse the repository at this point in the history
This allows more precise errors in the future and makes it easier to use
the try!() macro in some cases.

BREAKING CHANGE: Error enum extended. Return type of header/shared/
types changed.
  • Loading branch information
pyfisch committed May 20, 2015
1 parent ca6cf2b commit 5d66939
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 46 deletions.
4 changes: 2 additions & 2 deletions src/header/shared/charset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ impl Display for Charset {
}

impl FromStr for Charset {
type Err = ();
fn from_str(s: &str) -> Result<Charset, ()> {
type Err = ::Error;
fn from_str(s: &str) -> ::Result<Charset> {
Ok(match s.to_ascii_uppercase().as_ref() {
"US-ASCII" => Us_Ascii,
"ISO-8859-1" => Iso_8859_1,
Expand Down
6 changes: 2 additions & 4 deletions src/header/shared/encoding.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//! Provides an Encoding enum.

use std::fmt;
use std::str;

Expand Down Expand Up @@ -37,8 +35,8 @@ impl fmt::Display for Encoding {
}

impl str::FromStr for Encoding {
type Err = ();
fn from_str(s: &str) -> Result<Encoding, ()> {
type Err = ::Error;
fn from_str(s: &str) -> ::Result<Encoding> {
match s {
"chunked" => Ok(Chunked),
"deflate" => Ok(Deflate),
Expand Down
20 changes: 10 additions & 10 deletions src/header/shared/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ impl Display for EntityTag {
}

impl FromStr for EntityTag {
type Err = ();
fn from_str(s: &str) -> Result<EntityTag, ()> {
type Err = ::Error;
fn from_str(s: &str) -> ::Result<EntityTag> {
let length: usize = s.len();
let slice = &s[..];
// Early exits if it doesn't terminate in a DQUOTE.
if !slice.ends_with('"') {
return Err(());
return Err(::Error::Header);
}
// The etag is weak if its first char is not a DQUOTE.
if slice.starts_with('"') && check_slice_validity(&slice[1..length-1]) {
Expand All @@ -123,7 +123,7 @@ impl FromStr for EntityTag {
} else if slice.starts_with("W/\"") && check_slice_validity(&slice[3..length-1]) {
return Ok(EntityTag { weak: true, tag: slice[3..length-1].to_owned() });
}
Err(())
Err(::Error::Header)
}
}

Expand All @@ -144,12 +144,12 @@ mod tests {
#[test]
fn test_etag_parse_failures() {
// Expected failures
assert_eq!("no-dquotes".parse::<EntityTag>(), Err(()));
assert_eq!("w/\"the-first-w-is-case-sensitive\"".parse::<EntityTag>(), Err(()));
assert_eq!("".parse::<EntityTag>(), Err(()));
assert_eq!("\"unmatched-dquotes1".parse::<EntityTag>(), Err(()));
assert_eq!("unmatched-dquotes2\"".parse::<EntityTag>(), Err(()));
assert_eq!("matched-\"dquotes\"".parse::<EntityTag>(), Err(()));
assert!("no-dquotes".parse::<EntityTag>().is_err());
assert!("w/\"the-first-w-is-case-sensitive\"".parse::<EntityTag>().is_err());
assert!("".parse::<EntityTag>().is_err());
assert!("\"unmatched-dquotes1".parse::<EntityTag>().is_err());
assert!("unmatched-dquotes2\"".parse::<EntityTag>().is_err());
assert!("matched-\"dquotes\"".parse::<EntityTag>().is_err());
}

#[test]
Expand Down
14 changes: 7 additions & 7 deletions src/header/shared/httpdate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ use time;
pub struct HttpDate(pub time::Tm);

impl FromStr for HttpDate {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
type Err = ::Error;
fn from_str(s: &str) -> ::Result<HttpDate> {
match time::strptime(s, "%a, %d %b %Y %T %Z").or_else(|_| {
time::strptime(s, "%A, %d-%b-%y %T %Z")
}).or_else(|_| {
time::strptime(s, "%c")
}) {
Ok(t) => Ok(HttpDate(t)),
Err(_) => Err(()),
Err(_) => Err(::Error::Header),
}
}
}
Expand Down Expand Up @@ -71,21 +71,21 @@ mod tests {

#[test]
fn test_imf_fixdate() {
assert_eq!("Sun, 07 Nov 1994 08:48:37 GMT".parse(), Ok(NOV_07));
assert_eq!("Sun, 07 Nov 1994 08:48:37 GMT".parse::<HttpDate>().unwrap(), NOV_07);
}

#[test]
fn test_rfc_850() {
assert_eq!("Sunday, 07-Nov-94 08:48:37 GMT".parse(), Ok(NOV_07));
assert_eq!("Sunday, 07-Nov-94 08:48:37 GMT".parse::<HttpDate>().unwrap(), NOV_07);
}

#[test]
fn test_asctime() {
assert_eq!("Sun Nov 7 08:48:37 1994".parse(), Ok(NOV_07));
assert_eq!("Sun Nov 7 08:48:37 1994".parse::<HttpDate>().unwrap(), NOV_07);
}

#[test]
fn test_no_date() {
assert_eq!("this-is-no-date".parse(), Err::<HttpDate, ()>(()));
assert!("this-is-no-date".parse::<HttpDate>().is_err());
}
}
6 changes: 3 additions & 3 deletions src/header/shared/language.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ pub struct Language {
}

impl FromStr for Language {
type Err = ();
fn from_str(s: &str) -> Result<Language, ()> {
type Err = ::Error;
fn from_str(s: &str) -> ::Result<Language> {
let mut i = s.split("-");
let p = i.next();
let s = i.next();
Expand All @@ -29,7 +29,7 @@ impl FromStr for Language {
primary: p.to_owned(),
sub: None
}),
_ => Err(())
_ => Err(::Error::Header)
}
}
}
Expand Down
38 changes: 18 additions & 20 deletions src/header/shared/quality_item.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
//! Provides a struct for quality values.
//!
//! [RFC7231 Section 5.3.1](https://tools.ietf.org/html/rfc7231#section-5.3.1)
//! gives more information on quality values in HTTP header fields.

use std::cmp;
use std::default::Default;
use std::fmt;
Expand All @@ -19,6 +14,9 @@ use std::str;
/// floating point data type (`f32`) consumes four bytes, hyper uses an `u16` value to store the
/// quality internally. For performance reasons you may set quality directly to a value between
/// 0 and 1000 e.g. `Quality(532)` matches the quality `q=0.532`.
///
/// [RFC7231 Section 5.3.1](https://tools.ietf.org/html/rfc7231#section-5.3.1)
/// gives more information on quality values in HTTP header fields.
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Quality(pub u16);

Expand Down Expand Up @@ -73,8 +71,8 @@ impl<T: fmt::Display> fmt::Display for QualityItem<T> {
}

impl<T: str::FromStr> str::FromStr for QualityItem<T> {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
type Err = ::Error;
fn from_str(s: &str) -> ::Result<QualityItem<T>> {
// Set defaults used if parsing fails.
let mut raw_item = s;
let mut quality = 1f32;
Expand All @@ -85,25 +83,25 @@ impl<T: str::FromStr> str::FromStr for QualityItem<T> {
if start == "q=" || start == "Q=" {
let q_part = &parts[0][2..parts[0].len()];
if q_part.len() > 5 {
return Err(());
return Err(::Error::Header);
}
match q_part.parse::<f32>() {
Ok(q_value) => {
if 0f32 <= q_value && q_value <= 1f32 {
quality = q_value;
raw_item = parts[1];
} else {
return Err(());
return Err(::Error::Header);
}
},
Err(_) => return Err(()),
Err(_) => return Err(::Error::Header),
}
}
}
match raw_item.parse::<T>() {
// we already checked above that the quality is within range
Ok(item) => Ok(QualityItem::new(item, from_f32(quality))),
Err(_) => return Err(()),
Err(_) => return Err(::Error::Header),
}
}
}
Expand Down Expand Up @@ -155,40 +153,40 @@ mod tests {

#[test]
fn test_quality_item_from_str1() {
let x: Result<QualityItem<Encoding>, ()> = "chunked".parse();
let x: ::Result<QualityItem<Encoding>> = "chunked".parse();
assert_eq!(x.unwrap(), QualityItem{ item: Chunked, quality: Quality(1000), });
}
#[test]
fn test_quality_item_from_str2() {
let x: Result<QualityItem<Encoding>, ()> = "chunked; q=1".parse();
let x: ::Result<QualityItem<Encoding>> = "chunked; q=1".parse();
assert_eq!(x.unwrap(), QualityItem{ item: Chunked, quality: Quality(1000), });
}
#[test]
fn test_quality_item_from_str3() {
let x: Result<QualityItem<Encoding>, ()> = "gzip; q=0.5".parse();
let x: ::Result<QualityItem<Encoding>> = "gzip; q=0.5".parse();
assert_eq!(x.unwrap(), QualityItem{ item: Gzip, quality: Quality(500), });
}
#[test]
fn test_quality_item_from_str4() {
let x: Result<QualityItem<Encoding>, ()> = "gzip; q=0.273".parse();
let x: ::Result<QualityItem<Encoding>> = "gzip; q=0.273".parse();
assert_eq!(x.unwrap(), QualityItem{ item: Gzip, quality: Quality(273), });
}
#[test]
fn test_quality_item_from_str5() {
let x: Result<QualityItem<Encoding>, ()> = "gzip; q=0.2739999".parse();
assert_eq!(x, Err(()));
let x: ::Result<QualityItem<Encoding>> = "gzip; q=0.2739999".parse();
assert!(x.is_err());
}
#[test]
fn test_quality_item_from_str6() {
let x: Result<QualityItem<Encoding>, ()> = "gzip; q=2".parse();
assert_eq!(x, Err(()));
let x: ::Result<QualityItem<Encoding>> = "gzip; q=2".parse();
assert!(x.is_err());
}
#[test]
fn test_quality_item_ordering() {
let x: QualityItem<Encoding> = "gzip; q=0.5".parse().ok().unwrap();
let y: QualityItem<Encoding> = "gzip; q=0.273".parse().ok().unwrap();
let comparision_result: bool = x.gt(&y);
assert_eq!(comparision_result, true)
assert!(comparision_result)
}

#[test]
Expand Down

0 comments on commit 5d66939

Please sign in to comment.