Merge pull request #329 from hyperium/324

Rustup
This commit is contained in:
Sean McArthur
2015-02-21 18:12:49 -05:00
32 changed files with 129 additions and 113 deletions

View File

@@ -1,4 +1,4 @@
#![feature(core, io, test)] #![feature(core, old_io, test)]
extern crate hyper; extern crate hyper;
extern crate test; extern crate test;

View File

@@ -1,4 +1,4 @@
#![feature(collections, io, test)] #![feature(collections, old_io, test)]
extern crate hyper; extern crate hyper;
extern crate test; extern crate test;

View File

@@ -1,4 +1,4 @@
#![feature(io, test)] #![feature(old_io, test)]
extern crate hyper; extern crate hyper;
extern crate test; extern crate test;

View File

@@ -1,4 +1,4 @@
#![feature(env, io)] #![feature(env, old_io)]
extern crate hyper; extern crate hyper;
use std::env; use std::env;

View File

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

View File

@@ -1,4 +1,4 @@
#![feature(io)] #![feature(old_io)]
extern crate hyper; extern crate hyper;
#[macro_use] extern crate log; #[macro_use] extern crate log;
@@ -21,7 +21,7 @@ macro_rules! try_return(
fn echo(mut req: Request, mut res: Response) { fn echo(mut req: Request, mut res: Response) {
match req.uri { match req.uri {
AbsolutePath(ref path) => match (&req.method, &path[]) { AbsolutePath(ref path) => match (&req.method, &path[..]) {
(&Get, "/") | (&Get, "/echo") => { (&Get, "/") | (&Get, "/echo") => {
let out = b"Try POST /echo"; let out = b"Try POST /echo";

View File

@@ -197,7 +197,7 @@ impl<'a, U: IntoUrl, C: NetworkConnector> RequestBuilder<'a, U, C> {
// punching borrowck here // punching borrowck here
let loc = match res.headers.get::<Location>() { let loc = match res.headers.get::<Location>() {
Some(&Location(ref loc)) => { Some(&Location(ref loc)) => {
Some(UrlParser::new().base_url(&url).parse(&loc[])) Some(UrlParser::new().base_url(&url).parse(&loc[..]))
} }
None => { None => {
debug!("no Location header"); debug!("no Location header");
@@ -394,7 +394,7 @@ mod tests {
#[test] #[test]
fn test_redirect_followif() { fn test_redirect_followif() {
fn follow_if(url: &Url) -> bool { fn follow_if(url: &Url) -> bool {
!url.serialize()[].contains("127.0.0.3") !url.serialize().contains("127.0.0.3")
} }
let mut client = Client::with_connector(MockRedirectPolicy); let mut client = Client::with_connector(MockRedirectPolicy);
client.set_redirect_policy(RedirectPolicy::FollowIf(follow_if)); client.set_redirect_policy(RedirectPolicy::FollowIf(follow_if));

View File

@@ -1,5 +1,6 @@
//! Client Requests //! Client Requests
use std::old_io::{BufferedWriter, IoResult}; use std::old_io::{BufferedWriter, IoResult};
use std::marker::PhantomData;
use url::Url; use url::Url;
@@ -25,8 +26,13 @@ pub struct Request<W> {
body: HttpWriter<BufferedWriter<Box<NetworkStream + Send>>>, body: HttpWriter<BufferedWriter<Box<NetworkStream + Send>>>,
headers: Headers, headers: Headers,
method: method::Method, method: method::Method,
_marker: PhantomData<W>,
} }
//FIXME: remove once https://github.com/rust-lang/issues/22629 is fixed
unsafe impl<W> Send for Request<W> {}
impl<W> Request<W> { impl<W> Request<W> {
/// Read the Request headers. /// Read the Request headers.
#[inline] #[inline]
@@ -66,7 +72,8 @@ impl Request<Fresh> {
headers: headers, headers: headers,
url: url, url: url,
version: version::HttpVersion::Http11, version: version::HttpVersion::Http11,
body: stream body: stream,
_marker: PhantomData,
}) })
} }
@@ -77,7 +84,7 @@ impl Request<Fresh> {
//TODO: this needs a test //TODO: this needs a test
if let Some(ref q) = self.url.query { if let Some(ref q) = self.url.query {
uri.push('?'); uri.push('?');
uri.push_str(&q[]); uri.push_str(&q[..]);
} }
debug!("writing head: {:?} {:?} {:?}", self.method, uri, self.version); debug!("writing head: {:?} {:?} {:?}", self.method, uri, self.version);
@@ -136,7 +143,8 @@ impl Request<Fresh> {
headers: self.headers, headers: self.headers,
url: self.url, url: self.url,
version: self.version, version: self.version,
body: stream body: stream,
_marker: PhantomData,
}) })
} }
@@ -185,7 +193,7 @@ mod tests {
let stream = *req.body.end().unwrap() let stream = *req.body.end().unwrap()
.into_inner().downcast::<MockStream>().ok().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:"));
assert!(!s.contains("Transfer-Encoding:")); assert!(!s.contains("Transfer-Encoding:"));
} }
@@ -199,7 +207,7 @@ mod tests {
let stream = *req.body.end().unwrap() let stream = *req.body.end().unwrap()
.into_inner().downcast::<MockStream>().ok().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:"));
assert!(!s.contains("Transfer-Encoding:")); assert!(!s.contains("Transfer-Encoding:"));
} }

View File

@@ -1,6 +1,7 @@
//! Client Responses //! Client Responses
use std::num::FromPrimitive; use std::num::FromPrimitive;
use std::old_io::{BufferedReader, IoResult}; use std::old_io::{BufferedReader, IoResult};
use std::marker::PhantomData;
use header; use header;
use header::{ContentLength, TransferEncoding}; use header::{ContentLength, TransferEncoding};
@@ -23,8 +24,13 @@ pub struct Response<S = HttpStream> {
pub version: version::HttpVersion, pub version: version::HttpVersion,
status_raw: RawStatus, status_raw: RawStatus,
body: HttpReader<BufferedReader<Box<NetworkStream + Send>>>, body: HttpReader<BufferedReader<Box<NetworkStream + Send>>>,
_marker: PhantomData<S>,
} }
//FIXME: remove once https://github.com/rust-lang/issues/22629 is fixed
unsafe impl<S: Send> Send for Response<S> {}
impl Response { impl Response {
/// Creates a new response from a server. /// Creates a new response from a server.
@@ -72,6 +78,7 @@ impl Response {
headers: headers, headers: headers,
body: body, body: body,
status_raw: raw_status, status_raw: raw_status,
_marker: PhantomData,
}) })
} }
@@ -98,6 +105,7 @@ mod tests {
use std::borrow::Cow::Borrowed; use std::borrow::Cow::Borrowed;
use std::boxed::BoxAny; use std::boxed::BoxAny;
use std::old_io::BufferedReader; use std::old_io::BufferedReader;
use std::marker::PhantomData;
use header::Headers; use header::Headers;
use header::TransferEncoding; use header::TransferEncoding;
@@ -119,7 +127,8 @@ mod tests {
headers: Headers::new(), headers: Headers::new(),
version: version::HttpVersion::Http11, version: version::HttpVersion::Http11,
body: EofReader(BufferedReader::new(box MockStream::new() as Box<NetworkStream + Send>)), body: EofReader(BufferedReader::new(box MockStream::new() as Box<NetworkStream + Send>)),
status_raw: RawStatus(200, Borrowed("OK")) status_raw: RawStatus(200, Borrowed("OK")),
_marker: PhantomData,
}; };
let b = res.into_inner().downcast::<MockStream>().ok().unwrap(); let b = res.into_inner().downcast::<MockStream>().ok().unwrap();

View File

@@ -29,7 +29,7 @@ impl header::Header for AccessControlAllowOrigin {
fn parse_header(raw: &[Vec<u8>]) -> Option<AccessControlAllowOrigin> { fn parse_header(raw: &[Vec<u8>]) -> Option<AccessControlAllowOrigin> {
if raw.len() == 1 { if raw.len() == 1 {
match str::from_utf8(unsafe { &raw[].get_unchecked(0)[] }) { match str::from_utf8(unsafe { &raw.get_unchecked(0)[..] }) {
Ok(s) => { Ok(s) => {
if s == "*" { if s == "*" {
Some(AccessControlAllowOrigin::AllowStar) Some(AccessControlAllowOrigin::AllowStar)

View File

@@ -22,14 +22,14 @@ impl<S: Scheme> DerefMut for Authorization<S> {
} }
} }
impl<S: Scheme> Header for Authorization<S> { impl<S: Scheme + 'static> Header for Authorization<S> where <S as FromStr>::Err: 'static {
fn header_name() -> &'static str { fn header_name() -> &'static str {
"Authorization" "Authorization"
} }
fn parse_header(raw: &[Vec<u8>]) -> Option<Authorization<S>> { fn parse_header(raw: &[Vec<u8>]) -> Option<Authorization<S>> {
if raw.len() == 1 { if raw.len() == 1 {
match (from_utf8(unsafe { &raw[].get_unchecked(0)[] }), Scheme::scheme(None::<S>)) { match (from_utf8(unsafe { &raw.get_unchecked(0)[..] }), Scheme::scheme(None::<S>)) {
(Ok(header), Some(scheme)) (Ok(header), Some(scheme))
if header.starts_with(scheme) && header.len() > scheme.len() + 1 => { if header.starts_with(scheme) && header.len() > scheme.len() + 1 => {
header[scheme.len() + 1..].parse::<S>().map(|s| Authorization(s)).ok() header[scheme.len() + 1..].parse::<S>().map(|s| Authorization(s)).ok()
@@ -43,7 +43,7 @@ impl<S: Scheme> Header for Authorization<S> {
} }
} }
impl<S: Scheme> HeaderFormat for Authorization<S> { impl<S: Scheme + 'static> HeaderFormat for Authorization<S> where <S as FromStr>::Err: 'static {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match Scheme::scheme(None::<S>) { match Scheme::scheme(None::<S>) {
Some(scheme) => try!(write!(fmt, "{} ", scheme)), Some(scheme) => try!(write!(fmt, "{} ", scheme)),
@@ -96,7 +96,7 @@ impl Scheme for Basic {
let mut text = self.username.clone(); let mut text = self.username.clone();
text.push(':'); text.push(':');
if let Some(ref pass) = self.password { if let Some(ref pass) = self.password {
text.push_str(&pass[]); text.push_str(&pass[..]);
} }
write!(f, "{}", text.as_bytes().to_base64(Config { write!(f, "{}", text.as_bytes().to_base64(Config {
char_set: Standard, char_set: Standard,
@@ -113,7 +113,7 @@ impl FromStr for Basic {
match s.from_base64() { match s.from_base64() {
Ok(decoded) => match String::from_utf8(decoded) { Ok(decoded) => match String::from_utf8(decoded) {
Ok(text) => { Ok(text) => {
let mut parts = &mut text[].split(':'); let mut parts = &mut text.split(':');
let user = match parts.next() { let user = match parts.next() {
Some(part) => part.to_string(), Some(part) => part.to_string(),
None => return Err(()) None => return Err(())
@@ -160,7 +160,7 @@ mod tests {
#[test] #[test]
fn test_raw_auth_parse() { fn test_raw_auth_parse() {
let headers = Headers::from_raw(&mut mem("Authorization: foo bar baz\r\n\r\n")).unwrap(); let headers = Headers::from_raw(&mut mem("Authorization: foo bar baz\r\n\r\n")).unwrap();
assert_eq!(&headers.get::<Authorization<String>>().unwrap().0[], "foo bar baz"); assert_eq!(&headers.get::<Authorization<String>>().unwrap().0[..], "foo bar baz");
} }
#[test] #[test]
@@ -181,7 +181,7 @@ mod tests {
fn test_basic_auth_parse() { fn test_basic_auth_parse() {
let headers = Headers::from_raw(&mut mem("Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\r\n\r\n")).unwrap(); let headers = Headers::from_raw(&mut mem("Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\r\n\r\n")).unwrap();
let auth = headers.get::<Authorization<Basic>>().unwrap(); let auth = headers.get::<Authorization<Basic>>().unwrap();
assert_eq!(&auth.0.username[], "Aladdin"); assert_eq!(&auth.0.username[..], "Aladdin");
assert_eq!(auth.0.password, Some("open sesame".to_string())); assert_eq!(auth.0.password, Some("open sesame".to_string()));
} }

View File

@@ -16,7 +16,7 @@ impl Header for CacheControl {
fn parse_header(raw: &[Vec<u8>]) -> Option<CacheControl> { fn parse_header(raw: &[Vec<u8>]) -> Option<CacheControl> {
let directives = raw.iter() let directives = raw.iter()
.filter_map(|line| from_one_comma_delimited(&line[])) .filter_map(|line| from_one_comma_delimited(&line[..]))
.collect::<Vec<Vec<CacheDirective>>>() .collect::<Vec<Vec<CacheDirective>>>()
.concat(); .concat();
if directives.len() > 0 { if directives.len() > 0 {
@@ -29,7 +29,7 @@ impl Header for CacheControl {
impl HeaderFormat for CacheControl { impl HeaderFormat for CacheControl {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt_comma_delimited(fmt, &self[]) fmt_comma_delimited(fmt, &self[..])
} }
} }
@@ -88,7 +88,7 @@ impl fmt::Display for CacheDirective {
ProxyRevalidate => "proxy-revalidate", ProxyRevalidate => "proxy-revalidate",
SMaxAge(secs) => return write!(f, "s-maxage={}", secs), SMaxAge(secs) => return write!(f, "s-maxage={}", secs),
Extension(ref name, None) => &name[], Extension(ref name, None) => &name[..],
Extension(ref name, Some(ref arg)) => return write!(f, "{}={}", name, arg), Extension(ref name, Some(ref arg)) => return write!(f, "{}={}", name, arg),
}, f) }, f)

View File

@@ -64,7 +64,7 @@ impl Header for Connection {
impl HeaderFormat for Connection { impl HeaderFormat for Connection {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let Connection(ref parts) = *self; let Connection(ref parts) = *self;
fmt_comma_delimited(fmt, &parts[]) fmt_comma_delimited(fmt, &parts[..])
} }
} }

View File

@@ -26,7 +26,7 @@ impl Header for Cookie {
fn parse_header(raw: &[Vec<u8>]) -> Option<Cookie> { fn parse_header(raw: &[Vec<u8>]) -> Option<Cookie> {
let mut cookies = Vec::with_capacity(raw.len()); let mut cookies = Vec::with_capacity(raw.len());
for cookies_raw in raw.iter() { for cookies_raw in raw.iter() {
match from_utf8(&cookies_raw[]) { match from_utf8(&cookies_raw[..]) {
Ok(cookies_str) => { Ok(cookies_str) => {
for cookie_str in cookies_str.split(';') { for cookie_str in cookies_str.split(';') {
match cookie_str.trim().parse() { match cookie_str.trim().parse() {
@@ -82,7 +82,7 @@ impl Cookie {
#[test] #[test]
fn test_parse() { fn test_parse() {
let h = Header::parse_header(&[b"foo=bar; baz=quux".to_vec()][]); let h = Header::parse_header(&[b"foo=bar; baz=quux".to_vec()][..]);
let c1 = CookiePair::new("foo".to_string(), "bar".to_string()); let c1 = CookiePair::new("foo".to_string(), "bar".to_string());
let c2 = CookiePair::new("baz".to_string(), "quux".to_string()); let c2 = CookiePair::new("baz".to_string(), "quux".to_string());
assert_eq!(h, Some(Cookie(vec![c1, c2]))); assert_eq!(h, Some(Cookie(vec![c1, c2])));
@@ -99,7 +99,7 @@ fn test_fmt() {
let mut headers = Headers::new(); let mut headers = Headers::new();
headers.set(cookie_header); headers.set(cookie_header);
assert_eq!(&headers.to_string()[], "Cookie: foo=bar; baz=quux\r\n"); assert_eq!(&headers.to_string()[..], "Cookie: foo=bar; baz=quux\r\n");
} }
#[test] #[test]

View File

@@ -28,7 +28,7 @@ impl Header for Host {
// FIXME: use rust-url to parse this // FIXME: use rust-url to parse this
// https://github.com/servo/rust-url/issues/42 // https://github.com/servo/rust-url/issues/42
let idx = { let idx = {
let slice = &s[]; let slice = &s[..];
if slice.char_at(1) == '[' { if slice.char_at(1) == '[' {
match slice.rfind(']') { match slice.rfind(']') {
Some(idx) => { Some(idx) => {

View File

@@ -25,7 +25,7 @@ impl Header for IfMatch {
fn parse_header(raw: &[Vec<u8>]) -> Option<IfMatch> { fn parse_header(raw: &[Vec<u8>]) -> Option<IfMatch> {
from_one_raw_str(raw).and_then(|s: String| { from_one_raw_str(raw).and_then(|s: String| {
let slice = &s[]; let slice = &s[..];
match slice { match slice {
"" => None, "" => None,
"*" => Some(IfMatch::Any), "*" => Some(IfMatch::Any),
@@ -39,7 +39,7 @@ impl HeaderFormat for IfMatch {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
IfMatch::Any => write!(fmt, "*"), IfMatch::Any => write!(fmt, "*"),
IfMatch::EntityTags(ref fields) => fmt_comma_delimited(fmt, &fields[]) IfMatch::EntityTags(ref fields) => fmt_comma_delimited(fmt, &fields[..])
} }
} }
} }

View File

@@ -33,7 +33,7 @@ impl Header for IfNoneMatch {
fn parse_header(raw: &[Vec<u8>]) -> Option<IfNoneMatch> { fn parse_header(raw: &[Vec<u8>]) -> Option<IfNoneMatch> {
from_one_raw_str(raw).and_then(|s: String| { from_one_raw_str(raw).and_then(|s: String| {
let slice = &s[]; let slice = &s[..];
match slice { match slice {
"" => None, "" => None,
"*" => Some(IfNoneMatch::Any), "*" => Some(IfNoneMatch::Any),
@@ -47,7 +47,7 @@ impl HeaderFormat for IfNoneMatch {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
IfNoneMatch::Any => { write!(fmt, "*") } IfNoneMatch::Any => { write!(fmt, "*") }
IfNoneMatch::EntityTags(ref fields) => { fmt_comma_delimited(fmt, &fields[]) } IfNoneMatch::EntityTags(ref fields) => { fmt_comma_delimited(fmt, &fields[..]) }
} }
} }
} }

View File

@@ -50,13 +50,13 @@ macro_rules! bench_header(
fn bench_parse(b: &mut Bencher) { fn bench_parse(b: &mut Bencher) {
let val = $value; let val = $value;
b.iter(|| { b.iter(|| {
let _: $ty = Header::parse_header(&val[]).unwrap(); let _: $ty = Header::parse_header(&val[..]).unwrap();
}); });
} }
#[bench] #[bench]
fn bench_format(b: &mut Bencher) { fn bench_format(b: &mut Bencher) {
let val: $ty = Header::parse_header(&$value[]).unwrap(); let val: $ty = Header::parse_header(&$value[..]).unwrap();
let fmt = HeaderFormatter(&val); let fmt = HeaderFormatter(&val);
b.iter(|| { b.iter(|| {
format!("{}", fmt); format!("{}", fmt);
@@ -102,7 +102,7 @@ macro_rules! impl_list_header(
impl $crate::header::HeaderFormat for $from { impl $crate::header::HeaderFormat for $from {
fn fmt_header(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn fmt_header(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
$crate::header::parsing::fmt_comma_delimited(fmt, &self[]) $crate::header::parsing::fmt_comma_delimited(fmt, &self[..])
} }
} }

View File

@@ -31,7 +31,7 @@ impl Header for Pragma {
fn parse_header(raw: &[Vec<u8>]) -> Option<Pragma> { fn parse_header(raw: &[Vec<u8>]) -> Option<Pragma> {
parsing::from_one_raw_str(raw).and_then(|s: String| { parsing::from_one_raw_str(raw).and_then(|s: String| {
let slice = &s.to_ascii_lowercase()[]; let slice = &s.to_ascii_lowercase()[..];
match slice { match slice {
"" => None, "" => None,
"no-cache" => Some(Pragma::NoCache), "no-cache" => Some(Pragma::NoCache),

View File

@@ -23,7 +23,7 @@ impl Header for SetCookie {
fn parse_header(raw: &[Vec<u8>]) -> Option<SetCookie> { fn parse_header(raw: &[Vec<u8>]) -> Option<SetCookie> {
let mut set_cookies = Vec::with_capacity(raw.len()); let mut set_cookies = Vec::with_capacity(raw.len());
for set_cookies_raw in raw.iter() { for set_cookies_raw in raw.iter() {
match from_utf8(&set_cookies_raw[]) { match from_utf8(&set_cookies_raw[..]) {
Ok(s) if !s.is_empty() => { Ok(s) if !s.is_empty() => {
match s.parse() { match s.parse() {
Ok(cookie) => set_cookies.push(cookie), Ok(cookie) => set_cookies.push(cookie),
@@ -76,7 +76,7 @@ impl SetCookie {
#[test] #[test]
fn test_parse() { fn test_parse() {
let h = Header::parse_header(&[b"foo=bar; HttpOnly".to_vec()][]); let h = Header::parse_header(&[b"foo=bar; HttpOnly".to_vec()][..]);
let mut c1 = Cookie::new("foo".to_string(), "bar".to_string()); let mut c1 = Cookie::new("foo".to_string(), "bar".to_string());
c1.httponly = true; c1.httponly = true;
@@ -94,7 +94,7 @@ fn test_fmt() {
let mut headers = Headers::new(); let mut headers = Headers::new();
headers.set(cookies); headers.set(cookies);
assert_eq!(&headers.to_string()[], "Set-Cookie: foo=bar; HttpOnly; Path=/p\r\nSet-Cookie: baz=quux; Path=/\r\n"); assert_eq!(&headers.to_string()[..], "Set-Cookie: foo=bar; HttpOnly; Path=/p\r\nSet-Cookie: baz=quux; Path=/\r\n");
} }
#[test] #[test]

View File

@@ -55,7 +55,7 @@ impl Header for Upgrade {
impl HeaderFormat for Upgrade { impl HeaderFormat for Upgrade {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let Upgrade(ref parts) = *self; let Upgrade(ref parts) = *self;
fmt_comma_delimited(fmt, &parts[]) fmt_comma_delimited(fmt, &parts[..])
} }
} }

View File

@@ -21,7 +21,7 @@ impl Header for Vary {
fn parse_header(raw: &[Vec<u8>]) -> Option<Vary> { fn parse_header(raw: &[Vec<u8>]) -> Option<Vary> {
from_one_raw_str(raw).and_then(|s: String| { from_one_raw_str(raw).and_then(|s: String| {
let slice = &s[]; let slice = &s[..];
match slice { match slice {
"" => None, "" => None,
"*" => Some(Vary::Any), "*" => Some(Vary::Any),
@@ -35,7 +35,7 @@ impl HeaderFormat for Vary {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
Vary::Any => { write!(fmt, "*") } Vary::Any => { write!(fmt, "*") }
Vary::Headers(ref fields) => { fmt_comma_delimited(fmt, &fields[]) } Vary::Headers(ref fields) => { fmt_comma_delimited(fmt, &fields[..]) }
} }
} }
} }

View File

@@ -9,11 +9,10 @@ use std::borrow::Cow::{Borrowed, Owned};
use std::fmt; use std::fmt;
use std::raw::TraitObject; use std::raw::TraitObject;
use std::str::from_utf8; use std::str::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::iter::FromIterator; use std::iter::{FromIterator, IntoIterator};
use std::borrow::IntoCow; use std::borrow::{Cow, IntoCow};
use std::{mem, raw}; use std::{mem, raw};
use uany::{UnsafeAnyExt}; use uany::{UnsafeAnyExt};
@@ -30,7 +29,7 @@ mod common;
mod shared; mod shared;
pub mod parsing; pub mod parsing;
type HeaderName = UniCase<CowString<'static>>; type HeaderName = UniCase<Cow<'static, str>>;
/// 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.
/// ///
@@ -139,7 +138,7 @@ impl Headers {
loop { loop {
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[..]);
count += (name.len() + value.len()) as u32; count += (name.len() + value.len()) as u32;
if count > MAX_HEADERS_LENGTH { if count > MAX_HEADERS_LENGTH {
debug!("Max header size reached, aborting"); debug!("Max header size reached, aborting");
@@ -183,14 +182,14 @@ impl Headers {
.get(&UniCase(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.raw { if let Some(ref raw) = *item.raw {
return Some(&raw[]); return Some(&raw[..]);
} }
let raw = vec![item.typed.as_ref().unwrap().to_string().into_bytes()]; let raw = vec![item.typed.as_ref().unwrap().to_string().into_bytes()];
item.raw.set(raw); item.raw.set(raw);
let raw = item.raw.as_ref().unwrap(); let raw = item.raw.as_ref().unwrap();
Some(&raw[]) Some(&raw[..])
}) })
} }
@@ -203,7 +202,7 @@ impl Headers {
/// # let mut headers = Headers::new(); /// # let mut headers = Headers::new();
/// 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, str>>(&mut self, name: K, value: Vec<Vec<u8>>) {
self.data.insert(UniCase(name.into_cow()), Item::new_raw(value)); self.data.insert(UniCase(name.into_cow()), Item::new_raw(value));
} }
@@ -351,7 +350,7 @@ impl<'a> fmt::Debug for HeaderView<'a> {
} }
impl<'a> Extend<HeaderView<'a>> for Headers { impl<'a> Extend<HeaderView<'a>> for Headers {
fn extend<I: Iterator<Item=HeaderView<'a>>>(&mut self, iter: I) { fn extend<I: IntoIterator<Item=HeaderView<'a>>>(&mut self, 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());
} }
@@ -359,7 +358,7 @@ 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<Item=HeaderView<'a>>>(iter: I) -> Headers { fn from_iter<I: IntoIterator<Item=HeaderView<'a>>>(iter: I) -> Headers {
let mut headers = Headers::new(); let mut headers = Headers::new();
headers.extend(iter); headers.extend(iter);
headers headers
@@ -451,7 +450,7 @@ fn get_or_parse_mut<H: Header + HeaderFormat>(item: &mut Item) -> Option<&mut It
fn parse<H: Header + HeaderFormat>(item: &Item) { fn parse<H: Header + HeaderFormat>(item: &Item) {
match *item.raw { match *item.raw {
Some(ref raw) => match Header::parse_header(&raw[]) { Some(ref raw) => match Header::parse_header(&raw[..]) {
Some::<H>(h) => item.typed.set(box h as Box<HeaderFormat + Send + Sync>), Some::<H>(h) => item.typed.set(box h as Box<HeaderFormat + Send + Sync>),
None => () None => ()
}, },
@@ -476,7 +475,7 @@ impl fmt::Display 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() {
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);
@@ -532,12 +531,9 @@ impl<'a, H: HeaderFormat> fmt::Debug for HeaderFormatter<'a, H> {
mod tests { mod tests {
use std::old_io::MemReader; use std::old_io::MemReader;
use std::fmt; use std::fmt;
use std::borrow::Cow::Borrowed;
use std::hash::{SipHasher, hash};
use mime::Mime; use mime::Mime;
use mime::TopLevel::Text; use mime::TopLevel::Text;
use mime::SubLevel::Plain; use mime::SubLevel::Plain;
use unicase::UniCase;
use super::{Headers, Header, HeaderFormat, ContentLength, ContentType, use super::{Headers, Header, HeaderFormat, ContentLength, ContentType,
Accept, Host, QualityItem}; Accept, Host, QualityItem};
@@ -547,15 +543,6 @@ mod tests {
MemReader::new(s.as_bytes().to_vec()) MemReader::new(s.as_bytes().to_vec())
} }
#[test]
fn test_case_insensitive() {
let a = UniCase(Borrowed("foobar"));
let b = UniCase(Borrowed("FOOBAR"));
assert_eq!(a, b);
assert_eq!(hash::<_, SipHasher>(&a), hash::<_, SipHasher>(&b));
}
#[test] #[test]
fn test_from_raw() { fn test_from_raw() {
let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap(); let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
@@ -595,7 +582,7 @@ mod tests {
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 from_utf8(unsafe { &raw[].get_unchecked(0)[] }) { match from_utf8(unsafe { &raw.get_unchecked(0)[..] }) {
Ok(s) => FromStr::from_str(s).ok(), Ok(s) => FromStr::from_str(s).ok(),
Err(_) => None Err(_) => None
}.map(|u| CrazyLength(Some(false), u)) }.map(|u| CrazyLength(Some(false), u))
@@ -671,7 +658,7 @@ mod tests {
let mut headers = Headers::new(); let mut headers = Headers::new();
headers.set(ContentLength(10)); headers.set(ContentLength(10));
headers.set_raw("content-LENGTH", vec![b"20".to_vec()]); headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"20".to_vec()][]); assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"20".to_vec()][..]);
assert_eq!(headers.get(), Some(&ContentLength(20))); assert_eq!(headers.get(), Some(&ContentLength(20)));
} }

View File

@@ -11,7 +11,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(&raw[0][]) { match str::from_utf8(&raw[0][..]) {
Ok(s) => str::FromStr::from_str(s).ok(), Ok(s) => str::FromStr::from_str(s).ok(),
Err(_) => None Err(_) => None
} }
@@ -24,7 +24,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(&raw[0][]) 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

@@ -42,7 +42,7 @@ impl FromStr for EntityTag {
type Err = (); type Err = ();
fn from_str(s: &str) -> Result<EntityTag, ()> { fn from_str(s: &str) -> Result<EntityTag, ()> {
let length: usize = s.len(); let length: usize = s.len();
let slice = &s[]; let slice = &s[..];
// Early exits: // Early exits:
// 1. The string is empty, or, // 1. The string is empty, or,

View File

@@ -39,7 +39,7 @@ impl<T: fmt::Display> fmt::Display for QualityItem<T> {
write!(f, "{}", self.item) write!(f, "{}", self.item)
} else { } else {
write!(f, "{}; q={}", self.item, write!(f, "{}; q={}", self.item,
format!("{:.3}", self.quality).trim_right_matches(&['0', '.'][])) format!("{:.3}", self.quality).trim_right_matches(&['0', '.'][..]))
} }
} }
} }

View File

@@ -1,11 +1,10 @@
//! Pieces pertaining to the HTTP message protocol. //! Pieces pertaining to the HTTP message protocol.
use std::borrow::Cow::{Borrowed, Owned}; use std::borrow::Cow::{self, Borrowed, Owned};
use std::borrow::IntoCow; use std::borrow::IntoCow;
use std::cmp::min; use std::cmp::min;
use std::old_io::{self, Reader, IoResult, BufWriter}; use std::old_io::{self, Reader, IoResult, BufWriter};
use std::num::from_u16; use std::num::from_u16;
use std::str; use std::str;
use std::string::CowString;
use url::Url; use url::Url;
use url::ParseError as UrlError; use url::ParseError as UrlError;
@@ -395,7 +394,7 @@ pub fn read_method<R: Reader>(stream: &mut R) -> HttpResult<method::Method> {
debug!("maybe_method = {:?}", maybe_method); debug!("maybe_method = {:?}", maybe_method);
match (maybe_method, &buf[]) { match (maybe_method, &buf[..]) {
(Some(method), _) => Ok(method), (Some(method), _) => Ok(method),
(None, ext) => { (None, ext) => {
// We already checked that the buffer is ASCII // We already checked that the buffer is ASCII
@@ -587,7 +586,7 @@ pub type StatusLine = (HttpVersion, RawStatus);
/// The raw status code and reason-phrase. /// The raw status code and reason-phrase.
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub struct RawStatus(pub u16, pub CowString<'static>); pub struct RawStatus(pub u16, pub Cow<'static, str>);
impl Clone for RawStatus { impl Clone for RawStatus {
fn clone(&self) -> RawStatus { fn clone(&self) -> RawStatus {
@@ -664,7 +663,7 @@ pub fn read_status<R: Reader>(stream: &mut R) -> HttpResult<RawStatus> {
} }
} }
let reason = match str::from_utf8(&buf[]) { let reason = match str::from_utf8(&buf[..]) {
Ok(s) => s.trim(), Ok(s) => s.trim(),
Err(_) => return Err(HttpStatusError) Err(_) => return Err(HttpStatusError)
}; };

View File

@@ -1,5 +1,5 @@
#![feature(core, collections, hash, io, os, path, std_misc, #![feature(core, collections, io, old_io, os, old_path,
slicing_syntax, box_syntax, unsafe_destructor)] std_misc, box_syntax, unsafe_destructor)]
#![deny(missing_docs)] #![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))] #![cfg_attr(test, deny(warnings))]
#![cfg_attr(test, feature(alloc, test))] #![cfg_attr(test, feature(alloc, test))]

View File

@@ -58,7 +58,7 @@ pub trait NetworkAcceptor: Clone + Send {
} }
/// An iterator wrapper over a NetworkAcceptor. /// An iterator wrapper over a NetworkAcceptor.
pub struct NetworkConnections<'a, N: NetworkAcceptor>(&'a mut N); pub struct NetworkConnections<'a, N: NetworkAcceptor + 'a>(&'a mut N);
impl<'a, N: NetworkAcceptor> Iterator for NetworkConnections<'a, N> { impl<'a, N: NetworkAcceptor> Iterator for NetworkConnections<'a, N> {
type Item = IoResult<N::Stream>; type Item = IoResult<N::Stream>;

View File

@@ -1,13 +1,13 @@
use std::thread::{Thread, JoinGuard}; use std::thread::{self, JoinGuard};
use std::sync::Arc;
use std::sync::mpsc; use std::sync::mpsc;
use std::collections::VecMap;
use net::NetworkAcceptor; use net::NetworkAcceptor;
pub struct AcceptorPool<A: NetworkAcceptor> { pub struct AcceptorPool<A: NetworkAcceptor> {
acceptor: A acceptor: A
} }
impl<A: NetworkAcceptor> AcceptorPool<A> { impl<'a, A: NetworkAcceptor + 'a> AcceptorPool<A> {
/// Create a thread pool to manage the acceptor. /// Create a thread pool to manage the acceptor.
pub fn new(acceptor: A) -> AcceptorPool<A> { pub fn new(acceptor: A) -> AcceptorPool<A> {
AcceptorPool { acceptor: acceptor } AcceptorPool { acceptor: acceptor }
@@ -18,34 +18,39 @@ impl<A: NetworkAcceptor> AcceptorPool<A> {
/// ## Panics /// ## Panics
/// ///
/// Panics if threads == 0. /// Panics if threads == 0.
pub fn accept<F: Fn(A::Stream) + Send + Sync>(self, pub fn accept<F>(self, work: F, threads: usize)
work: F, where F: Fn(A::Stream) + Send + Sync + 'a {
threads: usize) -> JoinGuard<'static, ()> {
assert!(threads != 0, "Can't accept on 0 threads."); assert!(threads != 0, "Can't accept on 0 threads.");
// Replace with &F when Send changes land.
let work = Arc::new(work);
let (super_tx, supervisor_rx) = mpsc::channel(); let (super_tx, supervisor_rx) = mpsc::channel();
let spawn = let counter = &mut 0;
move || spawn_with(super_tx.clone(), work.clone(), self.acceptor.clone()); let work = &work;
let mut spawn = move || {
let id = *counter;
let guard = spawn_with(super_tx.clone(), work, self.acceptor.clone(), id);
*counter += 1;
(id, guard)
};
// Go // Go
for _ in 0..threads { spawn() } let mut guards: VecMap<_> = (0..threads).map(|_| spawn()).collect();
// Spawn the supervisor for id in supervisor_rx.iter() {
Thread::scoped(move || for () in supervisor_rx.iter() { spawn() }) guards.remove(&id);
let (id, guard) = spawn();
guards.insert(id, guard);
}
} }
} }
fn spawn_with<A, F>(supervisor: mpsc::Sender<()>, work: Arc<F>, mut acceptor: A) fn spawn_with<'a, A, F>(supervisor: mpsc::Sender<usize>, work: &'a F, mut acceptor: A, id: usize) -> JoinGuard<'a, ()>
where A: NetworkAcceptor, where A: NetworkAcceptor + 'a,
F: Fn(<A as NetworkAcceptor>::Stream) + Send + Sync { F: Fn(<A as NetworkAcceptor>::Stream) + Send + Sync + 'a {
use std::old_io::EndOfFile; use std::old_io::EndOfFile;
Thread::spawn(move || { thread::scoped(move || {
let sentinel = Sentinel::new(supervisor, ()); let sentinel = Sentinel::new(supervisor, id);
loop { loop {
match acceptor.accept() { match acceptor.accept() {
@@ -61,7 +66,7 @@ where A: NetworkAcceptor,
} }
} }
} }
}); })
} }
struct Sentinel<T: Send> { struct Sentinel<T: Send> {
@@ -83,7 +88,7 @@ impl<T: Send> Sentinel<T> {
} }
#[unsafe_destructor] #[unsafe_destructor]
impl<T: Send> Drop for Sentinel<T> { impl<T: Send + 'static> Drop for Sentinel<T> {
fn drop(&mut self) { fn drop(&mut self) {
// If we were cancelled, get out of here. // If we were cancelled, get out of here.
if !self.active { return; } if !self.active { return; }

View File

@@ -2,7 +2,7 @@
use std::old_io::{Listener, BufferedReader, BufferedWriter}; use std::old_io::{Listener, BufferedReader, BufferedWriter};
use std::old_io::net::ip::{IpAddr, Port, SocketAddr}; use std::old_io::net::ip::{IpAddr, Port, SocketAddr};
use std::os; use std::os;
use std::thread::JoinGuard; use std::thread::{self, JoinGuard};
pub use self::request::Request; pub use self::request::Request;
pub use self::response::Response; pub use self::response::Response;
@@ -56,7 +56,7 @@ impl Server<HttpListener> {
impl< impl<
L: NetworkListener<Acceptor=A> + Send, L: NetworkListener<Acceptor=A> + Send,
A: NetworkAcceptor<Stream=S> + Send, A: NetworkAcceptor<Stream=S> + Send + 'static,
S: NetworkStream + Clone + Send> Server<L> { S: NetworkStream + Clone + Send> Server<L> {
/// Creates a new server that will handle `HttpStream`s. /// Creates a new server that will handle `HttpStream`s.
pub fn with_listener(ip: IpAddr, port: Port, listener: L) -> Server<L> { pub fn with_listener(ip: IpAddr, port: Port, listener: L) -> Server<L> {
@@ -68,7 +68,7 @@ S: NetworkStream + Clone + Send> Server<L> {
} }
/// Binds to a socket, and starts handling connections using a task pool. /// 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>> { pub fn listen_threads<H: Handler + 'static>(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 acceptor = try!(self.listener.listen((self.ip, self.port))); let acceptor = try!(self.listener.listen((self.ip, self.port)));
let socket = try!(acceptor.socket_name()); let socket = try!(acceptor.socket_name());
@@ -77,15 +77,17 @@ S: NetworkStream + Clone + Send> Server<L> {
let pool = AcceptorPool::new(acceptor.clone()); let pool = AcceptorPool::new(acceptor.clone());
let work = move |stream| handle_connection(stream, &handler); let work = move |stream| handle_connection(stream, &handler);
let guard = thread::scoped(move || pool.accept(work, threads));
Ok(Listening { Ok(Listening {
_guard: pool.accept(work, threads), _guard: guard,
socket: socket, socket: socket,
acceptor: acceptor acceptor: acceptor
}) })
} }
/// 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<L::Acceptor>> { pub fn listen<H: Handler + 'static>(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)
} }

View File

@@ -3,6 +3,7 @@
//! These are responses sent by a `hyper::Server` to clients, after //! These are responses sent by a `hyper::Server` to clients, after
//! receiving a request. //! receiving a request.
use std::old_io::IoResult; use std::old_io::IoResult;
use std::marker::PhantomData;
use time::now_utc; use time::now_utc;
@@ -22,7 +23,9 @@ pub struct Response<'a, W = Fresh> {
// The status code for the request. // The status code for the request.
status: status::StatusCode, status: status::StatusCode,
// The outgoing headers on this response. // The outgoing headers on this response.
headers: header::Headers headers: header::Headers,
_marker: PhantomData<W>
} }
impl<'a, W> Response<'a, W> { impl<'a, W> Response<'a, W> {
@@ -42,7 +45,8 @@ impl<'a, W> Response<'a, W> {
status: status, status: status,
version: version, version: version,
body: body, body: body,
headers: headers headers: headers,
_marker: PhantomData,
} }
} }
@@ -60,7 +64,8 @@ impl<'a> Response<'a, Fresh> {
status: status::StatusCode::Ok, status: status::StatusCode::Ok,
version: version::HttpVersion::Http11, version: version::HttpVersion::Http11,
headers: header::Headers::new(), headers: header::Headers::new(),
body: ThroughWriter(stream) body: ThroughWriter(stream),
_marker: PhantomData,
} }
} }
@@ -119,7 +124,8 @@ impl<'a> Response<'a, Fresh> {
version: self.version, version: self.version,
body: stream, body: stream,
status: self.status, status: self.status,
headers: self.headers headers: self.headers,
_marker: PhantomData,
}) })
} }