@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#![feature(io, test)]
|
#![feature(old_io, test)]
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#![feature(env, io)]
|
#![feature(env, old_io)]
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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:"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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[..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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[..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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[..]) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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[..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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[..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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[..]) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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', '.'][..]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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))]
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user