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