Merge branch 'master' into accesscontrol

This commit is contained in:
Pyfisch
2015-01-06 20:37:23 +01:00
43 changed files with 201 additions and 180 deletions

View File

@@ -1,7 +1,7 @@
[package] [package]
name = "hyper" name = "hyper"
version = "0.0.20" version = "0.0.21"
description = "A modern HTTP library." description = "A modern HTTP library."
readme = "README.md" readme = "README.md"
documentation = "http://hyperium.github.io/hyper/hyper/index.html" documentation = "http://hyperium.github.io/hyper/hyper/index.html"

View File

@@ -4,7 +4,7 @@ extern crate hyper;
extern crate test; extern crate test;
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::io::net::ip::Ipv4Addr; use std::io::net::ip::Ipv4Addr;
use hyper::server::{Request, Response, Server}; use hyper::server::{Request, Response, Server};
use hyper::header::Headers; use hyper::header::Headers;
@@ -46,7 +46,7 @@ fn bench_curl(b: &mut test::Bencher) {
listening.close().unwrap(); listening.close().unwrap();
} }
#[deriving(Clone)] #[derive(Clone)]
struct Foo; struct Foo;
impl hyper::header::Header for Foo { impl hyper::header::Header for Foo {

View File

@@ -4,8 +4,7 @@ extern crate hyper;
extern crate test; extern crate test;
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::str::from_str;
use std::io::{IoResult, MemReader}; use std::io::{IoResult, MemReader};
use std::io::net::ip::SocketAddr; use std::io::net::ip::SocketAddr;
use std::os; use std::os;
@@ -65,7 +64,7 @@ fn bench_mock_curl(b: &mut test::Bencher) {
}); });
} }
#[deriving(Clone)] #[derive(Clone)]
struct Foo; struct Foo;
impl hyper::header::Header for Foo { impl hyper::header::Header for Foo {
@@ -85,7 +84,7 @@ impl hyper::header::HeaderFormat for Foo {
impl net::NetworkStream for MockStream { impl net::NetworkStream for MockStream {
fn peer_name(&mut self) -> IoResult<SocketAddr> { fn peer_name(&mut self) -> IoResult<SocketAddr> {
Ok(from_str("127.0.0.1:1337").unwrap()) Ok("127.0.0.1:1337".parse().unwrap())
} }
} }

View File

@@ -315,7 +315,7 @@ impl<'a> IntoUrl for &'a str {
} }
/// Behavior regarding how to handle redirects within a Client. /// Behavior regarding how to handle redirects within a Client.
#[deriving(Copy)] #[derive(Copy)]
pub enum RedirectPolicy { pub enum RedirectPolicy {
/// Don't follow any redirects. /// Don't follow any redirects.
FollowNone, FollowNone,

View File

@@ -6,7 +6,7 @@ use url::Url;
use method; use method;
use method::Method::{Get, Post, Delete, Put, Patch, Head, Options}; use method::Method::{Get, Post, Delete, Put, Patch, Head, Options};
use header::Headers; use header::Headers;
use header::common::{mod, Host}; use header::common::{self, Host};
use net::{NetworkStream, NetworkConnector, HttpConnector, Fresh, Streaming}; use net::{NetworkStream, NetworkConnector, HttpConnector, Fresh, Streaming};
use http::{HttpWriter, LINE_ENDING}; use http::{HttpWriter, LINE_ENDING};
use http::HttpWriter::{ThroughWriter, ChunkedWriter, SizedWriter, EmptyWriter}; use http::HttpWriter::{ThroughWriter, ChunkedWriter, SizedWriter, EmptyWriter};
@@ -114,15 +114,14 @@ impl Request<Fresh> {
} }
debug!("writing head: {} {} {}", self.method, uri, self.version); debug!("writing head: {} {} {}", self.method, uri, self.version);
try!(write!(&mut self.body, "{} {} {}", self.method, uri, self.version)); try!(write!(&mut self.body, "{} {} {}{}",
try!(self.body.write(LINE_ENDING)); self.method, uri, self.version, LINE_ENDING));
let stream = match self.method { let stream = match self.method {
Get | Head => { Get | Head => {
debug!("headers [\n{}]", self.headers); debug!("headers [\n{}]", self.headers);
try!(write!(&mut self.body, "{}", self.headers)); try!(write!(&mut self.body, "{}{}", self.headers, LINE_ENDING));
try!(self.body.write(LINE_ENDING));
EmptyWriter(self.body.unwrap()) EmptyWriter(self.body.unwrap())
}, },
_ => { _ => {
@@ -155,8 +154,7 @@ impl Request<Fresh> {
} }
debug!("headers [\n{}]", self.headers); debug!("headers [\n{}]", self.headers);
try!(write!(&mut self.body, "{}", self.headers)); try!(write!(&mut self.body, "{}{}", self.headers, LINE_ENDING));
try!(self.body.write(LINE_ENDING));
if chunked { if chunked {
ChunkedWriter(self.body.unwrap()) ChunkedWriter(self.body.unwrap())
@@ -217,7 +215,8 @@ mod tests {
Get, Url::parse("http://example.dom").unwrap(), &mut MockConnector Get, Url::parse("http://example.dom").unwrap(), &mut MockConnector
).unwrap(); ).unwrap();
let req = req.start().unwrap(); let req = req.start().unwrap();
let stream = *req.body.end().unwrap().into_inner().downcast::<MockStream>().unwrap(); let stream = *req.body.end().unwrap()
.into_inner().downcast::<MockStream>().ok().unwrap();
let bytes = stream.write.into_inner(); let bytes = stream.write.into_inner();
let s = from_utf8(bytes[]).unwrap(); let s = from_utf8(bytes[]).unwrap();
assert!(!s.contains("Content-Length:")); assert!(!s.contains("Content-Length:"));
@@ -230,7 +229,8 @@ mod tests {
Head, Url::parse("http://example.dom").unwrap(), &mut MockConnector Head, Url::parse("http://example.dom").unwrap(), &mut MockConnector
).unwrap(); ).unwrap();
let req = req.start().unwrap(); let req = req.start().unwrap();
let stream = *req.body.end().unwrap().into_inner().downcast::<MockStream>().unwrap(); let stream = *req.body.end().unwrap()
.into_inner().downcast::<MockStream>().ok().unwrap();
let bytes = stream.write.into_inner(); let bytes = stream.write.into_inner();
let s = from_utf8(bytes[]).unwrap(); let s = from_utf8(bytes[]).unwrap();
assert!(!s.contains("Content-Length:")); assert!(!s.contains("Content-Length:"));

View File

@@ -120,7 +120,7 @@ mod tests {
status_raw: RawStatus(200, Borrowed("OK")) status_raw: RawStatus(200, Borrowed("OK"))
}; };
let b = res.into_inner().downcast::<MockStream>().unwrap(); let b = res.into_inner().downcast::<MockStream>().ok().unwrap();
assert_eq!(b, box MockStream::new()); assert_eq!(b, box MockStream::new());
} }

View File

@@ -25,7 +25,7 @@ use mime;
/// qitem(Mime(Text, Html, vec![])), /// qitem(Mime(Text, Html, vec![])),
/// qitem(Mime(Text, Xml, vec![])) ])); /// qitem(Mime(Text, Xml, vec![])) ]));
/// ``` /// ```
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct Accept(pub Vec<shared::QualityItem<mime::Mime>>); pub struct Accept(pub Vec<shared::QualityItem<mime::Mime>>);
deref!(Accept -> Vec<shared::QualityItem<mime::Mime>>); deref!(Accept -> Vec<shared::QualityItem<mime::Mime>>);

View File

@@ -7,7 +7,7 @@ use header::shared;
/// ///
/// The `Accept-Encoding` header can be used by clients to indicate what /// The `Accept-Encoding` header can be used by clients to indicate what
/// response encodings they accept. /// response encodings they accept.
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct AcceptEncoding(pub Vec<shared::QualityItem<shared::Encoding>>); pub struct AcceptEncoding(pub Vec<shared::QualityItem<shared::Encoding>>);
deref!(AcceptEncoding -> Vec<shared::QualityItem<shared::Encoding>>); deref!(AcceptEncoding -> Vec<shared::QualityItem<shared::Encoding>>);

View File

@@ -1,12 +1,12 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use method::Method; use method::Method;
use std::fmt::{mod}; use std::fmt::{self};
use header::shared::util::{from_comma_delimited, fmt_comma_delimited}; use header::shared::util::{from_comma_delimited, fmt_comma_delimited};
/// The `Allow` header. /// The `Allow` header.
/// See also https://tools.ietf.org/html/rfc7231#section-7.4.1 /// See also https://tools.ietf.org/html/rfc7231#section-7.4.1
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct Allow(pub Vec<Method>); pub struct Allow(pub Vec<Method>);
deref!(Allow -> Vec<Method>); deref!(Allow -> Vec<Method>);
@@ -31,7 +31,7 @@ impl HeaderFormat for Allow {
mod tests { mod tests {
use super::Allow; use super::Allow;
use header::Header; use header::Header;
use method::Method::{mod, Options, Get, Put, Post, Delete, Head, Trace, Connect, Patch, Extension}; use method::Method::{self, Options, Get, Put, Post, Delete, Head, Trace, Connect, Patch, Extension};
#[test] #[test]
fn test_allow() { fn test_allow() {

View File

@@ -1,19 +1,22 @@
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::str::{FromStr, from_utf8}; use std::str::{FromStr, from_utf8};
use std::ops::{Deref, DerefMut};
use serialize::base64::{ToBase64, FromBase64, Standard, Config, Newline}; use serialize::base64::{ToBase64, FromBase64, Standard, Config, Newline};
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
/// The `Authorization` header field. /// The `Authorization` header field.
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct Authorization<S: Scheme>(pub S); pub struct Authorization<S: Scheme>(pub S);
impl<S: Scheme> Deref<S> for Authorization<S> { impl<S: Scheme> Deref for Authorization<S> {
type Target = S;
fn deref<'a>(&'a self) -> &'a S { fn deref<'a>(&'a self) -> &'a S {
&self.0 &self.0
} }
} }
impl<S: Scheme> DerefMut<S> for Authorization<S> { impl<S: Scheme> DerefMut for Authorization<S> {
fn deref_mut<'a>(&'a mut self) -> &'a mut S { fn deref_mut<'a>(&'a mut self) -> &'a mut S {
&mut self.0 &mut self.0
} }
@@ -72,7 +75,7 @@ impl Scheme for String {
} }
/// Credential holder for Basic Authentication /// Credential holder for Basic Authentication
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct Basic { pub struct Basic {
/// The username as a possibly empty string /// The username as a possibly empty string
pub username: String, pub username: String,

View File

@@ -4,7 +4,7 @@ use header::{Header, HeaderFormat};
use header::shared::util::{from_one_comma_delimited, fmt_comma_delimited}; use header::shared::util::{from_one_comma_delimited, fmt_comma_delimited};
/// The Cache-Control header. /// The Cache-Control header.
#[deriving(PartialEq, Clone, Show)] #[derive(PartialEq, Clone, Show)]
pub struct CacheControl(pub Vec<CacheDirective>); pub struct CacheControl(pub Vec<CacheDirective>);
deref!(CacheControl -> Vec<CacheDirective>); deref!(CacheControl -> Vec<CacheDirective>);
@@ -34,7 +34,7 @@ impl HeaderFormat for CacheControl {
} }
/// CacheControl contains a list of these directives. /// CacheControl contains a list of these directives.
#[deriving(PartialEq, Clone)] #[derive(PartialEq, Clone)]
pub enum CacheDirective { pub enum CacheDirective {
/// "no-cache" /// "no-cache"
NoCache, NoCache,

View File

@@ -1,18 +1,18 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::str::FromStr; use std::str::FromStr;
use header::shared::util::{from_comma_delimited, fmt_comma_delimited}; use header::shared::util::{from_comma_delimited, fmt_comma_delimited};
pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader}; pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader};
/// The `Connection` header. /// The `Connection` header.
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct Connection(pub Vec<ConnectionOption>); pub struct Connection(pub Vec<ConnectionOption>);
deref!(Connection -> Vec<ConnectionOption>); deref!(Connection -> Vec<ConnectionOption>);
/// Values that can be in the `Connection` header. /// Values that can be in the `Connection` header.
#[deriving(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum ConnectionOption { pub enum ConnectionOption {
/// The `keep-alive` connection value. /// The `keep-alive` connection value.
KeepAlive, KeepAlive,

View File

@@ -1,4 +1,4 @@
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use header::shared::util::from_one_raw_str; use header::shared::util::from_one_raw_str;
@@ -6,7 +6,7 @@ use header::shared::util::from_one_raw_str;
/// The `Content-Length` header. /// The `Content-Length` header.
/// ///
/// Simply a wrapper around a `uint`. /// Simply a wrapper around a `uint`.
#[deriving(Copy, Clone, PartialEq, Show)] #[derive(Copy, Clone, PartialEq, Show)]
pub struct ContentLength(pub uint); pub struct ContentLength(pub uint);
deref!(ContentLength -> uint); deref!(ContentLength -> uint);

View File

@@ -1,5 +1,5 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use header::shared::util::from_one_raw_str; use header::shared::util::from_one_raw_str;
use mime::Mime; use mime::Mime;
@@ -7,7 +7,7 @@ use mime::Mime;
/// ///
/// Used to describe the MIME type of message body. Can be used with both /// Used to describe the MIME type of message body. Can be used with both
/// requests and responses. /// requests and responses.
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct ContentType(pub Mime); pub struct ContentType(pub Mime);
deref!(ContentType -> Mime); deref!(ContentType -> Mime);

View File

@@ -1,5 +1,5 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::str::from_utf8; use std::str::from_utf8;
use cookie::Cookie; use cookie::Cookie;
@@ -13,7 +13,7 @@ use cookie::CookieJar;
/// ///
/// > When the user agent generates an HTTP request, the user agent MUST NOT /// > When the user agent generates an HTTP request, the user agent MUST NOT
/// > attach more than one Cookie header field. /// > attach more than one Cookie header field.
#[deriving(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 //TODO: remove when fixed in libstd

View File

@@ -1,4 +1,4 @@
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::str::FromStr; use std::str::FromStr;
use time::Tm; use time::Tm;
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
@@ -7,7 +7,7 @@ use header::shared::time::tm_from_str;
// Egh, replace as soon as something better than time::Tm exists. // Egh, replace as soon as something better than time::Tm exists.
/// The `Date` header field. /// The `Date` header field.
#[deriving(Copy, PartialEq, Clone)] #[derive(Copy, PartialEq, Clone)]
pub struct Date(pub Tm); pub struct Date(pub Tm);
deref!(Date -> Tm); deref!(Date -> Tm);

View File

@@ -1,5 +1,5 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt::{mod}; use std::fmt::{self};
use header::shared::util::from_one_raw_str; use header::shared::util::from_one_raw_str;
/// The `Etag` header. /// The `Etag` header.
@@ -8,7 +8,7 @@ use header::shared::util::from_one_raw_str;
/// Preceding the first double quote is an optional weakness indicator, /// Preceding the first double quote is an optional weakness indicator,
/// which always looks like this: W/ /// which always looks like this: W/
/// See also: https://tools.ietf.org/html/rfc7232#section-2.3 /// See also: https://tools.ietf.org/html/rfc7232#section-2.3
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct Etag { pub struct Etag {
/// Weakness indicator for the tag /// Weakness indicator for the tag
pub weak: bool, pub weak: bool,
@@ -81,7 +81,7 @@ impl Header for Etag {
impl HeaderFormat for Etag { impl HeaderFormat for Etag {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if self.weak { if self.weak {
try!(fmt.write(b"W/")); try!(fmt.write_str("W/"));
} }
write!(fmt, "\"{}\"", self.tag) write!(fmt, "\"{}\"", self.tag)
} }

View File

@@ -1,4 +1,4 @@
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::str::FromStr; use std::str::FromStr;
use time::Tm; use time::Tm;
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
@@ -6,7 +6,7 @@ use header::shared::util::from_one_raw_str;
use header::shared::time::tm_from_str; use header::shared::time::tm_from_str;
/// The `Expires` header field. /// The `Expires` header field.
#[deriving(Copy, PartialEq, Clone)] #[derive(Copy, PartialEq, Clone)]
pub struct Expires(pub Tm); pub struct Expires(pub Tm);
deref!(Expires -> Tm); deref!(Expires -> Tm);

View File

@@ -1,6 +1,6 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use Port; use Port;
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use header::shared::util::from_one_raw_str; use header::shared::util::from_one_raw_str;
/// The `Host` header. /// The `Host` header.
@@ -10,7 +10,7 @@ use header::shared::util::from_one_raw_str;
/// ///
/// Currently is just a String, but it should probably become a better type, /// Currently is just a String, but it should probably become a better type,
/// like url::Host or something. /// like url::Host or something.
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct Host { pub struct Host {
/// The hostname, such a example.domain. /// The hostname, such a example.domain.
pub hostname: String, pub hostname: String,

View File

@@ -1,4 +1,4 @@
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::str::FromStr; use std::str::FromStr;
use time::Tm; use time::Tm;
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
@@ -6,7 +6,7 @@ use header::shared::util::from_one_raw_str;
use header::shared::time::tm_from_str; use header::shared::time::tm_from_str;
/// The `If-Modified-Since` header field. /// The `If-Modified-Since` header field.
#[deriving(Copy, PartialEq, Clone)] #[derive(Copy, PartialEq, Clone)]
pub struct IfModifiedSince(pub Tm); pub struct IfModifiedSince(pub Tm);
deref!(IfModifiedSince -> Tm); deref!(IfModifiedSince -> Tm);

View File

@@ -1,4 +1,4 @@
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::str::FromStr; use std::str::FromStr;
use time::Tm; use time::Tm;
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
@@ -6,7 +6,7 @@ use header::shared::util::from_one_raw_str;
use header::shared::time::tm_from_str; use header::shared::time::tm_from_str;
/// The `LastModified` header field. /// The `LastModified` header field.
#[deriving(Copy, PartialEq, Clone)] #[derive(Copy, PartialEq, Clone)]
pub struct LastModified(pub Tm); pub struct LastModified(pub Tm);
deref!(LastModified -> Tm); deref!(LastModified -> Tm);

View File

@@ -1,5 +1,5 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use header::shared::util::from_one_raw_str; use header::shared::util::from_one_raw_str;
/// The `Location` header. /// The `Location` header.
@@ -13,7 +13,7 @@ use header::shared::util::from_one_raw_str;
/// ///
/// Currently is just a String, but it should probably become a better type, /// Currently is just a String, but it should probably become a better type,
/// like url::Url or something. /// like url::Url or something.
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct Location(pub String); pub struct Location(pub String);
deref!(Location -> String); deref!(Location -> String);

View File

@@ -60,13 +60,15 @@ macro_rules! bench_header(
macro_rules! deref( macro_rules! deref(
($from:ty -> $to:ty) => { ($from:ty -> $to:ty) => {
impl Deref<$to> for $from { impl ::std::ops::Deref for $from {
type Target = $to;
fn deref<'a>(&'a self) -> &'a $to { fn deref<'a>(&'a self) -> &'a $to {
&self.0 &self.0
} }
} }
impl DerefMut<$to> for $from { impl ::std::ops::DerefMut for $from {
fn deref_mut<'a>(&'a mut self) -> &'a mut $to { fn deref_mut<'a>(&'a mut self) -> &'a mut $to {
&mut self.0 &mut self.0
} }

View File

@@ -1,11 +1,11 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use header::shared::util::from_one_raw_str; use header::shared::util::from_one_raw_str;
/// The `Server` header field. /// The `Server` header field.
/// ///
/// They can contain any value, so it just wraps a `String`. /// They can contain any value, so it just wraps a `String`.
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct Server(pub String); pub struct Server(pub String);
deref!(Server -> String); deref!(Server -> String);

View File

@@ -1,5 +1,5 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::str::from_utf8; use std::str::from_utf8;
use cookie::Cookie; use cookie::Cookie;
@@ -10,7 +10,7 @@ use cookie::CookieJar;
/// Informally, the Set-Cookie response header contains the header name /// Informally, the Set-Cookie response header contains the header name
/// "Set-Cookie" followed by a ":" and a cookie. Each cookie begins with /// "Set-Cookie" followed by a ":" and a cookie. Each cookie begins with
/// a name-value-pair, followed by zero or more attribute-value pairs. /// a name-value-pair, followed by zero or more attribute-value pairs.
#[deriving(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 //TODO: remove when fixed in libstd
@@ -52,7 +52,7 @@ impl HeaderFormat for SetCookie {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, cookie) in self.0.iter().enumerate() { for (i, cookie) in self.0.iter().enumerate() {
if i != 0 { if i != 0 {
try!(f.write(b"\r\nSet-Cookie: ")); try!(f.write_str("\r\nSet-Cookie: "));
} }
try!(cookie.fmt(f)); try!(cookie.fmt(f));
} }

View File

@@ -18,7 +18,7 @@ use self::Encoding::{Chunked, Gzip, Deflate, Compress, EncodingExt};
/// this header should include `chunked` as the last encoding. /// this header should include `chunked` as the last encoding.
/// ///
/// The implementation uses a vector of `Encoding` values. /// The implementation uses a vector of `Encoding` values.
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct TransferEncoding(pub Vec<Encoding>); pub struct TransferEncoding(pub Vec<Encoding>);
deref!(TransferEncoding -> Vec<Encoding>); deref!(TransferEncoding -> Vec<Encoding>);
@@ -33,7 +33,7 @@ deref!(TransferEncoding -> Vec<Encoding>);
/// # use hyper::header::Headers; /// # use hyper::header::Headers;
/// # let mut headers = Headers::new(); /// # let mut headers = Headers::new();
/// headers.set(TransferEncoding(vec![Gzip, Chunked])); /// headers.set(TransferEncoding(vec![Gzip, Chunked]));
#[deriving(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum Encoding { pub enum Encoding {
/// The `chunked` encoding. /// The `chunked` encoding.
Chunked, Chunked,

View File

@@ -1,18 +1,18 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::str::FromStr; use std::str::FromStr;
use header::shared::util::{from_comma_delimited, fmt_comma_delimited}; use header::shared::util::{from_comma_delimited, fmt_comma_delimited};
use self::Protocol::{WebSocket, ProtocolExt}; use self::Protocol::{WebSocket, ProtocolExt};
/// The `Upgrade` header. /// The `Upgrade` header.
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct Upgrade(pub Vec<Protocol>); pub struct Upgrade(pub Vec<Protocol>);
deref!(Upgrade -> Vec<Protocol>); deref!(Upgrade -> Vec<Protocol>);
/// Protocol values that can appear in the Upgrade header. /// Protocol values that can appear in the Upgrade header.
#[deriving(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum Protocol { pub enum Protocol {
/// The websocket protocol. /// The websocket protocol.
WebSocket, WebSocket,

View File

@@ -1,11 +1,11 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use header::shared::util::from_one_raw_str; use header::shared::util::from_one_raw_str;
/// The `User-Agent` header field. /// The `User-Agent` header field.
/// ///
/// They can contain any value, so it just wraps a `String`. /// They can contain any value, so it just wraps a `String`.
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub struct UserAgent(pub String); pub struct UserAgent(pub String);
deref!(UserAgent -> String); deref!(UserAgent -> String);

View File

@@ -1,11 +1,11 @@
use header::{Header, HeaderFormat, CaseInsensitive}; use header::{Header, HeaderFormat, CaseInsensitive};
use std::fmt::{mod}; 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};
/// 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
#[deriving(Clone, PartialEq, Show)] #[derive(Clone, PartialEq, Show)]
pub enum Vary { pub enum Vary {
/// This corresponds to '*'. /// This corresponds to '*'.
Any, Any,

View File

@@ -7,18 +7,21 @@
use std::any::Any; use std::any::Any;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::Cow::{Borrowed, Owned}; use std::borrow::Cow::{Borrowed, Owned};
use std::fmt::{mod, Show}; use std::fmt::{self, Show};
use std::intrinsics::TypeId; use std::intrinsics::TypeId;
use std::raw::TraitObject; use std::raw::TraitObject;
use std::str::{SendStr, FromStr}; use std::str::{FromStr, from_utf8};
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::{hash, mem}; use std::iter::FromIterator;
use std::borrow::IntoCow;
use std::{hash, mem, raw};
use mucell::MuCell; use mucell::MuCell;
use uany::{UncheckedAnyDowncast, UncheckedAnyMutDowncast}; use uany::{UnsafeAnyExt};
use http::{mod, LineEnding}; use http::{self, LineEnding};
use {HttpResult}; use {HttpResult};
pub use self::common::*; pub use self::common::*;
@@ -81,19 +84,20 @@ impl HeaderFormat {
} }
} }
impl<'a> UncheckedAnyDowncast<'a> for &'a HeaderFormat { impl UnsafeAnyExt for HeaderFormat {
#[inline] #[inline]
unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T { unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
let to: TraitObject = mem::transmute_copy(&self); mem::transmute(mem::transmute::<&HeaderFormat, raw::TraitObject>(self).data)
mem::transmute(to.data)
}
} }
impl<'a> UncheckedAnyMutDowncast<'a> for &'a mut HeaderFormat {
#[inline] #[inline]
unsafe fn downcast_mut_unchecked<T: 'static>(self) -> &'a mut T { unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
let to: TraitObject = mem::transmute_copy(&self); mem::transmute(mem::transmute::<&mut HeaderFormat, raw::TraitObject>(self).data)
mem::transmute(to.data) }
#[inline]
unsafe fn downcast_unchecked<T: 'static>(self: Box<HeaderFormat>) -> Box<T> {
mem::transmute(mem::transmute::<Box<HeaderFormat>, raw::TraitObject>(self).data)
} }
} }
@@ -110,7 +114,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.
#[deriving(Clone)] #[derive(Clone)]
pub struct Headers { pub struct Headers {
data: HashMap<CaseInsensitive, MuCell<Item>> data: HashMap<CaseInsensitive, MuCell<Item>>
} }
@@ -132,8 +136,8 @@ impl Headers {
Some((name, value)) => { Some((name, value)) => {
debug!("raw header: {}={}", name, value[]); debug!("raw header: {}={}", name, value[]);
let name = CaseInsensitive(Owned(name)); let name = CaseInsensitive(Owned(name));
let mut item = match headers.data.entry(name) { let mut item = match headers.data.entry(&name) {
Entry::Vacant(entry) => entry.set(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()
}; };
@@ -278,7 +282,9 @@ pub struct HeadersItems<'a> {
inner: Iter<'a, CaseInsensitive, MuCell<Item>> inner: Iter<'a, CaseInsensitive, MuCell<Item>>
} }
impl<'a> Iterator<HeaderView<'a>> for HeadersItems<'a> { impl<'a> Iterator for HeadersItems<'a> {
type Item = HeaderView<'a>;
fn next(&mut self) -> Option<HeaderView<'a>> { fn next(&mut self) -> Option<HeaderView<'a>> {
match self.inner.next() { match self.inner.next() {
Some((k, v)) => Some(HeaderView(k, v)), Some((k, v)) => Some(HeaderView(k, v)),
@@ -327,7 +333,7 @@ impl<'a> fmt::Show for HeaderView<'a> {
} }
impl<'a> Extend<HeaderView<'a>> for Headers { impl<'a> Extend<HeaderView<'a>> for Headers {
fn extend<I: Iterator<HeaderView<'a>>>(&mut self, mut iter: I) { fn extend<I: Iterator<Item=HeaderView<'a>>>(&mut self, mut iter: I) {
for header in iter { for header in iter {
self.data.insert((*header.0).clone(), (*header.1).clone()); self.data.insert((*header.0).clone(), (*header.1).clone());
} }
@@ -335,14 +341,14 @@ impl<'a> Extend<HeaderView<'a>> for Headers {
} }
impl<'a> FromIterator<HeaderView<'a>> for Headers { impl<'a> FromIterator<HeaderView<'a>> for Headers {
fn from_iter<I: Iterator<HeaderView<'a>>>(iter: I) -> Headers { fn from_iter<I: Iterator<Item=HeaderView<'a>>>(iter: I) -> Headers {
let mut headers = Headers::new(); let mut headers = Headers::new();
headers.extend(iter); headers.extend(iter);
headers headers
} }
} }
#[deriving(Clone)] #[derive(Clone)]
struct Item { struct Item {
raw: Option<Vec<Vec<u8>>>, raw: Option<Vec<Vec<u8>>>,
typed: Option<Box<HeaderFormat + Send + Sync>> typed: Option<Box<HeaderFormat + Send + Sync>>
@@ -433,7 +439,13 @@ impl fmt::Show for Item {
None => match self.raw { None => match self.raw {
Some(ref raw) => { Some(ref raw) => {
for part in raw.iter() { for part in raw.iter() {
try!(fmt.write(part.as_slice())); match from_utf8(part[]) {
Ok(s) => try!(fmt.write_str(s)),
Err(e) => {
error!("raw header value is not utf8. header={}, error={}", part[], e);
return Err(fmt::Error);
}
}
} }
Ok(()) Ok(())
}, },
@@ -450,8 +462,7 @@ impl fmt::Show for Box<HeaderFormat + Send + Sync> {
} }
/// Case-insensitive string. /// Case-insensitive string.
//#[deriving(Clone)] pub struct CaseInsensitive(CowString<'static>);
pub struct CaseInsensitive(SendStr);
impl FromStr for CaseInsensitive { impl FromStr for CaseInsensitive {
fn from_str(s: &str) -> Option<CaseInsensitive> { fn from_str(s: &str) -> Option<CaseInsensitive> {
@@ -562,7 +573,7 @@ mod tests {
assert_eq!(accept, Some(Accept(vec![application_vendor, text_plain]))); assert_eq!(accept, Some(Accept(vec![application_vendor, text_plain])));
} }
#[deriving(Clone, Show)] #[derive(Clone, Show)]
struct CrazyLength(Option<bool>, uint); struct CrazyLength(Option<bool>, uint);
impl Header for CrazyLength { impl Header for CrazyLength {
@@ -641,6 +652,13 @@ mod tests {
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]
fn test_headers_show_raw() {
let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
let s = headers.to_string();
assert_eq!(s, "Content-Length: 10\r\n");
}
#[test] #[test]
fn test_set_raw() { fn test_set_raw() {
let mut headers = Headers::new(); let mut headers = Headers::new();

View File

@@ -7,7 +7,7 @@ pub use self::Encoding::{Chunked, Gzip, Deflate, Compress, Identity, EncodingExt
/// A value to represent an encoding used in `Transfer-Encoding` /// A value to represent an encoding used in `Transfer-Encoding`
/// or `Accept-Encoding` header. /// or `Accept-Encoding` header.
#[deriving(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum Encoding { pub enum Encoding {
/// The `chunked` encoding. /// The `chunked` encoding.
Chunked, Chunked,

View File

@@ -9,7 +9,7 @@ use std::str;
/// Represents an item with a quality value as defined in /// Represents an item with a quality value as defined in
/// [RFC7231](https://tools.ietf.org/html/rfc7231#section-5.3.1). /// [RFC7231](https://tools.ietf.org/html/rfc7231#section-5.3.1).
#[deriving(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct QualityItem<T> { pub struct QualityItem<T> {
/// The actual contents of the field. /// The actual contents of the field.
pub item: T, pub item: T,
@@ -79,7 +79,7 @@ pub fn qitem<T>(item: T) -> QualityItem<T> {
#[test] #[test]
fn test_quality_item_show1() { fn test_quality_item_show1() {
let x = qitem(Chunked); let x = qitem(Chunked);
assert_eq!(format!("{}", x), "chunked; q=1.000"); assert_eq!(format!("{}", x), "chunked; q=1");
} }
#[test] #[test]
fn test_quality_item_show2() { fn test_quality_item_show2() {
@@ -93,7 +93,7 @@ fn test_quality_item_show3() {
item: EncodingExt("identity".to_string()), item: EncodingExt("identity".to_string()),
quality: 0.5f32, quality: 0.5f32,
}; };
assert_eq!(format!("{}", x), "identity; q=0.500"); assert_eq!(format!("{}", x), "identity; q=0.5");
} }
#[test] #[test]

View File

@@ -9,7 +9,7 @@ pub fn from_one_raw_str<T: str::FromStr>(raw: &[Vec<u8>]) -> Option<T> {
return None; return None;
} }
// we JUST checked that raw.len() == 1, so raw[0] WILL exist. // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
match str::from_utf8(unsafe { raw[].unsafe_get(0)[] }) { match str::from_utf8(raw[0][]) {
Ok(s) => str::FromStr::from_str(s), Ok(s) => str::FromStr::from_str(s),
Err(_) => None Err(_) => None
} }
@@ -22,7 +22,7 @@ pub fn from_comma_delimited<T: str::FromStr>(raw: &[Vec<u8>]) -> Option<Vec<T>>
return None; return None;
} }
// we JUST checked that raw.len() == 1, so raw[0] WILL exist. // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
from_one_comma_delimited(unsafe { raw.as_slice().unsafe_get(0).as_slice() }) from_one_comma_delimited(raw[0][])
} }
/// Reads a comma-delimited raw string into a Vec. /// Reads a comma-delimited raw string into a Vec.

View File

@@ -1,10 +1,12 @@
//! Pieces pertaining to the HTTP message protocol. //! Pieces pertaining to the HTTP message protocol.
use std::borrow::Cow::{Borrowed, Owned}; use std::borrow::Cow::{Borrowed, Owned};
use std::borrow::IntoCow;
use std::cmp::min; use std::cmp::min;
use std::fmt; use std::fmt;
use std::io::{mod, Reader, IoResult, BufWriter}; use std::io::{self, Reader, IoResult, BufWriter};
use std::num::from_u16; use std::num::from_u16;
use std::str::{mod, SendStr, FromStr}; use std::str::{self, FromStr};
use std::string::CowString;
use url::Url; use url::Url;
use url::ParseError as UrlError; use url::ParseError as UrlError;
@@ -107,7 +109,7 @@ impl<R: Reader> Reader for HttpReader<R> {
*opt_remaining = if rem > 0 { *opt_remaining = if rem > 0 {
Some(rem) Some(rem)
} else { } else {
try!(eat(body, LINE_ENDING)); try!(eat(body, LINE_ENDING.as_bytes()));
None None
}; };
Ok(count) Ok(count)
@@ -236,9 +238,9 @@ impl<W: Writer> Writer for HttpWriter<W> {
ChunkedWriter(ref mut w) => { ChunkedWriter(ref mut w) => {
let chunk_size = msg.len(); let chunk_size = msg.len();
debug!("chunked write, size = {}", chunk_size); debug!("chunked write, size = {}", chunk_size);
try!(write!(w, "{:X}{}{}", chunk_size, CR as char, LF as char)); try!(write!(w, "{:X}{}", chunk_size, LINE_ENDING));
try!(w.write(msg)); try!(w.write(msg));
w.write(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();
@@ -282,7 +284,7 @@ pub const SP: u8 = b' ';
pub const CR: u8 = b'\r'; pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n'; pub const LF: u8 = b'\n';
pub const STAR: u8 = b'*'; pub const STAR: u8 = b'*';
pub const LINE_ENDING: &'static [u8] = &[CR, LF]; pub const LINE_ENDING: &'static str = "\r\n";
/// A `Show`able struct to easily write line endings to a formatter. /// A `Show`able struct to easily write line endings to a formatter.
pub struct LineEnding; pub struct LineEnding;
@@ -291,13 +293,7 @@ impl Copy for LineEnding {}
impl fmt::Show for LineEnding { impl fmt::Show for LineEnding {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write(LINE_ENDING) fmt.write_str(LINE_ENDING)
}
}
impl AsSlice<u8> for LineEnding {
fn as_slice(&self) -> &[u8] {
LINE_ENDING
} }
} }
@@ -582,8 +578,8 @@ pub fn read_request_line<R: Reader>(stream: &mut R) -> HttpResult<RequestLine> {
pub type StatusLine = (HttpVersion, RawStatus); pub type StatusLine = (HttpVersion, RawStatus);
/// The raw status code and reason-phrase. /// The raw status code and reason-phrase.
#[deriving(PartialEq, Show)] #[derive(PartialEq, Show)]
pub struct RawStatus(pub u16, pub SendStr); pub struct RawStatus(pub u16, pub CowString<'static>);
impl Clone for RawStatus { impl Clone for RawStatus {
fn clone(&self) -> RawStatus { fn clone(&self) -> RawStatus {
@@ -693,7 +689,7 @@ fn expect(r: IoResult<u8>, expected: u8) -> HttpResult<()> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::io::{mod, MemReader, MemWriter}; use std::io::{self, MemReader, MemWriter};
use std::borrow::Cow::{Borrowed, Owned}; use std::borrow::Cow::{Borrowed, Owned};
use test::Bencher; use test::Bencher;
use uri::RequestUri; use uri::RequestUri;

View File

@@ -1,4 +1,6 @@
#![feature(macro_rules, phase, default_type_params, slicing_syntax, globs)] #![feature(macro_rules, phase, default_type_params,
slicing_syntax, globs, associated_types,
old_orphan_check)]
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(warnings)] #![deny(warnings)]
#![experimental] #![experimental]
@@ -143,12 +145,9 @@ pub use method::Method::{Get, Head, Post, Delete};
pub use status::StatusCode::{Ok, BadRequest, NotFound}; pub use status::StatusCode::{Ok, BadRequest, NotFound};
pub use server::Server; pub use server::Server;
use std::fmt;
use std::error::{Error, FromError}; use std::error::{Error, FromError};
use std::io::IoError; use std::io::IoError;
use std::rt::backtrace;
use self::HttpError::{HttpMethodError, HttpUriError, HttpVersionError, use self::HttpError::{HttpMethodError, HttpUriError, HttpVersionError,
HttpHeaderError, HttpStatusError, HttpIoError}; HttpHeaderError, HttpStatusError, HttpIoError};
@@ -158,22 +157,6 @@ macro_rules! todo(
}) })
); );
#[allow(dead_code)]
struct Trace;
impl fmt::Show for Trace {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let _ = backtrace::write(fmt);
Result::Ok(())
}
}
macro_rules! trace(
($($arg:tt)*) => (if cfg!(not(ndebug)) {
log!(5, "{}\n{}", format_args!($($arg)*), ::Trace)
})
);
macro_rules! inspect( macro_rules! inspect(
($name:expr, $value:expr) => ({ ($name:expr, $value:expr) => ({
let v = $value; let v = $value;
@@ -207,7 +190,7 @@ mod mimewrapper {
pub type HttpResult<T> = Result<T, HttpError>; pub type HttpResult<T> = Result<T, HttpError>;
/// A set of errors that can occur parsing HTTP streams. /// A set of errors that can occur parsing HTTP streams.
#[deriving(Show, PartialEq, Clone)] #[derive(Show, PartialEq, Clone)]
pub enum HttpError { pub enum HttpError {
/// An invalid `Method`, such as `GE,T`. /// An invalid `Method`, such as `GE,T`.
HttpMethodError, HttpMethodError,

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.
#[deriving(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub enum Method { pub enum Method {
/// OPTIONS /// OPTIONS
Options, Options,

View File

@@ -92,7 +92,7 @@ macro_rules! mock_connector (
let key = format!("{}://{}", scheme, host); let key = format!("{}://{}", scheme, host);
// ignore port for now // ignore port for now
match map.find(&&*key) { match map.get(&&*key) {
Some(res) => Ok(::mock::MockStream { Some(res) => Ok(::mock::MockStream {
write: ::std::io::MemWriter::new(), write: ::std::io::MemWriter::new(),
read: ::std::io::MemReader::new(res.to_string().into_bytes()) read: ::std::io::MemReader::new(res.to_string().into_bytes())

View File

@@ -1,16 +1,15 @@
//! A collection of traits abstracting over Listeners and Streams. //! A collection of traits abstracting over Listeners and Streams.
use std::any::{Any, AnyRefExt}; use std::any::Any;
use std::boxed::BoxAny;
use std::fmt; use std::fmt;
use std::intrinsics::TypeId; use std::intrinsics::TypeId;
use std::io::{IoResult, IoError, ConnectionAborted, InvalidInput, OtherIoError, use std::io::{IoResult, IoError, ConnectionAborted, InvalidInput, OtherIoError,
Stream, Listener, Acceptor}; Stream, Listener, Acceptor};
use std::io::net::ip::{SocketAddr, ToSocketAddr, Port}; use std::io::net::ip::{SocketAddr, ToSocketAddr, Port};
use std::io::net::tcp::{TcpStream, TcpListener, TcpAcceptor}; use std::io::net::tcp::{TcpStream, TcpListener, TcpAcceptor};
use std::mem::{mod, transmute, transmute_copy}; use std::mem;
use std::raw::{mod, TraitObject}; use std::raw::{self, TraitObject};
use uany::UncheckedBoxAnyDowncast; use uany::UnsafeAnyExt;
use openssl::ssl::{Ssl, SslStream, SslContext, VerifyCallback}; use openssl::ssl::{Ssl, SslStream, SslContext, VerifyCallback};
use openssl::ssl::SslVerifyMode::SslVerifyPeer; use openssl::ssl::SslVerifyMode::SslVerifyPeer;
use openssl::ssl::SslMethod::Sslv23; use openssl::ssl::SslMethod::Sslv23;
@@ -105,38 +104,54 @@ impl<'a> Writer for &'a mut NetworkStream {
fn flush(&mut self) -> IoResult<()> { (**self).flush() } fn flush(&mut self) -> IoResult<()> { (**self).flush() }
} }
impl UncheckedBoxAnyDowncast for Box<NetworkStream + Send> { impl UnsafeAnyExt for NetworkStream {
unsafe fn downcast_unchecked<T: 'static>(self) -> Box<T> { unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
let to = *mem::transmute::<&Box<NetworkStream + Send>, &raw::TraitObject>(&self); mem::transmute(mem::transmute::<&NetworkStream,
// Prevent double-free. raw::TraitObject>(self).data)
mem::forget(self); }
mem::transmute(to.data)
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
mem::transmute(mem::transmute::<&mut NetworkStream,
raw::TraitObject>(self).data)
}
unsafe fn downcast_unchecked<T: 'static>(self: Box<NetworkStream>) -> Box<T> {
mem::transmute(mem::transmute::<Box<NetworkStream>,
raw::TraitObject>(self).data)
} }
} }
impl<'a> AnyRefExt<'a> for &'a (NetworkStream + 'static) { impl NetworkStream {
/// Is the underlying type in this trait object a T?
#[inline] #[inline]
fn is<T: 'static>(self) -> bool { pub fn is<T: 'static>(&self) -> bool {
self.get_type_id() == TypeId::of::<T>() self.get_type_id() == TypeId::of::<T>()
} }
/// If the underlying type is T, get a reference to the contained data.
#[inline] #[inline]
fn downcast_ref<T: 'static>(self) -> Option<&'a T> { pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
if self.is::<T>() { if self.is::<T>() {
unsafe { Some(unsafe { self.downcast_ref_unchecked() })
// Get the raw representation of the trait object
let to: TraitObject = transmute_copy(&self);
// Extract the data pointer
Some(transmute(to.data))
}
} else { } else {
None None
} }
} }
/// If the underlying type is T, get a mutable reference to the contained
/// data.
#[inline]
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
Some(unsafe { self.downcast_mut_unchecked() })
} else {
None
}
} }
impl BoxAny for Box<NetworkStream + Send> { /// If the underlying type is T, extract it.
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<NetworkStream + Send>> { pub fn downcast<T: 'static>(self: Box<NetworkStream>)
-> Result<Box<T>, Box<NetworkStream>> {
if self.is::<T>() { if self.is::<T>() {
Ok(unsafe { self.downcast_unchecked() }) Ok(unsafe { self.downcast_unchecked() })
} else { } else {
@@ -174,7 +189,7 @@ impl NetworkListener<HttpStream, HttpAcceptor> for HttpListener {
} }
/// A `NetworkAcceptor` for `HttpStream`s. /// A `NetworkAcceptor` for `HttpStream`s.
#[deriving(Clone)] #[derive(Clone)]
pub struct HttpAcceptor { pub struct HttpAcceptor {
inner: TcpAcceptor inner: TcpAcceptor
} }
@@ -194,7 +209,7 @@ impl NetworkAcceptor<HttpStream> for HttpAcceptor {
} }
/// A wrapper around a TcpStream. /// A wrapper around a TcpStream.
#[deriving(Clone)] #[derive(Clone)]
pub enum HttpStream { pub enum HttpStream {
/// A stream over the HTTP protocol. /// A stream over the HTTP protocol.
Http(TcpStream), Http(TcpStream),
@@ -293,7 +308,7 @@ fn lift_ssl_error(ssl: SslError) -> IoError {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::boxed::BoxAny; use std::boxed::BoxAny;
use uany::UncheckedBoxAnyDowncast; use uany::UnsafeAnyExt;
use mock::MockStream; use mock::MockStream;
use super::NetworkStream; use super::NetworkStream;
@@ -302,7 +317,7 @@ mod tests {
fn test_downcast_box_stream() { fn test_downcast_box_stream() {
let stream = box MockStream::new() as Box<NetworkStream + Send>; let stream = box MockStream::new() as Box<NetworkStream + Send>;
let mock = stream.downcast::<MockStream>().unwrap(); let mock = stream.downcast::<MockStream>().ok().unwrap();
assert_eq!(mock, box MockStream::new()); assert_eq!(mock, box MockStream::new());
} }

View File

@@ -7,7 +7,7 @@ use std::io::net::ip::SocketAddr;
use {HttpResult}; use {HttpResult};
use version::{HttpVersion}; use version::{HttpVersion};
use method::Method::{mod, Get, Head}; use method::Method::{self, Get, Head};
use header::Headers; use header::Headers;
use header::common::{ContentLength, TransferEncoding}; use header::common::{ContentLength, TransferEncoding};
use http::{read_request_line}; use http::{read_request_line};
@@ -78,9 +78,11 @@ mod tests {
use mock::MockStream; use mock::MockStream;
use super::Request; use super::Request;
macro_rules! sock( use std::io::net::ip::SocketAddr;
($s:expr) => (::std::str::from_str::<::std::io::net::ip::SocketAddr>($s).unwrap())
); fn sock(s: &str) -> SocketAddr {
s.parse().unwrap()
}
#[test] #[test]
fn test_get_empty_body() { fn test_get_empty_body() {
@@ -91,7 +93,7 @@ mod tests {
I'm a bad request.\r\n\ I'm a bad request.\r\n\
"); ");
let mut req = Request::new(&mut stream, sock!("127.0.0.1:80")).unwrap(); let mut req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
assert_eq!(req.read_to_string(), Ok("".to_string())); assert_eq!(req.read_to_string(), Ok("".to_string()));
} }
@@ -104,7 +106,7 @@ mod tests {
I'm a bad request.\r\n\ I'm a bad request.\r\n\
"); ");
let mut req = Request::new(&mut stream, sock!("127.0.0.1:80")).unwrap(); let mut req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
assert_eq!(req.read_to_string(), Ok("".to_string())); assert_eq!(req.read_to_string(), Ok("".to_string()));
} }
@@ -117,7 +119,7 @@ mod tests {
I'm a bad request.\r\n\ I'm a bad request.\r\n\
"); ");
let mut req = Request::new(&mut stream, sock!("127.0.0.1:80")).unwrap(); let mut req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
assert_eq!(req.read_to_string(), Ok("".to_string())); assert_eq!(req.read_to_string(), Ok("".to_string()));
} }
} }

View File

@@ -107,7 +107,7 @@ impl<'a> Response<'a, Fresh> {
debug!("headers [\n{}]", self.headers); debug!("headers [\n{}]", self.headers);
try!(write!(&mut self.body, "{}", self.headers)); try!(write!(&mut self.body, "{}", self.headers));
try!(self.body.write(LINE_ENDING)); try!(self.body.write_str(LINE_ENDING));
let stream = if chunked { let stream = if chunked {
ChunkedWriter(self.body.unwrap()) ChunkedWriter(self.body.unwrap())

View File

@@ -1,7 +1,10 @@
//! Status Codes //! Status Codes
use std::fmt; use std::fmt;
use std::num::{FromPrimitive, ToPrimitive};
use std::mem::transmute; use std::mem::transmute;
use std::cmp::Ordering::{self, Less, Equal, Greater};
// shamelessly lifted from Teepee. I tried a few schemes, this really // shamelessly lifted from Teepee. I tried a few schemes, this really
// does seem like the best. // does seem like the best.
@@ -1038,7 +1041,7 @@ impl StatusCode {
/// other times. /// other times.
/// ///
/// The reason phrase is defined as being exclusively for human readers. You should avoid /// The reason phrase is defined as being exclusively for human readers. You should avoid
/// deriving any meaning from it at all costs. /// derive any meaning from it at all costs.
/// ///
/// Bear in mind also that in HTTP/2.0 the reason phrase is abolished from transmission, and so /// Bear in mind also that in HTTP/2.0 the reason phrase is abolished from transmission, and so
/// this canonical reason phrase really is the only reason phrase youll find. /// this canonical reason phrase really is the only reason phrase youll find.
@@ -1600,7 +1603,7 @@ impl PartialEq for StatusCode {
impl Eq for StatusCode {} impl Eq for StatusCode {}
// Ditto (though #[deriving(Clone)] only takes about 0.4 seconds). // Ditto (though #[derive(Clone)] only takes about 0.4 seconds).
impl Clone for StatusCode { impl Clone for StatusCode {
#[inline] #[inline]
fn clone(&self) -> StatusCode { fn clone(&self) -> StatusCode {
@@ -1686,7 +1689,7 @@ impl ToPrimitive for StatusCode {
/// to get the appropriate *category* of status. /// to get the appropriate *category* of status.
/// ///
/// For HTTP/2.0, the 1xx Informational class is invalid. /// For HTTP/2.0, the 1xx Informational class is invalid.
#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
pub enum StatusClass { pub enum StatusClass {
/// 1xx: Informational - Request received, continuing process /// 1xx: Informational - Request received, continuing process
Informational = 100, Informational = 100,

View File

@@ -16,7 +16,7 @@ use url::Url;
/// > / authority-form /// > / authority-form
/// > / asterisk-form /// > / asterisk-form
/// > ``` /// > ```
#[deriving(Show, PartialEq, Clone)] #[derive(Show, PartialEq, Clone)]
pub enum RequestUri { pub enum RequestUri {
/// The most common request target, an absolute path and optional query. /// The most common request target, an absolute path and optional query.
/// ///

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.
#[deriving(PartialEq, PartialOrd, Copy)] #[derive(PartialEq, PartialOrd, Copy)]
pub enum HttpVersion { pub enum HttpVersion {
/// `HTTP/0.9` /// `HTTP/0.9`
Http09, Http09,