feat(lib): switch to non-blocking (asynchronous) IO
BREAKING CHANGE: This breaks a lot of the Client and Server APIs. Check the documentation for how Handlers can be used for asynchronous events.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use std::fmt::{self, Display};
|
||||
use std::str;
|
||||
use unicase::UniCase;
|
||||
use header::{Header, HeaderFormat};
|
||||
use header::{Header};
|
||||
|
||||
/// `Access-Control-Allow-Credentials` header, part of
|
||||
/// [CORS](http://www.w3.org/TR/cors/#access-control-allow-headers-response-header)
|
||||
@@ -62,9 +62,7 @@ impl Header for AccessControlAllowCredentials {
|
||||
}
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for AccessControlAllowCredentials {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("true")
|
||||
}
|
||||
@@ -86,4 +84,4 @@ mod test_access_control_allow_credentials {
|
||||
test_header!(not_bool, vec![b"false"], None);
|
||||
test_header!(only_single, vec![b"true", b"true"], None);
|
||||
test_header!(no_gibberish, vec!["\u{645}\u{631}\u{62d}\u{628}\u{627}".as_bytes()], None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use header::{Header, HeaderFormat};
|
||||
use header::{Header};
|
||||
|
||||
/// The `Access-Control-Allow-Origin` response header,
|
||||
/// part of [CORS](http://www.w3.org/TR/cors/#access-control-allow-origin-response-header)
|
||||
@@ -70,9 +70,7 @@ impl Header for AccessControlAllowOrigin {
|
||||
_ => AccessControlAllowOrigin::Value(try!(String::from_utf8(value.clone())))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for AccessControlAllowOrigin {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
AccessControlAllowOrigin::Any => f.write_str("*"),
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::fmt::{self, Display};
|
||||
use std::str::{FromStr, from_utf8};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use serialize::base64::{ToBase64, FromBase64, Standard, Config, Newline};
|
||||
use header::{Header, HeaderFormat};
|
||||
use header::{Header};
|
||||
|
||||
/// `Authorization` header, defined in [RFC7235](https://tools.ietf.org/html/rfc7235#section-4.2)
|
||||
///
|
||||
@@ -97,9 +97,7 @@ impl<S: Scheme + Any> Header for Authorization<S> where <S as FromStr>::Err: 'st
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Scheme + Any> HeaderFormat for Authorization<S> where <S as FromStr>::Err: 'static {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(scheme) = <S as Scheme>::scheme() {
|
||||
try!(write!(f, "{} ", scheme))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use header::{Header, HeaderFormat};
|
||||
use header::Header;
|
||||
use header::parsing::{from_comma_delimited, fmt_comma_delimited};
|
||||
|
||||
/// `Cache-Control` header, defined in [RFC7234](https://tools.ietf.org/html/rfc7234#section-5.2)
|
||||
@@ -62,9 +62,7 @@ impl Header for CacheControl {
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for CacheControl {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt_comma_delimited(f, &self[..])
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use std::fmt;
|
||||
use unicase::UniCase;
|
||||
use url::percent_encoding;
|
||||
|
||||
use header::{Header, HeaderFormat, parsing};
|
||||
use header::{Header, parsing};
|
||||
use header::parsing::{parse_extended_value, HTTP_VALUE};
|
||||
use header::shared::Charset;
|
||||
|
||||
@@ -144,9 +144,7 @@ impl Header for ContentDisposition {
|
||||
Ok(cd)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for ContentDisposition {
|
||||
#[inline]
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self, f)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::fmt;
|
||||
|
||||
use header::{HeaderFormat, Header, parsing};
|
||||
use header::{Header, parsing};
|
||||
|
||||
/// `Content-Length` header, defined in
|
||||
/// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.2)
|
||||
@@ -55,9 +55,7 @@ impl Header for ContentLength {
|
||||
.unwrap_or(Err(::Error::Header))
|
||||
.map(ContentLength)
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for ContentLength {
|
||||
#[inline]
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.0, f)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use header::{Header, HeaderFormat, CookiePair, CookieJar};
|
||||
use header::{Header, CookiePair, CookieJar};
|
||||
use std::fmt::{self, Display};
|
||||
use std::str::from_utf8;
|
||||
|
||||
@@ -61,9 +61,7 @@ impl Header for Cookie {
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for Cookie {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let cookies = &self.0;
|
||||
for (i, cookie) in cookies.iter().enumerate() {
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::str;
|
||||
|
||||
use unicase::UniCase;
|
||||
|
||||
use header::{Header, HeaderFormat};
|
||||
use header::{Header};
|
||||
|
||||
/// The `Expect` header.
|
||||
///
|
||||
@@ -53,9 +53,7 @@ impl Header for Expect {
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for Expect {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("100-continue")
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use header::{Header, HeaderFormat};
|
||||
use header::{Header};
|
||||
use std::fmt;
|
||||
use header::parsing::from_one_raw_str;
|
||||
|
||||
@@ -52,9 +52,7 @@ impl Header for Host {
|
||||
// https://github.com/servo/rust-url/issues/42
|
||||
let idx = {
|
||||
let slice = &s[..];
|
||||
let mut chars = slice.chars();
|
||||
chars.next();
|
||||
if chars.next().unwrap() == '[' {
|
||||
if slice.starts_with('[') {
|
||||
match slice.rfind(']') {
|
||||
Some(idx) => {
|
||||
if slice.len() > idx + 2 {
|
||||
@@ -86,9 +84,7 @@ impl Header for Host {
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for Host {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.port {
|
||||
None | Some(80) | Some(443) => f.write_str(&self.hostname[..]),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::fmt::{self, Display};
|
||||
use header::{self, Header, HeaderFormat, EntityTag, HttpDate};
|
||||
use header::{self, Header, EntityTag, HttpDate};
|
||||
|
||||
/// `If-Range` header, defined in [RFC7233](http://tools.ietf.org/html/rfc7233#section-3.2)
|
||||
///
|
||||
@@ -59,18 +59,16 @@ impl Header for IfRange {
|
||||
}
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<IfRange> {
|
||||
let etag: ::Result<EntityTag> = header::parsing::from_one_raw_str(raw);
|
||||
if etag.is_ok() {
|
||||
return Ok(IfRange::EntityTag(etag.unwrap()));
|
||||
if let Ok(etag) = etag {
|
||||
return Ok(IfRange::EntityTag(etag));
|
||||
}
|
||||
let date: ::Result<HttpDate> = header::parsing::from_one_raw_str(raw);
|
||||
if date.is_ok() {
|
||||
return Ok(IfRange::Date(date.unwrap()));
|
||||
if let Ok(date) = date {
|
||||
return Ok(IfRange::Date(date));
|
||||
}
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for IfRange {
|
||||
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
match *self {
|
||||
IfRange::EntityTag(ref x) => Display::fmt(x, f),
|
||||
|
||||
@@ -66,7 +66,7 @@ macro_rules! bench_header(
|
||||
use test::Bencher;
|
||||
use super::*;
|
||||
|
||||
use header::{Header, HeaderFormatter};
|
||||
use header::{Header};
|
||||
|
||||
#[bench]
|
||||
fn bench_parse(b: &mut Bencher) {
|
||||
@@ -79,7 +79,7 @@ macro_rules! bench_header(
|
||||
#[bench]
|
||||
fn bench_format(b: &mut Bencher) {
|
||||
let val: $ty = Header::parse_header(&$value[..]).unwrap();
|
||||
let fmt = HeaderFormatter(&val);
|
||||
let fmt = ::header::HeaderFormatter(&val);
|
||||
b.iter(|| {
|
||||
format!("{}", fmt);
|
||||
});
|
||||
@@ -222,15 +222,13 @@ macro_rules! header {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
|
||||
$crate::header::parsing::from_comma_delimited(raw).map($id)
|
||||
}
|
||||
}
|
||||
impl $crate::header::HeaderFormat for $id {
|
||||
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
$crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
|
||||
}
|
||||
}
|
||||
impl ::std::fmt::Display for $id {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
use $crate::header::HeaderFormat;
|
||||
use $crate::header::Header;
|
||||
self.fmt_header(f)
|
||||
}
|
||||
}
|
||||
@@ -250,15 +248,13 @@ macro_rules! header {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
|
||||
$crate::header::parsing::from_comma_delimited(raw).map($id)
|
||||
}
|
||||
}
|
||||
impl $crate::header::HeaderFormat for $id {
|
||||
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
$crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
|
||||
}
|
||||
}
|
||||
impl ::std::fmt::Display for $id {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
use $crate::header::HeaderFormat;
|
||||
use $crate::header::Header;
|
||||
self.fmt_header(f)
|
||||
}
|
||||
}
|
||||
@@ -277,8 +273,6 @@ macro_rules! header {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
|
||||
$crate::header::parsing::from_one_raw_str(raw).map($id)
|
||||
}
|
||||
}
|
||||
impl $crate::header::HeaderFormat for $id {
|
||||
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
::std::fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
@@ -313,8 +307,6 @@ macro_rules! header {
|
||||
}
|
||||
$crate::header::parsing::from_comma_delimited(raw).map($id::Items)
|
||||
}
|
||||
}
|
||||
impl $crate::header::HeaderFormat for $id {
|
||||
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
match *self {
|
||||
$id::Any => f.write_str("*"),
|
||||
@@ -325,7 +317,7 @@ macro_rules! header {
|
||||
}
|
||||
impl ::std::fmt::Display for $id {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
use $crate::header::HeaderFormat;
|
||||
use $crate::header::Header;
|
||||
self.fmt_header(f)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::fmt;
|
||||
use std::ascii::AsciiExt;
|
||||
|
||||
use header::{Header, HeaderFormat, parsing};
|
||||
use header::{Header, parsing};
|
||||
|
||||
/// The `Pragma` header defined by HTTP/1.0.
|
||||
///
|
||||
@@ -52,9 +52,7 @@ impl Header for Pragma {
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for Pragma {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(match *self {
|
||||
Pragma::NoCache => "no-cache",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use header::{Header, HeaderFormat};
|
||||
use header::{Header};
|
||||
use header::parsing::{from_comma_delimited, fmt_comma_delimited};
|
||||
|
||||
/// `Prefer` header, defined in [RFC7240](http://tools.ietf.org/html/rfc7240)
|
||||
@@ -64,9 +64,7 @@ impl Header for Prefer {
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for Prefer {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt_comma_delimited(f, &self[..])
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::fmt;
|
||||
use header::{Header, HeaderFormat, Preference};
|
||||
use header::{Header, Preference};
|
||||
use header::parsing::{from_comma_delimited, fmt_comma_delimited};
|
||||
|
||||
/// `Preference-Applied` header, defined in [RFC7240](http://tools.ietf.org/html/rfc7240)
|
||||
@@ -61,9 +61,7 @@ impl Header for PreferenceApplied {
|
||||
Err(::Error::Header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for PreferenceApplied {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let preferences: Vec<_> = self.0.iter().map(|pref| match pref {
|
||||
// The spec ignores parameters in `Preferences-Applied`
|
||||
@@ -80,7 +78,7 @@ impl HeaderFormat for PreferenceApplied {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use header::{HeaderFormat, Preference};
|
||||
use header::{Header, Preference};
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
@@ -90,7 +88,7 @@ mod tests {
|
||||
"foo".to_owned(),
|
||||
"bar".to_owned(),
|
||||
vec![("bar".to_owned(), "foo".to_owned()), ("buz".to_owned(), "".to_owned())]
|
||||
)]) as &(HeaderFormat + Send + Sync)),
|
||||
)]) as &(Header + Send + Sync)),
|
||||
"foo=bar".to_owned()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::fmt::{self, Display};
|
||||
use std::str::FromStr;
|
||||
|
||||
use header::{Header, HeaderFormat};
|
||||
use header::Header;
|
||||
use header::parsing::{from_one_raw_str, from_comma_delimited};
|
||||
|
||||
/// `Range` header, defined in [RFC7233](https://tools.ietf.org/html/rfc7233#section-3.1)
|
||||
@@ -182,9 +182,6 @@ impl Header for Range {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Range> {
|
||||
from_one_raw_str(raw)
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for Range {
|
||||
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use header::{Header, HeaderFormat, CookiePair, CookieJar};
|
||||
use header::{Header, CookiePair, CookieJar};
|
||||
use std::fmt::{self, Display};
|
||||
use std::str::from_utf8;
|
||||
|
||||
@@ -104,10 +104,6 @@ impl Header for SetCookie {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl HeaderFormat for SetCookie {
|
||||
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for (i, cookie) in self.0.iter().enumerate() {
|
||||
if i != 0 {
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::str::{self, FromStr};
|
||||
|
||||
use unicase::UniCase;
|
||||
|
||||
use header::{Header, HeaderFormat, parsing};
|
||||
use header::{Header, parsing};
|
||||
|
||||
/// `StrictTransportSecurity` header, defined in [RFC6797](https://tools.ietf.org/html/rfc6797)
|
||||
///
|
||||
@@ -127,9 +127,7 @@ impl Header for StrictTransportSecurity {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<StrictTransportSecurity> {
|
||||
parsing::from_one_raw_str(raw)
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for StrictTransportSecurity {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.include_subdomains {
|
||||
write!(f, "max-age={}; includeSubdomains", self.max_age)
|
||||
|
||||
@@ -49,5 +49,12 @@ header! {
|
||||
}
|
||||
}
|
||||
|
||||
impl TransferEncoding {
|
||||
/// Constructor for the most common Transfer-Encoding, `chunked`.
|
||||
pub fn chunked() -> TransferEncoding {
|
||||
TransferEncoding(vec![Encoding::Chunked])
|
||||
}
|
||||
}
|
||||
|
||||
bench_header!(normal, TransferEncoding, { vec![b"chunked, gzip".to_vec()] });
|
||||
bench_header!(ext, TransferEncoding, { vec![b"ext".to_vec()] });
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::any::{Any, TypeId};
|
||||
use std::cell::UnsafeCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
|
||||
@@ -53,7 +52,7 @@ enum PtrMap<T> {
|
||||
Many(HashMap<TypeId, T>)
|
||||
}
|
||||
|
||||
impl<V: ?Sized + fmt::Debug + Any + 'static> PtrMapCell<V> {
|
||||
impl<V: ?Sized + Any + 'static> PtrMapCell<V> {
|
||||
#[inline]
|
||||
pub fn new() -> PtrMapCell<V> {
|
||||
PtrMapCell(UnsafeCell::new(PtrMap::Empty))
|
||||
@@ -114,12 +113,12 @@ impl<V: ?Sized + fmt::Debug + Any + 'static> PtrMapCell<V> {
|
||||
let map = &*self.0.get();
|
||||
match *map {
|
||||
PtrMap::One(_, ref one) => one,
|
||||
_ => panic!("not PtrMap::One value, {:?}", *map)
|
||||
_ => panic!("not PtrMap::One value")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: ?Sized + fmt::Debug + Any + 'static> Clone for PtrMapCell<V> where Box<V>: Clone {
|
||||
impl<V: ?Sized + Any + 'static> Clone for PtrMapCell<V> where Box<V>: Clone {
|
||||
#[inline]
|
||||
fn clone(&self) -> PtrMapCell<V> {
|
||||
let cell = PtrMapCell::new();
|
||||
|
||||
@@ -4,13 +4,13 @@ use std::fmt;
|
||||
use std::str::from_utf8;
|
||||
|
||||
use super::cell::{OptCell, PtrMapCell};
|
||||
use header::{Header, HeaderFormat};
|
||||
use header::{Header};
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Item {
|
||||
raw: OptCell<Vec<Vec<u8>>>,
|
||||
typed: PtrMapCell<HeaderFormat + Send + Sync>
|
||||
typed: PtrMapCell<Header + Send + Sync>
|
||||
}
|
||||
|
||||
impl Item {
|
||||
@@ -23,7 +23,7 @@ impl Item {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_typed(ty: Box<HeaderFormat + Send + Sync>) -> Item {
|
||||
pub fn new_typed(ty: Box<Header + Send + Sync>) -> Item {
|
||||
let map = PtrMapCell::new();
|
||||
unsafe { map.insert((*ty).get_type(), ty); }
|
||||
Item {
|
||||
@@ -52,7 +52,7 @@ impl Item {
|
||||
&raw[..]
|
||||
}
|
||||
|
||||
pub fn typed<H: Header + HeaderFormat + Any>(&self) -> Option<&H> {
|
||||
pub fn typed<H: Header + Any>(&self) -> Option<&H> {
|
||||
let tid = TypeId::of::<H>();
|
||||
match self.typed.get(tid) {
|
||||
Some(val) => Some(val),
|
||||
@@ -68,7 +68,7 @@ impl Item {
|
||||
}.map(|typed| unsafe { typed.downcast_ref_unchecked() })
|
||||
}
|
||||
|
||||
pub fn typed_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> {
|
||||
pub fn typed_mut<H: Header>(&mut self) -> Option<&mut H> {
|
||||
let tid = TypeId::of::<H>();
|
||||
if self.typed.get_mut(tid).is_none() {
|
||||
match parse::<H>(self.raw.as_ref().expect("item.raw must exist")) {
|
||||
@@ -83,11 +83,11 @@ impl Item {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn parse<H: Header + HeaderFormat>(raw: &Vec<Vec<u8>>) ->
|
||||
::Result<Box<HeaderFormat + Send + Sync>> {
|
||||
fn parse<H: Header>(raw: &Vec<Vec<u8>>) ->
|
||||
::Result<Box<Header + Send + Sync>> {
|
||||
Header::parse_header(&raw[..]).map(|h: H| {
|
||||
// FIXME: Use Type ascription
|
||||
let h: Box<HeaderFormat + Send + Sync> = Box::new(h);
|
||||
let h: Box<Header + Send + Sync> = Box::new(h);
|
||||
h
|
||||
})
|
||||
}
|
||||
|
||||
@@ -31,18 +31,17 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This works well for simple "string" headers. But the header system
|
||||
//! actually involves 2 parts: parsing, and formatting. If you need to
|
||||
//! customize either part, you can do so.
|
||||
//! This works well for simple "string" headers. If you need more control,
|
||||
//! you can implement the trait directly.
|
||||
//!
|
||||
//! ## `Header` and `HeaderFormat`
|
||||
//! ## Implementing the `Header` trait
|
||||
//!
|
||||
//! Consider a Do Not Track header. It can be true or false, but it represents
|
||||
//! that via the numerals `1` and `0`.
|
||||
//!
|
||||
//! ```
|
||||
//! use std::fmt;
|
||||
//! use hyper::header::{Header, HeaderFormat};
|
||||
//! use hyper::header::Header;
|
||||
//!
|
||||
//! #[derive(Debug, Clone, Copy)]
|
||||
//! struct Dnt(bool);
|
||||
@@ -66,9 +65,7 @@
|
||||
//! }
|
||||
//! Err(hyper::Error::Header)
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! impl HeaderFormat for Dnt {
|
||||
//! fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
//! if self.0 {
|
||||
//! f.write_str("1")
|
||||
@@ -113,11 +110,11 @@ type HeaderName = UniCase<CowStr>;
|
||||
///
|
||||
/// This trait represents the construction and identification of headers,
|
||||
/// and contains trait-object unsafe methods.
|
||||
pub trait Header: Clone + Any + Send + Sync {
|
||||
pub trait Header: HeaderClone + Any + Typeable + Send + Sync {
|
||||
/// Returns the name of the header field this belongs to.
|
||||
///
|
||||
/// This will become an associated constant once available.
|
||||
fn header_name() -> &'static str;
|
||||
fn header_name() -> &'static str where Self: Sized;
|
||||
/// Parse a header from a raw stream of bytes.
|
||||
///
|
||||
/// It's possible that a request can include a header field more than once,
|
||||
@@ -125,35 +122,27 @@ pub trait Header: Clone + Any + Send + Sync {
|
||||
/// it's not necessarily the case that a Header is *allowed* to have more
|
||||
/// than one field value. If that's the case, you **should** return `None`
|
||||
/// if `raw.len() > 1`.
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Self>;
|
||||
|
||||
}
|
||||
|
||||
/// A trait for any object that will represent a header field and value.
|
||||
///
|
||||
/// This trait represents the formatting of a `Header` for output to a TcpStream.
|
||||
pub trait HeaderFormat: fmt::Debug + HeaderClone + Any + Typeable + Send + Sync {
|
||||
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Self> where Self: Sized;
|
||||
/// Format a header to be output into a TcpStream.
|
||||
///
|
||||
/// This method is not allowed to introduce an Err not produced
|
||||
/// by the passed-in Formatter.
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result;
|
||||
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait HeaderClone {
|
||||
fn clone_box(&self) -> Box<HeaderFormat + Send + Sync>;
|
||||
fn clone_box(&self) -> Box<Header + Send + Sync>;
|
||||
}
|
||||
|
||||
impl<T: HeaderFormat + Clone> HeaderClone for T {
|
||||
impl<T: Header + Clone> HeaderClone for T {
|
||||
#[inline]
|
||||
fn clone_box(&self) -> Box<HeaderFormat + Send + Sync> {
|
||||
fn clone_box(&self) -> Box<Header + Send + Sync> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat + Send + Sync {
|
||||
impl Header + Send + Sync {
|
||||
#[inline]
|
||||
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
|
||||
mem::transmute(traitobject::data(self))
|
||||
@@ -165,9 +154,9 @@ impl HeaderFormat + Send + Sync {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<HeaderFormat + Send + Sync> {
|
||||
impl Clone for Box<Header + Send + Sync> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Box<HeaderFormat + Send + Sync> {
|
||||
fn clone(&self) -> Box<Header + Send + Sync> {
|
||||
self.clone_box()
|
||||
}
|
||||
}
|
||||
@@ -183,6 +172,12 @@ pub struct Headers {
|
||||
data: HashMap<HeaderName, Item>
|
||||
}
|
||||
|
||||
impl Default for Headers {
|
||||
fn default() -> Headers {
|
||||
Headers::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Headers {
|
||||
|
||||
/// Creates a new, empty headers map.
|
||||
@@ -212,8 +207,8 @@ impl Headers {
|
||||
/// Set a header field to the corresponding value.
|
||||
///
|
||||
/// The field is determined by the type of the value being set.
|
||||
pub fn set<H: Header + HeaderFormat>(&mut self, value: H) {
|
||||
trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), value);
|
||||
pub fn set<H: Header>(&mut self, value: H) {
|
||||
trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), HeaderFormatter(&value));
|
||||
self.data.insert(UniCase(CowStr(Cow::Borrowed(header_name::<H>()))),
|
||||
Item::new_typed(Box::new(value)));
|
||||
}
|
||||
@@ -259,13 +254,13 @@ impl Headers {
|
||||
}
|
||||
|
||||
/// Get a reference to the header field's value, if it exists.
|
||||
pub fn get<H: Header + HeaderFormat>(&self) -> Option<&H> {
|
||||
pub fn get<H: Header>(&self) -> Option<&H> {
|
||||
self.data.get(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
|
||||
.and_then(Item::typed::<H>)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the header field's value, if it exists.
|
||||
pub fn get_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> {
|
||||
pub fn get_mut<H: Header>(&mut self) -> Option<&mut H> {
|
||||
self.data.get_mut(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
|
||||
.and_then(Item::typed_mut::<H>)
|
||||
}
|
||||
@@ -280,13 +275,13 @@ impl Headers {
|
||||
/// # let mut headers = Headers::new();
|
||||
/// let has_type = headers.has::<ContentType>();
|
||||
/// ```
|
||||
pub fn has<H: Header + HeaderFormat>(&self) -> bool {
|
||||
pub fn has<H: Header>(&self) -> bool {
|
||||
self.data.contains_key(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
|
||||
}
|
||||
|
||||
/// Removes a header from the map, if one existed.
|
||||
/// Returns true if a header has been removed.
|
||||
pub fn remove<H: Header + HeaderFormat>(&mut self) -> bool {
|
||||
pub fn remove<H: Header>(&mut self) -> bool {
|
||||
trace!("Headers.remove( {:?} )", header_name::<H>());
|
||||
self.data.remove(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))).is_some()
|
||||
}
|
||||
@@ -380,6 +375,7 @@ impl Deserialize for Headers {
|
||||
}
|
||||
|
||||
/// An `Iterator` over the fields in a `Headers` map.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct HeadersItems<'a> {
|
||||
inner: Iter<'a, HeaderName, Item>
|
||||
}
|
||||
@@ -410,7 +406,7 @@ impl<'a> HeaderView<'a> {
|
||||
|
||||
/// Cast the value to a certain Header type.
|
||||
#[inline]
|
||||
pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> {
|
||||
pub fn value<H: Header>(&self) -> Option<&'a H> {
|
||||
self.1.typed::<H>()
|
||||
}
|
||||
|
||||
@@ -449,7 +445,7 @@ impl<'a> FromIterator<HeaderView<'a>> for Headers {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) {
|
||||
impl<'a> fmt::Display for &'a (Header + Send + Sync) {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
(**self).fmt_header(f)
|
||||
@@ -461,16 +457,16 @@ impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) {
|
||||
/// This can be used like so: `format!("{}", HeaderFormatter(&header))` to
|
||||
/// get the representation of a Header which will be written to an
|
||||
/// outgoing `TcpStream`.
|
||||
pub struct HeaderFormatter<'a, H: HeaderFormat>(pub &'a H);
|
||||
pub struct HeaderFormatter<'a, H: Header>(pub &'a H);
|
||||
|
||||
impl<'a, H: HeaderFormat> fmt::Display for HeaderFormatter<'a, H> {
|
||||
impl<'a, H: Header> fmt::Display for HeaderFormatter<'a, H> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.0.fmt_header(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, H: HeaderFormat> fmt::Debug for HeaderFormatter<'a, H> {
|
||||
impl<'a, H: Header> fmt::Debug for HeaderFormatter<'a, H> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.0.fmt_header(f)
|
||||
@@ -519,7 +515,7 @@ mod tests {
|
||||
use mime::Mime;
|
||||
use mime::TopLevel::Text;
|
||||
use mime::SubLevel::Plain;
|
||||
use super::{Headers, Header, HeaderFormat, ContentLength, ContentType,
|
||||
use super::{Headers, Header, ContentLength, ContentType,
|
||||
Accept, Host, qitem};
|
||||
use httparse;
|
||||
|
||||
@@ -597,9 +593,7 @@ mod tests {
|
||||
None => Err(::Error::Header),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for CrazyLength {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let CrazyLength(ref opt, ref value) = *self;
|
||||
write!(f, "{:?}, {:?}", opt, value)
|
||||
|
||||
@@ -137,6 +137,12 @@ define_encode_set! {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for HTTP_VALUE {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad("HTTP_VALUE")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ExtendedValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let encoded_value =
|
||||
|
||||
Reference in New Issue
Block a user