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