From f7124bb8e28b4ecd87d76f8cd8bfad2bf2fd19c3 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Sat, 10 Jan 2015 00:46:43 -0800 Subject: [PATCH] rustup: sweeping fixes for all the changes in 1.0-alpha - Some switches to u64 instead of usize - For now, allow(unstable) - use associated types for all the Network stuff --- Cargo.toml | 17 ++-- benches/client.rs | 18 +--- benches/client_mock_tcp.rs | 21 +---- benches/server.rs | 1 + examples/client.rs | 1 + examples/hello.rs | 1 + examples/server.rs | 3 +- src/client/mod.rs | 34 +++---- src/client/request.rs | 49 ++-------- src/header/common/cache_control.rs | 15 +-- src/header/common/content_length.rs | 16 +--- src/header/common/cookie.rs | 4 - src/header/common/set_cookie.rs | 4 - src/header/common/vary.rs | 5 +- src/header/mod.rs | 129 ++++++++----------------- src/http.rs | 36 +++---- src/lib.rs | 10 +- src/method.rs | 8 +- src/mock.rs | 7 +- src/net.rs | 140 +++++++++++++++++----------- src/server/mod.rs | 57 +++++------ src/server/request.rs | 3 +- src/status.rs | 7 +- src/version.rs | 8 +- 24 files changed, 232 insertions(+), 362 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f81e97d3..228d43fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,16 +11,13 @@ authors = ["Sean McArthur ", "Jonathan Reem "] [dependencies] -url = "*" -openssl = "*" -mime = "*" -unsafe-any = "*" cookie = "*" -time = "*" -mucell = "*" log = "*" +mime = "*" +mucell = "*" +openssl = "*" rustc-serialize = "*" - -[dev-dependencies] -curl = "*" - +time = "*" +unicase = "*" +unsafe-any = "*" +url = "*" diff --git a/benches/client.rs b/benches/client.rs index 69179c00..07e464c4 100644 --- a/benches/client.rs +++ b/benches/client.rs @@ -1,5 +1,4 @@ -#![feature(macro_rules)] -extern crate curl; +#![allow(unstable)] extern crate hyper; extern crate test; @@ -31,21 +30,6 @@ fn handle(_r: Request, res: Response) { 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)] struct Foo; diff --git a/benches/client_mock_tcp.rs b/benches/client_mock_tcp.rs index 76d7c78b..1e037f88 100644 --- a/benches/client_mock_tcp.rs +++ b/benches/client_mock_tcp.rs @@ -1,5 +1,4 @@ -#![feature(default_type_params)] -extern crate curl; +#![allow(unstable)] extern crate hyper; 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)] struct Foo; @@ -90,7 +74,8 @@ impl net::NetworkStream for MockStream { struct MockConnector; -impl net::NetworkConnector for MockConnector { +impl net::NetworkConnector for MockConnector { + type Stream = MockStream; fn connect(&mut self, _: &str, _: u16, _: &str) -> IoResult { Ok(MockStream::new()) } diff --git a/benches/server.rs b/benches/server.rs index 6d51fe6e..e2a1fe89 100644 --- a/benches/server.rs +++ b/benches/server.rs @@ -1,3 +1,4 @@ +#![allow(unstable)] extern crate hyper; extern crate test; diff --git a/examples/client.rs b/examples/client.rs index abcbb9e9..517754a6 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -1,3 +1,4 @@ +#![allow(unstable)] extern crate hyper; use std::os; diff --git a/examples/hello.rs b/examples/hello.rs index b01e1a34..48d93671 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,3 +1,4 @@ +#![allow(unstable)] extern crate hyper; use std::io::net::ip::Ipv4Addr; diff --git a/examples/server.rs b/examples/server.rs index 5bedfc14..2ab23d6d 100644 --- a/examples/server.rs +++ b/examples/server.rs @@ -1,3 +1,4 @@ +#![allow(unstable)] extern crate hyper; #[macro_use] extern crate log; @@ -24,7 +25,7 @@ fn echo(mut req: Request, mut res: Response) { (&Get, "/") | (&Get, "/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()); try_return!(res.write(out)); try_return!(res.end()); diff --git a/src/client/mod.rs b/src/client/mod.rs index 71d3d096..2e77984e 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -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 { } -#[old_impl_check] -impl, S: NetworkStream> Client { +impl Client { /// Create a new client with a specific connector. pub fn with_connector(connector: C) -> Client { @@ -80,33 +79,33 @@ impl, S: NetworkStream> Client { } /// Execute a Get request. - pub fn get(&mut self, url: U) -> RequestBuilder { + pub fn get(&mut self, url: U) -> RequestBuilder { self.request(Method::Get, url) } /// Execute a Head request. - pub fn head(&mut self, url: U) -> RequestBuilder { + pub fn head(&mut self, url: U) -> RequestBuilder { self.request(Method::Head, url) } /// Execute a Post request. - pub fn post(&mut self, url: U) -> RequestBuilder { + pub fn post(&mut self, url: U) -> RequestBuilder { self.request(Method::Post, url) } /// Execute a Put request. - pub fn put(&mut self, url: U) -> RequestBuilder { + pub fn put(&mut self, url: U) -> RequestBuilder { self.request(Method::Put, url) } /// Execute a Delete request. - pub fn delete(&mut self, url: U) -> RequestBuilder { + pub fn delete(&mut self, url: U) -> RequestBuilder { self.request(Method::Delete, url) } /// Build a new request using this Client. - pub fn request(&mut self, method: Method, url: U) -> RequestBuilder { + pub fn request(&mut self, method: Method, url: U) -> RequestBuilder { RequestBuilder { client: self, method: method, @@ -121,7 +120,7 @@ impl, S: NetworkStream> Client { /// /// 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 + 'a, S: NetworkStream> { +pub struct RequestBuilder<'a, U: IntoUrl, C: NetworkConnector + 'a> { client: &'a mut Client, url: U, headers: Option, @@ -129,22 +128,22 @@ pub struct RequestBuilder<'a, U: IntoUrl, C: NetworkConnector + 'a, S: Networ body: Option>, } -impl<'a, U: IntoUrl, C: NetworkConnector, 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>(mut self, body: B) -> RequestBuilder<'a, U, C, S> { + pub fn body>(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(mut self, header: H) -> RequestBuilder<'a, U, C, S> { + pub fn header(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 { + fn size(&self) -> Option { match *self { - Body::SizedBody(_, len) | Body::BufBody(_, len) => Some(len), + Body::SizedBody(_, len) => Some(len), + Body::BufBody(_, len) => Some(len as u64), _ => None } } diff --git a/src/client/request.rs b/src/client/request.rs index 5cf8eecd..da3edba2 100644 --- a/src/client/request.rs +++ b/src/client/request.rs @@ -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 { } /// Create a new client request with a specific underlying NetworkStream. - pub fn with_connector, S: NetworkStream>(method: method::Method, url: Url, connector: &mut C) -> HttpResult> { - debug!("{:?} {:?}", method, url); + pub fn with_connector(method: method::Method, url: Url, connector: &mut C) + -> HttpResult> where + C: NetworkConnector, + 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)); let mut headers = Headers::new(); @@ -68,41 +70,6 @@ impl Request { }) } - /// Create a new GET request. - #[inline] - #[deprecated = "use hyper::Client"] - pub fn get(url: Url) -> HttpResult> { Request::new(Get, url) } - - /// Create a new POST request. - #[inline] - #[deprecated = "use hyper::Client"] - pub fn post(url: Url) -> HttpResult> { Request::new(Post, url) } - - /// Create a new DELETE request. - #[inline] - #[deprecated = "use hyper::Client"] - pub fn delete(url: Url) -> HttpResult> { Request::new(Delete, url) } - - /// Create a new PUT request. - #[inline] - #[deprecated = "use hyper::Client"] - pub fn put(url: Url) -> HttpResult> { Request::new(Put, url) } - - /// Create a new PATCH request. - #[inline] - #[deprecated = "use hyper::Client"] - pub fn patch(url: Url) -> HttpResult> { Request::new(Patch, url) } - - /// Create a new HEAD request. - #[inline] - #[deprecated = "use hyper::Client"] - pub fn head(url: Url) -> HttpResult> { Request::new(Head, url) } - - /// Create a new OPTIONS request. - #[inline] - #[deprecated = "use hyper::Client"] - pub fn options(url: Url) -> HttpResult> { Request::new(Options, url) } - /// Consume a Fresh Request, writing the headers and method, /// returning a Streaming Request. pub fn start(mut self) -> HttpResult> { @@ -119,7 +86,7 @@ impl Request { 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()) diff --git a/src/header/common/cache_control.rs b/src/header/common/cache_control.rs index cb94f4cb..05aef3d8 100644 --- a/src/header/common/cache_control.rs +++ b/src/header/common/cache_control.rs @@ -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) @@ -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 { use self::CacheDirective::*; diff --git a/src/header/common/content_length.rs b/src/header/common/content_length.rs index ff97cdb2..4b243eda 100644 --- a/src/header/common/content_length.rs +++ b/src/header/common/content_length.rs @@ -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) -> &'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) } } diff --git a/src/header/common/cookie.rs b/src/header/common/cookie.rs index d595e463..d2b22989 100644 --- a/src/header/common/cookie.rs +++ b/src/header/common/cookie.rs @@ -16,10 +16,6 @@ use cookie::CookieJar; #[derive(Clone, PartialEq, Show)] pub struct Cookies(pub Vec); -//TODO: remove when fixed in libstd -unsafe impl Send for Cookies {} -unsafe impl Sync for Cookies {} - deref!(Cookies => Vec); impl Header for Cookies { diff --git a/src/header/common/set_cookie.rs b/src/header/common/set_cookie.rs index a11fb110..5e2e964f 100644 --- a/src/header/common/set_cookie.rs +++ b/src/header/common/set_cookie.rs @@ -13,10 +13,6 @@ use cookie::CookieJar; #[derive(Clone, PartialEq, Show)] pub struct SetCookie(pub Vec); -//TODO: remove when fixed in libstd -unsafe impl Send for SetCookie {} -unsafe impl Sync for SetCookie {} - deref!(SetCookie => Vec); impl Header for SetCookie { diff --git a/src/header/common/vary.rs b/src/header/common/vary.rs index 74a5280a..69ca3c5a 100644 --- a/src/header/common/vary.rs +++ b/src/header/common/vary.rs @@ -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), + Headers(Vec>), } impl Header for Vary { diff --git a/src/header/mod.rs b/src/header/mod.rs index f3ea3eef..6f21234f 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -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>; + /// 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 HeaderClone for T { #[inline] fn clone_box(&self) -> Box { - box self.clone() + Box::new(self.clone()) } } @@ -116,7 +117,7 @@ fn header_name() -> &'static str { /// A map of header fields on requests and responses. #[derive(Clone)] pub struct Headers { - data: HashMap> + data: HashMap> } 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(&mut self, value: H) { - self.data.insert(CaseInsensitive(Borrowed(header_name::())), - MuCell::new(Item::typed(box value as Box))); + self.data.insert(UniCase(Borrowed(header_name::())), + 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]> { 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>(&mut self, name: K, value: Vec>) { - 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(&self) -> Option<&MuCell> { - self.data.get(&CaseInsensitive(Borrowed(header_name::()))).and_then(get_or_parse::) + self.data.get(&UniCase(Borrowed(header_name::()))).and_then(get_or_parse::) } fn get_or_parse_mut(&mut self) -> Option<&mut MuCell> { - self.data.get_mut(&CaseInsensitive(Borrowed(header_name::()))).and_then(get_or_parse_mut::) + self.data.get_mut(&UniCase(Borrowed(header_name::()))).and_then(get_or_parse_mut::) } /// Returns a boolean of whether a certain header is in the map. @@ -241,13 +242,13 @@ impl Headers { /// let has_type = headers.has::(); /// ``` pub fn has(&self) -> bool { - self.data.contains_key(&CaseInsensitive(Borrowed(header_name::()))) + self.data.contains_key(&UniCase(Borrowed(header_name::()))) } /// Removes a header from the map, if one existed. /// Returns true if a header has been removed. pub fn remove(&mut self) -> bool { - self.data.remove(&CaseInsensitive(Borrowed(Header::header_name(None::)))).is_some() + self.data.remove(&UniCase(Borrowed(Header::header_name(None::)))).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> + inner: Iter<'a, HeaderName, MuCell> } 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); +pub struct HeaderView<'a>(&'a HeaderName, &'a MuCell); impl<'a> HeaderView<'a> { /// Check if a HeaderView is a certain Header. #[inline] pub fn is(&self) -> bool { - CaseInsensitive(header_name::().into_cow()) == *self.0 + UniCase(header_name::().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 { 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 { } } -impl fmt::Show for Box { - 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 { - 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 hash::Hash 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::>(); + let mut pieces = s.split_str("\r\n").collect::>(); pieces.sort(); let s = pieces.into_iter().rev().collect::>().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] diff --git a/src/http.rs b/src/http.rs index 3bbff7c3..d00169d6 100644 --- a/src/http.rs +++ b/src/http.rs @@ -30,9 +30,9 @@ use self::HttpWriter::{ThroughWriter, ChunkedWriter, SizedWriter, EmptyWriter}; /// include a Content-Length header. pub enum HttpReader { /// 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), + ChunkedReader(R, Option), /// 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 Reader for HttpReader { 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 Reader for HttpReader { 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 Reader for HttpReader { 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(rdr: &mut R, bytes: &[u8]) -> IoResult<()> { } /// Chunked chunks start with 1*HEXDIGIT, indicating the size of the chunk. -fn read_chunk_size(rdr: &mut R) -> IoResult { - let mut size = 0us; +fn read_chunk_size(rdr: &mut R) -> IoResult { + 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(rdr: &mut R) -> IoResult { 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 { /// 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 Writer for HttpWriter { 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(stream: &mut R) -> HttpResult { 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) { + fn read(s: &str, result: IoResult) { assert_eq!(read_chunk_size(&mut mem(s)), result); } diff --git a/src/lib.rs b/src/lib.rs index 5623f926..aa19e062 100644 --- a/src/lib.rs +++ b/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 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() { _assert_send::>(); _assert_send::(); diff --git a/src/method.rs b/src/method.rs index 68aa100d..8f75f8bc 100644 --- a/src/method.rs +++ b/src/method.rs @@ -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; diff --git a/src/mock.rs b/src/mock.rs index e5cda053..419895f3 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -68,7 +68,9 @@ impl NetworkStream for MockStream { pub struct MockConnector; -impl NetworkConnector for MockConnector { +impl NetworkConnector for MockConnector { + type Stream = MockStream; + fn connect(&mut self, _host: &str, _port: u16, _scheme: &str) -> IoResult { 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); diff --git a/src/net.rs b/src/net.rs index 21d8fd98..579ddae4 100644 --- a/src/net.rs +++ b/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>: Listener { - /// Bind to a socket. - /// - /// Note: This does not start listening for connections. You must call - /// `listen()` to do that. - fn bind(addr: To) -> IoResult; - - /// Get the address this Listener ended up listening on. - fn socket_name(&mut self) -> IoResult; +pub trait NetworkListener { + type Acceptor: NetworkAcceptor; + /// Listens on a socket. + fn listen(&mut self, addr: To) -> IoResult; } /// An abstraction to receive `NetworkStream`s. -pub trait NetworkAcceptor: Acceptor + Clone + Send { +pub trait NetworkAcceptor: Clone + Send { + type Stream: NetworkStream + Send + Clone; + + /// Returns an iterator of streams. + fn accept(&mut self) -> IoResult; + + /// Get the address this Listener ended up listening on. + fn socket_name(&self) -> IoResult; + /// 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 { + 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; + fn next(&mut self) -> Option> { + 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; } + #[doc(hidden)] pub trait StreamClone { fn clone_box(&self) -> Box; @@ -57,14 +75,15 @@ pub trait StreamClone { impl StreamClone for T { #[inline] fn clone_box(&self) -> Box { - box self.clone() + Box::new(self.clone()) } } /// A connector creates a NetworkStream. -pub trait NetworkConnector { +pub trait NetworkConnector { + type Stream: NetworkStream + Send; /// Connect to a remote address. - fn connect(&mut self, host: &str, port: Port, scheme: &str) -> IoResult; + fn connect(&mut self, host: &str, port: Port, scheme: &str) -> IoResult; } impl fmt::Show for Box { @@ -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 for HttpListener { - #[inline] - fn listen(self) -> IoResult { - Ok(HttpAcceptor { - inner: try!(self.inner.listen()) - }) - } -} - -impl NetworkListener for HttpListener { - #[inline] - fn bind(addr: To) -> IoResult { - Ok(HttpListener { - inner: try!(TcpListener::bind(addr)) - }) - } +impl NetworkListener for HttpListener { + type Acceptor = HttpAcceptor; #[inline] - fn socket_name(&mut self) -> IoResult { - self.inner.socket_name() + fn listen(&mut self, addr: To) -> IoResult { + 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 for HttpAcceptor { +impl NetworkAcceptor for HttpAcceptor { + type Stream = HttpStream; + #[inline] fn accept(&mut self) -> IoResult { - 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 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 { + 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 { 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 { 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); -impl NetworkConnector for HttpConnector { +impl NetworkConnector for HttpConnector { + type Stream = HttpStream; + fn connect(&mut self, host: &str, port: Port, scheme: &str) -> IoResult { 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 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; diff --git a/src/server/mod.rs b/src/server/mod.rs index f9838a92..fa7f43d2 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -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 { ip: IpAddr, - port: Port + port: Port, + listener: L, } macro_rules! try_option( @@ -43,29 +44,28 @@ macro_rules! try_option( impl Server { /// 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 Server { - /// 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(self, handler: H, threads: usize) -> HttpResult> - where H: Handler, - S: NetworkStream + Clone, - A: NetworkAcceptor, - L: NetworkListener, { +impl< +L: NetworkListener + Send, +A: NetworkAcceptor + Send, +S: NetworkStream + Clone + Send> Server { + /// Creates a new server that will handle `HttpStream`s. + pub fn with_listener(ip: IpAddr, port: Port, listener: L) -> Server { + Server { + ip: ip, + port: port, + listener: listener, + } + } + + /// Binds to a socket, and starts handling connections using a task pool. + pub fn listen_threads(mut self, handler: H, threads: usize) -> HttpResult> { debug!("binding to {:?}:{:?}", self.ip, self.port); - let mut listener: L = try!(NetworkListener::::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 Server { socket: socket, }) } -} - -#[old_impl_check] -impl, S: NetworkStream, A: NetworkAcceptor> Server { - /// Binds to a socket and starts handling connections with the specified number of tasks. - pub fn listen_threads(self, handler: H, threads: usize) -> HttpResult> { - self.listen_network::(handler, threads) - } /// Binds to a socket and starts handling connections. - pub fn listen(self, handler: H) -> HttpResult> { + pub fn listen(self, handler: H) -> HttpResult> { self.listen_threads(handler, os::num_cpus() * 5 / 4) } @@ -158,8 +150,7 @@ pub struct Listening { pub socket: SocketAddr, } -#[old_impl_check] -impl, S: NetworkStream> Listening { +impl Listening { /// Causes the current thread to wait for this listening to complete. pub fn await(&mut self) { if let Some(guard) = self.guard.take() { diff --git a/src/server/request.rs b/src/server/request.rs index 1a44d6a6..3ea817a9 100644 --- a/src/server/request.rs +++ b/src/server/request.rs @@ -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) diff --git a/src/status.rs b/src/status.rs index 6bd267ae..ed93d0d2 100644 --- a/src/status.rs +++ b/src/status.rs @@ -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 { diff --git a/src/version.rs b/src/version.rs index 5a35b148..eb63fb5b 100644 --- a/src/version.rs +++ b/src/version.rs @@ -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) - } -} -