perf(header): improve on MemSlice usage in headers
This commit is contained in:
		| @@ -141,9 +141,7 @@ impl Header for RetryAfter { | |||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     extern crate httparse; |     use header::Header; | ||||||
|  |  | ||||||
|     use header::{Header, Headers}; |  | ||||||
|     use header::shared::HttpDate; |     use header::shared::HttpDate; | ||||||
|     use time::{Duration}; |     use time::{Duration}; | ||||||
|  |  | ||||||
| @@ -179,17 +177,15 @@ mod tests { | |||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn hyper_headers_from_raw_delay() { |     fn hyper_headers_from_raw_delay() { | ||||||
|         let headers = make_header!(b"Retry-After", b"300"); |         let retry_after = RetryAfter::parse_header(&b"300".to_vec().into()).unwrap(); | ||||||
|         let retry_after = headers.get::<RetryAfter>().unwrap(); |         assert_eq!(retry_after, RetryAfter::Delay(Duration::seconds(300))); | ||||||
|         assert_eq!(retry_after, &RetryAfter::Delay(Duration::seconds(300))); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn hyper_headers_from_raw_datetime() { |     fn hyper_headers_from_raw_datetime() { | ||||||
|         let headers = make_header!(b"Retry-After", b"Sun, 06 Nov 1994 08:49:37 GMT"); |         let retry_after = RetryAfter::parse_header(&b"Sun, 06 Nov 1994 08:49:37 GMT".to_vec().into()).unwrap(); | ||||||
|         let retry_after = headers.get::<RetryAfter>().unwrap(); |  | ||||||
|         let expected = "Sun, 06 Nov 1994 08:49:37 GMT".parse::<HttpDate>().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> { | impl<K: PartialEq, V> VecMap<K, V> { | ||||||
|     pub fn new() -> VecMap<K, V> { |     pub fn with_capacity(cap: usize) -> VecMap<K, V> { | ||||||
|         VecMap { |         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 len(&self) -> usize { self.vec.len() } | ||||||
|  |  | ||||||
|     pub fn iter(&self) -> ::std::slice::Iter<(K, V)> { |     pub fn iter(&self) -> ::std::slice::Iter<(K, V)> { | ||||||
|         self.vec.iter() |         self.vec.iter() | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -80,7 +80,6 @@ use std::borrow::{Cow, ToOwned}; | |||||||
| use std::iter::{FromIterator, IntoIterator}; | use std::iter::{FromIterator, IntoIterator}; | ||||||
| use std::{mem, fmt}; | use std::{mem, fmt}; | ||||||
|  |  | ||||||
| use httparse; |  | ||||||
| use unicase::UniCase; | use unicase::UniCase; | ||||||
|  |  | ||||||
| use self::internals::{Item, VecMap, Entry}; | use self::internals::{Item, VecMap, Entry}; | ||||||
| @@ -347,31 +346,17 @@ literals! { | |||||||
| impl Headers { | impl Headers { | ||||||
|  |  | ||||||
|     /// Creates a new, empty headers map. |     /// Creates a new, empty headers map. | ||||||
|  |     #[inline] | ||||||
|     pub fn new() -> Headers { |     pub fn new() -> Headers { | ||||||
|         Headers { |         Headers::with_capacity(0) | ||||||
|             data: VecMap::new() |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[doc(hidden)] |     /// Creates a new `Headers` struct with space reserved for `len` headers. | ||||||
|     pub fn from_raw(raw: &[httparse::Header], buf: MemSlice) -> ::Result<Headers> { |     #[inline] | ||||||
|         let mut headers = Headers::new(); |     pub fn with_capacity(len: usize) -> Headers { | ||||||
|         for header in raw { |         Headers { | ||||||
|             let name = HeaderName(UniCase(maybe_literal(header.name))); |             data: VecMap::with_capacity(len) | ||||||
|             let trim = header.value.iter().rev().take_while(|&&x| x == b' ').count(); |  | ||||||
|             let value_start = header.value.as_ptr() as usize - buf.get().as_ptr() as usize; |  | ||||||
|             let value_end = value_start + header.value.len() - trim; |  | ||||||
|  |  | ||||||
|             match headers.data.entry(name) { |  | ||||||
|                 Entry::Vacant(entry) => { |  | ||||||
|                     entry.insert(Item::new_raw(self::raw::parsed(buf.slice(value_start..value_end)))); |  | ||||||
|                 } |  | ||||||
|                 Entry::Occupied(entry) => { |  | ||||||
|                     entry.into_mut().mut_raw().push_slice(buf.slice(value_start..value_end)); |  | ||||||
|                 } |  | ||||||
|             }; |  | ||||||
|         } |         } | ||||||
|         Ok(headers) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Set a header field to the corresponding value. |     /// Set a header field to the corresponding value. | ||||||
| @@ -587,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 { | impl<'a> FromIterator<HeaderView<'a>> for Headers { | ||||||
|     fn from_iter<I: IntoIterator<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(); | ||||||
| @@ -659,33 +662,22 @@ mod tests { | |||||||
|     use mime::SubLevel::Plain; |     use mime::SubLevel::Plain; | ||||||
|     use super::{Headers, Header, Raw, ContentLength, ContentType, |     use super::{Headers, Header, Raw, ContentLength, ContentType, | ||||||
|                 Accept, Host, qitem}; |                 Accept, Host, qitem}; | ||||||
|     use httparse; |  | ||||||
|  |  | ||||||
|     #[cfg(feature = "nightly")] |     #[cfg(feature = "nightly")] | ||||||
|     use test::Bencher; |     use test::Bencher; | ||||||
|  |  | ||||||
|     macro_rules! raw { |     macro_rules! make_header { | ||||||
|         ($($line:expr),*) => ({ |         ($name:expr, $value:expr) => ({ | ||||||
|             [$({ |             let mut headers = Headers::new(); | ||||||
|                 // Slice.position_elem was unstable |             headers.set_raw(String::from_utf8($name.to_vec()).unwrap(), $value.to_vec()); | ||||||
|                 fn index_of(slice: &MemSlice, byte: u8) -> Option<usize> { |             headers | ||||||
|                     for (index, &b) in slice.as_ref().iter().enumerate() { |         }); | ||||||
|                         if b == byte { |         ($text:expr) => ({ | ||||||
|                             return Some(index); |             let bytes = $text; | ||||||
|                         } |             let colon = bytes.iter().position(|&x| x == b':').unwrap(); | ||||||
|                     } |             make_header!(&bytes[..colon], &bytes[colon + 2..]) | ||||||
|                     None |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 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..] |  | ||||||
|                 } |  | ||||||
|             }),*] |  | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_from_raw() { |     fn test_from_raw() { | ||||||
|         let headers = make_header!(b"Content-Length", b"10"); |         let headers = make_header!(b"Content-Length", b"10"); | ||||||
| @@ -759,7 +751,9 @@ mod tests { | |||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_different_reads() { |     fn test_different_reads() { | ||||||
|         let headers = make_header!(b"Content-Length: 10\r\nContent-Type: text/plain"); |         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 ContentLength(_) = *headers.get::<ContentLength>().unwrap(); | ||||||
|         let ContentType(_) = *headers.get::<ContentType>().unwrap(); |         let ContentType(_) = *headers.get::<ContentType>().unwrap(); | ||||||
|     } |     } | ||||||
| @@ -899,17 +893,6 @@ mod tests { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[cfg(feature = "nightly")] |  | ||||||
|     #[bench] |  | ||||||
|     fn bench_headers_from_raw(b: &mut Bencher) { |  | ||||||
|         use ::http::buf::MemSlice; |  | ||||||
|  |  | ||||||
|         let buf = MemSlice::from(b"Content-Length: 10" as &[u8]); |  | ||||||
|         let buf_clone = buf.clone(); |  | ||||||
|         let raw = raw!(buf_clone); |  | ||||||
|         b.iter(|| Headers::from_raw(&raw, buf.clone()).unwrap()) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[cfg(feature = "nightly")] |     #[cfg(feature = "nightly")] | ||||||
|     #[bench] |     #[bench] | ||||||
|     fn bench_headers_get(b: &mut Bencher) { |     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. | /// Reads a raw string into a value. | ||||||
| pub fn from_raw_str<T: str::FromStr>(raw: &[u8]) -> ::Result<T> { | 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)) |     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, |                           "" => None, | ||||||
|                           y => Some(y) |                           y => Some(y) | ||||||
|                       }) |                       }) | ||||||
|                       .filter_map(|x| x.parse().ok())) |                       .filter_map(|x| x.trim().parse().ok())) | ||||||
|     } |     } | ||||||
|     Ok(result) |     Ok(result) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -37,27 +37,17 @@ impl Raw { | |||||||
|  |  | ||||||
|     /// Append a line to this `Raw` header value. |     /// Append a line to this `Raw` header value. | ||||||
|     pub fn push(&mut self, val: &[u8]) { |     pub fn push(&mut self, val: &[u8]) { | ||||||
|         let lines = ::std::mem::replace(&mut self.0, Lines::Many(Vec::new())); |         self.push_line(maybe_literal(val.into())); | ||||||
|         match lines { |  | ||||||
|             Lines::One(line) => { |  | ||||||
|                 self.0 = Lines::Many(vec![line, maybe_literal(val.into())]); |  | ||||||
|             } |  | ||||||
|             Lines::Many(mut lines) => { |  | ||||||
|                 lines.push(maybe_literal(val.into())); |  | ||||||
|                 self.0 = Lines::Many(lines); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[doc(hidden)] |     fn push_line(&mut self, line: Line) { | ||||||
|     pub fn push_slice(&mut self, val: MemSlice) { |  | ||||||
|         let lines = ::std::mem::replace(&mut self.0, Lines::Many(Vec::new())); |         let lines = ::std::mem::replace(&mut self.0, Lines::Many(Vec::new())); | ||||||
|         match lines { |         match lines { | ||||||
|             Lines::One(line) => { |             Lines::One(one) => { | ||||||
|                 self.0 = Lines::Many(vec![line, Line::Shared(val)]); |                 self.0 = Lines::Many(vec![one, line]); | ||||||
|             } |             } | ||||||
|             Lines::Many(mut lines) => { |             Lines::Many(mut lines) => { | ||||||
|                 lines.push(Line::Shared(val)); |                 lines.push(line); | ||||||
|                 self.0 = Lines::Many(lines); |                 self.0 = Lines::Many(lines); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -190,6 +180,10 @@ pub fn parsed(val: MemSlice) -> Raw { | |||||||
|     Raw(Lines::One(From::from(val))) |     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 { | impl fmt::Debug for Raw { | ||||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         match self.0 { |         match self.0 { | ||||||
|   | |||||||
| @@ -1,14 +1,14 @@ | |||||||
| use std::borrow::Cow; | use std::borrow::Cow; | ||||||
| use std::cell::UnsafeCell; | use std::cell::{Cell, UnsafeCell}; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use std::io::{self, Read}; | 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::ptr; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
|  |  | ||||||
| pub struct MemBuf { | pub struct MemBuf { | ||||||
|     buf: Arc<UnsafeCell<Vec<u8>>>, |     buf: Arc<UnsafeCell<Vec<u8>>>, | ||||||
|     start: usize, |     start: Cell<usize>, | ||||||
|     end: usize, |     end: usize, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -20,13 +20,13 @@ impl MemBuf { | |||||||
|     pub fn with_capacity(cap: usize) -> MemBuf { |     pub fn with_capacity(cap: usize) -> MemBuf { | ||||||
|         MemBuf { |         MemBuf { | ||||||
|             buf: Arc::new(UnsafeCell::new(vec![0; cap])), |             buf: Arc::new(UnsafeCell::new(vec![0; cap])), | ||||||
|             start: 0, |             start: Cell::new(0), | ||||||
|             end: 0, |             end: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn bytes(&self) -> &[u8] { |     pub fn bytes(&self) -> &[u8] { | ||||||
|         &self.buf()[self.start..self.end] |         &self.buf()[self.start.get()..self.end] | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn is_empty(&self) -> bool { |     pub fn is_empty(&self) -> bool { | ||||||
| @@ -34,7 +34,7 @@ impl MemBuf { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn len(&self) -> usize { |     pub fn len(&self) -> usize { | ||||||
|         self.end - self.start |         self.end - self.start.get() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn capacity(&self) -> usize { |     pub fn capacity(&self) -> usize { | ||||||
| @@ -42,20 +42,21 @@ impl MemBuf { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn read_from<R: Read>(&mut self, io: &mut R) -> io::Result<usize> { |     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..])); |         let n = try!(io.read(&mut self.buf_mut()[start..])); | ||||||
|         self.end += n; |         self.end += n; | ||||||
|         Ok(n) |         Ok(n) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn slice(&mut self, len: usize) -> MemSlice { |     pub fn slice(&self, len: usize) -> MemSlice { | ||||||
|         assert!(self.end - self.start >= len); |         assert!(self.end - self.start.get() >= len); | ||||||
|         let start = self.start; |         let start = self.start.get(); | ||||||
|         self.start += len; |         let end = start + len; | ||||||
|  |         self.start.set(end); | ||||||
|         MemSlice { |         MemSlice { | ||||||
|             buf: self.buf.clone(), |             buf: self.buf.clone(), | ||||||
|             start: start, |             start: start, | ||||||
|             end: self.start, |             end: end, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -68,18 +69,18 @@ impl MemBuf { | |||||||
|         } |         } | ||||||
|         let is_unique = Arc::get_mut(&mut self.buf).is_some(); |         let is_unique = Arc::get_mut(&mut self.buf).is_some(); | ||||||
|         trace!("MemBuf::reserve {} access", if is_unique { "unique" } else { "shared" }); |         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 |             // we have unique access, we can mutate this vector | ||||||
|             trace!("MemBuf::reserve unique access, shifting"); |             trace!("MemBuf::reserve unique access, shifting"); | ||||||
|             unsafe { |             unsafe { | ||||||
|                 let mut buf = &mut *self.buf.get(); |                 let mut buf = &mut *self.buf.get(); | ||||||
|                 let len = self.len(); |                 let len = self.len(); | ||||||
|                 ptr::copy( |                 ptr::copy( | ||||||
|                     buf.as_ptr().offset(self.start as isize), |                     buf.as_ptr().offset(self.start.get() as isize), | ||||||
|                     buf.as_mut_ptr(), |                     buf.as_mut_ptr(), | ||||||
|                     len |                     len | ||||||
|                 ); |                 ); | ||||||
|                 self.start = 0; |                 self.start.set(0); | ||||||
|                 self.end = len; |                 self.end = len; | ||||||
|             } |             } | ||||||
|         } else if is_unique { |         } else if is_unique { | ||||||
| @@ -110,7 +111,7 @@ impl MemBuf { | |||||||
|         match Arc::get_mut(&mut self.buf) { |         match Arc::get_mut(&mut self.buf) { | ||||||
|             Some(_) => { |             Some(_) => { | ||||||
|                 trace!("MemBuf::reset was unique, re-using"); |                 trace!("MemBuf::reset was unique, re-using"); | ||||||
|                 self.start = 0; |                 self.start.set(0); | ||||||
|                 self.end = 0; |                 self.end = 0; | ||||||
|             }, |             }, | ||||||
|             None => { |             None => { | ||||||
| @@ -120,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] { |     fn buf_mut(&mut self) -> &mut [u8] { | ||||||
|         // The contract here is that we NEVER have a MemSlice that exists |         // The contract here is that we NEVER have a MemSlice that exists | ||||||
|         // with slice.end > self.start. |         // with slice.end > self.start. | ||||||
|         // In other words, we should *ALWAYS* be the only instance that can |         // In other words, we should *ALWAYS* be the only instance that can | ||||||
|         // look at the bytes on the right side of self.start. |         // look at the bytes on the right side of self.start. | ||||||
|         unsafe { |         unsafe { | ||||||
|             &mut (*self.buf.get())[self.start..] |             &mut (*self.buf.get())[self.start.get()..] | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -170,9 +177,9 @@ fn test_grow_zerofill() { | |||||||
| impl fmt::Debug for MemBuf { | impl fmt::Debug for MemBuf { | ||||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         f.debug_struct("MemBuf") |         f.debug_struct("MemBuf") | ||||||
|             .field("start", &self.start) |             .field("start", &self.start.get()) | ||||||
|             .field("end", &self.end) |             .field("end", &self.end) | ||||||
|             .field("buf", &&self.buf()[self.start..self.end]) |             .field("buf", &&self.buf()[self.start.get()..self.end]) | ||||||
|             .finish() |             .finish() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -183,7 +190,7 @@ impl From<Vec<u8>> for MemBuf { | |||||||
|         vec.shrink_to_fit(); |         vec.shrink_to_fit(); | ||||||
|         MemBuf { |         MemBuf { | ||||||
|             buf: Arc::new(UnsafeCell::new(vec)), |             buf: Arc::new(UnsafeCell::new(vec)), | ||||||
|             start: 0, |             start: Cell::new(0), | ||||||
|             end: end, |             end: end, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -196,11 +203,6 @@ pub struct MemSlice { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl MemSlice { | impl MemSlice { | ||||||
|     #[doc(hidden)] |  | ||||||
|     pub fn get(&self) -> &[u8] { |  | ||||||
|         unsafe { &(*self.buf.get())[self.start..self.end] } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn empty() -> MemSlice { |     pub fn empty() -> MemSlice { | ||||||
|         MemSlice { |         MemSlice { | ||||||
|             buf: Arc::new(UnsafeCell::new(Vec::new())), |             buf: Arc::new(UnsafeCell::new(Vec::new())), | ||||||
| @@ -209,9 +211,21 @@ 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 { |     pub fn slice<S: Slice>(&self, range: S) -> MemSlice { | ||||||
|         range.slice(self) |         range.slice(self) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn get(&self) -> &[u8] { | ||||||
|  |         unsafe { &(*self.buf.get())[self.start..self.end] } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl AsRef<[u8]> for MemSlice { | impl AsRef<[u8]> for MemSlice { | ||||||
| @@ -222,15 +236,14 @@ impl AsRef<[u8]> for MemSlice { | |||||||
|  |  | ||||||
| impl fmt::Debug for MemSlice { | impl fmt::Debug for MemSlice { | ||||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         fmt::Debug::fmt(&**self, f) |         fmt::Debug::fmt(&self.get(), f) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Deref for MemSlice { | impl Index<usize> for MemSlice { | ||||||
|     type Target = [u8]; |     type Output = u8; | ||||||
|  |     fn index(&self, i: usize) -> &u8 { | ||||||
|     fn deref(&self) -> &[u8] { |         &self.get()[i] | ||||||
|         self.get() |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -386,18 +399,18 @@ mod tests { | |||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_mem_slice_slice() { |     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 len = buf.len(); | ||||||
|         let full = buf.slice(len); |         let full = buf.slice(len); | ||||||
|  |  | ||||||
|         assert_eq!(&*full, b"Hello World"); |         assert_eq!(full.as_ref(), b"Hello World"); | ||||||
|         assert_eq!(&*full.slice(6..), b"World"); |         assert_eq!(full.slice(6..).as_ref(), b"World"); | ||||||
|         assert_eq!(&*full.slice(..5), b"Hello"); |         assert_eq!(full.slice(..5).as_ref(), b"Hello"); | ||||||
|         assert_eq!(&*full.slice(..), b"Hello World"); |         assert_eq!(full.slice(..).as_ref(), b"Hello World"); | ||||||
|         for a in 0..len { |         for a in 0..len { | ||||||
|             for b in a..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 { |         match self.0 { | ||||||
|             Inner::Owned(ref vec) => vec, |             Inner::Owned(ref vec) => vec, | ||||||
|             Inner::Referenced(ref vec) => vec, |             Inner::Referenced(ref vec) => vec, | ||||||
|             Inner::Mem(ref slice) => slice, |             Inner::Mem(ref slice) => slice.as_ref(), | ||||||
|             Inner::Static(slice) => slice, |             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] |     #[test] | ||||||
|     fn test_conn_closed_read() { |     fn test_conn_closed_read() { | ||||||
|         let io = AsyncIo::new_buf(vec![], 0); |         let io = AsyncIo::new_buf(vec![], 0); | ||||||
|   | |||||||
| @@ -88,7 +88,7 @@ impl Decoder { | |||||||
|                 } else { |                 } else { | ||||||
|                     let to_read = *remaining as usize; |                     let to_read = *remaining as usize; | ||||||
|                     let buf = try!(body.read_mem(to_read)); |                     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); |                     trace!("Length read: {}", num); | ||||||
|                     if num > *remaining { |                     if num > *remaining { | ||||||
|                         *remaining = 0; |                         *remaining = 0; | ||||||
| @@ -399,7 +399,7 @@ mod tests { | |||||||
|         let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..]; |         let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..]; | ||||||
|         let buf = Decoder::chunked().decode(&mut mock_buf).expect("decode"); |         let buf = Decoder::chunked().decode(&mut mock_buf).expect("decode"); | ||||||
|         assert_eq!(16, buf.len()); |         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); |         assert_eq!("1234567890abcdef", &result); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -411,7 +411,7 @@ mod tests { | |||||||
|         // normal read |         // normal read | ||||||
|         let buf = decoder.decode(&mut mock_buf).expect("decode"); |         let buf = decoder.decode(&mut mock_buf).expect("decode"); | ||||||
|         assert_eq!(16, buf.len()); |         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); |         assert_eq!("1234567890abcdef", &result); | ||||||
|  |  | ||||||
|         // eof read |         // eof read | ||||||
| @@ -438,7 +438,7 @@ mod tests { | |||||||
|                     if buf.is_empty() { |                     if buf.is_empty() { | ||||||
|                         break; // eof |                         break; // eof | ||||||
|                     } |                     } | ||||||
|                     outs.write(&buf).expect("write buffer"); |                     outs.write(buf.as_ref()).expect("write buffer"); | ||||||
|                 } |                 } | ||||||
|                 Err(e) => match e.kind() { |                 Err(e) => match e.kind() { | ||||||
|                     io::ErrorKind::WouldBlock => { |                     io::ErrorKind::WouldBlock => { | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ use httparse; | |||||||
| use header::{self, Headers, ContentLength, TransferEncoding}; | use header::{self, Headers, ContentLength, TransferEncoding}; | ||||||
| use http::{MessageHead, RawStatus, Http1Transaction, ParseResult, ServerTransaction, ClientTransaction, RequestLine}; | use http::{MessageHead, RawStatus, Http1Transaction, ParseResult, ServerTransaction, ClientTransaction, RequestLine}; | ||||||
| use http::h1::{Encoder, Decoder}; | use http::h1::{Encoder, Decoder}; | ||||||
| use http::buf::MemSlice; | use http::buf::{MemBuf, MemSlice}; | ||||||
| use method::Method; | use method::Method; | ||||||
| use status::StatusCode; | use status::StatusCode; | ||||||
| use version::HttpVersion::{Http10, Http11}; | use version::HttpVersion::{Http10, Http11}; | ||||||
| @@ -14,7 +14,7 @@ use version::HttpVersion::{Http10, Http11}; | |||||||
| const MAX_HEADERS: usize = 100; | const MAX_HEADERS: usize = 100; | ||||||
| const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific | const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific | ||||||
|  |  | ||||||
| pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: MemSlice) -> ParseResult<I> { | pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: &MemBuf) -> ParseResult<I> { | ||||||
|     if buf.len() == 0 { |     if buf.len() == 0 { | ||||||
|         return Ok(None); |         return Ok(None); | ||||||
|     } |     } | ||||||
| @@ -26,20 +26,26 @@ impl Http1Transaction for ServerTransaction { | |||||||
|     type Incoming = RequestLine; |     type Incoming = RequestLine; | ||||||
|     type Outgoing = StatusCode; |     type Outgoing = StatusCode; | ||||||
|  |  | ||||||
|     fn parse(buf: MemSlice) -> ParseResult<RequestLine> { |     fn parse(buf: &MemBuf) -> ParseResult<RequestLine> { | ||||||
|         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; |         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; | ||||||
|         trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); |         trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); | ||||||
|         let mut req = httparse::Request::new(&mut headers); |         let mut req = httparse::Request::new(&mut headers); | ||||||
|         Ok(match try!(req.parse(buf.clone().get())) { |         Ok(match try!(req.parse(buf.bytes())) { | ||||||
|             httparse::Status::Complete(len) => { |             httparse::Status::Complete(len) => { | ||||||
|                 trace!("Request.parse 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 { |                 Some((MessageHead { | ||||||
|                     version: if req.version.unwrap() == 1 { Http11 } else { Http10 }, |                     version: if req.version.unwrap() == 1 { Http11 } else { Http10 }, | ||||||
|                     subject: RequestLine( |                     subject: RequestLine( | ||||||
|                         try!(req.method.unwrap().parse()), |                         try!(req.method.unwrap().parse()), | ||||||
|                         try!(req.path.unwrap().parse()) |                         try!(req.path.unwrap().parse()) | ||||||
|                     ), |                     ), | ||||||
|                     headers: try!(Headers::from_raw(req.headers, buf)) |                     headers: headers, | ||||||
|                 }, len)) |                 }, len)) | ||||||
|             } |             } | ||||||
|             httparse::Status::Partial => None, |             httparse::Status::Partial => None, | ||||||
| @@ -113,11 +119,11 @@ impl Http1Transaction for ClientTransaction { | |||||||
|     type Incoming = RawStatus; |     type Incoming = RawStatus; | ||||||
|     type Outgoing = RequestLine; |     type Outgoing = RequestLine; | ||||||
|  |  | ||||||
|     fn parse(buf: MemSlice) -> ParseResult<RawStatus> { |     fn parse(buf: &MemBuf) -> ParseResult<RawStatus> { | ||||||
|         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; |         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; | ||||||
|         trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); |         trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); | ||||||
|         let mut res = httparse::Response::new(&mut headers); |         let mut res = httparse::Response::new(&mut headers); | ||||||
|         Ok(match try!(res.parse(buf.clone().get())) { |         Ok(match try!(res.parse(buf.bytes())) { | ||||||
|             httparse::Status::Complete(len) => { |             httparse::Status::Complete(len) => { | ||||||
|                 trace!("Response.try_parse Complete({})", len); |                 trace!("Response.try_parse Complete({})", len); | ||||||
|                 let code = res.code.unwrap(); |                 let code = res.code.unwrap(); | ||||||
| @@ -125,10 +131,16 @@ impl Http1Transaction for ClientTransaction { | |||||||
|                     Some(reason) if reason == res.reason.unwrap() => Cow::Borrowed(reason), |                     Some(reason) if reason == res.reason.unwrap() => Cow::Borrowed(reason), | ||||||
|                     _ => Cow::Owned(res.reason.unwrap().to_owned()) |                     _ => 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 { |                 Some((MessageHead { | ||||||
|                     version: if res.version.unwrap() == 1 { Http11 } else { Http10 }, |                     version: if res.version.unwrap() == 1 { Http11 } else { Http10 }, | ||||||
|                     subject: RawStatus(code, reason), |                     subject: RawStatus(code, reason), | ||||||
|                     headers: try!(Headers::from_raw(res.headers, buf)) |                     headers: headers, | ||||||
|                 }, len)) |                 }, len)) | ||||||
|             }, |             }, | ||||||
|             httparse::Status::Partial => None |             httparse::Status::Partial => None | ||||||
| @@ -217,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>); | struct FastWrite<'a>(&'a mut Vec<u8>); | ||||||
|  |  | ||||||
| impl<'a> fmt::Write for FastWrite<'a> { | impl<'a> fmt::Write for FastWrite<'a> { | ||||||
| @@ -245,23 +273,23 @@ fn extend(dst: &mut Vec<u8>, data: &[u8]) { | |||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use http; |     use http; | ||||||
|     use http::buf::MemSlice; |     use http::buf::MemBuf; | ||||||
|     use super::{parse}; |     use super::{parse}; | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_parse_request() { |     fn test_parse_request() { | ||||||
|         let raw = MemSlice::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n" as &[u8]); |         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(); |         parse::<http::ServerTransaction, _>(&raw).unwrap(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_parse_raw_status() { |     fn test_parse_raw_status() { | ||||||
|         let raw = MemSlice::from(b"HTTP/1.1 200 OK\r\n\r\n" as &[u8]); |         let raw = MemBuf::from(b"HTTP/1.1 200 OK\r\n\r\n".to_vec()); | ||||||
|         let (res, _) = parse::<http::ClientTransaction, _>(raw).unwrap().unwrap(); |         let (res, _) = parse::<http::ClientTransaction, _>(&raw).unwrap().unwrap(); | ||||||
|         assert_eq!(res.subject.1, "OK"); |         assert_eq!(res.subject.1, "OK"); | ||||||
|  |  | ||||||
|         let raw = MemSlice::from(b"HTTP/1.1 200 Howdy\r\n\r\n" as &[u8]); |         let raw = MemBuf::from(b"HTTP/1.1 200 Howdy\r\n\r\n".to_vec()); | ||||||
|         let (res, _) = parse::<http::ClientTransaction, _>(raw).unwrap().unwrap(); |         let (res, _) = parse::<http::ClientTransaction, _>(&raw).unwrap().unwrap(); | ||||||
|         assert_eq!(res.subject.1, "Howdy"); |         assert_eq!(res.subject.1, "Howdy"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -271,7 +299,7 @@ mod tests { | |||||||
|     #[cfg(feature = "nightly")] |     #[cfg(feature = "nightly")] | ||||||
|     #[bench] |     #[bench] | ||||||
|     fn bench_parse_incoming(b: &mut Bencher) { |     fn bench_parse_incoming(b: &mut Bencher) { | ||||||
|         let raw = MemSlice::from(b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\ |         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\ |                                   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=\ |                                   _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\ | ||||||
|                                   foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \ |                                   foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \ | ||||||
| @@ -287,9 +315,10 @@ mod tests { | |||||||
|                                   X-Content-Duration: None\r\nX-Content-Security-Policy: None\ |                                   X-Content-Duration: None\r\nX-Content-Security-Policy: None\ | ||||||
|                                   \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \ |                                   \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \ | ||||||
|                                   Something important obviously\r\nX-Requested-With: Nothing\ |                                   Something important obviously\r\nX-Requested-With: Nothing\ | ||||||
|                                   \r\n\r\n" as &[u8]); |                                   \r\n\r\n".to_vec()); | ||||||
|         b.iter(|| { |         b.iter(|| { | ||||||
|             parse::<http::ServerTransaction, _>(raw.clone()).unwrap() |             parse::<http::ServerTransaction, _>(&raw).unwrap(); | ||||||
|  |             raw.restart(); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -70,11 +70,11 @@ impl<T: Io> Buffered<T> { | |||||||
|                 _ => return Err(e.into()) |                 _ => return Err(e.into()) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         match try!(parse::<S, _>(MemSlice::from(self.read_buf.bytes()))) { |         match try!(parse::<S, _>(&self.read_buf)) { | ||||||
|             Some((head, len)) => { |             Some(head) => { | ||||||
|                 trace!("parsed {} bytes out of {}", len, self.read_buf.len()); |                 //trace!("parsed {} bytes out of {}", len, self.read_buf.len()); | ||||||
|                 self.read_buf.slice(len); |                 //self.read_buf.slice(len); | ||||||
|                 Ok(Some(head)) |                 Ok(Some(head.0)) | ||||||
|             }, |             }, | ||||||
|             None => { |             None => { | ||||||
|                 if self.read_buf.capacity() >= MAX_BUFFER_SIZE { |                 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: MemSlice) -> ParseResult<I> { | fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &MemBuf) -> ParseResult<I> { | ||||||
|     h1::parse::<T, I>(rdr) |     h1::parse::<T, I>(rdr) | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ use version::HttpVersion::{Http10, Http11}; | |||||||
| pub use self::conn::{Conn, KeepAlive, KA}; | pub use self::conn::{Conn, KeepAlive, KA}; | ||||||
| pub use self::body::{Body, TokioBody}; | pub use self::body::{Body, TokioBody}; | ||||||
| pub use self::chunk::Chunk; | pub use self::chunk::Chunk; | ||||||
| use self::buf::MemSlice; | use self::buf::MemBuf; | ||||||
|  |  | ||||||
| mod body; | mod body; | ||||||
| #[doc(hidden)] | #[doc(hidden)] | ||||||
| @@ -125,7 +125,7 @@ pub trait Http1Transaction { | |||||||
|     type Incoming; |     type Incoming; | ||||||
|     type Outgoing: Default; |     type Outgoing: Default; | ||||||
|     //type KeepAlive: KeepAlive; |     //type KeepAlive: KeepAlive; | ||||||
|     fn parse(bytes: MemSlice) -> ParseResult<Self::Incoming>; |     fn parse(bytes: &MemBuf) -> ParseResult<Self::Incoming>; | ||||||
|     fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<h1::Decoder>; |     fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<h1::Decoder>; | ||||||
|     fn encode(head: &mut MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> h1::Encoder; |     fn encode(head: &mut MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> h1::Encoder; | ||||||
|     fn should_set_length(head: &MessageHead<Self::Outgoing>) -> bool; |     fn should_set_length(head: &MessageHead<Self::Outgoing>) -> bool; | ||||||
|   | |||||||
							
								
								
									
										43
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| #![doc(html_root_url = "https://hyperium.github.io/hyper/")] | #![doc(html_root_url = "https://hyperium.github.io/hyper/")] | ||||||
| #![deny(missing_docs)] | #![deny(missing_docs)] | ||||||
| //#![deny(warnings)] | #![deny(warnings)] | ||||||
| #![deny(missing_debug_implementations)] | #![deny(missing_debug_implementations)] | ||||||
| #![cfg_attr(all(test, feature = "nightly"), feature(test))] | #![cfg_attr(all(test, feature = "nightly"), feature(test))] | ||||||
|  |  | ||||||
| @@ -55,47 +55,6 @@ macro_rules! unimplemented { | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| #[cfg(test)] |  | ||||||
| macro_rules! make_header { |  | ||||||
|     ($name:expr, $value:expr) => {{ |  | ||||||
|         use ::http::buf::MemSlice; |  | ||||||
|  |  | ||||||
|         let mut headers = [httparse::EMPTY_HEADER; 100]; |  | ||||||
|         let mut req = httparse::Request::new(&mut headers); |  | ||||||
|  |  | ||||||
|         let mut v: Vec<u8> = Vec::with_capacity($name.len() + $value.len() + 32); |  | ||||||
|         v.extend_from_slice(b"GET /404 HTTP/1.1\r\n" as &[u8]); |  | ||||||
|         v.extend_from_slice($name as &[u8]); |  | ||||||
|         v.extend_from_slice(b": " as &[u8]); |  | ||||||
|         v.extend_from_slice($value as &[u8]); |  | ||||||
|         v.extend_from_slice(b"\r\n\r\n" as &[u8]); |  | ||||||
|         let buf = MemSlice::from(v); |  | ||||||
|         match req.parse(buf.clone().get()).expect("parse failed") { |  | ||||||
|             _ => { |  | ||||||
|                 Headers::from_raw(req.headers, buf).expect("from_raw failed") |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     }}; |  | ||||||
|     ($name:expr) => {{ |  | ||||||
|         use ::http::buf::MemSlice; |  | ||||||
|  |  | ||||||
|         let mut headers = [httparse::EMPTY_HEADER; 100]; |  | ||||||
|         let mut req = httparse::Request::new(&mut headers); |  | ||||||
|  |  | ||||||
|         let mut v: Vec<u8> = Vec::with_capacity($name.len() + 25); |  | ||||||
|         v.extend_from_slice(b"GET /404 HTTP/1.1\r\n" as &[u8]); |  | ||||||
|         v.extend_from_slice($name as &[u8]); |  | ||||||
|         v.extend_from_slice(b"\r\n\r\n" as &[u8]); |  | ||||||
|         let buf = MemSlice::from(v); |  | ||||||
|         match req.parse(buf.clone().get()).expect("parse failed") { |  | ||||||
|             httparse::Status::Complete(_) => { |  | ||||||
|                 Headers::from_raw(req.headers, buf).expect("from_raw failed") |  | ||||||
|             } |  | ||||||
|             _ => panic!("got unexpected value"), |  | ||||||
|         } |  | ||||||
|     }} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod mock; | mod mock; | ||||||
| pub mod client; | pub mod client; | ||||||
|   | |||||||
| @@ -6,7 +6,8 @@ use tokio::io::Io; | |||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Buf { | pub struct Buf { | ||||||
|     vec: Vec<u8> |     vec: Vec<u8>, | ||||||
|  |     pos: usize, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Buf { | impl Buf { | ||||||
| @@ -17,6 +18,7 @@ impl Buf { | |||||||
|     pub fn wrap(vec: Vec<u8>) -> Buf { |     pub fn wrap(vec: Vec<u8>) -> Buf { | ||||||
|         Buf { |         Buf { | ||||||
|             vec: vec, |             vec: vec, | ||||||
|  |             pos: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -48,7 +50,10 @@ impl Write for Buf { | |||||||
|  |  | ||||||
| impl Read for Buf { | impl Read for Buf { | ||||||
|     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |     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