Skip to content

Commit

Permalink
Merge branch 'master' of github.com:hyperium/hyper
Browse files Browse the repository at this point in the history
  • Loading branch information
lame-nickname committed Jun 14, 2015
2 parents d503bd6 + c37d857 commit 287dc39
Show file tree
Hide file tree
Showing 30 changed files with 407 additions and 156 deletions.
7 changes: 6 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Contributing to Hyper

You want to contribute? You're awesome! When submitting a Pull Request, please have your commits follow these guidelines:
You want to contribute? You're awesome! Don't know where to start? Check the [easy tag][].

[easy tag]: https://github.com/hyperium/hyper/issues/labels/easy

When submitting a Pull Request, please have your commits follow these guidelines:


## Git Commit Guidelines

Expand Down
5 changes: 2 additions & 3 deletions benches/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ impl hyper::header::Header for Foo {
fn header_name() -> &'static str {
"x-foo"
}
fn parse_header(_: &[Vec<u8>]) -> Option<Foo> {
None
fn parse_header(_: &[Vec<u8>]) -> hyper::Result<Foo> {
Err(hyper::Error::Header)
}
}

Expand Down Expand Up @@ -104,4 +104,3 @@ fn bench_mock_hyper(b: &mut test::Bencher) {
.read_to_string(&mut s).unwrap()
});
}

2 changes: 1 addition & 1 deletion examples/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn main() {
}
};

let mut client = Client::new();
let client = Client::new();

let mut res = client.get(&*url)
.header(Connection::close())
Expand Down
2 changes: 1 addition & 1 deletion examples/client_http2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn main() {
}
};

let mut client = Client::with_protocol(h2::new_protocol());
let client = Client::with_protocol(h2::new_protocol());

// `Connection: Close` is not a valid header for HTTP/2, but the client handles it gracefully.
let mut res = client.get(&*url)
Expand Down
46 changes: 35 additions & 11 deletions src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//!
//! ```no_run
//! # use hyper::Client;
//! let mut client = Client::new();
//! let client = Client::new();
//!
//! let res = client.get("http://example.domain").send().unwrap();
//! assert_eq!(res.status, hyper::Ok);
Expand All @@ -23,14 +23,38 @@
//!
//! ```no_run
//! # use hyper::Client;
//! let mut client = Client::new();
//! let client = Client::new();
//!
//! let res = client.post("http://example.domain")
//! .body("foo=bar")
//! .send()
//! .unwrap();
//! assert_eq!(res.status, hyper::Ok);
//! ```
//!
//! # Sync
//!
//! The `Client` implements `Sync`, so you can share it among multiple threads
//! and make multiple requests simultaneously.
//!
//! ```no_run
//! # use hyper::Client;
//! use std::sync::Arc;
//! use std::thread;
//!
//! // Note: an Arc is used here because `thread::spawn` creates threads that
//! // can outlive the main thread, so we must use reference counting to keep
//! // the Client alive long enough. Scoped threads could skip the Arc.
//! let client = Arc::new(Client::new());
//! let clone1 = client.clone();
//! let clone2 = client.clone();
//! thread::spawn(move || {
//! clone1.get("http://example.domain").send().unwrap();
//! });
//! thread::spawn(move || {
//! clone2.post("http://example.domain/post").body("foo=bar").send().unwrap();
//! });
//! ```
use std::default::Default;
use std::io::{self, copy, Read};
use std::iter::Extend;
Expand Down Expand Up @@ -61,7 +85,7 @@ use http::h1::Http11Protocol;
///
/// Clients can handle things such as: redirect policy, connection pooling.
pub struct Client {
protocol: Box<Protocol + Send>,
protocol: Box<Protocol + Send + Sync>,
redirect_policy: RedirectPolicy,
}

Expand All @@ -79,12 +103,12 @@ impl Client {

/// Create a new client with a specific connector.
pub fn with_connector<C, S>(connector: C) -> Client
where C: NetworkConnector<Stream=S> + Send + 'static, S: NetworkStream + Send {
where C: NetworkConnector<Stream=S> + Send + Sync + 'static, S: NetworkStream + Send {
Client::with_protocol(Http11Protocol::with_connector(connector))
}

/// Create a new client with a specific `Protocol`.
pub fn with_protocol<P: Protocol + Send + 'static>(protocol: P) -> Client {
pub fn with_protocol<P: Protocol + Send + Sync + 'static>(protocol: P) -> Client {
Client {
protocol: Box::new(protocol),
redirect_policy: Default::default()
Expand All @@ -102,33 +126,33 @@ impl Client {
}

/// Build a Get request.
pub fn get<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> {
self.request(Method::Get, url)
}

/// Build a Head request.
pub fn head<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> {
self.request(Method::Head, url)
}

/// Build a Post request.
pub fn post<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> {
self.request(Method::Post, url)
}

/// Build a Put request.
pub fn put<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> {
self.request(Method::Put, url)
}

/// Build a Delete request.
pub fn delete<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> {
self.request(Method::Delete, url)
}


/// Build a new request using this Client.
pub fn request<U: IntoUrl>(&mut self, method: Method, url: U) -> RequestBuilder<U> {
pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder<U> {
RequestBuilder {
client: self,
method: method,
Expand Down
11 changes: 11 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;
use std::str::Utf8Error;

use httparse;
use openssl::ssl::error::SslError;
Expand All @@ -18,6 +19,7 @@ use self::Error::{
Ssl,
TooLarge,
Http2,
Utf8
};


Expand Down Expand Up @@ -45,6 +47,8 @@ pub enum Error {
Ssl(SslError),
/// An HTTP/2-specific error, coming from the `solicit` library.
Http2(Http2Error),
/// Parsing a field as string failed
Utf8(Utf8Error),

#[doc(hidden)]
__Nonexhaustive(Void)
Expand Down Expand Up @@ -77,6 +81,7 @@ impl StdError for Error {
Io(ref e) => e.description(),
Ssl(ref e) => e.description(),
Http2(ref e) => e.description(),
Utf8(ref e) => e.description(),
Error::__Nonexhaustive(ref void) => match *void {}
}
}
Expand Down Expand Up @@ -113,6 +118,12 @@ impl From<SslError> for Error {
}
}

impl From<Utf8Error> for Error {
fn from(err: Utf8Error) -> Error {
Utf8(err)
}
}

impl From<httparse::Error> for Error {
fn from(err: httparse::Error) -> Error {
match err {
Expand Down
4 changes: 2 additions & 2 deletions src/header/common/accept_ranges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
12 changes: 5 additions & 7 deletions src/header/common/access_control_allow_origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
}
}

Expand Down
37 changes: 22 additions & 15 deletions src/header/common/authorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
}
Expand Down Expand Up @@ -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()),
Expand All @@ -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)
}
}
}
Expand Down
20 changes: 10 additions & 10 deletions src/header/common/cache_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Expand Down Expand Up @@ -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)
}
}

Expand Down
Loading

0 comments on commit 287dc39

Please sign in to comment.