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>"]
[dependencies]
url = "*"
openssl = "*"
mime = "*"
unsafe-any = "*"
cookie = "*"
time = "*"
mucell = "*"
log = "*"
mime = "*"
mucell = "*"
openssl = "*"
rustc-serialize = "*"
[dev-dependencies]
curl = "*"
time = "*"
unicase = "*"
unsafe-any = "*"
url = "*"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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