feat(lib): redesign API to use Futures and Tokio
There are many changes involved with this, but let's just talk about
user-facing changes.
- Creating a `Client` and `Server` now needs a Tokio `Core` event loop
to attach to.
- `Request` and `Response` both no longer implement the
`std::io::{Read,Write}` traits, but instead represent their bodies as a
`futures::Stream` of items, where each item is a `Chunk`.
- The `Client.request` method now takes a `Request`, instead of being
used as a builder, and returns a `Future` that resolves to `Response`.
- The `Handler` trait for servers is no more, and instead the Tokio
`Service` trait is used. This allows interoperability with generic
middleware.
BREAKING CHANGE: A big sweeping set of breaking changes.
			
			
This commit is contained in:
		
							
								
								
									
										97
									
								
								src/http/body.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/http/body.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| use std::convert::From; | ||||
| use std::sync::Arc; | ||||
|  | ||||
| use tokio_proto; | ||||
| use http::Chunk; | ||||
| use futures::{Poll, Stream}; | ||||
| use futures::sync::mpsc; | ||||
|  | ||||
| pub type TokioBody = tokio_proto::streaming::Body<Chunk, ::Error>; | ||||
|  | ||||
| /// A `Stream` for `Chunk`s used in requests and responses. | ||||
| #[derive(Debug)] | ||||
| pub struct Body(TokioBody); | ||||
|  | ||||
| impl Body { | ||||
|     /// Return an empty body stream | ||||
|     pub fn empty() -> Body { | ||||
|         Body(TokioBody::empty()) | ||||
|     } | ||||
|  | ||||
|     /// Return a body stream with an associated sender half | ||||
|     pub fn pair() -> (mpsc::Sender<Result<Chunk, ::Error>>, Body) { | ||||
|         let (tx, rx) = TokioBody::pair(); | ||||
|         let rx = Body(rx); | ||||
|         (tx, rx) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Stream for Body { | ||||
|     type Item = Chunk; | ||||
|     type Error = ::Error; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<Chunk>, ::Error> { | ||||
|         self.0.poll() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Body> for tokio_proto::streaming::Body<Chunk, ::Error> { | ||||
|     fn from(b: Body) -> tokio_proto::streaming::Body<Chunk, ::Error> { | ||||
|         b.0 | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<tokio_proto::streaming::Body<Chunk, ::Error>> for Body { | ||||
|     fn from(tokio_body: tokio_proto::streaming::Body<Chunk, ::Error>) -> Body { | ||||
|         Body(tokio_body) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<mpsc::Receiver<Result<Chunk, ::Error>>> for Body { | ||||
|     fn from(src: mpsc::Receiver<Result<Chunk, ::Error>>) -> Body { | ||||
|         Body(src.into()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Chunk> for Body { | ||||
|     fn from (chunk: Chunk) -> Body { | ||||
|         Body(TokioBody::from(chunk)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Vec<u8>> for Body { | ||||
|     fn from (vec: Vec<u8>) -> Body { | ||||
|         Body(TokioBody::from(Chunk::from(vec))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Arc<Vec<u8>>> for Body { | ||||
|     fn from (vec: Arc<Vec<u8>>) -> Body { | ||||
|         Body(TokioBody::from(Chunk::from(vec))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<&'static [u8]> for Body { | ||||
|     fn from (slice: &'static [u8]) -> Body { | ||||
|         Body(TokioBody::from(Chunk::from(slice))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<String> for Body { | ||||
|     fn from (s: String) -> Body { | ||||
|         Body(TokioBody::from(Chunk::from(s.into_bytes()))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<&'static str> for Body { | ||||
|     fn from (slice: &'static str) -> Body { | ||||
|         Body(TokioBody::from(Chunk::from(slice.as_bytes()))) | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn _assert_send() { | ||||
|     fn _assert<T: Send>() {} | ||||
|  | ||||
|     _assert::<Body>(); | ||||
|     _assert::<Chunk>(); | ||||
| } | ||||
| @@ -1,16 +1,16 @@ | ||||
| use std::cmp; | ||||
| use std::io::{self, Read}; | ||||
| use std::io::{self, Read, Write}; | ||||
| use std::ptr; | ||||
|  | ||||
|  | ||||
| const INIT_BUFFER_SIZE: usize = 4096; | ||||
| const MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100; | ||||
| pub const MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100; | ||||
|  | ||||
| #[derive(Debug, Default)] | ||||
| pub struct Buffer { | ||||
|     vec: Vec<u8>, | ||||
|     read_pos: usize, | ||||
|     write_pos: usize, | ||||
|     tail: usize, | ||||
|     head: usize, | ||||
| } | ||||
|  | ||||
| impl Buffer { | ||||
| @@ -24,7 +24,17 @@ impl Buffer { | ||||
|  | ||||
|     #[inline] | ||||
|     pub fn len(&self) -> usize { | ||||
|         self.read_pos - self.write_pos | ||||
|         self.tail - self.head | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     fn available(&self) -> usize { | ||||
|         self.vec.len() - self.tail | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     pub fn is_max_size(&self) -> bool { | ||||
|         self.len() >= MAX_BUFFER_SIZE | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
| @@ -34,45 +44,88 @@ impl Buffer { | ||||
|  | ||||
|     #[inline] | ||||
|     pub fn bytes(&self) -> &[u8] { | ||||
|         &self.vec[self.write_pos..self.read_pos] | ||||
|         &self.vec[self.head..self.tail] | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     pub fn consume(&mut self, pos: usize) { | ||||
|         debug_assert!(self.read_pos >= self.write_pos + pos); | ||||
|         self.write_pos += pos; | ||||
|         if self.write_pos == self.read_pos { | ||||
|             self.write_pos = 0; | ||||
|             self.read_pos = 0; | ||||
|         debug_assert!(self.tail >= self.head + pos); | ||||
|         self.head += pos; | ||||
|         if self.head == self.tail { | ||||
|             self.head = 0; | ||||
|             self.tail = 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn consume_leading_lines(&mut self) { | ||||
|         while !self.is_empty() { | ||||
|             match self.vec[self.head] { | ||||
|                 b'\r' | b'\n' => { | ||||
|                     self.consume(1); | ||||
|                 }, | ||||
|                 _ => return | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn read_from<R: Read>(&mut self, r: &mut R) -> io::Result<usize> { | ||||
|         self.maybe_reserve(); | ||||
|         let n = try!(r.read(&mut self.vec[self.read_pos..])); | ||||
|         self.read_pos += n; | ||||
|         self.maybe_reserve(1); | ||||
|         let n = try!(r.read(&mut self.vec[self.tail..])); | ||||
|         self.tail += n; | ||||
|         self.maybe_reset(); | ||||
|         Ok(n) | ||||
|     } | ||||
|  | ||||
|     pub fn write_into<W: Write>(&mut self, w: &mut W) -> io::Result<usize> { | ||||
|         if self.is_empty() { | ||||
|             Ok(0) | ||||
|         } else { | ||||
|             let n = try!(w.write(&mut self.vec[self.head..self.tail])); | ||||
|             self.head += n; | ||||
|             self.maybe_reset(); | ||||
|             Ok(n) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn write(&mut self, data: &[u8]) -> usize { | ||||
|         trace!("Buffer::write len = {:?}", data.len()); | ||||
|         self.maybe_reserve(data.len()); | ||||
|         let len = cmp::min(self.available(), data.len()); | ||||
|         assert!(self.available() >= len); | ||||
|         unsafe { | ||||
|             // in rust 1.9, we could use slice::copy_from_slice | ||||
|             ptr::copy( | ||||
|                 data.as_ptr(), | ||||
|                 self.vec.as_mut_ptr().offset(self.tail as isize), | ||||
|                 len | ||||
|             ); | ||||
|         } | ||||
|         self.tail += len; | ||||
|         len | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     fn maybe_reserve(&mut self) { | ||||
|     fn maybe_reserve(&mut self, needed: usize) { | ||||
|         let cap = self.vec.len(); | ||||
|         if cap == 0 { | ||||
|             trace!("reserving initial {}", INIT_BUFFER_SIZE); | ||||
|             self.vec = vec![0; INIT_BUFFER_SIZE]; | ||||
|         } else if self.write_pos > 0  && self.read_pos == cap { | ||||
|             let count = self.read_pos - self.write_pos; | ||||
|             // first reserve | ||||
|             let init = cmp::max(INIT_BUFFER_SIZE, needed); | ||||
|             trace!("reserving initial {}", init); | ||||
|             self.vec = vec![0; init]; | ||||
|         } else if self.head > 0  && self.tail == cap && self.head >= needed { | ||||
|             // there is space to shift over | ||||
|             let count = self.tail - self.head; | ||||
|             trace!("moving buffer bytes over by {}", count); | ||||
|             unsafe { | ||||
|                 ptr::copy( | ||||
|                     self.vec.as_ptr().offset(self.write_pos as isize), | ||||
|                     self.vec.as_ptr().offset(self.head as isize), | ||||
|                     self.vec.as_mut_ptr(), | ||||
|                     count | ||||
|                 ); | ||||
|             } | ||||
|             self.read_pos -= count; | ||||
|             self.write_pos = 0; | ||||
|         } else if self.read_pos == cap && cap < MAX_BUFFER_SIZE { | ||||
|             self.tail -= count; | ||||
|             self.head = 0; | ||||
|         } else if self.tail == cap && cap < MAX_BUFFER_SIZE { | ||||
|             self.vec.reserve(cmp::min(cap * 4, MAX_BUFFER_SIZE) - cap); | ||||
|             let new = self.vec.capacity() - cap; | ||||
|             trace!("reserved {}", new); | ||||
| @@ -80,36 +133,11 @@ impl Buffer { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn wrap<'a, 'b: 'a, R: io::Read>(&'a mut self, reader: &'b mut R) -> BufReader<'a, R> { | ||||
|         BufReader { | ||||
|             buf: self, | ||||
|             reader: reader | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct BufReader<'a, R: io::Read + 'a> { | ||||
|     buf: &'a mut Buffer, | ||||
|     reader: &'a mut R | ||||
| } | ||||
|  | ||||
| impl<'a, R: io::Read + 'a> BufReader<'a, R> { | ||||
|     pub fn get_ref(&self) -> &R { | ||||
|         self.reader | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, R: io::Read> Read for BufReader<'a, R> { | ||||
|     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||||
|         trace!("BufReader.read self={}, buf={}", self.buf.len(), buf.len()); | ||||
|         let n = try!(self.buf.bytes().read(buf)); | ||||
|         self.buf.consume(n); | ||||
|         if n == 0 { | ||||
|             self.buf.reset(); | ||||
|             self.reader.read(&mut buf[n..]) | ||||
|         } else { | ||||
|             Ok(n) | ||||
|     #[inline] | ||||
|     fn maybe_reset(&mut self) { | ||||
|         if self.tail != 0 && self.tail == self.head { | ||||
|             self.tail = 0; | ||||
|             self.head = 0; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,96 +0,0 @@ | ||||
| use std::fmt; | ||||
| use std::sync::{Arc, mpsc}; | ||||
| use std::sync::atomic::{AtomicBool, Ordering}; | ||||
| use ::rotor; | ||||
|  | ||||
| pub use std::sync::mpsc::TryRecvError; | ||||
|  | ||||
| pub fn new<T>(notify: rotor::Notifier) -> (Sender<T>, Receiver<T>) { | ||||
|     let b = Arc::new(AtomicBool::new(false)); | ||||
|     let (tx, rx) = mpsc::channel(); | ||||
|     (Sender { | ||||
|         awake: b.clone(), | ||||
|         notify: notify, | ||||
|         tx: tx, | ||||
|     }, | ||||
|     Receiver { | ||||
|         awake: b, | ||||
|         rx: rx, | ||||
|     }) | ||||
| } | ||||
|  | ||||
| pub fn share<T, U>(other: &Sender<U>) -> (Sender<T>, Receiver<T>) { | ||||
|     let (tx, rx) = mpsc::channel(); | ||||
|     let notify = other.notify.clone(); | ||||
|     let b = other.awake.clone(); | ||||
|     (Sender { | ||||
|         awake: b.clone(), | ||||
|         notify: notify, | ||||
|         tx: tx, | ||||
|     }, | ||||
|     Receiver { | ||||
|         awake: b, | ||||
|         rx: rx, | ||||
|     }) | ||||
| } | ||||
|  | ||||
| pub struct Sender<T> { | ||||
|     awake: Arc<AtomicBool>, | ||||
|     notify: rotor::Notifier, | ||||
|     tx: mpsc::Sender<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Send> Sender<T> { | ||||
|     pub fn send(&self, val: T) -> Result<(), SendError<T>> { | ||||
|         try!(self.tx.send(val)); | ||||
|         if !self.awake.swap(true, Ordering::SeqCst) { | ||||
|             try!(self.notify.wakeup()); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Clone for Sender<T> { | ||||
|     fn clone(&self) -> Sender<T> { | ||||
|         Sender { | ||||
|             awake: self.awake.clone(), | ||||
|             notify: self.notify.clone(), | ||||
|             tx: self.tx.clone(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> fmt::Debug for Sender<T> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.debug_struct("Sender") | ||||
|             .field("notify", &self.notify) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct SendError<T>(pub Option<T>); | ||||
|  | ||||
| impl<T> From<mpsc::SendError<T>> for SendError<T> { | ||||
|     fn from(e: mpsc::SendError<T>) -> SendError<T> { | ||||
|         SendError(Some(e.0)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> From<rotor::WakeupError> for SendError<T> { | ||||
|     fn from(_e: rotor::WakeupError) -> SendError<T> { | ||||
|         SendError(None) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct Receiver<T> { | ||||
|     awake: Arc<AtomicBool>, | ||||
|     rx: mpsc::Receiver<T>, | ||||
| } | ||||
|  | ||||
| impl<T: Send> Receiver<T> { | ||||
|     pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> { | ||||
|         self.awake.store(false, Ordering::Relaxed); | ||||
|         self.rx.try_recv() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										77
									
								
								src/http/chunk.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/http/chunk.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| use std::borrow::Borrow; | ||||
| use std::fmt; | ||||
| use std::sync::Arc; | ||||
|  | ||||
| /// A piece of a message body. | ||||
| pub struct Chunk(Inner); | ||||
|  | ||||
| enum Inner { | ||||
|     Owned(Vec<u8>), | ||||
|     Referenced(Arc<Vec<u8>>), | ||||
|     Static(&'static [u8]), | ||||
| } | ||||
|  | ||||
| impl From<Vec<u8>> for Chunk { | ||||
|     #[inline] | ||||
|     fn from(v: Vec<u8>) -> Chunk { | ||||
|         Chunk(Inner::Owned(v)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Arc<Vec<u8>>> for Chunk { | ||||
|     #[inline] | ||||
|     fn from(v: Arc<Vec<u8>>) -> Chunk { | ||||
|         Chunk(Inner::Referenced(v)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<&'static [u8]> for Chunk { | ||||
|     #[inline] | ||||
|     fn from(slice: &'static [u8]) -> Chunk { | ||||
|         Chunk(Inner::Static(slice)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<String> for Chunk { | ||||
|     #[inline] | ||||
|     fn from(s: String) -> Chunk { | ||||
|         s.into_bytes().into() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<&'static str> for Chunk { | ||||
|     #[inline] | ||||
|     fn from(slice: &'static str) -> Chunk { | ||||
|         slice.as_bytes().into() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ::std::ops::Deref for Chunk { | ||||
|     type Target = [u8]; | ||||
|  | ||||
|     #[inline] | ||||
|     fn deref(&self) -> &Self::Target { | ||||
|         self.as_ref() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl AsRef<[u8]> for Chunk { | ||||
|     #[inline] | ||||
|     fn as_ref(&self) -> &[u8] { | ||||
|         match self.0 { | ||||
|             Inner::Owned(ref vec) => vec, | ||||
|             Inner::Referenced(ref vec) => { | ||||
|                 let v: &Vec<u8> = vec.borrow(); | ||||
|                 v.as_slice() | ||||
|             } | ||||
|             Inner::Static(slice) => slice, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for Chunk { | ||||
|     #[inline] | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         fmt::Debug::fmt(self.as_ref(), f) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1607
									
								
								src/http/conn.rs
									
									
									
									
									
								
							
							
						
						
									
										1607
									
								
								src/http/conn.rs
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -277,7 +277,7 @@ mod tests { | ||||
|     use std::io::Write; | ||||
|     use super::Decoder; | ||||
|     use super::ChunkedState; | ||||
|     use mock::Async; | ||||
|     use mock::AsyncIo; | ||||
|  | ||||
|     #[test] | ||||
|     fn test_read_chunk_size() { | ||||
| @@ -422,7 +422,7 @@ mod tests { | ||||
|                   -> String { | ||||
|         let content_len = content.len(); | ||||
|         let mock_buf = io::Cursor::new(content.clone()); | ||||
|         let mut ins = Async::new(mock_buf, block_at); | ||||
|         let mut ins = AsyncIo::new(mock_buf, block_at); | ||||
|         let mut outs = vec![]; | ||||
|         loop { | ||||
|             let mut buf = vec![0; read_buffer_size]; | ||||
|   | ||||
| @@ -1,15 +1,12 @@ | ||||
| use std::borrow::Cow; | ||||
| use std::cmp; | ||||
| use std::io::{self, Write}; | ||||
|  | ||||
| use http::internal::{AtomicWrite, WriteBuf}; | ||||
| use http::io::AtomicWrite; | ||||
|  | ||||
| /// Encoders to handle different Transfer-Encodings. | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Encoder { | ||||
|     kind: Kind, | ||||
|     prefix: Prefix, | ||||
|     is_closed: bool, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| @@ -26,27 +23,16 @@ impl Encoder { | ||||
|     pub fn chunked() -> Encoder { | ||||
|         Encoder { | ||||
|             kind: Kind::Chunked(Chunked::Init), | ||||
|             prefix: Prefix(None), | ||||
|             is_closed: false, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn length(len: u64) -> Encoder { | ||||
|         Encoder { | ||||
|             kind: Kind::Length(len), | ||||
|             prefix: Prefix(None), | ||||
|             is_closed: false, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn prefix(&mut self, prefix: WriteBuf<Vec<u8>>) { | ||||
|         self.prefix.0 = Some(prefix); | ||||
|     } | ||||
|  | ||||
|     pub fn is_eof(&self) -> bool { | ||||
|         if self.prefix.0.is_some() { | ||||
|             return false; | ||||
|         } | ||||
|         match self.kind { | ||||
|             Kind::Length(0) | | ||||
|             Kind::Chunked(Chunked::End) => true, | ||||
| @@ -54,71 +40,26 @@ impl Encoder { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// User has called `encoder.close()` in a `Handler`. | ||||
|     pub fn is_closed(&self) -> bool { | ||||
|         self.is_closed | ||||
|     } | ||||
|  | ||||
|     pub fn close(&mut self) { | ||||
|         self.is_closed = true; | ||||
|     } | ||||
|  | ||||
|     pub fn finish(self) -> Option<WriteBuf<Cow<'static, [u8]>>> { | ||||
|         let trailer = self.trailer(); | ||||
|         let buf = self.prefix.0; | ||||
|  | ||||
|         match (buf, trailer) { | ||||
|             (Some(mut buf), Some(trailer)) => { | ||||
|                 buf.bytes.extend_from_slice(trailer); | ||||
|                 Some(WriteBuf { | ||||
|                     bytes: Cow::Owned(buf.bytes), | ||||
|                     pos: buf.pos, | ||||
|                 }) | ||||
|             }, | ||||
|             (Some(buf), None) => Some(WriteBuf { | ||||
|                 bytes: Cow::Owned(buf.bytes), | ||||
|                 pos: buf.pos | ||||
|             }), | ||||
|             (None, Some(trailer)) => { | ||||
|                 Some(WriteBuf { | ||||
|                     bytes: Cow::Borrowed(trailer), | ||||
|                     pos: 0, | ||||
|                 }) | ||||
|             }, | ||||
|             (None, None) => None | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn trailer(&self) -> Option<&'static [u8]> { | ||||
|         match self.kind { | ||||
|             Kind::Chunked(Chunked::Init) => { | ||||
|                 Some(b"0\r\n\r\n") | ||||
|             } | ||||
|             _ => None | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn encode<W: AtomicWrite>(&mut self, w: &mut W, msg: &[u8]) -> io::Result<usize> { | ||||
|         match self.kind { | ||||
|             Kind::Chunked(ref mut chunked) => { | ||||
|                 chunked.encode(w, &mut self.prefix, msg) | ||||
|                 chunked.encode(w, msg) | ||||
|             }, | ||||
|             Kind::Length(ref mut remaining) => { | ||||
|                 let mut n = { | ||||
|                 let n = { | ||||
|                     let max = cmp::min(*remaining as usize, msg.len()); | ||||
|                     trace!("sized write, len = {}", max); | ||||
|                     let slice = &msg[..max]; | ||||
|  | ||||
|                     let prefix = self.prefix.0.as_ref().map(|buf| &buf.bytes[buf.pos..]).unwrap_or(b""); | ||||
|  | ||||
|                     try!(w.write_atomic(&[prefix, slice])) | ||||
|                     try!(w.write_atomic(&[slice])) | ||||
|                 }; | ||||
|  | ||||
|                 n = self.prefix.update(n); | ||||
|                 if n == 0 { | ||||
|                     return Err(io::Error::new(io::ErrorKind::WouldBlock, "would block")); | ||||
|                 } | ||||
|  | ||||
|                 *remaining -= n as u64; | ||||
|                 trace!("sized write complete, remaining = {}", remaining); | ||||
|                 Ok(n) | ||||
|             }, | ||||
|         } | ||||
| @@ -138,7 +79,7 @@ enum Chunked { | ||||
| } | ||||
|  | ||||
| impl Chunked { | ||||
|     fn encode<W: AtomicWrite>(&mut self, w: &mut W, prefix: &mut Prefix, msg: &[u8]) -> io::Result<usize> { | ||||
|     fn encode<W: AtomicWrite>(&mut self, w: &mut W, msg: &[u8]) -> io::Result<usize> { | ||||
|         match *self { | ||||
|             Chunked::Init => { | ||||
|                 let mut size = ChunkSize { | ||||
| @@ -158,28 +99,24 @@ impl Chunked { | ||||
|             let pieces = match *self { | ||||
|                 Chunked::Init => unreachable!("Chunked::Init should have become Chunked::Size"), | ||||
|                 Chunked::Size(ref size) => [ | ||||
|                     prefix.0.as_ref().map(|buf| &buf.bytes[buf.pos..]).unwrap_or(b""), | ||||
|                     &size.bytes[size.pos.into() .. size.len.into()], | ||||
|                     &b"\r\n"[..], | ||||
|                     msg, | ||||
|                     &b"\r\n"[..], | ||||
|                 ], | ||||
|                 Chunked::SizeCr => [ | ||||
|                     &b""[..], | ||||
|                     &b""[..], | ||||
|                     &b"\r\n"[..], | ||||
|                     msg, | ||||
|                     &b"\r\n"[..], | ||||
|                 ], | ||||
|                 Chunked::SizeLf => [ | ||||
|                     &b""[..], | ||||
|                     &b""[..], | ||||
|                     &b"\n"[..], | ||||
|                     msg, | ||||
|                     &b"\r\n"[..], | ||||
|                 ], | ||||
|                 Chunked::Body(pos) => [ | ||||
|                     &b""[..], | ||||
|                     &b""[..], | ||||
|                     &b""[..], | ||||
|                     &msg[pos..], | ||||
| @@ -189,14 +126,12 @@ impl Chunked { | ||||
|                     &b""[..], | ||||
|                     &b""[..], | ||||
|                     &b""[..], | ||||
|                     &b""[..], | ||||
|                     &b"\r\n"[..], | ||||
|                 ], | ||||
|                 Chunked::BodyLf => [ | ||||
|                     &b""[..], | ||||
|                     &b""[..], | ||||
|                     &b""[..], | ||||
|                     &b""[..], | ||||
|                     &b"\n"[..], | ||||
|                 ], | ||||
|                 Chunked::End => unreachable!("Chunked::End shouldn't write more") | ||||
| @@ -204,9 +139,6 @@ impl Chunked { | ||||
|             try!(w.write_atomic(&pieces)) | ||||
|         }; | ||||
|  | ||||
|         if n > 0 { | ||||
|             n = prefix.update(n); | ||||
|         } | ||||
|         while n > 0 { | ||||
|             match *self { | ||||
|                 Chunked::Init => unreachable!("Chunked::Init should have become Chunked::Size"), | ||||
| @@ -321,30 +253,10 @@ impl io::Write for ChunkSize { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone)] | ||||
| struct Prefix(Option<WriteBuf<Vec<u8>>>); | ||||
|  | ||||
| impl Prefix { | ||||
|     fn update(&mut self, n: usize) -> usize { | ||||
|         if let Some(mut buf) = self.0.take() { | ||||
|             if buf.bytes.len() - buf.pos > n { | ||||
|                 buf.pos += n; | ||||
|                 self.0 = Some(buf); | ||||
|                 0 | ||||
|             } else { | ||||
|                 let nbuf = buf.bytes.len() - buf.pos; | ||||
|                 n - nbuf | ||||
|             } | ||||
|         } else { | ||||
|             n | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::Encoder; | ||||
|     use mock::{Async, Buf}; | ||||
|     use mock::{AsyncIo, Buf}; | ||||
|  | ||||
|     #[test] | ||||
|     fn test_chunked_encode_sync() { | ||||
| @@ -359,7 +271,7 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     fn test_chunked_encode_async() { | ||||
|         let mut dst = Async::new(Buf::new(), 7); | ||||
|         let mut dst = AsyncIo::new(Buf::new(), 7); | ||||
|         let mut encoder = Encoder::chunked(); | ||||
|  | ||||
|         assert!(encoder.encode(&mut dst, b"foo bar").is_err()); | ||||
|   | ||||
| @@ -1,21 +1,3 @@ | ||||
| /* | ||||
| use std::fmt; | ||||
| use std::io::{self, Write}; | ||||
| use std::marker::PhantomData; | ||||
| use std::sync::mpsc; | ||||
|  | ||||
| use url::Url; | ||||
| use tick; | ||||
| use time::now_utc; | ||||
|  | ||||
| use header::{self, Headers}; | ||||
| use http::{self, conn}; | ||||
| use method::Method; | ||||
| use net::{Fresh, Streaming}; | ||||
| use status::StatusCode; | ||||
| use version::HttpVersion; | ||||
| */ | ||||
|  | ||||
| pub use self::decode::Decoder; | ||||
| pub use self::encode::Encoder; | ||||
|  | ||||
| @@ -23,7 +5,7 @@ pub use self::parse::parse; | ||||
|  | ||||
| mod decode; | ||||
| mod encode; | ||||
| mod parse; | ||||
| pub mod parse; | ||||
|  | ||||
| /* | ||||
| fn should_have_response_body(method: &Method, status: u16) -> bool { | ||||
|   | ||||
| @@ -4,7 +4,7 @@ use std::fmt::{self, Write}; | ||||
| use httparse; | ||||
|  | ||||
| use header::{self, Headers, ContentLength, TransferEncoding}; | ||||
| use http::{MessageHead, RawStatus, Http1Message, ParseResult, ServerMessage, ClientMessage, RequestLine}; | ||||
| use http::{MessageHead, RawStatus, Http1Transaction, ParseResult, ServerTransaction, ClientTransaction, RequestLine}; | ||||
| use http::h1::{Encoder, Decoder}; | ||||
| use method::Method; | ||||
| use status::StatusCode; | ||||
| @@ -13,17 +13,15 @@ use version::HttpVersion::{Http10, Http11}; | ||||
| const MAX_HEADERS: usize = 100; | ||||
| const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific | ||||
|  | ||||
| pub fn parse<T: Http1Message<Incoming=I>, I>(buf: &[u8]) -> ParseResult<I> { | ||||
| pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: &[u8]) -> ParseResult<I> { | ||||
|     if buf.len() == 0 { | ||||
|         return Ok(None); | ||||
|     } | ||||
|     trace!("parse({:?})", buf); | ||||
|     <T as Http1Message>::parse(buf) | ||||
|     <T as Http1Transaction>::parse(buf) | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| impl Http1Message for ServerMessage { | ||||
| impl Http1Transaction for ServerTransaction { | ||||
|     type Incoming = RequestLine; | ||||
|     type Outgoing = StatusCode; | ||||
|  | ||||
| @@ -60,7 +58,7 @@ impl Http1Message for ServerMessage { | ||||
|     } | ||||
|  | ||||
|  | ||||
|     fn encode(mut head: MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> Encoder { | ||||
|     fn encode(head: &mut MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> Encoder { | ||||
|         use ::header; | ||||
|         trace!("writing head: {:?}", head); | ||||
|  | ||||
| @@ -103,9 +101,14 @@ impl Http1Message for ServerMessage { | ||||
|         } | ||||
|         body | ||||
|     } | ||||
|  | ||||
|     fn should_set_length(_head: &MessageHead<Self::Outgoing>) -> bool { | ||||
|         //TODO: pass method, check if method == HEAD | ||||
|         true | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Http1Message for ClientMessage { | ||||
| impl Http1Transaction for ClientTransaction { | ||||
|     type Incoming = RawStatus; | ||||
|     type Outgoing = RequestLine; | ||||
|  | ||||
| @@ -162,7 +165,7 @@ impl Http1Message for ClientMessage { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn encode(mut head: MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> Encoder { | ||||
|     fn encode(head: &mut MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> Encoder { | ||||
|         trace!("writing head: {:?}", head); | ||||
|  | ||||
|  | ||||
| @@ -203,6 +206,14 @@ impl Http1Message for ClientMessage { | ||||
|  | ||||
|         body | ||||
|     } | ||||
|  | ||||
|  | ||||
|     fn should_set_length(head: &MessageHead<Self::Outgoing>) -> bool { | ||||
|         match &head.subject.0 { | ||||
|             &Method::Get | &Method::Head => false, | ||||
|             _ => true | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct FastWrite<'a>(&'a mut Vec<u8>); | ||||
| @@ -238,17 +249,17 @@ mod tests { | ||||
|     #[test] | ||||
|     fn test_parse_request() { | ||||
|         let raw = b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n"; | ||||
|         parse::<http::ServerMessage, _>(raw).unwrap(); | ||||
|         parse::<http::ServerTransaction, _>(raw).unwrap(); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_parse_raw_status() { | ||||
|         let raw = b"HTTP/1.1 200 OK\r\n\r\n"; | ||||
|         let (res, _) = parse::<http::ClientMessage, _>(raw).unwrap().unwrap(); | ||||
|         let (res, _) = parse::<http::ClientTransaction, _>(raw).unwrap().unwrap(); | ||||
|         assert_eq!(res.subject.1, "OK"); | ||||
|  | ||||
|         let raw = b"HTTP/1.1 200 Howdy\r\n\r\n"; | ||||
|         let (res, _) = parse::<http::ClientMessage, _>(raw).unwrap().unwrap(); | ||||
|         let (res, _) = parse::<http::ClientTransaction, _>(raw).unwrap().unwrap(); | ||||
|         assert_eq!(res.subject.1, "Howdy"); | ||||
|     } | ||||
|  | ||||
| @@ -260,7 +271,7 @@ mod tests { | ||||
|     fn bench_parse_incoming(b: &mut Bencher) { | ||||
|         let raw = b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n"; | ||||
|         b.iter(|| { | ||||
|             parse::<http::ServerMessage, _>(raw).unwrap() | ||||
|             parse::<http::ServerTransaction, _>(raw).unwrap() | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										207
									
								
								src/http/io.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								src/http/io.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | ||||
| use std::fmt; | ||||
| use std::io::{self, Read, Write}; | ||||
|  | ||||
| use futures::Async; | ||||
| use tokio::io::Io; | ||||
|  | ||||
| use http::{Http1Transaction, h1, MessageHead, ParseResult}; | ||||
| use http::buffer::Buffer; | ||||
|  | ||||
| pub struct Buffered<T> { | ||||
|     io: T, | ||||
|     read_buf: Buffer, | ||||
|     write_buf: Buffer, | ||||
| } | ||||
|  | ||||
| impl<T> fmt::Debug for Buffered<T> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.debug_struct("Buffered") | ||||
|             .field("read_buf", &self.read_buf) | ||||
|             .field("write_buf", &self.write_buf) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Io> Buffered<T> { | ||||
|     pub fn new(io: T) -> Buffered<T> { | ||||
|         Buffered { | ||||
|             io: io, | ||||
|             read_buf: Buffer::new(), | ||||
|             write_buf: Buffer::new(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn read_buf(&self) -> &[u8] { | ||||
|         self.read_buf.bytes() | ||||
|     } | ||||
|  | ||||
|     pub fn consume_leading_lines(&mut self) { | ||||
|         self.read_buf.consume_leading_lines(); | ||||
|     } | ||||
|  | ||||
|     pub fn poll_read(&mut self) -> Async<()> { | ||||
|         self.io.poll_read() | ||||
|     } | ||||
|  | ||||
|     pub fn parse<S: Http1Transaction>(&mut self) -> ::Result<Option<MessageHead<S::Incoming>>> { | ||||
|         match self.read_buf.read_from(&mut self.io) { | ||||
|             Ok(0) => { | ||||
|                 trace!("parse eof"); | ||||
|                 return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "parse eof").into()); | ||||
|             } | ||||
|             Ok(_) => {}, | ||||
|             Err(e) => match e.kind() { | ||||
|                 io::ErrorKind::WouldBlock => {}, | ||||
|                 _ => return Err(e.into()) | ||||
|             } | ||||
|         } | ||||
|         match try!(parse::<S, _>(self.read_buf.bytes())) { | ||||
|             Some((head, len)) => { | ||||
|                 trace!("parsed {} bytes out of {}", len, self.read_buf.len()); | ||||
|                 self.read_buf.consume(len); | ||||
|                 Ok(Some(head)) | ||||
|             }, | ||||
|             None => { | ||||
|                 if self.read_buf.is_max_size() { | ||||
|                     debug!("MAX_BUFFER_SIZE reached, closing"); | ||||
|                     Err(::Error::TooLarge) | ||||
|                 } else { | ||||
|                     Ok(None) | ||||
|                 } | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn buffer<B: AsRef<[u8]>>(&mut self, buf: B) { | ||||
|         self.write_buf.write(buf.as_ref()); | ||||
|     } | ||||
|  | ||||
|     #[cfg(test)] | ||||
|     pub fn io_mut(&mut self) -> &mut T { | ||||
|         &mut self.io | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Read> Read for Buffered<T> { | ||||
|     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||||
|         trace!("Buffered.read self={}, buf={}", self.read_buf.len(), buf.len()); | ||||
|         let n = try!(self.read_buf.bytes().read(buf)); | ||||
|         self.read_buf.consume(n); | ||||
|         if n == 0 { | ||||
|             self.read_buf.reset(); | ||||
|             self.io.read(&mut buf[n..]) | ||||
|         } else { | ||||
|             Ok(n) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Write> Write for Buffered<T> { | ||||
|     fn write(&mut self, data: &[u8]) -> io::Result<usize> { | ||||
|         Ok(self.write_buf.write(data)) | ||||
|     } | ||||
|  | ||||
|     fn flush(&mut self) -> io::Result<()> { | ||||
|         self.write_buf.write_into(&mut self.io).and_then(|_n| { | ||||
|             if self.write_buf.is_empty() { | ||||
|                 Ok(()) | ||||
|             } else { | ||||
|                 Err(io::Error::new(io::ErrorKind::WouldBlock, "wouldblock")) | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &[u8]) -> ParseResult<I> { | ||||
|     h1::parse::<T, I>(rdr) | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct Cursor<T: AsRef<[u8]>> { | ||||
|     bytes: T, | ||||
|     pos: usize, | ||||
| } | ||||
|  | ||||
| impl<T: AsRef<[u8]>> Cursor<T> { | ||||
|     pub fn new(bytes: T) -> Cursor<T> { | ||||
|         Cursor { | ||||
|             bytes: bytes, | ||||
|             pos: 0, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn is_written(&self) -> bool { | ||||
|         trace!("Cursor::is_written pos = {}, len = {}", self.pos, self.bytes.as_ref().len()); | ||||
|         self.pos >= self.bytes.as_ref().len() | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|     pub fn write_to<W: Write>(&mut self, dst: &mut W) -> io::Result<usize> { | ||||
|         dst.write(&self.bytes.as_ref()[self.pos..]).map(|n| { | ||||
|             self.pos += n; | ||||
|             n | ||||
|         }) | ||||
|     } | ||||
|     */ | ||||
|  | ||||
|     #[inline] | ||||
|     pub fn buf(&self) -> &[u8] { | ||||
|         &self.bytes.as_ref()[self.pos..] | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     pub fn consume(&mut self, num: usize) { | ||||
|         trace!("Cursor::consume({})", num); | ||||
|         self.pos = ::std::cmp::min(self.bytes.as_ref().len(), self.pos + num); | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: AsRef<[u8]>> fmt::Debug for Cursor<T> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         let bytes = self.buf(); | ||||
|         let reasonable_max = ::std::cmp::min(bytes.len(), 32); | ||||
|         write!(f, "Cursor({:?})", &bytes[..reasonable_max]) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait AtomicWrite { | ||||
|     fn write_atomic(&mut self, data: &[&[u8]]) -> io::Result<usize>; | ||||
| } | ||||
|  | ||||
| /* | ||||
| #[cfg(not(windows))] | ||||
| impl<T: Write + ::vecio::Writev> AtomicWrite for T { | ||||
|  | ||||
|     fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> { | ||||
|         self.writev(bufs) | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| #[cfg(windows)] | ||||
| */ | ||||
| impl<T: Write> AtomicWrite for T { | ||||
|     fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> { | ||||
|         if cfg!(not(windows)) { | ||||
|             warn!("write_atomic not using writev"); | ||||
|         } | ||||
|         let vec = bufs.concat(); | ||||
|         self.write(&vec) | ||||
|     } | ||||
| } | ||||
| //} | ||||
|  | ||||
|  | ||||
| #[test] | ||||
| fn test_iobuf_write_empty_slice() { | ||||
|     use mock::{AsyncIo, Buf as MockBuf}; | ||||
|  | ||||
|     let mut mock = AsyncIo::new(MockBuf::new(), 256); | ||||
|     mock.error(io::Error::new(io::ErrorKind::Other, "logic error")); | ||||
|  | ||||
|     let mut io_buf = Buffered::new(mock); | ||||
|  | ||||
|     // underlying io will return the logic error upon write, | ||||
|     // so we are testing that the io_buf does not trigger a write | ||||
|     // when there is nothing to flush | ||||
|     io_buf.flush().expect("should short-circuit flush"); | ||||
| } | ||||
							
								
								
									
										397
									
								
								src/http/mod.rs
									
									
									
									
									
								
							
							
						
						
									
										397
									
								
								src/http/mod.rs
									
									
									
									
									
								
							| @@ -1,227 +1,44 @@ | ||||
| //! Pieces pertaining to the HTTP message protocol. | ||||
| use std::borrow::Cow; | ||||
| use std::fmt; | ||||
| use std::io::{self, Read, Write}; | ||||
| use std::time::Duration; | ||||
|  | ||||
| use header::Connection; | ||||
| use header::ConnectionOption::{KeepAlive, Close}; | ||||
| use header::{Connection, ConnectionOption}; | ||||
| use header::Headers; | ||||
| use method::Method; | ||||
| use net::Transport; | ||||
| use status::StatusCode; | ||||
| use uri::RequestUri; | ||||
| use version::HttpVersion; | ||||
| use version::HttpVersion::{Http10, Http11}; | ||||
|  | ||||
| #[cfg(feature = "serde-serialization")] | ||||
| use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||||
|  | ||||
| pub use self::conn::{Conn, MessageHandler, MessageHandlerFactory, Seed, Key, ReadyResult}; | ||||
| pub use self::conn::{Conn, KeepAlive, KA}; | ||||
| pub use self::body::{Body, TokioBody}; | ||||
| pub use self::chunk::Chunk; | ||||
|  | ||||
| mod body; | ||||
| //mod buf; | ||||
| mod buffer; | ||||
| pub mod channel; | ||||
| mod chunk; | ||||
| mod conn; | ||||
| mod io; | ||||
| mod h1; | ||||
| //mod h2; | ||||
|  | ||||
| /// Wraps a `Transport` to provide HTTP decoding when reading. | ||||
| #[derive(Debug)] | ||||
| pub struct Decoder<'a, T: Read + 'a>(DecoderImpl<'a, T>); | ||||
|  | ||||
| /// Wraps a `Transport` to provide HTTP encoding when writing. | ||||
| #[derive(Debug)] | ||||
| pub struct Encoder<'a, T: Transport + 'a>(EncoderImpl<'a, T>); | ||||
|  | ||||
| #[derive(Debug)] | ||||
| enum DecoderImpl<'a, T: Read + 'a> { | ||||
|     H1(&'a mut h1::Decoder, Trans<'a, T>), | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| enum Trans<'a, T: Read + 'a> { | ||||
|     Port(&'a mut T), | ||||
|     Buf(self::buffer::BufReader<'a, T>) | ||||
| } | ||||
|  | ||||
| impl<'a, T: Read + 'a> Trans<'a, T> { | ||||
|     fn get_ref(&self) -> &T { | ||||
|         match *self { | ||||
|             Trans::Port(ref t) => &*t, | ||||
|             Trans::Buf(ref buf) => buf.get_ref() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, T: Read + 'a> Read for Trans<'a, T> { | ||||
|     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||||
|         match *self { | ||||
|             Trans::Port(ref mut t) => t.read(buf), | ||||
|             Trans::Buf(ref mut b) => b.read(buf) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| enum EncoderImpl<'a, T: Transport + 'a> { | ||||
|     H1(&'a mut h1::Encoder, &'a mut T), | ||||
| } | ||||
|  | ||||
| impl<'a, T: Read> Decoder<'a, T> { | ||||
|     fn h1(decoder: &'a mut h1::Decoder, transport: Trans<'a, T>) -> Decoder<'a, T> { | ||||
|         Decoder(DecoderImpl::H1(decoder, transport)) | ||||
|     } | ||||
|  | ||||
|     /// Read from the `Transport`. | ||||
|     #[inline] | ||||
|     pub fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||||
|         match self.0 { | ||||
|             DecoderImpl::H1(ref mut decoder, ref mut transport) => { | ||||
|                 decoder.decode(transport, buf) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Try to read from the `Transport`. | ||||
|     /// | ||||
|     /// This method looks for the `WouldBlock` error. If the read did not block, | ||||
|     /// a return value would be `Ok(Some(x))`. If the read would block, | ||||
|     /// this method would return `Ok(None)`. | ||||
|     #[inline] | ||||
|     pub fn try_read(&mut self, buf: &mut [u8]) -> io::Result<Option<usize>> { | ||||
|         match self.read(buf) { | ||||
| /* | ||||
| macro_rules! nonblocking { | ||||
|     ($e:expr) => ({ | ||||
|         match $e { | ||||
|             Ok(n) => Ok(Some(n)), | ||||
|             Err(e) => match e.kind() { | ||||
|                 io::ErrorKind::WouldBlock => Ok(None), | ||||
|                 stdio::ErrorKind::WouldBlock => Ok(None), | ||||
|                 _ => Err(e) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Get a reference to the transport. | ||||
|     pub fn get_ref(&self) -> &T { | ||||
|         match self.0 { | ||||
|             DecoderImpl::H1(_, ref transport) => transport.get_ref() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, T: Transport> Encoder<'a, T> { | ||||
|     fn h1(encoder: &'a mut h1::Encoder, transport: &'a mut T) -> Encoder<'a, T> { | ||||
|         Encoder(EncoderImpl::H1(encoder, transport)) | ||||
|     } | ||||
|  | ||||
|     /// Write to the `Transport`. | ||||
|     #[inline] | ||||
|     pub fn write(&mut self, data: &[u8]) -> io::Result<usize> { | ||||
|         if data.is_empty() { | ||||
|             return Ok(0); | ||||
|         } | ||||
|         match self.0 { | ||||
|             EncoderImpl::H1(ref mut encoder, ref mut transport) => { | ||||
|                 if encoder.is_closed() { | ||||
|                     Ok(0) | ||||
|                 } else { | ||||
|                     encoder.encode(*transport, data) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Try to write to the `Transport`. | ||||
|     /// | ||||
|     /// This method looks for the `WouldBlock` error. If the write did not block, | ||||
|     /// a return value would be `Ok(Some(x))`. If the write would block, | ||||
|     /// this method would return `Ok(None)`. | ||||
|     #[inline] | ||||
|     pub fn try_write(&mut self, data: &[u8]) -> io::Result<Option<usize>> { | ||||
|         match self.write(data) { | ||||
|             Ok(n) => Ok(Some(n)), | ||||
|             Err(e) => match e.kind() { | ||||
|                 io::ErrorKind::WouldBlock => Ok(None), | ||||
|                 _ => Err(e) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Closes an encoder, signaling that no more writing will occur. | ||||
|     /// | ||||
|     /// This is needed for encodings that don't know the length of the content | ||||
|     /// beforehand. Most common instance would be usage of | ||||
|     /// `Transfer-Enciding: chunked`. You would call `close()` to signal | ||||
|     /// the `Encoder` should write the end chunk, or `0\r\n\r\n`. | ||||
|     pub fn close(&mut self) { | ||||
|         match self.0 { | ||||
|             EncoderImpl::H1(ref mut encoder, _) => encoder.close() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Get a reference to the transport. | ||||
|     pub fn get_ref(&self) -> &T { | ||||
|         match self.0 { | ||||
|             EncoderImpl::H1(_, ref transport) => &*transport | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, T: Read> Read for Decoder<'a, T> { | ||||
|     #[inline] | ||||
|     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||||
|         self.read(buf) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, T: Transport> Write for Encoder<'a, T> { | ||||
|     #[inline] | ||||
|     fn write(&mut self, data: &[u8]) -> io::Result<usize> { | ||||
|         self.write(data) | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     fn flush(&mut self) -> io::Result<()> { | ||||
|         match self.0 { | ||||
|             EncoderImpl::H1(_, ref mut transport) => { | ||||
|                 transport.flush() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Because privacy rules. Reasons. | ||||
| /// https://github.com/rust-lang/rust/issues/30905 | ||||
| mod internal { | ||||
|     use std::io::{self, Write}; | ||||
|  | ||||
|     #[derive(Debug, Clone)] | ||||
|     pub struct WriteBuf<T: AsRef<[u8]>> { | ||||
|         pub bytes: T, | ||||
|         pub pos: usize, | ||||
|     } | ||||
|  | ||||
|     pub trait AtomicWrite { | ||||
|         fn write_atomic(&mut self, data: &[&[u8]]) -> io::Result<usize>; | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(windows))] | ||||
|     impl<T: Write + ::vecio::Writev> AtomicWrite for T { | ||||
|  | ||||
|         fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> { | ||||
|             self.writev(bufs) | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     #[cfg(windows)] | ||||
|     impl<T: Write> AtomicWrite for T { | ||||
|         fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> { | ||||
|             let vec = bufs.concat(); | ||||
|             self.write(&vec) | ||||
|         } | ||||
|     } | ||||
|     }); | ||||
| } | ||||
| */ | ||||
|  | ||||
| /// An Incoming Message head. Includes request/status line, and headers. | ||||
| #[derive(Debug, Default)] | ||||
| #[derive(Debug, Default, PartialEq)] | ||||
| pub struct MessageHead<S> { | ||||
|     /// HTTP version of the message. | ||||
|     pub version: HttpVersion, | ||||
| @@ -234,7 +51,7 @@ pub struct MessageHead<S> { | ||||
| /// An incoming request message. | ||||
| pub type RequestHead = MessageHead<RequestLine>; | ||||
|  | ||||
| #[derive(Debug, Default)] | ||||
| #[derive(Debug, Default, PartialEq)] | ||||
| pub struct RequestLine(pub Method, pub RequestUri); | ||||
|  | ||||
| impl fmt::Display for RequestLine { | ||||
| @@ -274,18 +91,13 @@ impl Default for RawStatus { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "serde-serialization")] | ||||
| impl Serialize for RawStatus { | ||||
|     fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { | ||||
|         (self.0, &self.1).serialize(serializer) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "serde-serialization")] | ||||
| impl Deserialize for RawStatus { | ||||
|     fn deserialize<D>(deserializer: &mut D) -> Result<RawStatus, D::Error> where D: Deserializer { | ||||
|         let representation: (u16, String) = try!(Deserialize::deserialize(deserializer)); | ||||
|         Ok(RawStatus(representation.0, Cow::Owned(representation.1))) | ||||
| impl From<MessageHead<::StatusCode>> for MessageHead<RawStatus> { | ||||
|     fn from(head: MessageHead<::StatusCode>) -> MessageHead<RawStatus> { | ||||
|         MessageHead { | ||||
|             subject: head.subject.into(), | ||||
|             version: head.version, | ||||
|             headers: head.headers, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -294,174 +106,31 @@ impl Deserialize for RawStatus { | ||||
| pub fn should_keep_alive(version: HttpVersion, headers: &Headers) -> bool { | ||||
|     let ret = match (version, headers.get::<Connection>()) { | ||||
|         (Http10, None) => false, | ||||
|         (Http10, Some(conn)) if !conn.contains(&KeepAlive) => false, | ||||
|         (Http11, Some(conn)) if conn.contains(&Close)  => false, | ||||
|         (Http10, Some(conn)) if !conn.contains(&ConnectionOption::KeepAlive) => false, | ||||
|         (Http11, Some(conn)) if conn.contains(&ConnectionOption::Close)  => false, | ||||
|         _ => true | ||||
|     }; | ||||
|     trace!("should_keep_alive(version={:?}, header={:?}) = {:?}", version, headers.get::<Connection>(), ret); | ||||
|     ret | ||||
| } | ||||
|  | ||||
| pub type ParseResult<T> = ::Result<Option<(MessageHead<T>, usize)>>; | ||||
|  | ||||
| pub fn parse<T: Http1Message<Incoming=I>, I>(rdr: &[u8]) -> ParseResult<I> { | ||||
|     h1::parse::<T, I>(rdr) | ||||
| } | ||||
|  | ||||
| // These 2 enums are not actually dead_code. They are used in the server and | ||||
| // and client modules, respectively. However, their being used as associated | ||||
| // types doesn't mark them as used, so the dead_code linter complains. | ||||
|  | ||||
| #[allow(dead_code)] | ||||
| #[derive(Debug)] | ||||
| pub enum ServerMessage {} | ||||
| pub enum ServerTransaction {} | ||||
|  | ||||
| #[allow(dead_code)] | ||||
| #[derive(Debug)] | ||||
| pub enum ClientMessage {} | ||||
| pub enum ClientTransaction {} | ||||
|  | ||||
| pub trait Http1Message { | ||||
| pub trait Http1Transaction { | ||||
|     type Incoming; | ||||
|     type Outgoing: Default; | ||||
|     //type KeepAlive: KeepAlive; | ||||
|     fn parse(bytes: &[u8]) -> ParseResult<Self::Incoming>; | ||||
|     fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<h1::Decoder>; | ||||
|     fn encode(head: 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; | ||||
| } | ||||
|  | ||||
| /// Used to signal desired events when working with asynchronous IO. | ||||
| #[must_use] | ||||
| #[derive(Clone)] | ||||
| pub struct Next { | ||||
|     interest: Next_, | ||||
|     timeout: Option<Duration>, | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for Next { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         try!(write!(f, "Next::{:?}", &self.interest)); | ||||
|         match self.timeout { | ||||
|             Some(ref d) => write!(f, "({:?})", d), | ||||
|             None => Ok(()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Internal enum for `Next` | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| enum Next_ { | ||||
|     Read, | ||||
|     Write, | ||||
|     ReadWrite, | ||||
|     Wait, | ||||
|     End, | ||||
|     Remove, | ||||
| } | ||||
|  | ||||
| // An enum representing all the possible actions to taken when registering | ||||
| // with the event loop. | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| enum Reg { | ||||
|     Read, | ||||
|     Write, | ||||
|     ReadWrite, | ||||
|     Wait, | ||||
|     Remove | ||||
| } | ||||
|  | ||||
| /// A notifier to wakeup a socket after having used `Next::wait()` | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Control { | ||||
|     tx: self::channel::Sender<Next>, | ||||
| } | ||||
|  | ||||
| impl Control { | ||||
|     /// Wakeup a waiting socket to listen for a certain event. | ||||
|     pub fn ready(&self, next: Next) -> Result<(), ControlError> { | ||||
|         //TODO: assert!( next.interest != Next_::Wait ) ? | ||||
|         self.tx.send(next).map_err(|_| ControlError(())) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// An error occured trying to tell a Control it is ready. | ||||
| #[derive(Debug)] | ||||
| pub struct ControlError(()); | ||||
|  | ||||
| impl ::std::error::Error for ControlError { | ||||
|     fn description(&self) -> &str { | ||||
|         "Cannot wakeup event loop: loop is closed" | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for ControlError { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.write_str(::std::error::Error::description(self)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Next { | ||||
|     fn new(interest: Next_) -> Next { | ||||
|         Next { | ||||
|             interest: interest, | ||||
|             timeout: None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|     fn reg(&self) -> Reg { | ||||
|         self.interest.register() | ||||
|     } | ||||
|     */ | ||||
|  | ||||
|     /// Signals the desire to read from the transport. | ||||
|     pub fn read() -> Next { | ||||
|         Next::new(Next_::Read) | ||||
|     } | ||||
|  | ||||
|     /// Signals the desire to write to the transport. | ||||
|     pub fn write() -> Next { | ||||
|         Next::new(Next_::Write) | ||||
|     } | ||||
|  | ||||
|     /// Signals the desire to read and write to the transport. | ||||
|     pub fn read_and_write() -> Next { | ||||
|         Next::new(Next_::ReadWrite) | ||||
|     } | ||||
|  | ||||
|     /// Signals the desire to end the current HTTP message. | ||||
|     pub fn end() -> Next { | ||||
|         Next::new(Next_::End) | ||||
|     } | ||||
|  | ||||
|     /// Signals the desire to abruptly remove the current transport from the | ||||
|     /// event loop. | ||||
|     pub fn remove() -> Next { | ||||
|         Next::new(Next_::Remove) | ||||
|     } | ||||
|  | ||||
|     /// Signals the desire to wait until some future time before acting again. | ||||
|     pub fn wait() -> Next { | ||||
|         Next::new(Next_::Wait) | ||||
|     } | ||||
|  | ||||
|     /// Signals a maximum duration to be waited for the desired event. | ||||
|     pub fn timeout(mut self, dur: Duration) -> Next { | ||||
|         self.timeout = Some(dur); | ||||
|         self | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Next_ { | ||||
|     fn register(&self) -> Reg { | ||||
|         match *self { | ||||
|             Next_::Read => Reg::Read, | ||||
|             Next_::Write => Reg::Write, | ||||
|             Next_::ReadWrite => Reg::ReadWrite, | ||||
|             Next_::Wait => Reg::Wait, | ||||
|             Next_::End => Reg::Remove, | ||||
|             Next_::Remove => Reg::Remove, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| type ParseResult<T> = ::Result<Option<(MessageHead<T>, usize)>>; | ||||
|  | ||||
| #[test] | ||||
| fn test_should_keep_alive() { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user