feat(http): use the bytes crate for Chunk and internally
This commit is contained in:
		| @@ -20,7 +20,8 @@ include = [ | |||||||
| ] | ] | ||||||
|  |  | ||||||
| [dependencies] | [dependencies] | ||||||
| base64 = "0.4.0" | base64 = "0.4" | ||||||
|  | bytes = "0.4" | ||||||
| futures = "0.1.7" | futures = "0.1.7" | ||||||
| futures-cpupool = "0.1" | futures-cpupool = "0.1" | ||||||
| httparse = "1.0" | httparse = "1.0" | ||||||
|   | |||||||
| @@ -933,7 +933,7 @@ mod tests { | |||||||
|     use header::Header; |     use header::Header; | ||||||
|  |  | ||||||
|     use http::{ServerTransaction, Http1Transaction}; |     use http::{ServerTransaction, Http1Transaction}; | ||||||
|     use http::buf::MemBuf; |     use bytes::BytesMut; | ||||||
|  |  | ||||||
|     use mime::Mime; |     use mime::Mime; | ||||||
|     use mime::TopLevel::Text; |     use mime::TopLevel::Text; | ||||||
| @@ -1018,7 +1018,7 @@ mod tests { | |||||||
|  |  | ||||||
|         let expected_link = Link::new(vec![first_link, second_link, third_link]); |         let expected_link = Link::new(vec![first_link, second_link, third_link]); | ||||||
|  |  | ||||||
|         let raw = MemBuf::from(b"GET /super_short_uri/and_whatever HTTP/1.1\r\nHost: \ |         let mut raw = BytesMut::from(b"GET /super_short_uri/and_whatever HTTP/1.1\r\nHost: \ | ||||||
|                                   hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \ |                                   hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \ | ||||||
|                                   utf8\r\nAccept-Encoding: *\r\nLink: </TheBook/chapter2>; \ |                                   utf8\r\nAccept-Encoding: *\r\nLink: </TheBook/chapter2>; \ | ||||||
|                                   rel=\"previous\"; title*=UTF-8'de'letztes%20Kapitel, \ |                                   rel=\"previous\"; title*=UTF-8'de'letztes%20Kapitel, \ | ||||||
| @@ -1029,7 +1029,7 @@ mod tests { | |||||||
|                                   rel=\"previous\"; rev=next; title=\"previous chapter\"\ |                                   rel=\"previous\"; rev=next; title=\"previous chapter\"\ | ||||||
|                                   \r\n\r\n".to_vec()); |                                   \r\n\r\n".to_vec()); | ||||||
|  |  | ||||||
|         let (mut res, _) = ServerTransaction::parse(&raw).unwrap().unwrap(); |         let (mut res, _) = ServerTransaction::parse(&mut raw).unwrap().unwrap(); | ||||||
|  |  | ||||||
|         let link = res.headers.remove::<Link>().unwrap(); |         let link = res.headers.remove::<Link>().unwrap(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -87,7 +87,7 @@ use self::internals::{Item, VecMap, Entry}; | |||||||
| pub use self::shared::*; | pub use self::shared::*; | ||||||
| pub use self::common::*; | pub use self::common::*; | ||||||
| pub use self::raw::Raw; | pub use self::raw::Raw; | ||||||
| use http::buf::MemSlice; | use bytes::Bytes; | ||||||
|  |  | ||||||
| mod common; | mod common; | ||||||
| mod internals; | mod internals; | ||||||
| @@ -611,8 +611,8 @@ impl<'a> Extend<HeaderView<'a>> for Headers { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> Extend<(&'a str, MemSlice)> for Headers { | impl<'a> Extend<(&'a str, Bytes)> for Headers { | ||||||
|     fn extend<I: IntoIterator<Item=(&'a str, MemSlice)>>(&mut self, iter: I) { |     fn extend<I: IntoIterator<Item=(&'a str, Bytes)>>(&mut self, iter: I) { | ||||||
|         for (name, value) in iter { |         for (name, value) in iter { | ||||||
|             let name = HeaderName(UniCase(maybe_literal(name))); |             let name = HeaderName(UniCase(maybe_literal(name))); | ||||||
|             //let trim = header.value.iter().rev().take_while(|&&x| x == b' ').count(); |             //let trim = header.value.iter().rev().take_while(|&&x| x == b' ').count(); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| use std::borrow::Cow; | use std::borrow::Cow; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use http::buf::MemSlice; | use bytes::Bytes; | ||||||
|  |  | ||||||
| /// A raw header value. | /// A raw header value. | ||||||
| #[derive(Clone, PartialEq, Eq)] | #[derive(Clone, PartialEq, Eq)] | ||||||
| @@ -72,7 +72,7 @@ enum Lines { | |||||||
| enum Line { | enum Line { | ||||||
|     Static(&'static [u8]), |     Static(&'static [u8]), | ||||||
|     Owned(Vec<u8>), |     Owned(Vec<u8>), | ||||||
|     Shared(MemSlice), |     Shared(Bytes), | ||||||
| } | } | ||||||
|  |  | ||||||
| fn eq<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: &[A], b: &[B]) -> bool { | fn eq<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: &[A], b: &[B]) -> bool { | ||||||
| @@ -152,9 +152,9 @@ impl<'a> From<&'a [u8]> for Raw { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<MemSlice> for Raw { | impl From<Bytes> for Raw { | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn from(val: MemSlice) -> Raw { |     fn from(val: Bytes) -> Raw { | ||||||
|         Raw(Lines::One(Line::Shared(val))) |         Raw(Lines::One(Line::Shared(val))) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -166,9 +166,9 @@ impl From<Vec<u8>> for Line { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<MemSlice> for Line { | impl From<Bytes> for Line { | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn from(val: MemSlice) -> Line { |     fn from(val: Bytes) -> Line { | ||||||
|         Line::Shared(val) |         Line::Shared(val) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -183,11 +183,11 @@ impl AsRef<[u8]> for Line { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub fn parsed(val: MemSlice) -> Raw { | pub fn parsed(val: Bytes) -> Raw { | ||||||
|     Raw(Lines::One(From::from(val))) |     Raw(Lines::One(From::from(val))) | ||||||
| } | } | ||||||
|  |  | ||||||
| pub fn push(raw: &mut Raw, val: MemSlice) { | pub fn push(raw: &mut Raw, val: Bytes) { | ||||||
|     raw.push_line(Line::from(val)); |     raw.push_line(Line::from(val)); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| use std::convert::From; | use bytes::Bytes; | ||||||
|  |  | ||||||
| use tokio_proto; |  | ||||||
| use http::Chunk; |  | ||||||
| use futures::{Poll, Stream}; | use futures::{Poll, Stream}; | ||||||
| use futures::sync::mpsc; | use futures::sync::mpsc; | ||||||
|  | use tokio_proto; | ||||||
|  |  | ||||||
|  | use http::Chunk; | ||||||
|  |  | ||||||
| pub type TokioBody = tokio_proto::streaming::Body<Chunk, ::Error>; | pub type TokioBody = tokio_proto::streaming::Body<Chunk, ::Error>; | ||||||
|  |  | ||||||
| @@ -58,6 +58,12 @@ impl From<Chunk> for Body { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl From<Bytes> for Body { | ||||||
|  |     fn from (bytes: Bytes) -> Body { | ||||||
|  |         Body(TokioBody::from(Chunk::from(bytes))) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl From<Vec<u8>> for Body { | impl From<Vec<u8>> for Body { | ||||||
|     fn from (vec: Vec<u8>) -> Body { |     fn from (vec: Vec<u8>) -> Body { | ||||||
|         Body(TokioBody::from(Chunk::from(vec))) |         Body(TokioBody::from(Chunk::from(vec))) | ||||||
|   | |||||||
							
								
								
									
										432
									
								
								src/http/buf.rs
									
									
									
									
									
								
							
							
						
						
									
										432
									
								
								src/http/buf.rs
									
									
									
									
									
								
							| @@ -1,432 +0,0 @@ | |||||||
| use std::borrow::Cow; |  | ||||||
| use std::cell::{Cell, UnsafeCell}; |  | ||||||
| use std::fmt; |  | ||||||
| use std::io::{self, Read}; |  | ||||||
| use std::ops::{Index, Range, RangeFrom, RangeTo, RangeFull}; |  | ||||||
| use std::ptr; |  | ||||||
| use std::str; |  | ||||||
| use std::sync::Arc; |  | ||||||
|  |  | ||||||
| pub struct MemBuf { |  | ||||||
|     buf: Arc<UnsafeCell<Vec<u8>>>, |  | ||||||
|     start: Cell<usize>, |  | ||||||
|     end: usize, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl MemBuf { |  | ||||||
|     pub fn new() -> MemBuf { |  | ||||||
|         MemBuf::with_capacity(0) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn with_capacity(cap: usize) -> MemBuf { |  | ||||||
|         MemBuf { |  | ||||||
|             buf: Arc::new(UnsafeCell::new(vec![0; cap])), |  | ||||||
|             start: Cell::new(0), |  | ||||||
|             end: 0, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn bytes(&self) -> &[u8] { |  | ||||||
|         &self.buf()[self.start.get()..self.end] |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn is_empty(&self) -> bool { |  | ||||||
|         self.len() == 0 |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn len(&self) -> usize { |  | ||||||
|         self.end - self.start.get() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn capacity(&self) -> usize { |  | ||||||
|         self.buf().len() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn read_from<R: Read>(&mut self, io: &mut R) -> io::Result<usize> { |  | ||||||
|         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(&self, len: usize) -> MemSlice { |  | ||||||
|         let start = self.start.get(); |  | ||||||
|         assert!(!(self.end - start < len)); |  | ||||||
|         let end = start + len; |  | ||||||
|         self.start.set(end); |  | ||||||
|         MemSlice { |  | ||||||
|             buf: self.buf.clone(), |  | ||||||
|             start: start, |  | ||||||
|             end: end, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn reserve(&mut self, needed: usize) { |  | ||||||
|         let orig_cap = self.capacity(); |  | ||||||
|         let remaining = orig_cap - self.end; |  | ||||||
|         if remaining >= needed { |  | ||||||
|             // all done |  | ||||||
|             return |  | ||||||
|         } |  | ||||||
|         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.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.get() as isize), |  | ||||||
|                     buf.as_mut_ptr(), |  | ||||||
|                     len |  | ||||||
|                 ); |  | ||||||
|                 self.start.set(0); |  | ||||||
|                 self.end = len; |  | ||||||
|             } |  | ||||||
|         } else if is_unique { |  | ||||||
|             // we have unique access, we can mutate this vector |  | ||||||
|             trace!("MemBuf::reserve unique access, growing"); |  | ||||||
|             unsafe { |  | ||||||
|                 let mut vec = &mut *self.buf.get(); |  | ||||||
|                 grow_zerofill(vec, needed); |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             // we need to allocate more space, but don't have unique |  | ||||||
|             // access, so we need to make a new buffer |  | ||||||
|             trace!("MemBuf::reserve shared buffer, creating new"); |  | ||||||
|             let mut new = MemBuf::with_capacity(needed); |  | ||||||
|             unsafe { |  | ||||||
|                 ptr::copy_nonoverlapping( |  | ||||||
|                     self.bytes().as_ptr(), |  | ||||||
|                     new.buf_mut().as_mut_ptr(), |  | ||||||
|                     self.len() |  | ||||||
|                 ); |  | ||||||
|             } |  | ||||||
|             new.end = self.len(); |  | ||||||
|             *self = new; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn reset(&mut self) { |  | ||||||
|         match Arc::get_mut(&mut self.buf) { |  | ||||||
|             Some(_) => { |  | ||||||
|                 trace!("MemBuf::reset was unique, re-using"); |  | ||||||
|                 self.start.set(0); |  | ||||||
|                 self.end = 0; |  | ||||||
|             }, |  | ||||||
|             None => { |  | ||||||
|                 trace!("MemBuf::reset not unique, creating new MemBuf"); |  | ||||||
|                 *self = MemBuf::with_capacity(self.buf().len()); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[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.get()..] |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn buf(&self) -> &Vec<u8> { |  | ||||||
|         unsafe { |  | ||||||
|             &*self.buf.get() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[inline] |  | ||||||
| unsafe fn grow_zerofill(buf: &mut Vec<u8>, additional: usize) { |  | ||||||
|     let orig_cap = buf.capacity(); |  | ||||||
|     buf.reserve(additional); |  | ||||||
|     let new_cap = buf.capacity(); |  | ||||||
|     let reserved = new_cap - orig_cap; |  | ||||||
|     let orig_len = buf.len(); |  | ||||||
|     zero(buf, orig_len, reserved); |  | ||||||
|     buf.set_len(orig_len + reserved); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     unsafe fn zero(buf: &mut Vec<u8>, offset: usize, len: usize) { |  | ||||||
|         assert!(buf.capacity() >= len + offset, |  | ||||||
|             "offset of {} with len of {} is bigger than capacity of {}", |  | ||||||
|             offset, len, buf.capacity()); |  | ||||||
|         ptr::write_bytes(buf.as_mut_ptr().offset(offset as isize), 0, len); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[test] |  | ||||||
| fn test_grow_zerofill() { |  | ||||||
|     for init in 0..100 { |  | ||||||
|         for reserve in (0..100).rev() { |  | ||||||
|             let mut vec = vec![0; init]; |  | ||||||
|             unsafe { grow_zerofill(&mut vec, reserve) } |  | ||||||
|             assert_eq!(vec.len(), vec.capacity()); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl fmt::Debug for MemBuf { |  | ||||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |  | ||||||
|         f.debug_struct("MemBuf") |  | ||||||
|             .field("start", &self.start.get()) |  | ||||||
|             .field("end", &self.end) |  | ||||||
|             .field("buf", &&self.buf()[self.start.get()..self.end]) |  | ||||||
|             .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl From<Vec<u8>> for MemBuf { |  | ||||||
|     fn from(mut vec: Vec<u8>) -> MemBuf { |  | ||||||
|         let end = vec.iter().find(|&&x| x == 0).map(|&x| x as usize).unwrap_or(vec.len()); |  | ||||||
|         vec.shrink_to_fit(); |  | ||||||
|         MemBuf { |  | ||||||
|             buf: Arc::new(UnsafeCell::new(vec)), |  | ||||||
|             start: Cell::new(0), |  | ||||||
|             end: end, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Debug, Clone, PartialEq, Eq)] |  | ||||||
| pub struct MemStr(MemSlice); |  | ||||||
|  |  | ||||||
| impl MemStr { |  | ||||||
|     pub unsafe fn from_utf8_unchecked(slice: MemSlice) -> MemStr { |  | ||||||
|         MemStr(slice) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn as_str(&self) -> &str { |  | ||||||
|         unsafe { str::from_utf8_unchecked(self.0.as_ref()) } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pub struct MemSlice { |  | ||||||
|     buf: Arc<UnsafeCell<Vec<u8>>>, |  | ||||||
|     start: usize, |  | ||||||
|     end: usize, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl MemSlice { |  | ||||||
|     pub fn empty() -> MemSlice { |  | ||||||
|         MemSlice { |  | ||||||
|             buf: Arc::new(UnsafeCell::new(Vec::new())), |  | ||||||
|             start: 0, |  | ||||||
|             end: 0, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     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) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn get(&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, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pub trait Slice { |  | ||||||
|     fn slice(self, subject: &MemSlice) -> MemSlice; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| impl Slice for Range<usize> { |  | ||||||
|     fn slice(self, subject: &MemSlice) -> MemSlice { |  | ||||||
|         assert!(subject.start + self.start <= subject.end); |  | ||||||
|         assert!(subject.start + self.end <= subject.end); |  | ||||||
|         MemSlice { |  | ||||||
|             buf: subject.buf.clone(), |  | ||||||
|             start: subject.start + self.start, |  | ||||||
|             end: subject.start + self.end, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl Slice for RangeFrom<usize> { |  | ||||||
|     fn slice(self, subject: &MemSlice) -> MemSlice { |  | ||||||
|         assert!(subject.start + self.start <= subject.end); |  | ||||||
|         MemSlice { |  | ||||||
|             buf: subject.buf.clone(), |  | ||||||
|             start: subject.start + self.start, |  | ||||||
|             end: subject.end, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl Slice for RangeTo<usize> { |  | ||||||
|     fn slice(self, subject: &MemSlice) -> MemSlice { |  | ||||||
|         assert!(subject.start + self.end <= subject.end); |  | ||||||
|         MemSlice { |  | ||||||
|             buf: subject.buf.clone(), |  | ||||||
|             start: subject.start, |  | ||||||
|             end: subject.start + self.end, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl Slice for RangeFull { |  | ||||||
|     fn slice(self, subject: &MemSlice) -> MemSlice { |  | ||||||
|         MemSlice { |  | ||||||
|             buf: subject.buf.clone(), |  | ||||||
|             start: subject.start, |  | ||||||
|             end: subject.end, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| unsafe impl Send for MemBuf {} |  | ||||||
| unsafe impl Send for MemSlice {} |  | ||||||
| unsafe impl Sync for MemSlice {} |  | ||||||
|  |  | ||||||
| #[cfg(test)] |  | ||||||
| impl<T: Read> ::http::io::MemRead for ::mock::AsyncIo<T> { |  | ||||||
|     fn read_mem(&mut self, len: usize) -> io::Result<MemSlice> { |  | ||||||
|         let mut v = vec![0; len]; |  | ||||||
|         let n = try!(self.read(v.as_mut_slice())); |  | ||||||
|         v.truncate(n); |  | ||||||
|         Ok(MemSlice { |  | ||||||
|             buf: Arc::new(UnsafeCell::new(v)), |  | ||||||
|             start: 0, |  | ||||||
|             end: n, |  | ||||||
|         }) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[cfg(test)] |  | ||||||
| mod tests { |  | ||||||
|     use super::{MemBuf}; |  | ||||||
|  |  | ||||||
|     #[test] |  | ||||||
|     fn test_mem_slice_slice() { |  | ||||||
|         let buf = MemBuf::from(b"Hello World".to_vec()); |  | ||||||
|  |  | ||||||
|         let len = buf.len(); |  | ||||||
|         let full = buf.slice(len); |  | ||||||
|  |  | ||||||
|         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).as_ref(), &b"Hello World"[a..b], "{}..{}", a, b); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,27 +1,25 @@ | |||||||
| use std::fmt; | use std::fmt; | ||||||
|  |  | ||||||
| use http::buf::MemSlice; | use bytes::Bytes; | ||||||
|  |  | ||||||
| /// A piece of a message body. | /// A piece of a message body. | ||||||
| pub struct Chunk(Inner); | pub struct Chunk(Inner); | ||||||
|  |  | ||||||
| enum Inner { | enum Inner { | ||||||
|     Owned(Vec<u8>), |     Shared(Bytes), | ||||||
|     Mem(MemSlice), |  | ||||||
|     Static(&'static [u8]), |  | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<Vec<u8>> for Chunk { | impl From<Vec<u8>> for Chunk { | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn from(v: Vec<u8>) -> Chunk { |     fn from(v: Vec<u8>) -> Chunk { | ||||||
|         Chunk(Inner::Owned(v)) |         Chunk::from(Bytes::from(v)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<&'static [u8]> for Chunk { | impl From<&'static [u8]> for Chunk { | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn from(slice: &'static [u8]) -> Chunk { |     fn from(slice: &'static [u8]) -> Chunk { | ||||||
|         Chunk(Inner::Static(slice)) |         Chunk::from(Bytes::from_static(slice)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -39,9 +37,9 @@ impl From<&'static str> for Chunk { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<MemSlice> for Chunk { | impl From<Bytes> for Chunk { | ||||||
|     fn from(mem: MemSlice) -> Chunk { |     fn from(mem: Bytes) -> Chunk { | ||||||
|         Chunk(Inner::Mem(mem)) |         Chunk(Inner::Shared(mem)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -58,9 +56,7 @@ impl AsRef<[u8]> for Chunk { | |||||||
|     #[inline] |     #[inline] | ||||||
|     fn as_ref(&self) -> &[u8] { |     fn as_ref(&self) -> &[u8] { | ||||||
|         match self.0 { |         match self.0 { | ||||||
|             Inner::Owned(ref vec) => vec, |             Inner::Shared(ref slice) => slice, | ||||||
|             Inner::Mem(ref slice) => slice.as_ref(), |  | ||||||
|             Inner::Static(slice) => slice, |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| use std::usize; | use std::usize; | ||||||
| use std::io; | use std::io; | ||||||
|  |  | ||||||
| use http::buf::MemSlice; | use bytes::Bytes; | ||||||
| use http::io::MemRead; | use http::io::MemRead; | ||||||
|  |  | ||||||
| use self::Kind::{Length, Chunked, Eof}; | use self::Kind::{Length, Chunked, Eof}; | ||||||
| @@ -79,12 +79,12 @@ impl Decoder { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl Decoder { | impl Decoder { | ||||||
|     pub fn decode<R: MemRead>(&mut self, body: &mut R) -> io::Result<MemSlice> { |     pub fn decode<R: MemRead>(&mut self, body: &mut R) -> io::Result<Bytes> { | ||||||
|         match self.kind { |         match self.kind { | ||||||
|             Length(ref mut remaining) => { |             Length(ref mut remaining) => { | ||||||
|                 trace!("Sized read, remaining={:?}", remaining); |                 trace!("Sized read, remaining={:?}", remaining); | ||||||
|                 if *remaining == 0 { |                 if *remaining == 0 { | ||||||
|                     Ok(MemSlice::empty()) |                     Ok(Bytes::new()) | ||||||
|                 } 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)); | ||||||
| @@ -107,7 +107,7 @@ impl Decoder { | |||||||
|                     *state = try!(state.step(body, size, &mut buf)); |                     *state = try!(state.step(body, size, &mut buf)); | ||||||
|                     if *state == ChunkedState::End { |                     if *state == ChunkedState::End { | ||||||
|                         trace!("end of chunked"); |                         trace!("end of chunked"); | ||||||
|                         return Ok(MemSlice::empty()); |                         return Ok(Bytes::new()); | ||||||
|                     } |                     } | ||||||
|                     if let Some(buf) = buf { |                     if let Some(buf) = buf { | ||||||
|                         return Ok(buf); |                         return Ok(buf); | ||||||
| @@ -116,7 +116,7 @@ impl Decoder { | |||||||
|             } |             } | ||||||
|             Eof(ref mut is_eof) => { |             Eof(ref mut is_eof) => { | ||||||
|                 if *is_eof { |                 if *is_eof { | ||||||
|                     Ok(MemSlice::empty()) |                     Ok(Bytes::new()) | ||||||
|                 } else { |                 } else { | ||||||
|                     // 8192 chosen because its about 2 packets, there probably |                     // 8192 chosen because its about 2 packets, there probably | ||||||
|                     // won't be that much available, so don't have MemReaders |                     // won't be that much available, so don't have MemReaders | ||||||
| @@ -150,7 +150,7 @@ impl ChunkedState { | |||||||
|     fn step<R: MemRead>(&self, |     fn step<R: MemRead>(&self, | ||||||
|                         body: &mut R, |                         body: &mut R, | ||||||
|                         size: &mut u64, |                         size: &mut u64, | ||||||
|                         buf: &mut Option<MemSlice>) |                         buf: &mut Option<Bytes>) | ||||||
|                         -> io::Result<ChunkedState> { |                         -> io::Result<ChunkedState> { | ||||||
|         use self::ChunkedState::*; |         use self::ChunkedState::*; | ||||||
|         Ok(match *self { |         Ok(match *self { | ||||||
| @@ -223,7 +223,7 @@ impl ChunkedState { | |||||||
|  |  | ||||||
|     fn read_body<R: MemRead>(rdr: &mut R, |     fn read_body<R: MemRead>(rdr: &mut R, | ||||||
|                           rem: &mut u64, |                           rem: &mut u64, | ||||||
|                           buf: &mut Option<MemSlice>) |                           buf: &mut Option<Bytes>) | ||||||
|                           -> io::Result<ChunkedState> { |                           -> io::Result<ChunkedState> { | ||||||
|         trace!("Chunked read, remaining={:?}", rem); |         trace!("Chunked read, remaining={:?}", rem); | ||||||
|  |  | ||||||
| @@ -285,18 +285,19 @@ mod tests { | |||||||
|     use super::Decoder; |     use super::Decoder; | ||||||
|     use super::ChunkedState; |     use super::ChunkedState; | ||||||
|     use http::io::MemRead; |     use http::io::MemRead; | ||||||
|     use http::buf::{MemBuf, MemSlice}; |     use bytes::{BytesMut, Bytes}; | ||||||
|     use mock::AsyncIo; |     use mock::AsyncIo; | ||||||
|  |  | ||||||
|     impl<'a> MemRead for &'a [u8] { |     impl<'a> MemRead for &'a [u8] { | ||||||
|         fn read_mem(&mut self, len: usize) -> io::Result<MemSlice> { |         fn read_mem(&mut self, len: usize) -> io::Result<Bytes> { | ||||||
|             let n = ::std::cmp::min(len, self.len()); |             let n = ::std::cmp::min(len, self.len()); | ||||||
|             if n > 0 { |             if n > 0 { | ||||||
|                 let mut buf = MemBuf::with_capacity(n); |                 let (a, b) = self.split_at(n); | ||||||
|                 buf.read_from(self).unwrap(); |                 let mut buf = BytesMut::from(a); | ||||||
|                 Ok(buf.slice(n)) |                 *self = b; | ||||||
|  |                 Ok(buf.drain_to(n).freeze()) | ||||||
|             } else { |             } else { | ||||||
|                 Ok(MemSlice::empty()) |                 Ok(Bytes::new()) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -2,11 +2,11 @@ use std::borrow::Cow; | |||||||
| use std::fmt::{self, Write}; | use std::fmt::{self, Write}; | ||||||
|  |  | ||||||
| use httparse; | use httparse; | ||||||
|  | use bytes::{BytesMut, Bytes}; | ||||||
|  |  | ||||||
| use header::{self, Headers, ContentLength, TransferEncoding}; | use header::{self, Headers, ContentLength, TransferEncoding}; | ||||||
| use http::{MessageHead, RawStatus, Http1Transaction, ParseResult, ServerTransaction, ClientTransaction, RequestLine}; | use http::{ByteStr, MessageHead, RawStatus, Http1Transaction, ParseResult, ServerTransaction, ClientTransaction, RequestLine}; | ||||||
| use http::h1::{Encoder, Decoder}; | use http::h1::{Encoder, Decoder}; | ||||||
| use http::buf::{MemBuf, MemSlice, MemStr}; |  | ||||||
| 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: &MemBuf) -> ParseResult<I> { | pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: &mut BytesMut) -> ParseResult<I> { | ||||||
|     if buf.len() == 0 { |     if buf.len() == 0 { | ||||||
|         return Ok(None); |         return Ok(None); | ||||||
|     } |     } | ||||||
| @@ -26,38 +26,54 @@ impl Http1Transaction for ServerTransaction { | |||||||
|     type Incoming = RequestLine; |     type Incoming = RequestLine; | ||||||
|     type Outgoing = StatusCode; |     type Outgoing = StatusCode; | ||||||
|  |  | ||||||
|     fn parse(buf: &MemBuf) -> ParseResult<RequestLine> { |     fn parse(buf: &mut BytesMut) -> ParseResult<RequestLine> { | ||||||
|         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; |         let mut headers_indices = [HeaderIndices { | ||||||
|         trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); |             name: (0, 0), | ||||||
|         let mut req = httparse::Request::new(&mut headers); |             value: (0, 0) | ||||||
|         Ok(match try!(req.parse(buf.bytes())) { |         }; MAX_HEADERS]; | ||||||
|             httparse::Status::Complete(len) => { |         let (len, method, path, version, headers_len) = { | ||||||
|                 trace!("Request.parse Complete({})", len); |             let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; | ||||||
|                 let slice = buf.slice(len); |             trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); | ||||||
|                 let path = req.path.unwrap(); |             let mut req = httparse::Request::new(&mut headers); | ||||||
|                 let path_start = path.as_ptr() as usize - slice.as_ref().as_ptr() as usize; |             match try!(req.parse(&buf)) { | ||||||
|                 let path_end = path_start + path.len(); |                 httparse::Status::Complete(len) => { | ||||||
|                 let path = slice.slice(path_start..path_end); |                     trace!("httparse Complete({})", len); | ||||||
|                 // path was found to be utf8 by httparse |                     let method = try!(req.method.unwrap().parse()); | ||||||
|                 let path = unsafe { MemStr::from_utf8_unchecked(path) }; |                     let path = req.path.unwrap(); | ||||||
|                 let subject = RequestLine( |                     let bytes_ptr = buf.as_ref().as_ptr() as usize; | ||||||
|                     try!(req.method.unwrap().parse()), |                     let path_start = path.as_ptr() as usize - bytes_ptr; | ||||||
|                     try!(::uri::from_mem_str(path)), |                     let path_end = path_start + path.len(); | ||||||
|                 ); |                     let path = (path_start, path_end); | ||||||
|                 let mut headers = Headers::with_capacity(req.headers.len()); |                     let version = if req.version.unwrap() == 1 { Http11 } else { Http10 }; | ||||||
|                 headers.extend(HeadersAsMemSliceIter { |  | ||||||
|                     headers: req.headers.iter(), |  | ||||||
|                     slice: slice, |  | ||||||
|                 }); |  | ||||||
|  |  | ||||||
|                 Some((MessageHead { |                     record_header_indices(buf.as_ref(), &req.headers, &mut headers_indices); | ||||||
|                     version: if req.version.unwrap() == 1 { Http11 } else { Http10 }, |                     let headers_len = req.headers.len(); | ||||||
|                     subject: subject, |                     (len, method, path, version, headers_len) | ||||||
|                     headers: headers, |                 } | ||||||
|                 }, len)) |                 httparse::Status::Partial => return Ok(None), | ||||||
|             } |             } | ||||||
|             httparse::Status::Partial => None, |         }; | ||||||
|         }) |  | ||||||
|  |         let mut headers = Headers::with_capacity(headers_len); | ||||||
|  |         let slice = buf.drain_to(len).freeze(); | ||||||
|  |         let path = slice.slice(path.0, path.1); | ||||||
|  |         // path was found to be utf8 by httparse | ||||||
|  |         let path = unsafe { ByteStr::from_utf8_unchecked(path) }; | ||||||
|  |         let subject = RequestLine( | ||||||
|  |             method, | ||||||
|  |             try!(::uri::from_mem_str(path)), | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         headers.extend(HeadersAsBytesIter { | ||||||
|  |             headers: headers_indices[..headers_len].iter(), | ||||||
|  |             slice: slice, | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         Ok(Some((MessageHead { | ||||||
|  |             version: version, | ||||||
|  |             subject: subject, | ||||||
|  |             headers: headers, | ||||||
|  |         }, len))) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<Decoder> { |     fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<Decoder> { | ||||||
| @@ -127,32 +143,44 @@ impl Http1Transaction for ClientTransaction { | |||||||
|     type Incoming = RawStatus; |     type Incoming = RawStatus; | ||||||
|     type Outgoing = RequestLine; |     type Outgoing = RequestLine; | ||||||
|  |  | ||||||
|     fn parse(buf: &MemBuf) -> ParseResult<RawStatus> { |     fn parse(buf: &mut BytesMut) -> ParseResult<RawStatus> { | ||||||
|         let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; |         let mut headers_indices = [HeaderIndices { | ||||||
|         trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); |             name: (0, 0), | ||||||
|         let mut res = httparse::Response::new(&mut headers); |             value: (0, 0) | ||||||
|         Ok(match try!(res.parse(buf.bytes())) { |         }; MAX_HEADERS]; | ||||||
|             httparse::Status::Complete(len) => { |         let (len, code, reason, version, headers_len) = { | ||||||
|                 trace!("Response.try_parse Complete({})", len); |             let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS]; | ||||||
|                 let code = res.code.unwrap(); |             trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len()); | ||||||
|                 let reason = match StatusCode::from_u16(code).canonical_reason() { |             let mut res = httparse::Response::new(&mut headers); | ||||||
|                     Some(reason) if reason == res.reason.unwrap() => Cow::Borrowed(reason), |             let bytes = buf.as_ref(); | ||||||
|                     _ => Cow::Owned(res.reason.unwrap().to_owned()) |             match try!(res.parse(bytes)) { | ||||||
|                 }; |                 httparse::Status::Complete(len) => { | ||||||
|                 let mut headers = Headers::with_capacity(res.headers.len()); |                     trace!("Response.try_parse Complete({})", len); | ||||||
|                 let slice = buf.slice(len); |                     let code = res.code.unwrap(); | ||||||
|                 headers.extend(HeadersAsMemSliceIter { |                     let reason = match StatusCode::from_u16(code).canonical_reason() { | ||||||
|                     headers: res.headers.iter(), |                         Some(reason) if reason == res.reason.unwrap() => Cow::Borrowed(reason), | ||||||
|                     slice: slice, |                         _ => Cow::Owned(res.reason.unwrap().to_owned()) | ||||||
|                 }); |                     }; | ||||||
|                 Some((MessageHead { |                     let version = if res.version.unwrap() == 1 { Http11 } else { Http10 }; | ||||||
|                     version: if res.version.unwrap() == 1 { Http11 } else { Http10 }, |                     record_header_indices(bytes, &res.headers, &mut headers_indices); | ||||||
|                     subject: RawStatus(code, reason), |                     let headers_len = res.headers.len(); | ||||||
|                     headers: headers, |                     (len, code, reason, version, headers_len) | ||||||
|                 }, len)) |                 }, | ||||||
|             }, |                 httparse::Status::Partial => return Ok(None), | ||||||
|             httparse::Status::Partial => None, |             } | ||||||
|         }) |         }; | ||||||
|  |  | ||||||
|  |         let mut headers = Headers::with_capacity(headers_len); | ||||||
|  |         let slice = buf.drain_to(len).freeze(); | ||||||
|  |         headers.extend(HeadersAsBytesIter { | ||||||
|  |             headers: headers_indices[..headers_len].iter(), | ||||||
|  |             slice: slice, | ||||||
|  |         }); | ||||||
|  |         Ok(Some((MessageHead { | ||||||
|  |             version: version, | ||||||
|  |             subject: RawStatus(code, reason), | ||||||
|  |             headers: headers, | ||||||
|  |         }, len))) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn decoder(inc: &MessageHead<Self::Incoming>) -> ::Result<Decoder> { |     fn decoder(inc: &MessageHead<Self::Incoming>) -> ::Result<Decoder> { | ||||||
| @@ -237,18 +265,41 @@ impl Http1Transaction for ClientTransaction { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| struct HeadersAsMemSliceIter<'a> { | #[derive(Clone, Copy)] | ||||||
|     headers: ::std::slice::Iter<'a, httparse::Header<'a>>, | struct HeaderIndices { | ||||||
|     slice: MemSlice, |     name: (usize, usize), | ||||||
|  |     value: (usize, usize), | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> Iterator for HeadersAsMemSliceIter<'a> { | fn record_header_indices(bytes: &[u8], headers: &[httparse::Header], indices: &mut [HeaderIndices]) { | ||||||
|     type Item = (&'a str, MemSlice); |     let bytes_ptr = bytes.as_ptr() as usize; | ||||||
|  |     for (header, indices) in headers.iter().zip(indices.iter_mut()) { | ||||||
|  |         let name_start = header.name.as_ptr() as usize - bytes_ptr; | ||||||
|  |         let name_end = name_start + header.name.len(); | ||||||
|  |         indices.name = (name_start, name_end); | ||||||
|  |         let value_start = header.value.as_ptr() as usize - bytes_ptr; | ||||||
|  |         let value_end = value_start + header.value.len(); | ||||||
|  |         indices.value = (value_start, value_end); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct HeadersAsBytesIter<'a> { | ||||||
|  |     headers: ::std::slice::Iter<'a, HeaderIndices>, | ||||||
|  |     slice: Bytes, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<'a> Iterator for HeadersAsBytesIter<'a> { | ||||||
|  |     type Item = (&'a str, Bytes); | ||||||
|     fn next(&mut self) -> Option<Self::Item> { |     fn next(&mut self) -> Option<Self::Item> { | ||||||
|         self.headers.next().map(|header| { |         self.headers.next().map(|header| { | ||||||
|             let value_start = header.value.as_ptr() as usize - self.slice.as_ref().as_ptr() as usize; |             let name = unsafe { | ||||||
|             let value_end = value_start + header.value.len(); |                 let bytes = ::std::slice::from_raw_parts( | ||||||
|             (header.name, self.slice.slice(value_start..value_end)) |                     self.slice.as_ref().as_ptr().offset(header.name.0 as isize), | ||||||
|  |                     header.name.1 - header.name.0 | ||||||
|  |                 ); | ||||||
|  |                 ::std::str::from_utf8_unchecked(bytes) | ||||||
|  |             }; | ||||||
|  |             (name, self.slice.slice(header.value.0, header.value.1)) | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -281,28 +332,53 @@ fn extend(dst: &mut Vec<u8>, data: &[u8]) { | |||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use http; |     use http; | ||||||
|     use http::buf::MemBuf; |     use bytes::BytesMut; | ||||||
|     use super::{parse}; |     use super::{parse}; | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_parse_request() { |     fn test_parse_request() { | ||||||
|         let raw = MemBuf::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec()); |         extern crate pretty_env_logger; | ||||||
|         parse::<http::ServerTransaction, _>(&raw).unwrap(); |         let _ = pretty_env_logger::init(); | ||||||
|  |         let mut raw = BytesMut::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec()); | ||||||
|  |         let expected_len = raw.len(); | ||||||
|  |         let (req, len) = parse::<http::ServerTransaction, _>(&mut raw).unwrap().unwrap(); | ||||||
|  |         assert_eq!(len, expected_len); | ||||||
|  |         assert_eq!(req.subject.0, ::Method::Get); | ||||||
|  |         assert_eq!(req.subject.1, "/echo".parse().unwrap()); | ||||||
|  |         assert_eq!(req.version, ::HttpVersion::Http11); | ||||||
|  |         assert_eq!(req.headers.len(), 1); | ||||||
|  |         assert_eq!(req.headers.get_raw("Host").map(|raw| &raw[0]), Some(b"hyper.rs".as_ref())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn test_parse_response() { | ||||||
|  |         extern crate pretty_env_logger; | ||||||
|  |         let _ = pretty_env_logger::init(); | ||||||
|  |         let mut raw = BytesMut::from(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".to_vec()); | ||||||
|  |         let expected_len = raw.len(); | ||||||
|  |         let (req, len) = parse::<http::ClientTransaction, _>(&mut raw).unwrap().unwrap(); | ||||||
|  |         assert_eq!(len, expected_len); | ||||||
|  |         assert_eq!(req.subject.0, 200); | ||||||
|  |         assert_eq!(req.subject.1, "OK"); | ||||||
|  |         assert_eq!(req.version, ::HttpVersion::Http11); | ||||||
|  |         assert_eq!(req.headers.len(), 1); | ||||||
|  |         assert_eq!(req.headers.get_raw("Content-Length").map(|raw| &raw[0]), Some(b"0".as_ref())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_parse_request_errors() { |     fn test_parse_request_errors() { | ||||||
|         let raw = MemBuf::from(b"GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec()); |         let mut raw = BytesMut::from(b"GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec()); | ||||||
|         parse::<http::ServerTransaction, _>(&raw).unwrap_err(); |         parse::<http::ServerTransaction, _>(&mut raw).unwrap_err(); | ||||||
|     } |     } | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_parse_raw_status() { |     fn test_parse_raw_status() { | ||||||
|         let raw = MemBuf::from(b"HTTP/1.1 200 OK\r\n\r\n".to_vec()); |         let mut raw = BytesMut::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, _>(&mut raw).unwrap().unwrap(); | ||||||
|         assert_eq!(res.subject.1, "OK"); |         assert_eq!(res.subject.1, "OK"); | ||||||
|  |  | ||||||
|         let raw = MemBuf::from(b"HTTP/1.1 200 Howdy\r\n\r\n".to_vec()); |         let mut raw = BytesMut::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, _>(&mut raw).unwrap().unwrap(); | ||||||
|         assert_eq!(res.subject.1, "Howdy"); |         assert_eq!(res.subject.1, "Howdy"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -312,26 +388,39 @@ 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 mut raw = MemBuf::from(b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\ |         let mut raw = BytesMut::from( | ||||||
|                                   I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\ |             b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\ | ||||||
|                                   _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\ |             I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\ | ||||||
|                                   foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \ |             _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\ | ||||||
|                                   hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \ |             foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \ | ||||||
|                                   utf8\r\nAccept-Encoding: *\r\nAccess-Control-Allow-\ |             hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \ | ||||||
|                                   Credentials: None\r\nAccess-Control-Allow-Origin: None\r\n\ |             utf8\r\nAccept-Encoding: *\r\nAccess-Control-Allow-\ | ||||||
|                                   Access-Control-Allow-Methods: None\r\nAccess-Control-Allow-\ |             Credentials: None\r\nAccess-Control-Allow-Origin: None\r\n\ | ||||||
|                                   Headers: None\r\nContent-Encoding: utf8\r\nContent-Security-\ |             Access-Control-Allow-Methods: None\r\nAccess-Control-Allow-\ | ||||||
|                                   Policy: None\r\nContent-Type: text/html\r\nOrigin: hyper\ |             Headers: None\r\nContent-Encoding: utf8\r\nContent-Security-\ | ||||||
|                                   \r\nSec-Websocket-Extensions: It looks super important!\r\n\ |             Policy: None\r\nContent-Type: text/html\r\nOrigin: hyper\ | ||||||
|                                   Sec-Websocket-Origin: hyper\r\nSec-Websocket-Version: 4.3\r\ |             \r\nSec-Websocket-Extensions: It looks super important!\r\n\ | ||||||
|                                   \nStrict-Transport-Security: None\r\nUser-Agent: hyper\r\n\ |             Sec-Websocket-Origin: hyper\r\nSec-Websocket-Version: 4.3\r\ | ||||||
|                                   X-Content-Duration: None\r\nX-Content-Security-Policy: None\ |             \nStrict-Transport-Security: None\r\nUser-Agent: hyper\r\n\ | ||||||
|                                   \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \ |             X-Content-Duration: None\r\nX-Content-Security-Policy: None\ | ||||||
|                                   Something important obviously\r\nX-Requested-With: Nothing\ |             \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \ | ||||||
|                                   \r\n\r\n".to_vec()); |             Something important obviously\r\nX-Requested-With: Nothing\ | ||||||
|  |             \r\n\r\n".to_vec() | ||||||
|  |         ); | ||||||
|  |         let len = raw.len(); | ||||||
|  |  | ||||||
|  |         b.bytes = len as u64; | ||||||
|         b.iter(|| { |         b.iter(|| { | ||||||
|             parse::<http::ServerTransaction, _>(&raw).unwrap(); |             parse::<http::ServerTransaction, _>(&mut raw).unwrap(); | ||||||
|             raw.restart(); |             restart(&mut raw, len); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         fn restart(b: &mut BytesMut, len: usize) { | ||||||
|  |             b.reserve(1); | ||||||
|  |             unsafe { | ||||||
|  |                 b.set_len(len); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,20 +1,20 @@ | |||||||
| use std::cmp; | use std::cmp; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use std::io::{self, Read, Write}; | use std::io::{self, Write}; | ||||||
| use std::ptr; | use std::ptr; | ||||||
|  |  | ||||||
| use futures::Async; | use futures::Async; | ||||||
| use tokio::io::Io; | use tokio::io::Io; | ||||||
|  |  | ||||||
| use http::{Http1Transaction, h1, MessageHead, ParseResult, DebugTruncate}; | use http::{Http1Transaction, h1, MessageHead, ParseResult, DebugTruncate}; | ||||||
| use http::buf::{MemBuf, MemSlice}; | use bytes::{BytesMut, Bytes}; | ||||||
|  |  | ||||||
| const INIT_BUFFER_SIZE: usize = 4096; | const INIT_BUFFER_SIZE: usize = 4096; | ||||||
| pub const MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100; | pub const MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100; | ||||||
|  |  | ||||||
| pub struct Buffered<T> { | pub struct Buffered<T> { | ||||||
|     io: T, |     io: T, | ||||||
|     read_buf: MemBuf, |     read_buf: BytesMut, | ||||||
|     write_buf: WriteBuf, |     write_buf: WriteBuf, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -31,25 +31,25 @@ impl<T: Io> Buffered<T> { | |||||||
|     pub fn new(io: T) -> Buffered<T> { |     pub fn new(io: T) -> Buffered<T> { | ||||||
|         Buffered { |         Buffered { | ||||||
|             io: io, |             io: io, | ||||||
|             read_buf: MemBuf::new(), |             read_buf: BytesMut::with_capacity(0), | ||||||
|             write_buf: WriteBuf::new(), |             write_buf: WriteBuf::new(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn read_buf(&self) -> &[u8] { |     pub fn read_buf(&self) -> &[u8] { | ||||||
|         self.read_buf.bytes() |         self.read_buf.as_ref() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn consume_leading_lines(&mut self) { |     pub fn consume_leading_lines(&mut self) { | ||||||
|         if !self.read_buf.is_empty() { |         if !self.read_buf.is_empty() { | ||||||
|             let mut i = 0; |             let mut i = 0; | ||||||
|             while i < self.read_buf.len() { |             while i < self.read_buf.len() { | ||||||
|                 match self.read_buf.bytes()[i] { |                 match self.read_buf[i] { | ||||||
|                     b'\r' | b'\n' => i += 1, |                     b'\r' | b'\n' => i += 1, | ||||||
|                     _ => break, |                     _ => break, | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             self.read_buf.slice(i); |             self.read_buf.drain_to(i); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -59,7 +59,7 @@ impl<T: Io> Buffered<T> { | |||||||
|  |  | ||||||
|     pub fn parse<S: Http1Transaction>(&mut self) -> ::Result<Option<MessageHead<S::Incoming>>> { |     pub fn parse<S: Http1Transaction>(&mut self) -> ::Result<Option<MessageHead<S::Incoming>>> { | ||||||
|         self.reserve_read_buf(); |         self.reserve_read_buf(); | ||||||
|         match self.read_buf.read_from(&mut self.io) { |         match self.read_from_io() { | ||||||
|             Ok(0) => { |             Ok(0) => { | ||||||
|                 trace!("parse eof"); |                 trace!("parse eof"); | ||||||
|                 return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "parse eof").into()); |                 return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "parse eof").into()); | ||||||
| @@ -70,7 +70,7 @@ impl<T: Io> Buffered<T> { | |||||||
|                 _ => return Err(e.into()) |                 _ => return Err(e.into()) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         match try!(parse::<S, _>(&self.read_buf)) { |         match try!(parse::<S, _>(&mut self.read_buf)) { | ||||||
|             Some(head) => { |             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); | ||||||
| @@ -87,8 +87,26 @@ impl<T: Io> Buffered<T> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn read_from_io(&mut self) -> io::Result<usize> { | ||||||
|  |         use bytes::BufMut; | ||||||
|  |         unsafe { | ||||||
|  |             let n = try!(self.io.read(self.read_buf.bytes_mut())); | ||||||
|  |             self.read_buf.advance_mut(n); | ||||||
|  |             Ok(n) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     fn reserve_read_buf(&mut self) { |     fn reserve_read_buf(&mut self) { | ||||||
|  |         use bytes::BufMut; | ||||||
|  |         if self.read_buf.remaining_mut() >= INIT_BUFFER_SIZE { | ||||||
|  |             return | ||||||
|  |         } | ||||||
|         self.read_buf.reserve(INIT_BUFFER_SIZE); |         self.read_buf.reserve(INIT_BUFFER_SIZE); | ||||||
|  |         unsafe { | ||||||
|  |             let buf = self.read_buf.bytes_mut(); | ||||||
|  |             let len = buf.len(); | ||||||
|  |             ptr::write_bytes(buf.as_mut_ptr(), 0, len); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn buffer<B: AsRef<[u8]>>(&mut self, buf: B) -> usize { |     pub fn buffer<B: AsRef<[u8]>>(&mut self, buf: B) -> usize { | ||||||
| @@ -101,7 +119,6 @@ impl<T: Io> Buffered<T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| impl<T: Write> Write for Buffered<T> { | impl<T: Write> Write for Buffered<T> { | ||||||
|     fn write(&mut self, data: &[u8]) -> io::Result<usize> { |     fn write(&mut self, data: &[u8]) -> io::Result<usize> { | ||||||
|         Ok(self.write_buf.buffer(data)) |         Ok(self.write_buf.buffer(data)) | ||||||
| @@ -122,25 +139,25 @@ impl<T: Write> Write for Buffered<T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &MemBuf) -> ParseResult<I> { | fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &mut BytesMut) -> ParseResult<I> { | ||||||
|     h1::parse::<T, I>(rdr) |     h1::parse::<T, I>(rdr) | ||||||
| } | } | ||||||
|  |  | ||||||
| pub trait MemRead { | pub trait MemRead { | ||||||
|     fn read_mem(&mut self, len: usize) -> io::Result<MemSlice>; |     fn read_mem(&mut self, len: usize) -> io::Result<Bytes>; | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: Read> MemRead for Buffered<T> { | impl<T: Io> MemRead for Buffered<T> { | ||||||
|     fn read_mem(&mut self, len: usize) -> io::Result<MemSlice> { |     fn read_mem(&mut self, len: usize) -> io::Result<Bytes> { | ||||||
|         trace!("Buffered.read_mem read_buf={}, wanted={}", self.read_buf.len(), len); |         trace!("Buffered.read_mem read_buf={}, wanted={}", self.read_buf.len(), len); | ||||||
|         if !self.read_buf.is_empty() { |         if !self.read_buf.is_empty() { | ||||||
|             let n = ::std::cmp::min(len, self.read_buf.len()); |             let n = ::std::cmp::min(len, self.read_buf.len()); | ||||||
|             trace!("Buffered.read_mem read_buf is not empty, slicing {}", n); |             trace!("Buffered.read_mem read_buf is not empty, slicing {}", n); | ||||||
|             Ok(self.read_buf.slice(n)) |             Ok(self.read_buf.drain_to(n).freeze()) | ||||||
|         } else { |         } else { | ||||||
|             self.read_buf.reset(); |             self.reserve_read_buf(); | ||||||
|             let n = try!(self.read_buf.read_from(&mut self.io)); |             let n = try!(self.read_from_io()); | ||||||
|             Ok(self.read_buf.slice(::std::cmp::min(len, n))) |             Ok(self.read_buf.drain_to(::std::cmp::min(len, n)).freeze()) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -288,6 +305,18 @@ impl WriteBuf { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | use std::io::Read; | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | impl<T: Read> MemRead for ::mock::AsyncIo<T> { | ||||||
|  |     fn read_mem(&mut self, len: usize) -> io::Result<Bytes> { | ||||||
|  |         let mut v = vec![0; len]; | ||||||
|  |         let n = try!(self.read(v.as_mut_slice())); | ||||||
|  |         Ok(BytesMut::from(&v[..n]).freeze()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| #[test] | #[test] | ||||||
| fn test_iobuf_write_empty_slice() { | fn test_iobuf_write_empty_slice() { | ||||||
|     use mock::{AsyncIo, Buf as MockBuf}; |     use mock::{AsyncIo, Buf as MockBuf}; | ||||||
|   | |||||||
| @@ -2,6 +2,8 @@ | |||||||
| use std::borrow::Cow; | use std::borrow::Cow; | ||||||
| use std::fmt; | use std::fmt; | ||||||
|  |  | ||||||
|  | use bytes::BytesMut; | ||||||
|  |  | ||||||
| use header::{Connection, ConnectionOption}; | use header::{Connection, ConnectionOption}; | ||||||
| use header::Headers; | use header::Headers; | ||||||
| use method::Method; | use method::Method; | ||||||
| @@ -13,16 +15,15 @@ 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::MemBuf; | pub use self::str::ByteStr; | ||||||
|  |  | ||||||
| mod body; | mod body; | ||||||
| #[doc(hidden)] |  | ||||||
| pub mod buf; |  | ||||||
| mod chunk; | mod chunk; | ||||||
| mod conn; | mod conn; | ||||||
| mod io; | mod io; | ||||||
| mod h1; | mod h1; | ||||||
| //mod h2; | //mod h2; | ||||||
|  | mod str; | ||||||
|  |  | ||||||
| /* | /* | ||||||
| macro_rules! nonblocking { | macro_rules! nonblocking { | ||||||
| @@ -124,8 +125,7 @@ pub enum ClientTransaction {} | |||||||
| pub trait Http1Transaction { | pub trait Http1Transaction { | ||||||
|     type Incoming; |     type Incoming; | ||||||
|     type Outgoing: Default; |     type Outgoing: Default; | ||||||
|     //type KeepAlive: KeepAlive; |     fn parse(bytes: &mut BytesMut) -> 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; | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								src/http/str.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/http/str.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | use std::str; | ||||||
|  |  | ||||||
|  | use bytes::Bytes; | ||||||
|  |  | ||||||
|  | #[derive(Debug, Clone, PartialEq, Eq)] | ||||||
|  | pub struct ByteStr(Bytes); | ||||||
|  |  | ||||||
|  | impl ByteStr { | ||||||
|  |     pub unsafe fn from_utf8_unchecked(slice: Bytes) -> ByteStr { | ||||||
|  |         ByteStr(slice) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn as_str(&self) -> &str { | ||||||
|  |         unsafe { str::from_utf8_unchecked(self.0.as_ref()) } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -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))] | ||||||
|  |  | ||||||
| @@ -14,6 +14,7 @@ | |||||||
| //! [Server](server/index.html), along with a | //! [Server](server/index.html), along with a | ||||||
| //! [typed Headers system](header/index.html). | //! [typed Headers system](header/index.html). | ||||||
|  |  | ||||||
|  | extern crate bytes; | ||||||
| #[macro_use] extern crate futures; | #[macro_use] extern crate futures; | ||||||
| extern crate futures_cpupool; | extern crate futures_cpupool; | ||||||
| extern crate httparse; | extern crate httparse; | ||||||
|   | |||||||
| @@ -2,7 +2,8 @@ use std::borrow::Cow; | |||||||
| use std::fmt::{Display, self}; | use std::fmt::{Display, self}; | ||||||
| use std::ops::Deref; | use std::ops::Deref; | ||||||
| use std::str::{self, FromStr}; | use std::str::{self, FromStr}; | ||||||
| use http::buf::MemStr; |  | ||||||
|  | use http::ByteStr; | ||||||
| use Url; | use Url; | ||||||
| use url::ParseError as UrlError; | use url::ParseError as UrlError; | ||||||
|  |  | ||||||
| @@ -279,14 +280,14 @@ impl Display for Uri { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub fn from_mem_str(s: MemStr) -> Result<Uri, Error> { | pub fn from_mem_str(s: ByteStr) -> Result<Uri, Error> { | ||||||
|     Uri::new(InternalUri::Shared(s)) |     Uri::new(InternalUri::Shared(s)) | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| enum InternalUri { | enum InternalUri { | ||||||
|     Cow(Cow<'static, str>), |     Cow(Cow<'static, str>), | ||||||
|     Shared(MemStr), |     Shared(ByteStr), | ||||||
| } | } | ||||||
|  |  | ||||||
| impl InternalUri { | impl InternalUri { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user