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