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
This commit is contained in:
Sean McArthur
2015-01-10 00:46:43 -08:00
parent 4026ec1d73
commit f7124bb8e2
24 changed files with 232 additions and 362 deletions

View File

@@ -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 = "*"

View File

@@ -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;

View File

@@ -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())
} }

View File

@@ -1,3 +1,4 @@
#![allow(unstable)]
extern crate hyper; extern crate hyper;
extern crate test; extern crate test;

View File

@@ -1,3 +1,4 @@
#![allow(unstable)]
extern crate hyper; extern crate hyper;
use std::os; use std::os;

View File

@@ -1,3 +1,4 @@
#![allow(unstable)]
extern crate hyper; extern crate hyper;
use std::io::net::ip::Ipv4Addr; use std::io::net::ip::Ipv4Addr;

View File

@@ -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());

View File

@@ -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
} }
} }

View File

@@ -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())

View File

@@ -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::*;

View File

@@ -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
} }
} }

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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.
@@ -269,9 +270,9 @@ 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]

View File

@@ -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);
} }

View File

@@ -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>();

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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<
/// Binds to a socket, and starts handling connections using a task pool. L: NetworkListener<Acceptor=A> + Send,
/// A: NetworkAcceptor<Stream=S> + Send,
/// This method has unbound type parameters, so can be used when you want to use S: NetworkStream + Clone + Send> Server<L> {
/// something other than the provided HttpStream, HttpAcceptor, and HttpListener. /// Creates a new server that will handle `HttpStream`s.
pub fn listen_network<H, S, A, L>(self, handler: H, threads: usize) -> HttpResult<Listening<A>> pub fn with_listener(ip: IpAddr, port: Port, listener: L) -> Server<L> {
where H: Handler, Server {
S: NetworkStream + Clone, ip: ip,
A: NetworkAcceptor<S>, port: port,
L: NetworkListener<S, A>, { listener: listener,
}
}
/// Binds to a socket, and starts handling connections using a task pool.
pub fn listen_threads<H: Handler>(mut self, handler: H, threads: usize) -> HttpResult<Listening<L::Acceptor>> {
debug!("binding to {:?}:{:?}", self.ip, self.port); 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() {

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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)
}
}