| @@ -30,7 +30,7 @@ use openssl::ssl::VerifyCallback; | ||||
| use header::{Headers, Header, HeaderFormat}; | ||||
| use header::common::{ContentLength, Location}; | ||||
| use method::Method; | ||||
| use net::{NetworkConnector, NetworkStream, HttpConnector}; | ||||
| use net::{NetworkConnector, HttpConnector}; | ||||
| use status::StatusClass::Redirection; | ||||
| use {Url, Port, HttpResult}; | ||||
| use HttpError::HttpUriError; | ||||
| @@ -63,8 +63,7 @@ impl Client<HttpConnector> { | ||||
|  | ||||
| } | ||||
|  | ||||
| #[old_impl_check] | ||||
| impl<C: NetworkConnector<S>, S: NetworkStream> Client<C> { | ||||
| impl<C: NetworkConnector> Client<C> { | ||||
|  | ||||
|     /// Create a new client with a specific connector. | ||||
|     pub fn with_connector(connector: C) -> Client<C> { | ||||
| @@ -80,33 +79,33 @@ impl<C: NetworkConnector<S>, S: NetworkStream> Client<C> { | ||||
|     } | ||||
|  | ||||
|     /// Execute a Get request. | ||||
|     pub fn get<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C, S> { | ||||
|     pub fn get<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C> { | ||||
|         self.request(Method::Get, url) | ||||
|     } | ||||
|  | ||||
|     /// Execute a Head request. | ||||
|     pub fn head<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C, S> { | ||||
|     pub fn head<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C> { | ||||
|         self.request(Method::Head, url) | ||||
|     } | ||||
|  | ||||
|     /// Execute a Post request. | ||||
|     pub fn post<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C, S> { | ||||
|     pub fn post<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C> { | ||||
|         self.request(Method::Post, url) | ||||
|     } | ||||
|  | ||||
|     /// Execute a Put request. | ||||
|     pub fn put<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C, S> { | ||||
|     pub fn put<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C> { | ||||
|         self.request(Method::Put, url) | ||||
|     } | ||||
|  | ||||
|     /// Execute a Delete request. | ||||
|     pub fn delete<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C, S> { | ||||
|     pub fn delete<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C> { | ||||
|         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, C, S> { | ||||
|     pub fn request<U: IntoUrl>(&mut self, method: Method, url: U) -> RequestBuilder<U, C> { | ||||
|         RequestBuilder { | ||||
|             client: self, | ||||
|             method: method, | ||||
| @@ -121,7 +120,7 @@ impl<C: NetworkConnector<S>, S: NetworkStream> Client<C> { | ||||
| /// | ||||
| /// One of these will be built for you if you use one of the convenience | ||||
| /// methods, such as `get()`, `post()`, etc. | ||||
| pub struct RequestBuilder<'a, U: IntoUrl, C: NetworkConnector<S> + 'a, S: NetworkStream> { | ||||
| pub struct RequestBuilder<'a, U: IntoUrl, C: NetworkConnector + 'a> { | ||||
|     client: &'a mut Client<C>, | ||||
|     url: U, | ||||
|     headers: Option<Headers>, | ||||
| @@ -129,22 +128,22 @@ pub struct RequestBuilder<'a, U: IntoUrl, C: NetworkConnector<S> + 'a, S: Networ | ||||
|     body: Option<Body<'a>>, | ||||
| } | ||||
|  | ||||
| impl<'a, U: IntoUrl, C: NetworkConnector<S>, S: NetworkStream> RequestBuilder<'a, U, C, S> { | ||||
| impl<'a, U: IntoUrl, C: NetworkConnector> RequestBuilder<'a, U, C> { | ||||
|  | ||||
|     /// Set a request body to be sent. | ||||
|     pub fn body<B: IntoBody<'a>>(mut self, body: B) -> RequestBuilder<'a, U, C, S> { | ||||
|     pub fn body<B: IntoBody<'a>>(mut self, body: B) -> RequestBuilder<'a, U, C> { | ||||
|         self.body = Some(body.into_body()); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Add additional headers to the request. | ||||
|     pub fn headers(mut self, headers: Headers) -> RequestBuilder<'a, U, C, S> { | ||||
|     pub fn headers(mut self, headers: Headers) -> RequestBuilder<'a, U, C> { | ||||
|         self.headers = Some(headers); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Add an individual new header to the request. | ||||
|     pub fn header<H: Header + HeaderFormat>(mut self, header: H) -> RequestBuilder<'a, U, C, S> { | ||||
|     pub fn header<H: Header + HeaderFormat>(mut self, header: H) -> RequestBuilder<'a, U, C> { | ||||
|         { | ||||
|             let mut headers = match self.headers { | ||||
|                 Some(ref mut h) => h, | ||||
| @@ -243,15 +242,16 @@ pub enum Body<'a> { | ||||
|     /// A Reader does not necessarily know it's size, so it is chunked. | ||||
|     ChunkedBody(&'a mut (Reader + 'a)), | ||||
|     /// For Readers that can know their size, like a `File`. | ||||
|     SizedBody(&'a mut (Reader + 'a), usize), | ||||
|     SizedBody(&'a mut (Reader + 'a), u64), | ||||
|     /// A String has a size, and uses Content-Length. | ||||
|     BufBody(&'a [u8] , usize), | ||||
| } | ||||
|  | ||||
| impl<'a> Body<'a> { | ||||
|     fn size(&self) -> Option<usize> { | ||||
|     fn size(&self) -> Option<u64> { | ||||
|         match *self { | ||||
|             Body::SizedBody(_, len) | Body::BufBody(_, len) => Some(len), | ||||
|             Body::SizedBody(_, len) => Some(len), | ||||
|             Body::BufBody(_, len) => Some(len as u64), | ||||
|             _ => None | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -3,8 +3,7 @@ use std::io::{BufferedWriter, IoResult}; | ||||
|  | ||||
| use url::Url; | ||||
|  | ||||
| use method; | ||||
| use method::Method::{Get, Post, Delete, Put, Patch, Head, Options}; | ||||
| use method::{self, Method}; | ||||
| use header::Headers; | ||||
| use header::common::{self, Host}; | ||||
| use net::{NetworkStream, NetworkConnector, HttpConnector, Fresh, Streaming}; | ||||
| @@ -46,11 +45,14 @@ impl Request<Fresh> { | ||||
|     } | ||||
|  | ||||
|     /// Create a new client request with a specific underlying NetworkStream. | ||||
|     pub fn with_connector<C: NetworkConnector<S>, S: NetworkStream>(method: method::Method, url: Url, connector: &mut C) -> HttpResult<Request<Fresh>> { | ||||
|         debug!("{:?} {:?}", method, url); | ||||
|     pub fn with_connector<C, S>(method: method::Method, url: Url, connector: &mut C) | ||||
|         -> HttpResult<Request<Fresh>> where | ||||
|         C: NetworkConnector<Stream=S>, | ||||
|         S: NetworkStream + Send { | ||||
|         debug!("{} {}", method, url); | ||||
|         let (host, port) = try!(get_host_and_port(&url)); | ||||
|  | ||||
|         let stream: S = try!(connector.connect(&host[], port, &*url.scheme)); | ||||
|         let stream = try!(connector.connect(&*host, port, &*url.scheme)); | ||||
|         let stream = ThroughWriter(BufferedWriter::new(box stream as Box<NetworkStream + Send>)); | ||||
|  | ||||
|         let mut headers = Headers::new(); | ||||
| @@ -68,41 +70,6 @@ impl Request<Fresh> { | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// Create a new GET request. | ||||
|     #[inline] | ||||
|     #[deprecated = "use hyper::Client"] | ||||
|     pub fn get(url: Url) -> HttpResult<Request<Fresh>> { Request::new(Get, url) } | ||||
|  | ||||
|     /// Create a new POST request. | ||||
|     #[inline] | ||||
|     #[deprecated = "use hyper::Client"] | ||||
|     pub fn post(url: Url) -> HttpResult<Request<Fresh>> { Request::new(Post, url) } | ||||
|  | ||||
|     /// Create a new DELETE request. | ||||
|     #[inline] | ||||
|     #[deprecated = "use hyper::Client"] | ||||
|     pub fn delete(url: Url) -> HttpResult<Request<Fresh>> { Request::new(Delete, url) } | ||||
|  | ||||
|     /// Create a new PUT request. | ||||
|     #[inline] | ||||
|     #[deprecated = "use hyper::Client"] | ||||
|     pub fn put(url: Url) -> HttpResult<Request<Fresh>> { Request::new(Put, url) } | ||||
|  | ||||
|     /// Create a new PATCH request. | ||||
|     #[inline] | ||||
|     #[deprecated = "use hyper::Client"] | ||||
|     pub fn patch(url: Url) -> HttpResult<Request<Fresh>> { Request::new(Patch, url) } | ||||
|  | ||||
|     /// Create a new HEAD request. | ||||
|     #[inline] | ||||
|     #[deprecated = "use hyper::Client"] | ||||
|     pub fn head(url: Url) -> HttpResult<Request<Fresh>> { Request::new(Head, url) } | ||||
|  | ||||
|     /// Create a new OPTIONS request. | ||||
|     #[inline] | ||||
|     #[deprecated = "use hyper::Client"] | ||||
|     pub fn options(url: Url) -> HttpResult<Request<Fresh>> { Request::new(Options, url) } | ||||
|  | ||||
|     /// Consume a Fresh Request, writing the headers and method, | ||||
|     /// returning a Streaming Request. | ||||
|     pub fn start(mut self) -> HttpResult<Request<Streaming>> { | ||||
| @@ -119,7 +86,7 @@ impl Request<Fresh> { | ||||
|  | ||||
|  | ||||
|         let stream = match self.method { | ||||
|             Get | Head => { | ||||
|             Method::Get | Method::Head => { | ||||
|                 debug!("headers [\n{:?}]", self.headers); | ||||
|                 try!(write!(&mut self.body, "{}{}", self.headers, LINE_ENDING)); | ||||
|                 EmptyWriter(self.body.unwrap()) | ||||
|   | ||||
| @@ -34,7 +34,7 @@ impl HeaderFormat for CacheControl { | ||||
| } | ||||
|  | ||||
| /// CacheControl contains a list of these directives. | ||||
| #[derive(PartialEq, Clone)] | ||||
| #[derive(PartialEq, Clone, Show)] | ||||
| pub enum CacheDirective { | ||||
|     /// "no-cache" | ||||
|     NoCache, | ||||
| @@ -47,11 +47,11 @@ pub enum CacheDirective { | ||||
|  | ||||
|     // request directives | ||||
|     /// "max-age=delta" | ||||
|     MaxAge(usize), | ||||
|     MaxAge(u32), | ||||
|     /// "max-stale=delta" | ||||
|     MaxStale(usize), | ||||
|     MaxStale(u32), | ||||
|     /// "min-fresh=delta" | ||||
|     MinFresh(usize), | ||||
|     MinFresh(u32), | ||||
|  | ||||
|     // response directives | ||||
|     /// "must-revalidate" | ||||
| @@ -63,7 +63,7 @@ pub enum CacheDirective { | ||||
|     /// "proxy-revalidate" | ||||
|     ProxyRevalidate, | ||||
|     /// "s-maxage=delta" | ||||
|     SMaxAge(usize), | ||||
|     SMaxAge(u32), | ||||
|  | ||||
|     /// Extension directives. Optionally include an argument. | ||||
|     Extension(String, Option<String>) | ||||
| @@ -95,11 +95,6 @@ impl fmt::String for CacheDirective { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Show for CacheDirective { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
| 		self.to_string().fmt(fmt) | ||||
| 	} | ||||
| } | ||||
| impl FromStr for CacheDirective { | ||||
|     fn from_str(s: &str) -> Option<CacheDirective> { | ||||
|         use self::CacheDirective::*; | ||||
|   | ||||
| @@ -7,9 +7,9 @@ use header::shared::util::from_one_raw_str; | ||||
| /// | ||||
| /// Simply a wrapper around a `usize`. | ||||
| #[derive(Copy, Clone, PartialEq, Show)] | ||||
| pub struct ContentLength(pub usize); | ||||
| pub struct ContentLength(pub u64); | ||||
|  | ||||
| deref!(ContentLength => usize); | ||||
| deref!(ContentLength => u64); | ||||
|  | ||||
| impl Header for ContentLength { | ||||
|     fn header_name(_: Option<ContentLength>) -> &'static str { | ||||
| @@ -23,17 +23,7 @@ impl Header for ContentLength { | ||||
|  | ||||
| impl HeaderFormat for ContentLength { | ||||
|     fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         let ContentLength(ref value) = *self; | ||||
|         write!(fmt, "{}", value) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ContentLength { | ||||
|     /// Returns the wrapped length. | ||||
|     #[deprecated = "use Deref instead"] | ||||
|     #[inline] | ||||
|     pub fn len(&self) -> usize { | ||||
|         **self | ||||
|        fmt::String::fmt(&self.0, fmt) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -16,10 +16,6 @@ use cookie::CookieJar; | ||||
| #[derive(Clone, PartialEq, Show)] | ||||
| pub struct Cookies(pub Vec<Cookie>); | ||||
|  | ||||
| //TODO: remove when fixed in libstd | ||||
| unsafe impl Send for Cookies {} | ||||
| unsafe impl Sync for Cookies {} | ||||
|  | ||||
| deref!(Cookies => Vec<Cookie>); | ||||
|  | ||||
| impl Header for Cookies { | ||||
|   | ||||
| @@ -13,10 +13,6 @@ use cookie::CookieJar; | ||||
| #[derive(Clone, PartialEq, Show)] | ||||
| pub struct SetCookie(pub Vec<Cookie>); | ||||
|  | ||||
| //TODO: remove when fixed in libstd | ||||
| unsafe impl Send for SetCookie {} | ||||
| unsafe impl Sync for SetCookie {} | ||||
|  | ||||
| deref!(SetCookie => Vec<Cookie>); | ||||
|  | ||||
| impl Header for SetCookie { | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| use header::{Header, HeaderFormat, CaseInsensitive}; | ||||
| use header::{Header, HeaderFormat}; | ||||
| use std::fmt::{self}; | ||||
| use header::shared::util::{from_comma_delimited, fmt_comma_delimited, from_one_raw_str}; | ||||
| use unicase::UniCase; | ||||
|  | ||||
| /// The `Allow` header. | ||||
| /// See also https://tools.ietf.org/html/rfc7231#section-7.1.4 | ||||
| @@ -10,7 +11,7 @@ pub enum Vary { | ||||
|     /// This corresponds to '*'. | ||||
|     Any, | ||||
|     /// The header field names which will influence the response representation. | ||||
|     Headers(Vec<CaseInsensitive>), | ||||
|     Headers(Vec<UniCase<String>>), | ||||
| } | ||||
|  | ||||
| impl Header for Vary { | ||||
|   | ||||
| @@ -5,24 +5,23 @@ | ||||
| //! must implement the `Header` trait from this module. Several common headers | ||||
| //! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others. | ||||
| use std::any::Any; | ||||
| use std::ascii::AsciiExt; | ||||
| use std::borrow::Cow::{Borrowed, Owned}; | ||||
| use std::fmt::{self, Show}; | ||||
| use std::fmt; | ||||
| use std::intrinsics::TypeId; | ||||
| use std::raw::TraitObject; | ||||
| use std::str::{FromStr, from_utf8}; | ||||
| use std::str::from_utf8; | ||||
| use std::string::CowString; | ||||
| use std::collections::HashMap; | ||||
| use std::collections::hash_map::{Iter, Entry}; | ||||
| use std::iter::FromIterator; | ||||
| use std::borrow::IntoCow; | ||||
| use std::{hash, mem, raw}; | ||||
| use std::{mem, raw}; | ||||
|  | ||||
| use mucell::MuCell; | ||||
| use uany::{UnsafeAnyExt}; | ||||
| use unicase::UniCase; | ||||
|  | ||||
| use http::{self, LineEnding}; | ||||
| use {HttpResult}; | ||||
| use {http, HttpResult}; | ||||
|  | ||||
| pub use self::common::*; | ||||
| pub use self::shared::*; | ||||
| @@ -32,6 +31,8 @@ pub mod common; | ||||
|  | ||||
| pub mod shared; | ||||
|  | ||||
| type HeaderName = UniCase<CowString<'static>>; | ||||
|  | ||||
| /// A trait for any object that will represent a header field and value. | ||||
| /// | ||||
| /// This trait represents the construction and identification of headers, | ||||
| @@ -73,7 +74,7 @@ pub trait HeaderClone { | ||||
| impl<T: HeaderFormat + Send + Sync + Clone> HeaderClone for T { | ||||
|     #[inline] | ||||
|     fn clone_box(&self) -> Box<HeaderFormat + Sync + Send> { | ||||
|         box self.clone() | ||||
|         Box::new(self.clone()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -116,7 +117,7 @@ fn header_name<T: Header>() -> &'static str { | ||||
| /// A map of header fields on requests and responses. | ||||
| #[derive(Clone)] | ||||
| pub struct Headers { | ||||
|     data: HashMap<CaseInsensitive, MuCell<Item>> | ||||
|     data: HashMap<HeaderName, MuCell<Item>> | ||||
| } | ||||
|  | ||||
| impl Headers { | ||||
| @@ -135,7 +136,7 @@ impl Headers { | ||||
|             match try!(http::read_header(rdr)) { | ||||
|                 Some((name, value)) => { | ||||
|                     debug!("raw header: {:?}={:?}", name, &value[]); | ||||
|                     let name = CaseInsensitive(Owned(name)); | ||||
|                     let name = UniCase(Owned(name)); | ||||
|                     let mut item = match headers.data.entry(name) { | ||||
|                         Entry::Vacant(entry) => entry.insert(MuCell::new(Item::raw(vec![]))), | ||||
|                         Entry::Occupied(entry) => entry.into_mut() | ||||
| @@ -157,8 +158,8 @@ impl Headers { | ||||
|     /// | ||||
|     /// The field is determined by the type of the value being set. | ||||
|     pub fn set<H: Header + HeaderFormat>(&mut self, value: H) { | ||||
|         self.data.insert(CaseInsensitive(Borrowed(header_name::<H>())), | ||||
|                          MuCell::new(Item::typed(box value as Box<HeaderFormat + Send + Sync>))); | ||||
|         self.data.insert(UniCase(Borrowed(header_name::<H>())), | ||||
|                          MuCell::new(Item::typed(Box::new(value)))); | ||||
|     } | ||||
|  | ||||
|     /// Access the raw value of a header. | ||||
| @@ -175,7 +176,7 @@ impl Headers { | ||||
|     pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> { | ||||
|         self.data | ||||
|             // FIXME(reem): Find a better way to do this lookup without find_equiv. | ||||
|             .get(&CaseInsensitive(Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))) | ||||
|             .get(&UniCase(Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))) | ||||
|             .and_then(|item| { | ||||
|                 if let Some(ref raw) = item.borrow().raw { | ||||
|                     return unsafe { mem::transmute(Some(&raw[])) }; | ||||
| @@ -203,7 +204,7 @@ impl Headers { | ||||
|     /// headers.set_raw("content-length", vec![b"5".to_vec()]); | ||||
|     /// ``` | ||||
|     pub fn set_raw<K: IntoCow<'static, String, str>>(&mut self, name: K, value: Vec<Vec<u8>>) { | ||||
|         self.data.insert(CaseInsensitive(name.into_cow()), MuCell::new(Item::raw(value))); | ||||
|         self.data.insert(UniCase(name.into_cow()), MuCell::new(Item::raw(value))); | ||||
|     } | ||||
|  | ||||
|     /// Get a reference to the header field's value, if it exists. | ||||
| @@ -223,11 +224,11 @@ impl Headers { | ||||
|     } | ||||
|  | ||||
|     fn get_or_parse<H: Header + HeaderFormat>(&self) -> Option<&MuCell<Item>> { | ||||
|         self.data.get(&CaseInsensitive(Borrowed(header_name::<H>()))).and_then(get_or_parse::<H>) | ||||
|         self.data.get(&UniCase(Borrowed(header_name::<H>()))).and_then(get_or_parse::<H>) | ||||
|     } | ||||
|  | ||||
|     fn get_or_parse_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut MuCell<Item>> { | ||||
|         self.data.get_mut(&CaseInsensitive(Borrowed(header_name::<H>()))).and_then(get_or_parse_mut::<H>) | ||||
|         self.data.get_mut(&UniCase(Borrowed(header_name::<H>()))).and_then(get_or_parse_mut::<H>) | ||||
|     } | ||||
|  | ||||
|     /// Returns a boolean of whether a certain header is in the map. | ||||
| @@ -241,13 +242,13 @@ impl Headers { | ||||
|     /// let has_type = headers.has::<ContentType>(); | ||||
|     /// ``` | ||||
|     pub fn has<H: Header + HeaderFormat>(&self) -> bool { | ||||
|         self.data.contains_key(&CaseInsensitive(Borrowed(header_name::<H>()))) | ||||
|         self.data.contains_key(&UniCase(Borrowed(header_name::<H>()))) | ||||
|     } | ||||
|  | ||||
|     /// Removes a header from the map, if one existed. | ||||
|     /// Returns true if a header has been removed. | ||||
|     pub fn remove<H: Header + HeaderFormat>(&mut self) -> bool { | ||||
|         self.data.remove(&CaseInsensitive(Borrowed(Header::header_name(None::<H>)))).is_some() | ||||
|         self.data.remove(&UniCase(Borrowed(Header::header_name(None::<H>)))).is_some() | ||||
|     } | ||||
|  | ||||
|     /// Returns an iterator over the header fields. | ||||
| @@ -269,9 +270,9 @@ impl Headers { | ||||
| } | ||||
|  | ||||
| impl fmt::String for Headers { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         for header in self.iter() { | ||||
|             try!(write!(fmt, "{}{}", header, LineEnding)); | ||||
|             try!(write!(fmt, "{}\r\n", header)); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| @@ -279,13 +280,18 @@ impl fmt::String for Headers { | ||||
|  | ||||
| impl fmt::Show for Headers { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         self.to_string().fmt(fmt) | ||||
|         try!(fmt.write_str("Headers {{ ")); | ||||
|         for header in self.iter() { | ||||
|             try!(write!(fmt, "{:?}, ", header)); | ||||
|         } | ||||
|         try!(fmt.write_str("}}")); | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// An `Iterator` over the fields in a `Headers` map. | ||||
| pub struct HeadersItems<'a> { | ||||
|     inner: Iter<'a, CaseInsensitive, MuCell<Item>> | ||||
|     inner: Iter<'a, HeaderName, MuCell<Item>> | ||||
| } | ||||
|  | ||||
| impl<'a> Iterator for HeadersItems<'a> { | ||||
| @@ -300,13 +306,13 @@ impl<'a> Iterator for HeadersItems<'a> { | ||||
| } | ||||
|  | ||||
| /// Returned with the `HeadersItems` iterator. | ||||
| pub struct HeaderView<'a>(&'a CaseInsensitive, &'a MuCell<Item>); | ||||
| pub struct HeaderView<'a>(&'a HeaderName, &'a MuCell<Item>); | ||||
|  | ||||
| impl<'a> HeaderView<'a> { | ||||
|     /// Check if a HeaderView is a certain Header. | ||||
|     #[inline] | ||||
|     pub fn is<H: Header>(&self) -> bool { | ||||
|         CaseInsensitive(header_name::<H>().into_cow()) == *self.0 | ||||
|         UniCase(header_name::<H>().into_cow()) == *self.0 | ||||
|     } | ||||
|  | ||||
|     /// Get the Header name as a slice. | ||||
| @@ -454,7 +460,7 @@ impl fmt::String for Item { | ||||
|                         match from_utf8(&part[]) { | ||||
|                             Ok(s) => try!(fmt.write_str(s)), | ||||
|                             Err(e) => { | ||||
|                                 error!("raw header value is not utf8. header={:?}, error={:?}", &part[], e); | ||||
|                                 error!("raw header value is not utf8. header={:?}, error={:?}", part, e); | ||||
|                                 return Err(fmt::Error); | ||||
|                             } | ||||
|                         } | ||||
| @@ -467,9 +473,10 @@ impl fmt::String for Item { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> fmt::Show for Item { | ||||
|  | ||||
| impl fmt::Show for Box<HeaderFormat + Send + Sync> { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         self.to_string().fmt(fmt) | ||||
|         (**self).fmt_header(fmt) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -479,64 +486,6 @@ impl fmt::String for Box<HeaderFormat + Send + Sync> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Show for Box<HeaderFormat + Send + Sync> { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         self.to_string().fmt(fmt) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Case-insensitive string. | ||||
| pub struct CaseInsensitive(CowString<'static>); | ||||
|  | ||||
| impl FromStr for CaseInsensitive { | ||||
|     fn from_str(s: &str) -> Option<CaseInsensitive> { | ||||
|         Some(CaseInsensitive(Owned(s.to_string()))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Clone for CaseInsensitive { | ||||
|     fn clone(&self) -> CaseInsensitive { | ||||
|         CaseInsensitive(self.0.clone().into_cow()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Str for CaseInsensitive { | ||||
|     fn as_slice(&self) -> &str { | ||||
|         let CaseInsensitive(ref s) = *self; | ||||
|         s.as_slice() | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| impl fmt::String for CaseInsensitive { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         write!(fmt, "{}", self.as_slice()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Show for CaseInsensitive { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         self.to_string().fmt(fmt) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl PartialEq for CaseInsensitive { | ||||
|     fn eq(&self, other: &CaseInsensitive) -> bool { | ||||
|         self.as_slice().eq_ignore_ascii_case(other.as_slice()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Eq for CaseInsensitive {} | ||||
|  | ||||
| impl<H: hash::Writer + hash::Hasher> hash::Hash<H> for CaseInsensitive { | ||||
|     #[inline] | ||||
|     fn hash(&self, hasher: &mut H) { | ||||
|         for b in self.as_slice().bytes() { | ||||
|             hasher.write(&[b.to_ascii_lowercase()]) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A wrapper around any Header with a Show impl that calls fmt_header. | ||||
| /// | ||||
| /// This can be used like so: `format!("{}", HeaderFormatter(&header))` to | ||||
| @@ -550,7 +499,7 @@ impl<'a, H: HeaderFormat> fmt::String for HeaderFormatter<'a, H> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, H: HeaderFormat> Show for HeaderFormatter<'a, H> { | ||||
| impl<'a, H: HeaderFormat> fmt::Show for HeaderFormatter<'a, H> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         self.0.fmt_header(f) | ||||
|     } | ||||
| @@ -565,7 +514,7 @@ mod tests { | ||||
|     use mime::Mime; | ||||
|     use mime::TopLevel::Text; | ||||
|     use mime::SubLevel::Plain; | ||||
|     use super::CaseInsensitive; | ||||
|     use unicase::UniCase; | ||||
|     use super::{Headers, Header, HeaderFormat}; | ||||
|     use super::common::{ContentLength, ContentType, Accept, Host}; | ||||
|     use super::shared::{QualityItem}; | ||||
| @@ -578,8 +527,8 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_case_insensitive() { | ||||
|         let a = CaseInsensitive(Borrowed("foobar")); | ||||
|         let b = CaseInsensitive(Borrowed("FOOBAR")); | ||||
|         let a = UniCase(Borrowed("foobar")); | ||||
|         let b = UniCase(Borrowed("FOOBAR")); | ||||
|  | ||||
|         assert_eq!(a, b); | ||||
|         assert_eq!(hash::<_, SipHasher>(&a), hash::<_, SipHasher>(&b)); | ||||
| @@ -682,10 +631,10 @@ mod tests { | ||||
|  | ||||
|         let s = headers.to_string(); | ||||
|         // hashmap's iterators have arbitrary order, so we must sort first | ||||
|         let mut pieces = s[].split_str("\r\n").collect::<Vec<&str>>(); | ||||
|         let mut pieces = s.split_str("\r\n").collect::<Vec<&str>>(); | ||||
|         pieces.sort(); | ||||
|         let s = pieces.into_iter().rev().collect::<Vec<&str>>().connect("\r\n"); | ||||
|         assert_eq!(&s[], "Host: foo.bar\r\nContent-Length: 15\r\n"); | ||||
|         assert_eq!(s, "Host: foo.bar\r\nContent-Length: 15\r\n"); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|   | ||||
							
								
								
									
										36
									
								
								src/http.rs
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								src/http.rs
									
									
									
									
									
								
							| @@ -30,9 +30,9 @@ use self::HttpWriter::{ThroughWriter, ChunkedWriter, SizedWriter, EmptyWriter}; | ||||
| /// include a Content-Length header. | ||||
| pub enum HttpReader<R> { | ||||
|     /// A Reader used when a Content-Length header is passed with a positive integer. | ||||
|     SizedReader(R, usize), | ||||
|     SizedReader(R, u64), | ||||
|     /// A Reader used when Transfer-Encoding is `chunked`. | ||||
|     ChunkedReader(R, Option<usize>), | ||||
|     ChunkedReader(R, Option<u64>), | ||||
|     /// A Reader used for responses that don't indicate a length or chunked. | ||||
|     /// | ||||
|     /// Note: This should only used for `Response`s. It is illegal for a | ||||
| @@ -75,13 +75,13 @@ impl<R: Reader> Reader for HttpReader<R> { | ||||
|                 if *remaining == 0 { | ||||
|                     Err(io::standard_error(io::EndOfFile)) | ||||
|                 } else { | ||||
|                     let num = try!(body.read(buf)); | ||||
|                     let num = try!(body.read(buf)) as u64; | ||||
|                     if num > *remaining { | ||||
|                         *remaining = 0; | ||||
|                     } else { | ||||
|                         *remaining -= num; | ||||
|                     } | ||||
|                     Ok(num) | ||||
|                     Ok(num as usize) | ||||
|                 } | ||||
|             }, | ||||
|             ChunkedReader(ref mut body, ref mut opt_remaining) => { | ||||
| @@ -102,8 +102,8 @@ impl<R: Reader> Reader for HttpReader<R> { | ||||
|                     return Err(io::standard_error(io::EndOfFile)); | ||||
|                 } | ||||
|  | ||||
|                 let to_read = min(rem, buf.len()); | ||||
|                 let count = try!(body.read(buf.slice_to_mut(to_read))); | ||||
|                 let to_read = min(rem as usize, buf.len()); | ||||
|                 let count = try!(body.read(buf.slice_to_mut(to_read))) as u64; | ||||
|  | ||||
|                 rem -= count; | ||||
|                 *opt_remaining = if rem > 0 { | ||||
| @@ -112,7 +112,7 @@ impl<R: Reader> Reader for HttpReader<R> { | ||||
|                     try!(eat(body, LINE_ENDING.as_bytes())); | ||||
|                     None | ||||
|                 }; | ||||
|                 Ok(count) | ||||
|                 Ok(count as usize) | ||||
|             }, | ||||
|             EofReader(ref mut body) => { | ||||
|                 body.read(buf) | ||||
| @@ -133,8 +133,8 @@ fn eat<R: Reader>(rdr: &mut R, bytes: &[u8]) -> IoResult<()> { | ||||
| } | ||||
|  | ||||
| /// Chunked chunks start with 1*HEXDIGIT, indicating the size of the chunk. | ||||
| fn read_chunk_size<R: Reader>(rdr: &mut R) -> IoResult<usize> { | ||||
|     let mut size = 0us; | ||||
| fn read_chunk_size<R: Reader>(rdr: &mut R) -> IoResult<u64> { | ||||
|     let mut size = 0u64; | ||||
|     let radix = 16; | ||||
|     let mut in_ext = false; | ||||
|     let mut in_chunk_size = true; | ||||
| @@ -142,15 +142,15 @@ fn read_chunk_size<R: Reader>(rdr: &mut R) -> IoResult<usize> { | ||||
|         match try!(rdr.read_byte()) { | ||||
|             b@b'0'...b'9' if in_chunk_size => { | ||||
|                 size *= radix; | ||||
|                 size += (b - b'0') as usize; | ||||
|                 size += (b - b'0') as u64; | ||||
|             }, | ||||
|             b@b'a'...b'f' if in_chunk_size => { | ||||
|                 size *= radix; | ||||
|                 size += (b + 10 - b'a') as usize; | ||||
|                 size += (b + 10 - b'a') as u64; | ||||
|             }, | ||||
|             b@b'A'...b'F' if in_chunk_size => { | ||||
|                 size *= radix; | ||||
|                 size += (b + 10 - b'A') as usize; | ||||
|                 size += (b + 10 - b'A') as u64; | ||||
|             }, | ||||
|             CR => { | ||||
|                 match try!(rdr.read_byte()) { | ||||
| @@ -196,7 +196,7 @@ pub enum HttpWriter<W: Writer> { | ||||
|     /// A Writer for when Content-Length is set. | ||||
|     /// | ||||
|     /// Enforces that the body is not longer than the Content-Length header. | ||||
|     SizedWriter(W, usize), | ||||
|     SizedWriter(W, u64), | ||||
|     /// A writer that should not write any body. | ||||
|     EmptyWriter(W), | ||||
| } | ||||
| @@ -263,12 +263,12 @@ impl<W: Writer> Writer for HttpWriter<W> { | ||||
|                 w.write_str(LINE_ENDING) | ||||
|             }, | ||||
|             SizedWriter(ref mut w, ref mut remaining) => { | ||||
|                 let len = msg.len(); | ||||
|                 let len = msg.len() as u64; | ||||
|                 if len > *remaining { | ||||
|                     let len = *remaining; | ||||
|                     *remaining = 0; | ||||
|                     try!(w.write(msg.slice_to(len))); // msg[...len] | ||||
|                     Err(io::standard_error(io::ShortWrite(len))) | ||||
|                     try!(w.write(&msg[..len as usize])); | ||||
|                     Err(io::standard_error(io::ShortWrite(len as usize))) | ||||
|                 } else { | ||||
|                     *remaining -= len; | ||||
|                     w.write(msg) | ||||
| @@ -666,7 +666,7 @@ pub fn read_status<R: Reader>(stream: &mut R) -> HttpResult<RawStatus> { | ||||
|                 b => match bufwrt.write_u8(b) { | ||||
|                     Ok(_) => (), | ||||
|                     Err(_) => { | ||||
|                         for _ in range(0us, 128) { | ||||
|                         for _ in 0u8..128 { | ||||
|                             match try!(stream.read_byte()) { | ||||
|                                 CR => match try!(stream.read_byte()) { | ||||
|                                     LF => break 'read, | ||||
| @@ -839,7 +839,7 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_read_chunk_size() { | ||||
|         fn read(s: &str, result: IoResult<usize>) { | ||||
|         fn read(s: &str, result: IoResult<u64>) { | ||||
|             assert_eq!(read_chunk_size(&mut mem(s)), result); | ||||
|         } | ||||
|  | ||||
|   | ||||
							
								
								
									
										10
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -1,8 +1,7 @@ | ||||
| #![feature(slicing_syntax, box_syntax, old_orphan_check, old_impl_check)] | ||||
| #![allow(unstable)] | ||||
| #![feature(slicing_syntax, box_syntax)] | ||||
| #![deny(missing_docs)] | ||||
| #![deny(warnings)] | ||||
| #![experimental] | ||||
| #![allow(unstable)] | ||||
| #![cfg_attr(test, deny(warnings))] | ||||
|  | ||||
| //! # Hyper | ||||
| //! Hyper is a fast, modern HTTP implementation written in and for Rust. It | ||||
| @@ -135,6 +134,7 @@ extern crate openssl; | ||||
| extern crate "unsafe-any" as uany; | ||||
| extern crate cookie; | ||||
| extern crate mucell; | ||||
| extern crate unicase; | ||||
|  | ||||
| pub use std::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr, Port}; | ||||
| pub use mimewrapper::mime; | ||||
| @@ -238,8 +238,6 @@ impl FromError<url::ParseError> for HttpError { | ||||
|     } | ||||
| } | ||||
|  | ||||
| //FIXME: when Opt-in Built-in Types becomes a thing, we can force these structs | ||||
| //to be Send. For now, this has the compiler do a static check. | ||||
| fn _assert_send<T: Send>() { | ||||
|     _assert_send::<client::Request<net::Fresh>>(); | ||||
|     _assert_send::<client::Response>(); | ||||
|   | ||||
| @@ -13,7 +13,7 @@ use self::Method::{Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch, | ||||
| /// | ||||
| /// It may make sense to grow this to include all variants currently | ||||
| /// registered with IANA, if they are at all common to use. | ||||
| #[derive(Clone, PartialEq, Eq, Hash)] | ||||
| #[derive(Clone, PartialEq, Eq, Hash, Show)] | ||||
| pub enum Method { | ||||
|     /// OPTIONS | ||||
|     Options, | ||||
| @@ -105,12 +105,6 @@ impl fmt::String for Method { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Show for Method { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         self.to_string().fmt(fmt) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use std::collections::HashMap; | ||||
|   | ||||
| @@ -68,7 +68,9 @@ impl NetworkStream for MockStream { | ||||
|  | ||||
| pub struct MockConnector; | ||||
|  | ||||
| impl NetworkConnector<MockStream> for MockConnector { | ||||
| impl NetworkConnector for MockConnector { | ||||
|     type Stream = MockStream; | ||||
|  | ||||
|     fn connect(&mut self, _host: &str, _port: u16, _scheme: &str) -> IoResult<MockStream> { | ||||
|         Ok(MockStream::new()) | ||||
|     } | ||||
| @@ -82,7 +84,8 @@ macro_rules! mock_connector ( | ||||
|  | ||||
|         struct $name; | ||||
|  | ||||
|         impl ::net::NetworkConnector<::mock::MockStream> for $name { | ||||
|         impl ::net::NetworkConnector for $name { | ||||
|             type Stream = ::mock::MockStream; | ||||
|             fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::std::io::IoResult<::mock::MockStream> { | ||||
|                 use std::collections::HashMap; | ||||
|                 debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme); | ||||
|   | ||||
							
								
								
									
										140
									
								
								src/net.rs
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								src/net.rs
									
									
									
									
									
								
							| @@ -15,8 +15,6 @@ use openssl::ssl::SslVerifyMode::SslVerifyPeer; | ||||
| use openssl::ssl::SslMethod::Sslv23; | ||||
| use openssl::ssl::error::{SslError, StreamError, OpenSslErrors, SslSessionClosed}; | ||||
|  | ||||
| use self::HttpStream::{Http, Https}; | ||||
|  | ||||
| /// The write-status indicating headers have not been written. | ||||
| #[allow(missing_copy_implementations)] | ||||
| pub struct Fresh; | ||||
| @@ -26,29 +24,49 @@ pub struct Fresh; | ||||
| pub struct Streaming; | ||||
|  | ||||
| /// An abstraction to listen for connections on a certain port. | ||||
| pub trait NetworkListener<S: NetworkStream, A: NetworkAcceptor<S>>: Listener<S, A> { | ||||
|     /// Bind to a socket. | ||||
|     /// | ||||
|     /// Note: This does not start listening for connections. You must call | ||||
|     /// `listen()` to do that. | ||||
|     fn bind<To: ToSocketAddr>(addr: To) -> IoResult<Self>; | ||||
|  | ||||
|     /// Get the address this Listener ended up listening on. | ||||
|     fn socket_name(&mut self) -> IoResult<SocketAddr>; | ||||
| pub trait NetworkListener { | ||||
|     type Acceptor: NetworkAcceptor; | ||||
|     /// Listens on a socket. | ||||
|     fn listen<To: ToSocketAddr>(&mut self, addr: To) -> IoResult<Self::Acceptor>; | ||||
| } | ||||
|  | ||||
| /// An abstraction to receive `NetworkStream`s. | ||||
| pub trait NetworkAcceptor<S: NetworkStream>: Acceptor<S> + Clone + Send { | ||||
| pub trait NetworkAcceptor: Clone + Send { | ||||
|     type Stream: NetworkStream + Send + Clone; | ||||
|  | ||||
|     /// Returns an iterator of streams. | ||||
|     fn accept(&mut self) -> IoResult<Self::Stream>; | ||||
|  | ||||
|     /// Get the address this Listener ended up listening on. | ||||
|     fn socket_name(&self) -> IoResult<SocketAddr>; | ||||
|  | ||||
|     /// Closes the Acceptor, so no more incoming connections will be handled. | ||||
|     fn close(&mut self) -> IoResult<()>; | ||||
|  | ||||
|     /// Returns an iterator over incoming connections. | ||||
|     fn incoming(&mut self) -> NetworkConnections<Self> { | ||||
|         NetworkConnections(self) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// An iterator wrapper over a NetworkAcceptor. | ||||
| pub struct NetworkConnections<'a, N: NetworkAcceptor>(&'a mut N); | ||||
|  | ||||
| impl<'a, N: NetworkAcceptor> Iterator for NetworkConnections<'a, N> { | ||||
|     type Item = IoResult<N::Stream>; | ||||
|     fn next(&mut self) -> Option<IoResult<N::Stream>> { | ||||
|         Some(self.0.accept()) | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// An abstraction over streams that a Server can utilize. | ||||
| pub trait NetworkStream: Stream + Any + StreamClone + Send { | ||||
|     /// Get the remote address of the underlying connection. | ||||
|     fn peer_name(&mut self) -> IoResult<SocketAddr>; | ||||
| } | ||||
|  | ||||
|  | ||||
| #[doc(hidden)] | ||||
| pub trait StreamClone { | ||||
|     fn clone_box(&self) -> Box<NetworkStream + Send>; | ||||
| @@ -57,14 +75,15 @@ pub trait StreamClone { | ||||
| impl<T: NetworkStream + Send + Clone> StreamClone for T { | ||||
|     #[inline] | ||||
|     fn clone_box(&self) -> Box<NetworkStream + Send> { | ||||
|         box self.clone() | ||||
|         Box::new(self.clone()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A connector creates a NetworkStream. | ||||
| pub trait NetworkConnector<S: NetworkStream> { | ||||
| pub trait NetworkConnector { | ||||
|     type Stream: NetworkStream + Send; | ||||
|     /// Connect to a remote address. | ||||
|     fn connect(&mut self, host: &str, port: Port, scheme: &str) -> IoResult<S>; | ||||
|     fn connect(&mut self, host: &str, port: Port, scheme: &str) -> IoResult<Self::Stream>; | ||||
| } | ||||
|  | ||||
| impl fmt::Show for Box<NetworkStream + Send> { | ||||
| @@ -161,50 +180,62 @@ impl NetworkStream { | ||||
| } | ||||
|  | ||||
| /// A `NetworkListener` for `HttpStream`s. | ||||
| pub struct HttpListener { | ||||
|     inner: TcpListener | ||||
| #[allow(missing_copy_implementations)] | ||||
| pub enum HttpListener { | ||||
|     /// Http variant. | ||||
|     Http, | ||||
|     /// Https variant. | ||||
|     Https, | ||||
| } | ||||
|  | ||||
| impl Listener<HttpStream, HttpAcceptor> for HttpListener { | ||||
|     #[inline] | ||||
|     fn listen(self) -> IoResult<HttpAcceptor> { | ||||
|         Ok(HttpAcceptor { | ||||
|             inner: try!(self.inner.listen()) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl NetworkListener<HttpStream, HttpAcceptor> for HttpListener { | ||||
|     #[inline] | ||||
|     fn bind<To: ToSocketAddr>(addr: To) -> IoResult<HttpListener> { | ||||
|         Ok(HttpListener { | ||||
|             inner: try!(TcpListener::bind(addr)) | ||||
|         }) | ||||
|     } | ||||
| impl NetworkListener for HttpListener { | ||||
|     type Acceptor = HttpAcceptor; | ||||
|  | ||||
|     #[inline] | ||||
|     fn socket_name(&mut self) -> IoResult<SocketAddr> { | ||||
|         self.inner.socket_name() | ||||
|     fn listen<To: ToSocketAddr>(&mut self, addr: To) -> IoResult<HttpAcceptor> { | ||||
|         let mut tcp = try!(TcpListener::bind(addr)); | ||||
|         let addr = try!(tcp.socket_name()); | ||||
|         Ok(match *self { | ||||
|             HttpListener::Http => HttpAcceptor::Http(try!(tcp.listen()), addr), | ||||
|             HttpListener::Https => unimplemented!(), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A `NetworkAcceptor` for `HttpStream`s. | ||||
| #[derive(Clone)] | ||||
| pub struct HttpAcceptor { | ||||
|     inner: TcpAcceptor | ||||
| pub enum HttpAcceptor { | ||||
|     /// Http variant. | ||||
|     Http(TcpAcceptor, SocketAddr), | ||||
|     /// Https variant. | ||||
|     Https(TcpAcceptor, SocketAddr), | ||||
| } | ||||
|  | ||||
| impl Acceptor<HttpStream> for HttpAcceptor { | ||||
| impl NetworkAcceptor for HttpAcceptor { | ||||
|     type Stream = HttpStream; | ||||
|  | ||||
|     #[inline] | ||||
|     fn accept(&mut self) -> IoResult<HttpStream> { | ||||
|         Ok(Http(try!(self.inner.accept()))) | ||||
|         Ok(match *self { | ||||
|             HttpAcceptor::Http(ref mut tcp, _) => HttpStream::Http(try!(tcp.accept())), | ||||
|             HttpAcceptor::Https(ref mut _tcp, _) => unimplemented!(), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl NetworkAcceptor<HttpStream> for HttpAcceptor { | ||||
|     #[inline] | ||||
|     fn close(&mut self) -> IoResult<()> { | ||||
|         self.inner.close_accept() | ||||
|         match *self { | ||||
|             HttpAcceptor::Http(ref mut tcp, _) => tcp.close_accept(), | ||||
|             HttpAcceptor::Https(ref mut tcp, _) => tcp.close_accept(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     fn socket_name(&self) -> IoResult<SocketAddr> { | ||||
|         match *self { | ||||
|             HttpAcceptor::Http(_, addr) => Ok(addr), | ||||
|             HttpAcceptor::Https(_, addr) => Ok(addr), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -221,8 +252,8 @@ impl Reader for HttpStream { | ||||
|     #[inline] | ||||
|     fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { | ||||
|         match *self { | ||||
|             Http(ref mut inner) => inner.read(buf), | ||||
|             Https(ref mut inner) => inner.read(buf) | ||||
|             HttpStream::Http(ref mut inner) => inner.read(buf), | ||||
|             HttpStream::Https(ref mut inner) => inner.read(buf) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -231,15 +262,15 @@ impl Writer for HttpStream { | ||||
|     #[inline] | ||||
|     fn write(&mut self, msg: &[u8]) -> IoResult<()> { | ||||
|         match *self { | ||||
|             Http(ref mut inner) => inner.write(msg), | ||||
|             Https(ref mut inner) => inner.write(msg) | ||||
|             HttpStream::Http(ref mut inner) => inner.write(msg), | ||||
|             HttpStream::Https(ref mut inner) => inner.write(msg) | ||||
|         } | ||||
|     } | ||||
|     #[inline] | ||||
|     fn flush(&mut self) -> IoResult<()> { | ||||
|         match *self { | ||||
|             Http(ref mut inner) => inner.flush(), | ||||
|             Https(ref mut inner) => inner.flush(), | ||||
|             HttpStream::Http(ref mut inner) => inner.flush(), | ||||
|             HttpStream::Https(ref mut inner) => inner.flush(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -247,8 +278,8 @@ impl Writer for HttpStream { | ||||
| impl NetworkStream for HttpStream { | ||||
|     fn peer_name(&mut self) -> IoResult<SocketAddr> { | ||||
|         match *self { | ||||
|             Http(ref mut inner) => inner.peer_name(), | ||||
|             Https(ref mut inner) => inner.get_mut().peer_name() | ||||
|             HttpStream::Http(ref mut inner) => inner.peer_name(), | ||||
|             HttpStream::Https(ref mut inner) => inner.get_mut().peer_name() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -257,13 +288,15 @@ impl NetworkStream for HttpStream { | ||||
| #[allow(missing_copy_implementations)] | ||||
| pub struct HttpConnector(pub Option<VerifyCallback>); | ||||
|  | ||||
| impl NetworkConnector<HttpStream> for HttpConnector { | ||||
| impl NetworkConnector for HttpConnector { | ||||
|     type Stream = HttpStream; | ||||
|  | ||||
|     fn connect(&mut self, host: &str, port: Port, scheme: &str) -> IoResult<HttpStream> { | ||||
|         let addr = (host, port); | ||||
|         match scheme { | ||||
|             "http" => { | ||||
|                 debug!("http scheme"); | ||||
|                 Ok(Http(try!(TcpStream::connect(addr)))) | ||||
|                 Ok(HttpStream::Http(try!(TcpStream::connect(addr)))) | ||||
|             }, | ||||
|             "https" => { | ||||
|                 debug!("https scheme"); | ||||
| @@ -273,7 +306,7 @@ impl NetworkConnector<HttpStream> for HttpConnector { | ||||
|                 let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error)); | ||||
|                 try!(ssl.set_hostname(host).map_err(lift_ssl_error)); | ||||
|                 let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error)); | ||||
|                 Ok(Https(stream)) | ||||
|                 Ok(HttpStream::Https(stream)) | ||||
|             }, | ||||
|             _ => { | ||||
|                 Err(IoError { | ||||
| @@ -307,7 +340,6 @@ fn lift_ssl_error(ssl: SslError) -> IoError { | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use std::boxed::BoxAny; | ||||
|     use uany::UnsafeAnyExt; | ||||
|  | ||||
|     use mock::MockStream; | ||||
|   | ||||
| @@ -15,8 +15,8 @@ use HttpError::HttpIoError; | ||||
| use {HttpResult}; | ||||
| use header::common::Connection; | ||||
| use header::common::connection::{KeepAlive, Close}; | ||||
| use net::{NetworkListener, NetworkAcceptor, NetworkStream, | ||||
|           HttpAcceptor, HttpListener, HttpStream}; | ||||
| use net::{NetworkListener, NetworkStream, NetworkAcceptor, | ||||
|           HttpAcceptor, HttpListener}; | ||||
| use version::HttpVersion::{Http10, Http11}; | ||||
|  | ||||
| pub mod request; | ||||
| @@ -28,7 +28,8 @@ pub mod response; | ||||
| /// incoming connection, and hand them to the provided handler. | ||||
| pub struct Server<L = HttpListener> { | ||||
|     ip: IpAddr, | ||||
|     port: Port | ||||
|     port: Port, | ||||
|     listener: L, | ||||
| } | ||||
|  | ||||
| macro_rules! try_option( | ||||
| @@ -43,29 +44,28 @@ macro_rules! try_option( | ||||
| impl Server<HttpListener> { | ||||
|     /// Creates a new server that will handle `HttpStream`s. | ||||
|     pub fn http(ip: IpAddr, port: Port) -> Server { | ||||
|         Server { | ||||
|             ip: ip, | ||||
|             port: port | ||||
|         } | ||||
|         Server::with_listener(ip, port, HttpListener::Http) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<X> Server<X> { | ||||
| 	/// Binds to a socket, and starts handling connections using a task pool. | ||||
|     /// | ||||
|     /// This method has unbound type parameters, so can be used when you want to use | ||||
|     /// something other than the provided HttpStream, HttpAcceptor, and HttpListener. | ||||
|     pub fn listen_network<H, S, A, L>(self, handler: H, threads: usize) -> HttpResult<Listening<A>> | ||||
|     where H: Handler, | ||||
|           S: NetworkStream + Clone, | ||||
|           A: NetworkAcceptor<S>, | ||||
|           L: NetworkListener<S, A>, { | ||||
| impl< | ||||
| L: NetworkListener<Acceptor=A> + Send, | ||||
| A: NetworkAcceptor<Stream=S> + Send, | ||||
| S: NetworkStream + Clone + Send> Server<L> { | ||||
|     /// Creates a new server that will handle `HttpStream`s. | ||||
|     pub fn with_listener(ip: IpAddr, port: Port, listener: L) -> Server<L> { | ||||
|         Server { | ||||
|             ip: ip, | ||||
|             port: port, | ||||
|             listener: listener, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Binds to a socket, and starts handling connections using a task pool. | ||||
|     pub fn listen_threads<H: Handler>(mut self, handler: H, threads: usize) -> HttpResult<Listening<L::Acceptor>> { | ||||
|         debug!("binding to {:?}:{:?}", self.ip, self.port); | ||||
|         let mut listener: L = try!(NetworkListener::<S, A>::bind((self.ip, self.port))); | ||||
|  | ||||
|         let socket = try!(listener.socket_name()); | ||||
|  | ||||
|         let acceptor = try!(listener.listen()); | ||||
|         let acceptor = try!(self.listener.listen((self.ip, self.port))); | ||||
|         let socket = try!(acceptor.socket_name()); | ||||
|  | ||||
|         let mut captured = acceptor.clone(); | ||||
|         let guard = Builder::new().name("hyper acceptor".to_string()).scoped(move || { | ||||
| @@ -134,17 +134,9 @@ impl<X> Server<X> { | ||||
|             socket: socket, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[old_impl_check] | ||||
| impl<L: NetworkListener<S, A>, S: NetworkStream, A: NetworkAcceptor<S>> Server<L> { | ||||
|     /// Binds to a socket and starts handling connections with the specified number of tasks. | ||||
|     pub fn listen_threads<H: Handler>(self, handler: H, threads: usize) -> HttpResult<Listening<HttpAcceptor>> { | ||||
|         self.listen_network::<H, HttpStream, HttpAcceptor, HttpListener>(handler, threads) | ||||
|     } | ||||
|  | ||||
|     /// Binds to a socket and starts handling connections. | ||||
|     pub fn listen<H: Handler>(self, handler: H) -> HttpResult<Listening<HttpAcceptor>> { | ||||
|     pub fn listen<H: Handler>(self, handler: H) -> HttpResult<Listening<L::Acceptor>> { | ||||
|         self.listen_threads(handler, os::num_cpus() * 5 / 4) | ||||
|     } | ||||
|  | ||||
| @@ -158,8 +150,7 @@ pub struct Listening<A = HttpAcceptor> { | ||||
|     pub socket: SocketAddr, | ||||
| } | ||||
|  | ||||
| #[old_impl_check] | ||||
| impl<A: NetworkAcceptor<S>, S: NetworkStream> Listening<A> { | ||||
| impl<A: NetworkAcceptor> Listening<A> { | ||||
|     /// Causes the current thread to wait for this listening to complete. | ||||
|     pub fn await(&mut self) { | ||||
|         if let Some(guard) = self.guard.take() { | ||||
|   | ||||
| @@ -39,8 +39,7 @@ impl<'a> Request<'a> { | ||||
|         let (method, uri, version) = try!(read_request_line(&mut stream)); | ||||
|         debug!("Request Line: {:?} {:?} {:?}", method, uri, version); | ||||
|         let headers = try!(Headers::from_raw(&mut stream)); | ||||
|         debug!("Headers: [\n{:?}]", headers); | ||||
|  | ||||
|         debug!("{:?}", headers); | ||||
|  | ||||
|         let body = if method == Get || method == Head { | ||||
|             EmptyReader(stream) | ||||
|   | ||||
| @@ -26,6 +26,7 @@ use std::cmp::Ordering::{self, Less, Equal, Greater}; | ||||
| /// # use hyper::status::StatusCode::{Code123, Continue}; | ||||
| /// assert_eq!(Code123.class().default_code(), Continue); | ||||
| /// ``` | ||||
| #[derive(Show)] | ||||
| pub enum StatusCode { | ||||
|     /// 100 Continue | ||||
|     Continue = 100, | ||||
| @@ -1595,12 +1596,6 @@ impl fmt::String for StatusCode { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Show for StatusCode { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         self.to_string().fmt(fmt) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Specified manually because the codegen for derived is slow (at the time of writing on the machine | ||||
| // of writing, 1.2 seconds) and verbose (though the optimiser cuts it down to size). | ||||
| impl PartialEq for StatusCode { | ||||
|   | ||||
| @@ -7,7 +7,7 @@ use std::fmt; | ||||
| use self::HttpVersion::{Http09, Http10, Http11, Http20}; | ||||
|  | ||||
| /// Represents a version of the HTTP spec. | ||||
| #[derive(PartialEq, PartialOrd, Copy)] | ||||
| #[derive(PartialEq, PartialOrd, Copy, Show)] | ||||
| pub enum HttpVersion { | ||||
|     /// `HTTP/0.9` | ||||
|     Http09, | ||||
| @@ -30,9 +30,3 @@ impl fmt::String for HttpVersion { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Show for HttpVersion { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         self.to_string().fmt(fmt) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user