Merge pull request #1038 from hyperium/headers-mem-slice
use MemSlice in Headers
This commit is contained in:
		| @@ -40,6 +40,7 @@ impl Header for ContentLength { | ||||
|         static NAME: &'static str = "Content-Length"; | ||||
|         NAME | ||||
|     } | ||||
|  | ||||
|     fn parse_header(raw: &Raw) -> ::Result<ContentLength> { | ||||
|         // If multiple Content-Length headers were sent, everything can still | ||||
|         // be alright if they all contain the same value, and all parse | ||||
| @@ -49,9 +50,9 @@ impl Header for ContentLength { | ||||
|             .fold(None, |prev, x| { | ||||
|                 match (prev, x) { | ||||
|                     (None, x) => Some(x), | ||||
|                     (e@Some(Err(_)), _ ) => e, | ||||
|                     (e @ Some(Err(_)), _ ) => e, | ||||
|                     (Some(Ok(prev)), Ok(x)) if prev == x => Some(Ok(prev)), | ||||
|                     _ => Some(Err(::Error::Header)) | ||||
|                     _ => Some(Err(::Error::Header)), | ||||
|                 } | ||||
|             }) | ||||
|             .unwrap_or(Err(::Error::Header)) | ||||
|   | ||||
| @@ -141,9 +141,7 @@ impl Header for RetryAfter { | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     extern crate httparse; | ||||
|  | ||||
|     use header::{Header, Headers}; | ||||
|     use header::Header; | ||||
|     use header::shared::HttpDate; | ||||
|     use time::{Duration}; | ||||
|  | ||||
| @@ -179,17 +177,15 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn hyper_headers_from_raw_delay() { | ||||
|         let headers = Headers::from_raw(&[httparse::Header { name: "Retry-After", value: b"300" }]).unwrap(); | ||||
|         let retry_after = headers.get::<RetryAfter>().unwrap(); | ||||
|         assert_eq!(retry_after, &RetryAfter::Delay(Duration::seconds(300))); | ||||
|         let retry_after = RetryAfter::parse_header(&b"300".to_vec().into()).unwrap(); | ||||
|         assert_eq!(retry_after, RetryAfter::Delay(Duration::seconds(300))); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn hyper_headers_from_raw_datetime() { | ||||
|         let headers = Headers::from_raw(&[httparse::Header { name: "Retry-After", value: b"Sun, 06 Nov 1994 08:49:37 GMT" }]).unwrap(); | ||||
|         let retry_after = headers.get::<RetryAfter>().unwrap(); | ||||
|         let retry_after = RetryAfter::parse_header(&b"Sun, 06 Nov 1994 08:49:37 GMT".to_vec().into()).unwrap(); | ||||
|         let expected = "Sun, 06 Nov 1994 08:49:37 GMT".parse::<HttpDate>().unwrap(); | ||||
|  | ||||
|         assert_eq!(retry_after, &RetryAfter::DateTime(expected.0)); | ||||
|         assert_eq!(retry_after, RetryAfter::DateTime(expected.0)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -4,9 +4,9 @@ pub struct VecMap<K, V> { | ||||
| } | ||||
|  | ||||
| impl<K: PartialEq, V> VecMap<K, V> { | ||||
|     pub fn new() -> VecMap<K, V> { | ||||
|     pub fn with_capacity(cap: usize) -> VecMap<K, V> { | ||||
|         VecMap { | ||||
|             vec: Vec::new() | ||||
|             vec: Vec::with_capacity(cap) | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -43,6 +43,7 @@ impl<K: PartialEq, V> VecMap<K, V> { | ||||
|     } | ||||
|  | ||||
|     pub fn len(&self) -> usize { self.vec.len() } | ||||
|  | ||||
|     pub fn iter(&self) -> ::std::slice::Iter<(K, V)> { | ||||
|         self.vec.iter() | ||||
|     } | ||||
|   | ||||
| @@ -80,7 +80,6 @@ use std::borrow::{Cow, ToOwned}; | ||||
| use std::iter::{FromIterator, IntoIterator}; | ||||
| use std::{mem, fmt}; | ||||
|  | ||||
| use httparse; | ||||
| use unicase::UniCase; | ||||
|  | ||||
| use self::internals::{Item, VecMap, Entry}; | ||||
| @@ -88,6 +87,7 @@ use self::internals::{Item, VecMap, Entry}; | ||||
| pub use self::shared::*; | ||||
| pub use self::common::*; | ||||
| pub use self::raw::Raw; | ||||
| use http::buf::MemSlice; | ||||
|  | ||||
| mod common; | ||||
| mod internals; | ||||
| @@ -346,31 +346,17 @@ literals! { | ||||
| impl Headers { | ||||
|  | ||||
|     /// Creates a new, empty headers map. | ||||
|     #[inline] | ||||
|     pub fn new() -> Headers { | ||||
|         Headers { | ||||
|             data: VecMap::new() | ||||
|         } | ||||
|         Headers::with_capacity(0) | ||||
|     } | ||||
|  | ||||
|     #[doc(hidden)] | ||||
|     pub fn from_raw(raw: &[httparse::Header]) -> ::Result<Headers> { | ||||
|         let mut headers = Headers::new(); | ||||
|         for header in raw { | ||||
|             trace!("raw header: {:?}={:?}", header.name, &header.value[..]); | ||||
|             let name = HeaderName(UniCase(maybe_literal(header.name))); | ||||
|             let trim = header.value.iter().rev().take_while(|&&x| x == b' ').count(); | ||||
|             let value = &header.value[.. header.value.len() - trim]; | ||||
|  | ||||
|             match headers.data.entry(name) { | ||||
|                 Entry::Vacant(entry) => { | ||||
|                     entry.insert(Item::new_raw(self::raw::parsed(value))); | ||||
|                 } | ||||
|                 Entry::Occupied(entry) => { | ||||
|                     entry.into_mut().mut_raw().push(value); | ||||
|                 } | ||||
|             }; | ||||
|     /// Creates a new `Headers` struct with space reserved for `len` headers. | ||||
|     #[inline] | ||||
|     pub fn with_capacity(len: usize) -> Headers { | ||||
|         Headers { | ||||
|             data: VecMap::with_capacity(len) | ||||
|         } | ||||
|         Ok(headers) | ||||
|     } | ||||
|  | ||||
|     /// Set a header field to the corresponding value. | ||||
| @@ -586,6 +572,24 @@ impl<'a> Extend<HeaderView<'a>> for Headers { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> Extend<(&'a str, MemSlice)> for Headers { | ||||
|     fn extend<I: IntoIterator<Item=(&'a str, MemSlice)>>(&mut self, iter: I) { | ||||
|         for (name, value) in iter { | ||||
|             let name = HeaderName(UniCase(maybe_literal(name))); | ||||
|             //let trim = header.value.iter().rev().take_while(|&&x| x == b' ').count(); | ||||
|  | ||||
|             match self.data.entry(name) { | ||||
|                 Entry::Vacant(entry) => { | ||||
|                     entry.insert(Item::new_raw(self::raw::parsed(value))); | ||||
|                 } | ||||
|                 Entry::Occupied(entry) => { | ||||
|                     self::raw::push(entry.into_mut().mut_raw(), value); | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> FromIterator<HeaderView<'a>> for Headers { | ||||
|     fn from_iter<I: IntoIterator<Item=HeaderView<'a>>>(iter: I) -> Headers { | ||||
|         let mut headers = Headers::new(); | ||||
| @@ -658,37 +662,25 @@ mod tests { | ||||
|     use mime::SubLevel::Plain; | ||||
|     use super::{Headers, Header, Raw, ContentLength, ContentType, | ||||
|                 Accept, Host, qitem}; | ||||
|     use httparse; | ||||
|  | ||||
|     #[cfg(feature = "nightly")] | ||||
|     use test::Bencher; | ||||
|  | ||||
|     // Slice.position_elem was unstable | ||||
|     fn index_of(slice: &[u8], byte: u8) -> Option<usize> { | ||||
|         for (index, &b) in slice.iter().enumerate() { | ||||
|             if b == byte { | ||||
|                 return Some(index); | ||||
|             } | ||||
|         } | ||||
|         None | ||||
|     } | ||||
|  | ||||
|     macro_rules! raw { | ||||
|         ($($line:expr),*) => ({ | ||||
|             [$({ | ||||
|                 let line = $line; | ||||
|                 let pos = index_of(line, b':').expect("raw splits on ':', not found"); | ||||
|                 httparse::Header { | ||||
|                     name: ::std::str::from_utf8(&line[..pos]).unwrap(), | ||||
|                     value: &line[pos + 2..] | ||||
|                 } | ||||
|             }),*] | ||||
|     macro_rules! make_header { | ||||
|         ($name:expr, $value:expr) => ({ | ||||
|             let mut headers = Headers::new(); | ||||
|             headers.set_raw(String::from_utf8($name.to_vec()).unwrap(), $value.to_vec()); | ||||
|             headers | ||||
|         }); | ||||
|         ($text:expr) => ({ | ||||
|             let bytes = $text; | ||||
|             let colon = bytes.iter().position(|&x| x == b':').unwrap(); | ||||
|             make_header!(&bytes[..colon], &bytes[colon + 2..]) | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_from_raw() { | ||||
|         let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap(); | ||||
|         let headers = make_header!(b"Content-Length", b"10"); | ||||
|         assert_eq!(headers.get(), Some(&ContentLength(10))); | ||||
|     } | ||||
|  | ||||
| @@ -738,20 +730,20 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_different_structs_for_same_header() { | ||||
|         let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap(); | ||||
|         let headers = make_header!(b"Content-Length: 10"); | ||||
|         assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10))); | ||||
|         assert_eq!(headers.get::<CrazyLength>(), Some(&CrazyLength(Some(false), 10))); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_trailing_whitespace() { | ||||
|         let headers = Headers::from_raw(&raw!(b"Content-Length: 10   ")).unwrap(); | ||||
|         let headers = make_header!(b"Content-Length: 10   "); | ||||
|         assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10))); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_multiple_reads() { | ||||
|         let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap(); | ||||
|         let headers = make_header!(b"Content-Length: 10"); | ||||
|         let ContentLength(one) = *headers.get::<ContentLength>().unwrap(); | ||||
|         let ContentLength(two) = *headers.get::<ContentLength>().unwrap(); | ||||
|         assert_eq!(one, two); | ||||
| @@ -759,15 +751,16 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_different_reads() { | ||||
|         let headers = Headers::from_raw( | ||||
|             &raw!(b"Content-Length: 10", b"Content-Type: text/plain")).unwrap(); | ||||
|         let mut headers = Headers::new(); | ||||
|         headers.set_raw("Content-Length", "10"); | ||||
|         headers.set_raw("Content-Type", "text/plain"); | ||||
|         let ContentLength(_) = *headers.get::<ContentLength>().unwrap(); | ||||
|         let ContentType(_) = *headers.get::<ContentType>().unwrap(); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_get_mutable() { | ||||
|         let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap(); | ||||
|         let mut headers = make_header!(b"Content-Length: 10"); | ||||
|         *headers.get_mut::<ContentLength>().unwrap() = ContentLength(20); | ||||
|         assert_eq!(headers.get_raw("content-length").unwrap(), &[b"20".to_vec()][..]); | ||||
|         assert_eq!(*headers.get::<ContentLength>().unwrap(), ContentLength(20)); | ||||
| @@ -786,7 +779,7 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_headers_to_string_raw() { | ||||
|         let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap(); | ||||
|         let mut headers = make_header!(b"Content-Length: 10"); | ||||
|         headers.set_raw("x-foo", vec![b"foo".to_vec(), b"bar".to_vec()]); | ||||
|         let s = headers.to_string(); | ||||
|         assert_eq!(s, "Content-Length: 10\r\nx-foo: foo\r\nx-foo: bar\r\n"); | ||||
| @@ -900,13 +893,6 @@ mod tests { | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "nightly")] | ||||
|     #[bench] | ||||
|     fn bench_headers_from_raw(b: &mut Bencher) { | ||||
|         let raw = raw!(b"Content-Length: 10"); | ||||
|         b.iter(|| Headers::from_raw(&raw).unwrap()) | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "nightly")] | ||||
|     #[bench] | ||||
|     fn bench_headers_get(b: &mut Bencher) { | ||||
|   | ||||
| @@ -21,7 +21,7 @@ pub fn from_one_raw_str<T: str::FromStr>(raw: &Raw) -> ::Result<T> { | ||||
|  | ||||
| /// Reads a raw string into a value. | ||||
| pub fn from_raw_str<T: str::FromStr>(raw: &[u8]) -> ::Result<T> { | ||||
|     let s = try!(str::from_utf8(raw)); | ||||
|     let s = try!(str::from_utf8(raw)).trim(); | ||||
|     T::from_str(s).or(Err(::Error::Header)) | ||||
| } | ||||
|  | ||||
| @@ -36,7 +36,7 @@ pub fn from_comma_delimited<T: str::FromStr>(raw: &Raw) -> ::Result<Vec<T>> { | ||||
|                           "" => None, | ||||
|                           y => Some(y) | ||||
|                       }) | ||||
|                       .filter_map(|x| x.parse().ok())) | ||||
|                       .filter_map(|x| x.trim().parse().ok())) | ||||
|     } | ||||
|     Ok(result) | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| use std::borrow::Cow; | ||||
| use std::fmt; | ||||
| use http::buf::MemSlice; | ||||
|  | ||||
| /// A raw header value. | ||||
| #[derive(Clone, PartialEq, Eq)] | ||||
| @@ -19,8 +20,8 @@ impl Raw { | ||||
|     #[inline] | ||||
|     pub fn one(&self) -> Option<&[u8]> { | ||||
|         match self.0 { | ||||
|             Lines::One(ref line) => Some(line), | ||||
|             Lines::Many(ref lines) if lines.len() == 1 => Some(&lines[0]), | ||||
|             Lines::One(ref line) => Some(line.as_ref()), | ||||
|             Lines::Many(ref lines) if lines.len() == 1 => Some(lines[0].as_ref()), | ||||
|             _ => None | ||||
|         } | ||||
|     } | ||||
| @@ -29,37 +30,42 @@ impl Raw { | ||||
|     #[inline] | ||||
|     pub fn iter(&self) -> RawLines { | ||||
|         RawLines { | ||||
|             inner: match self.0 { | ||||
|                 Lines::One(ref line) => unsafe { | ||||
|                     ::std::slice::from_raw_parts(line, 1) | ||||
|                 }.iter(), | ||||
|                 Lines::Many(ref lines) => lines.iter() | ||||
|             } | ||||
|             inner: &self.0, | ||||
|             pos: 0, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Append a line to this `Raw` header value. | ||||
|     pub fn push(&mut self, val: &[u8]) { | ||||
|         self.push_line(maybe_literal(val.into())); | ||||
|     } | ||||
|  | ||||
|     fn push_line(&mut self, line: Line) { | ||||
|         let lines = ::std::mem::replace(&mut self.0, Lines::Many(Vec::new())); | ||||
|         match lines { | ||||
|             Lines::One(line) => { | ||||
|                 self.0 = Lines::Many(vec![line, maybe_literal(val.into())]); | ||||
|             Lines::One(one) => { | ||||
|                 self.0 = Lines::Many(vec![one, line]); | ||||
|             } | ||||
|             Lines::Many(mut lines) => { | ||||
|                 lines.push(maybe_literal(val.into())); | ||||
|                 lines.push(line); | ||||
|                 self.0 = Lines::Many(lines); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Clone, PartialEq, Eq)] | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| enum Lines { | ||||
|     One(Line), | ||||
|     Many(Vec<Line>) | ||||
|     Many(Vec<Line>), | ||||
| } | ||||
|  | ||||
| type Line = Cow<'static, [u8]>; | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| enum Line { | ||||
|     Static(&'static [u8]), | ||||
|     Owned(Vec<u8>), | ||||
|     Shared(MemSlice), | ||||
| } | ||||
|  | ||||
| fn eq<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: &[A], b: &[B]) -> bool { | ||||
|     if a.len() != b.len() { | ||||
| @@ -123,24 +129,59 @@ impl From<String> for Raw { | ||||
| impl From<Vec<u8>> for Raw { | ||||
|     #[inline] | ||||
|     fn from(val: Vec<u8>) -> Raw { | ||||
|         Raw(Lines::One(Cow::Owned(val))) | ||||
|         Raw(Lines::One(Line::from(val))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<&'static str> for Raw { | ||||
|     fn from(val: &'static str) -> Raw { | ||||
|         Raw(Lines::One(Cow::Borrowed(val.as_bytes()))) | ||||
|         Raw(Lines::One(Line::Static(val.as_bytes()))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<&'static [u8]> for Raw { | ||||
|     fn from(val: &'static [u8]) -> Raw { | ||||
|         Raw(Lines::One(Cow::Borrowed(val))) | ||||
|         Raw(Lines::One(Line::Static(val))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn parsed(val: &[u8]) -> Raw { | ||||
|     Raw(Lines::One(maybe_literal(val.into()))) | ||||
| impl From<MemSlice> for Raw { | ||||
|     #[inline] | ||||
|     fn from(val: MemSlice) -> Raw { | ||||
|         Raw(Lines::One(Line::Shared(val))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Vec<u8>> for Line { | ||||
|     #[inline] | ||||
|     fn from(val: Vec<u8>) -> Line { | ||||
|         Line::Owned(val) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<MemSlice> for Line { | ||||
|     #[inline] | ||||
|     fn from(val: MemSlice) -> Line { | ||||
|         Line::Shared(val) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl AsRef<[u8]> for Line { | ||||
|     fn as_ref(&self) -> &[u8] { | ||||
|         match *self { | ||||
|             Line::Static(ref s) => s, | ||||
|             Line::Owned(ref v) => v.as_ref(), | ||||
|             Line::Shared(ref m) => m.as_ref(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn parsed(val: MemSlice) -> Raw { | ||||
|     Raw(Lines::One(From::from(val))) | ||||
| } | ||||
|  | ||||
| pub fn push(raw: &mut Raw, val: MemSlice) { | ||||
|     raw.push_line(Line::from(val)); | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for Raw { | ||||
| @@ -154,6 +195,7 @@ impl fmt::Debug for Raw { | ||||
|  | ||||
| impl ::std::ops::Index<usize> for Raw { | ||||
|     type Output = [u8]; | ||||
|  | ||||
|     fn index(&self, idx: usize) -> &[u8] { | ||||
|         match self.0 { | ||||
|             Lines::One(ref line) => if idx == 0 { | ||||
| @@ -168,12 +210,12 @@ impl ::std::ops::Index<usize> for Raw { | ||||
|  | ||||
| macro_rules! literals { | ||||
|     ($($len:expr => $($value:expr),+;)+) => ( | ||||
|         fn maybe_literal<'a>(s: Cow<'a, [u8]>) -> Cow<'static, [u8]> { | ||||
|         fn maybe_literal<'a>(s: Cow<'a, [u8]>) -> Line { | ||||
|             match s.len() { | ||||
|                 $($len => { | ||||
|                     $( | ||||
|                     if s.as_ref() == $value { | ||||
|                         return Cow::Borrowed($value); | ||||
|                         return Line::Static($value); | ||||
|                     } | ||||
|                     )+ | ||||
|                 })+ | ||||
| @@ -181,7 +223,7 @@ macro_rules! literals { | ||||
|                 _ => () | ||||
|             } | ||||
|  | ||||
|             Cow::Owned(s.into_owned()) | ||||
|             Line::from(s.into_owned()) | ||||
|         } | ||||
|  | ||||
|         #[test] | ||||
| @@ -216,7 +258,8 @@ impl<'a> IntoIterator for &'a Raw { | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct RawLines<'a> { | ||||
|     inner: ::std::slice::Iter<'a, Cow<'static, [u8]>> | ||||
|     inner: &'a Lines, | ||||
|     pos: usize, | ||||
| } | ||||
|  | ||||
| impl<'a> Iterator for RawLines<'a> { | ||||
| @@ -224,6 +267,17 @@ impl<'a> Iterator for RawLines<'a> { | ||||
|  | ||||
|     #[inline] | ||||
|     fn next(&mut self) -> Option<&'a [u8]> { | ||||
|         self.inner.next().map(AsRef::as_ref) | ||||
|         let current_pos = self.pos; | ||||
|         self.pos += 1; | ||||
|         match *self.inner { | ||||
|             Lines::One(ref line) => { | ||||
|                 if current_pos == 0 { | ||||
|                     Some(line.as_ref()) | ||||
|                 } else { | ||||
|                     None | ||||
|                 } | ||||
|             } | ||||
|             Lines::Many(ref lines) => lines.get(current_pos).map(|l| l.as_ref()), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										175
									
								
								src/http/buf.rs
									
									
									
									
									
								
							
							
						
						
									
										175
									
								
								src/http/buf.rs
									
									
									
									
									
								
							| @@ -1,13 +1,14 @@ | ||||
| use std::cell::UnsafeCell; | ||||
| use std::borrow::Cow; | ||||
| use std::cell::{Cell, UnsafeCell}; | ||||
| use std::fmt; | ||||
| use std::io::{self, Read}; | ||||
| use std::ops::{Deref, Range, RangeFrom, RangeTo, RangeFull}; | ||||
| use std::ops::{Index, Range, RangeFrom, RangeTo, RangeFull}; | ||||
| use std::ptr; | ||||
| use std::sync::Arc; | ||||
|  | ||||
| pub struct MemBuf { | ||||
|     buf: Arc<UnsafeCell<Vec<u8>>>, | ||||
|     start: usize, | ||||
|     start: Cell<usize>, | ||||
|     end: usize, | ||||
| } | ||||
|  | ||||
| @@ -19,13 +20,13 @@ impl MemBuf { | ||||
|     pub fn with_capacity(cap: usize) -> MemBuf { | ||||
|         MemBuf { | ||||
|             buf: Arc::new(UnsafeCell::new(vec![0; cap])), | ||||
|             start: 0, | ||||
|             start: Cell::new(0), | ||||
|             end: 0, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn bytes(&self) -> &[u8] { | ||||
|         &self.buf()[self.start..self.end] | ||||
|         &self.buf()[self.start.get()..self.end] | ||||
|     } | ||||
|  | ||||
|     pub fn is_empty(&self) -> bool { | ||||
| @@ -33,7 +34,7 @@ impl MemBuf { | ||||
|     } | ||||
|  | ||||
|     pub fn len(&self) -> usize { | ||||
|         self.end - self.start | ||||
|         self.end - self.start.get() | ||||
|     } | ||||
|  | ||||
|     pub fn capacity(&self) -> usize { | ||||
| @@ -41,20 +42,21 @@ impl MemBuf { | ||||
|     } | ||||
|  | ||||
|     pub fn read_from<R: Read>(&mut self, io: &mut R) -> io::Result<usize> { | ||||
|         let start = self.end - self.start; | ||||
|         let start = self.end - self.start.get(); | ||||
|         let n = try!(io.read(&mut self.buf_mut()[start..])); | ||||
|         self.end += n; | ||||
|         Ok(n) | ||||
|     } | ||||
|  | ||||
|     pub fn slice(&mut self, len: usize) -> MemSlice { | ||||
|         assert!(self.end - self.start >= len); | ||||
|         let start = self.start; | ||||
|         self.start += len; | ||||
|     pub fn slice(&self, len: usize) -> MemSlice { | ||||
|         assert!(self.end - self.start.get() >= len); | ||||
|         let start = self.start.get(); | ||||
|         let end = start + len; | ||||
|         self.start.set(end); | ||||
|         MemSlice { | ||||
|             buf: self.buf.clone(), | ||||
|             start: start, | ||||
|             end: self.start, | ||||
|             end: end, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -67,18 +69,18 @@ impl MemBuf { | ||||
|         } | ||||
|         let is_unique = Arc::get_mut(&mut self.buf).is_some(); | ||||
|         trace!("MemBuf::reserve {} access", if is_unique { "unique" } else { "shared" }); | ||||
|         if is_unique && remaining + self.start >= needed { | ||||
|         if is_unique && remaining + self.start.get() >= needed { | ||||
|             // we have unique access, we can mutate this vector | ||||
|             trace!("MemBuf::reserve unique access, shifting"); | ||||
|             unsafe { | ||||
|                 let mut buf = &mut *self.buf.get(); | ||||
|                 let len = self.len(); | ||||
|                 ptr::copy( | ||||
|                     buf.as_ptr().offset(self.start as isize), | ||||
|                     buf.as_ptr().offset(self.start.get() as isize), | ||||
|                     buf.as_mut_ptr(), | ||||
|                     len | ||||
|                 ); | ||||
|                 self.start = 0; | ||||
|                 self.start.set(0); | ||||
|                 self.end = len; | ||||
|             } | ||||
|         } else if is_unique { | ||||
| @@ -109,7 +111,7 @@ impl MemBuf { | ||||
|         match Arc::get_mut(&mut self.buf) { | ||||
|             Some(_) => { | ||||
|                 trace!("MemBuf::reset was unique, re-using"); | ||||
|                 self.start = 0; | ||||
|                 self.start.set(0); | ||||
|                 self.end = 0; | ||||
|             }, | ||||
|             None => { | ||||
| @@ -119,13 +121,19 @@ impl MemBuf { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(all(feature = "nightly", test))] | ||||
|     pub fn restart(&mut self) { | ||||
|         Arc::get_mut(&mut self.buf).unwrap(); | ||||
|         self.start.set(0); | ||||
|     } | ||||
|  | ||||
|     fn buf_mut(&mut self) -> &mut [u8] { | ||||
|         // The contract here is that we NEVER have a MemSlice that exists | ||||
|         // with slice.end > self.start. | ||||
|         // In other words, we should *ALWAYS* be the only instance that can | ||||
|         // look at the bytes on the right side of self.start. | ||||
|         unsafe { | ||||
|             &mut (*self.buf.get())[self.start..] | ||||
|             &mut (*self.buf.get())[self.start.get()..] | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -169,9 +177,9 @@ fn test_grow_zerofill() { | ||||
| impl fmt::Debug for MemBuf { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.debug_struct("MemBuf") | ||||
|             .field("start", &self.start) | ||||
|             .field("start", &self.start.get()) | ||||
|             .field("end", &self.end) | ||||
|             .field("buf", &&self.buf()[self.start..self.end]) | ||||
|             .field("buf", &&self.buf()[self.start.get()..self.end]) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
| @@ -182,7 +190,7 @@ impl From<Vec<u8>> for MemBuf { | ||||
|         vec.shrink_to_fit(); | ||||
|         MemBuf { | ||||
|             buf: Arc::new(UnsafeCell::new(vec)), | ||||
|             start: 0, | ||||
|             start: Cell::new(0), | ||||
|             end: end, | ||||
|         } | ||||
|     } | ||||
| @@ -203,23 +211,118 @@ impl MemSlice { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn len(&self) -> usize { | ||||
|         self.get().len() | ||||
|     } | ||||
|  | ||||
|     pub fn is_empty(&self) -> bool { | ||||
|         self.get().is_empty() | ||||
|     } | ||||
|  | ||||
|     pub fn slice<S: Slice>(&self, range: S) -> MemSlice { | ||||
|         range.slice(self) | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| impl fmt::Debug for MemSlice { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         fmt::Debug::fmt(&**self, f) | ||||
|     fn get(&self) -> &[u8] { | ||||
|         unsafe { &(*self.buf.get())[self.start..self.end] } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Deref for  MemSlice { | ||||
|     type Target = [u8]; | ||||
|     fn deref(&self) -> &[u8] { | ||||
|         unsafe { | ||||
|             &(*self.buf.get())[self.start..self.end] | ||||
| impl AsRef<[u8]> for MemSlice { | ||||
|     fn as_ref(&self) -> &[u8] { | ||||
|         self.get() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for MemSlice { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         fmt::Debug::fmt(&self.get(), f) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Index<usize> for MemSlice { | ||||
|     type Output = u8; | ||||
|     fn index(&self, i: usize) -> &u8 { | ||||
|         &self.get()[i] | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> From<&'a [u8]> for MemSlice { | ||||
|     fn from(v: &'a [u8]) -> MemSlice { | ||||
|         MemSlice { | ||||
|             buf: Arc::new(UnsafeCell::new(v.to_vec())), | ||||
|             start: 0, | ||||
|             end: v.len(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Vec<u8>> for MemSlice { | ||||
|     fn from(v: Vec<u8>) -> MemSlice { | ||||
|         let len = v.len(); | ||||
|         MemSlice { | ||||
|             buf: Arc::new(UnsafeCell::new(v)), | ||||
|             start: 0, | ||||
|             end: len, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> From<&'a str> for MemSlice { | ||||
|     fn from(v: &'a str) -> MemSlice { | ||||
|         let v = v.as_bytes(); | ||||
|         MemSlice { | ||||
|             buf: Arc::new(UnsafeCell::new(v.to_vec())), | ||||
|             start: 0, | ||||
|             end: v.len(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> From<Cow<'a, [u8]>> for MemSlice { | ||||
|     fn from(v: Cow<'a, [u8]>) -> MemSlice { | ||||
|         let v = v.into_owned(); | ||||
|         let len = v.len(); | ||||
|         MemSlice { | ||||
|             buf: Arc::new(UnsafeCell::new(v)), | ||||
|             start: 0, | ||||
|             end: len, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl PartialEq for MemSlice { | ||||
|     fn eq(&self, other: &MemSlice) -> bool { | ||||
|         self.get() == other.get() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl PartialEq<[u8]> for MemSlice { | ||||
|     fn eq(&self, other: &[u8]) -> bool { | ||||
|         self.get() == other | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl PartialEq<str> for MemSlice { | ||||
|     fn eq(&self, other: &str) -> bool { | ||||
|         self.get() == other.as_bytes() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl PartialEq<Vec<u8>> for MemSlice { | ||||
|     fn eq(&self, other: &Vec<u8>) -> bool { | ||||
|         self.get() == other.as_slice() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Eq for MemSlice {} | ||||
|  | ||||
| impl Clone for MemSlice { | ||||
|     fn clone(&self) -> MemSlice { | ||||
|         MemSlice { | ||||
|             buf: self.buf.clone(), | ||||
|             start: self.start, | ||||
|             end: self.end, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -296,18 +399,18 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_mem_slice_slice() { | ||||
|         let mut buf = MemBuf::from(b"Hello World".to_vec()); | ||||
|         let buf = MemBuf::from(b"Hello World".to_vec()); | ||||
|  | ||||
|         let len = buf.len(); | ||||
|         let full = buf.slice(len); | ||||
|  | ||||
|         assert_eq!(&*full, b"Hello World"); | ||||
|         assert_eq!(&*full.slice(6..), b"World"); | ||||
|         assert_eq!(&*full.slice(..5), b"Hello"); | ||||
|         assert_eq!(&*full.slice(..), b"Hello World"); | ||||
|         assert_eq!(full.as_ref(), b"Hello World"); | ||||
|         assert_eq!(full.slice(6..).as_ref(), b"World"); | ||||
|         assert_eq!(full.slice(..5).as_ref(), b"Hello"); | ||||
|         assert_eq!(full.slice(..).as_ref(), b"Hello World"); | ||||
|         for a in 0..len { | ||||
|             for b in a..len { | ||||
|                 assert_eq!(&*full.slice(a..b), &b"Hello World"[a..b], "{}..{}", a, b); | ||||
|                 assert_eq!(full.slice(a..b).as_ref(), &b"Hello World"[a..b], "{}..{}", a, b); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -69,7 +69,7 @@ impl AsRef<[u8]> for Chunk { | ||||
|         match self.0 { | ||||
|             Inner::Owned(ref vec) => vec, | ||||
|             Inner::Referenced(ref vec) => vec, | ||||
|             Inner::Mem(ref slice) => slice, | ||||
|             Inner::Mem(ref slice) => slice.as_ref(), | ||||
|             Inner::Static(slice) => slice, | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -595,6 +595,21 @@ mod tests { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_conn_parse_partial() { | ||||
|         let good_message = b"GET / HTTP/1.1\r\nHost: foo.bar\r\n\r\n".to_vec(); | ||||
|         let io = AsyncIo::new_buf(good_message, 10); | ||||
|         let mut conn = Conn::<_, ServerTransaction>::new(io, Default::default()); | ||||
|         assert!(conn.poll().unwrap().is_not_ready()); | ||||
|         conn.io.io_mut().block_in(50); | ||||
|         let async = conn.poll().unwrap(); | ||||
|         assert!(async.is_ready()); | ||||
|         match async { | ||||
|             Async::Ready(Some(Frame::Message { .. })) => (), | ||||
|             f => panic!("frame is not Message: {:?}", f), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_conn_closed_read() { | ||||
|         let io = AsyncIo::new_buf(vec![], 0); | ||||
|   | ||||
| @@ -88,7 +88,7 @@ impl Decoder { | ||||
|                 } else { | ||||
|                     let to_read = *remaining as usize; | ||||
|                     let buf = try!(body.read_mem(to_read)); | ||||
|                     let num = buf.len() as u64; | ||||
|                     let num = buf.as_ref().len() as u64; | ||||
|                     trace!("Length read: {}", num); | ||||
|                     if num > *remaining { | ||||
|                         *remaining = 0; | ||||
| @@ -399,7 +399,7 @@ mod tests { | ||||
|         let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..]; | ||||
|         let buf = Decoder::chunked().decode(&mut mock_buf).expect("decode"); | ||||
|         assert_eq!(16, buf.len()); | ||||
|         let result = String::from_utf8(buf.to_vec()).expect("decode String"); | ||||
|         let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String"); | ||||
|         assert_eq!("1234567890abcdef", &result); | ||||
|     } | ||||
|  | ||||
| @@ -411,7 +411,7 @@ mod tests { | ||||
|         // normal read | ||||
|         let buf = decoder.decode(&mut mock_buf).expect("decode"); | ||||
|         assert_eq!(16, buf.len()); | ||||
|         let result = String::from_utf8(buf.to_vec()).expect("decode String"); | ||||
|         let result = String::from_utf8(buf.as_ref().to_vec()).expect("decode String"); | ||||
|         assert_eq!("1234567890abcdef", &result); | ||||
|  | ||||
|         // eof read | ||||
| @@ -438,7 +438,7 @@ mod tests { | ||||
|                     if buf.is_empty() { | ||||
|                         break; // eof | ||||
|                     } | ||||
|                     outs.write(&buf).expect("write buffer"); | ||||
|                     outs.write(buf.as_ref()).expect("write buffer"); | ||||
|                 } | ||||
|                 Err(e) => match e.kind() { | ||||
|                     io::ErrorKind::WouldBlock => { | ||||
|   | ||||
| @@ -6,6 +6,7 @@ use httparse; | ||||
| use header::{self, Headers, ContentLength, TransferEncoding}; | ||||
| use http::{MessageHead, RawStatus, Http1Transaction, ParseResult, ServerTransaction, ClientTransaction, RequestLine}; | ||||
| use http::h1::{Encoder, Decoder}; | ||||
| use http::buf::{MemBuf, MemSlice}; | ||||
| use method::Method; | ||||
| use status::StatusCode; | ||||
| use version::HttpVersion::{Http10, Http11}; | ||||
| @@ -13,7 +14,7 @@ use version::HttpVersion::{Http10, Http11}; | ||||
| const MAX_HEADERS: usize = 100; | ||||
| const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific | ||||
|  | ||||
| pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: &[u8]) -> ParseResult<I> { | ||||
| pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: &MemBuf) -> ParseResult<I> { | ||||
|     if buf.len() == 0 { | ||||
|         return Ok(None); | ||||
|     } | ||||
| @@ -25,23 +26,29 @@ impl Http1Transaction for ServerTransaction { | ||||
|     type Incoming = RequestLine; | ||||
|     type Outgoing = StatusCode; | ||||
|  | ||||
|     fn parse(buf: &[u8]) -> ParseResult<RequestLine> { | ||||
|     fn parse(buf: &MemBuf) -> ParseResult<RequestLine> { | ||||
|         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; | ||||
|         trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); | ||||
|         let mut req = httparse::Request::new(&mut headers); | ||||
|         Ok(match try!(req.parse(buf)) { | ||||
|         Ok(match try!(req.parse(buf.bytes())) { | ||||
|             httparse::Status::Complete(len) => { | ||||
|                 trace!("Request.parse Complete({})", len); | ||||
|                 let mut headers = Headers::with_capacity(req.headers.len()); | ||||
|                 let slice = buf.slice(len); | ||||
|                 headers.extend(HeadersAsMemSliceIter { | ||||
|                     headers: req.headers.iter(), | ||||
|                     slice: slice, | ||||
|                 }); | ||||
|                 Some((MessageHead { | ||||
|                     version: if req.version.unwrap() == 1 { Http11 } else { Http10 }, | ||||
|                     subject: RequestLine( | ||||
|                         try!(req.method.unwrap().parse()), | ||||
|                         try!(req.path.unwrap().parse()) | ||||
|                     ), | ||||
|                     headers: try!(Headers::from_raw(req.headers)) | ||||
|                     headers: headers, | ||||
|                 }, len)) | ||||
|             }, | ||||
|             httparse::Status::Partial => None | ||||
|             } | ||||
|             httparse::Status::Partial => None, | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| @@ -112,11 +119,11 @@ impl Http1Transaction for ClientTransaction { | ||||
|     type Incoming = RawStatus; | ||||
|     type Outgoing = RequestLine; | ||||
|  | ||||
|     fn parse(buf: &[u8]) -> ParseResult<RawStatus> { | ||||
|     fn parse(buf: &MemBuf) -> ParseResult<RawStatus> { | ||||
|         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; | ||||
|         trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); | ||||
|         let mut res = httparse::Response::new(&mut headers); | ||||
|         Ok(match try!(res.parse(buf)) { | ||||
|         Ok(match try!(res.parse(buf.bytes())) { | ||||
|             httparse::Status::Complete(len) => { | ||||
|                 trace!("Response.try_parse Complete({})", len); | ||||
|                 let code = res.code.unwrap(); | ||||
| @@ -124,10 +131,16 @@ impl Http1Transaction for ClientTransaction { | ||||
|                     Some(reason) if reason == res.reason.unwrap() => Cow::Borrowed(reason), | ||||
|                     _ => Cow::Owned(res.reason.unwrap().to_owned()) | ||||
|                 }; | ||||
|                 let mut headers = Headers::with_capacity(res.headers.len()); | ||||
|                 let slice = buf.slice(len); | ||||
|                 headers.extend(HeadersAsMemSliceIter { | ||||
|                     headers: res.headers.iter(), | ||||
|                     slice: slice, | ||||
|                 }); | ||||
|                 Some((MessageHead { | ||||
|                     version: if res.version.unwrap() == 1 { Http11 } else { Http10 }, | ||||
|                     subject: RawStatus(code, reason), | ||||
|                     headers: try!(Headers::from_raw(res.headers)) | ||||
|                     headers: headers, | ||||
|                 }, len)) | ||||
|             }, | ||||
|             httparse::Status::Partial => None | ||||
| @@ -216,6 +229,22 @@ impl Http1Transaction for ClientTransaction { | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct HeadersAsMemSliceIter<'a> { | ||||
|     headers: ::std::slice::Iter<'a, httparse::Header<'a>>, | ||||
|     slice: MemSlice, | ||||
| } | ||||
|  | ||||
| impl<'a> Iterator for HeadersAsMemSliceIter<'a> { | ||||
|     type Item = (&'a str, MemSlice); | ||||
|     fn next(&mut self) -> Option<Self::Item> { | ||||
|         self.headers.next().map(|header| { | ||||
|             let value_start = header.value.as_ptr() as usize - self.slice.as_ref().as_ptr() as usize; | ||||
|             let value_end = value_start + header.value.len(); | ||||
|             (header.name, self.slice.slice(value_start..value_end)) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct FastWrite<'a>(&'a mut Vec<u8>); | ||||
|  | ||||
| impl<'a> fmt::Write for FastWrite<'a> { | ||||
| @@ -244,22 +273,23 @@ fn extend(dst: &mut Vec<u8>, data: &[u8]) { | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use http; | ||||
|     use http::buf::MemBuf; | ||||
|     use super::{parse}; | ||||
|  | ||||
|     #[test] | ||||
|     fn test_parse_request() { | ||||
|         let raw = b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n"; | ||||
|         parse::<http::ServerTransaction, _>(raw).unwrap(); | ||||
|         let raw = MemBuf::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec()); | ||||
|         parse::<http::ServerTransaction, _>(&raw).unwrap(); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_parse_raw_status() { | ||||
|         let raw = b"HTTP/1.1 200 OK\r\n\r\n"; | ||||
|         let (res, _) = parse::<http::ClientTransaction, _>(raw).unwrap().unwrap(); | ||||
|         let raw = MemBuf::from(b"HTTP/1.1 200 OK\r\n\r\n".to_vec()); | ||||
|         let (res, _) = parse::<http::ClientTransaction, _>(&raw).unwrap().unwrap(); | ||||
|         assert_eq!(res.subject.1, "OK"); | ||||
|  | ||||
|         let raw = b"HTTP/1.1 200 Howdy\r\n\r\n"; | ||||
|         let (res, _) = parse::<http::ClientTransaction, _>(raw).unwrap().unwrap(); | ||||
|         let raw = MemBuf::from(b"HTTP/1.1 200 Howdy\r\n\r\n".to_vec()); | ||||
|         let (res, _) = parse::<http::ClientTransaction, _>(&raw).unwrap().unwrap(); | ||||
|         assert_eq!(res.subject.1, "Howdy"); | ||||
|     } | ||||
|  | ||||
| @@ -269,9 +299,26 @@ mod tests { | ||||
|     #[cfg(feature = "nightly")] | ||||
|     #[bench] | ||||
|     fn bench_parse_incoming(b: &mut Bencher) { | ||||
|         let raw = b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n"; | ||||
|         let mut raw = MemBuf::from(b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\ | ||||
|                                   I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\ | ||||
|                                   _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\ | ||||
|                                   foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \ | ||||
|                                   hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \ | ||||
|                                   utf8\r\nAccept-Encoding: *\r\nAccess-Control-Allow-\ | ||||
|                                   Credentials: None\r\nAccess-Control-Allow-Origin: None\r\n\ | ||||
|                                   Access-Control-Allow-Methods: None\r\nAccess-Control-Allow-\ | ||||
|                                   Headers: None\r\nContent-Encoding: utf8\r\nContent-Security-\ | ||||
|                                   Policy: None\r\nContent-Type: text/html\r\nOrigin: hyper\ | ||||
|                                   \r\nSec-Websocket-Extensions: It looks super important!\r\n\ | ||||
|                                   Sec-Websocket-Origin: hyper\r\nSec-Websocket-Version: 4.3\r\ | ||||
|                                   \nStrict-Transport-Security: None\r\nUser-Agent: hyper\r\n\ | ||||
|                                   X-Content-Duration: None\r\nX-Content-Security-Policy: None\ | ||||
|                                   \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \ | ||||
|                                   Something important obviously\r\nX-Requested-With: Nothing\ | ||||
|                                   \r\n\r\n".to_vec()); | ||||
|         b.iter(|| { | ||||
|             parse::<http::ServerTransaction, _>(raw).unwrap() | ||||
|             parse::<http::ServerTransaction, _>(&raw).unwrap(); | ||||
|             raw.restart(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -70,11 +70,11 @@ impl<T: Io> Buffered<T> { | ||||
|                 _ => return Err(e.into()) | ||||
|             } | ||||
|         } | ||||
|         match try!(parse::<S, _>(self.read_buf.bytes())) { | ||||
|             Some((head, len)) => { | ||||
|                 trace!("parsed {} bytes out of {}", len, self.read_buf.len()); | ||||
|                 self.read_buf.slice(len); | ||||
|                 Ok(Some(head)) | ||||
|         match try!(parse::<S, _>(&self.read_buf)) { | ||||
|             Some(head) => { | ||||
|                 //trace!("parsed {} bytes out of {}", len, self.read_buf.len()); | ||||
|                 //self.read_buf.slice(len); | ||||
|                 Ok(Some(head.0)) | ||||
|             }, | ||||
|             None => { | ||||
|                 if self.read_buf.capacity() >= MAX_BUFFER_SIZE { | ||||
| @@ -140,7 +140,7 @@ impl<T: Write> Write for Buffered<T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &[u8]) -> ParseResult<I> { | ||||
| fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &MemBuf) -> ParseResult<I> { | ||||
|     h1::parse::<T, I>(rdr) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -13,9 +13,11 @@ use version::HttpVersion::{Http10, Http11}; | ||||
| pub use self::conn::{Conn, KeepAlive, KA}; | ||||
| pub use self::body::{Body, TokioBody}; | ||||
| pub use self::chunk::Chunk; | ||||
| use self::buf::MemBuf; | ||||
|  | ||||
| mod body; | ||||
| mod buf; | ||||
| #[doc(hidden)] | ||||
| pub mod buf; | ||||
| mod chunk; | ||||
| mod conn; | ||||
| mod io; | ||||
| @@ -123,7 +125,7 @@ pub trait Http1Transaction { | ||||
|     type Incoming; | ||||
|     type Outgoing: Default; | ||||
|     //type KeepAlive: KeepAlive; | ||||
|     fn parse(bytes: &[u8]) -> ParseResult<Self::Incoming>; | ||||
|     fn parse(bytes: &MemBuf) -> ParseResult<Self::Incoming>; | ||||
|     fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<h1::Decoder>; | ||||
|     fn encode(head: &mut MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> h1::Encoder; | ||||
|     fn should_set_length(head: &MessageHead<Self::Outgoing>) -> bool; | ||||
|   | ||||
| @@ -6,7 +6,8 @@ use tokio::io::Io; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct Buf { | ||||
|     vec: Vec<u8> | ||||
|     vec: Vec<u8>, | ||||
|     pos: usize, | ||||
| } | ||||
|  | ||||
| impl Buf { | ||||
| @@ -17,6 +18,7 @@ impl Buf { | ||||
|     pub fn wrap(vec: Vec<u8>) -> Buf { | ||||
|         Buf { | ||||
|             vec: vec, | ||||
|             pos: 0, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -48,7 +50,10 @@ impl Write for Buf { | ||||
|  | ||||
| impl Read for Buf { | ||||
|     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||||
|         (&*self.vec).read(buf) | ||||
|         (&self.vec[self.pos..]).read(buf).map(|n| { | ||||
|             self.pos += n; | ||||
|             n | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user