feat(body): make Body know about incoming Content-Length
				
					
				
			When getting a `Body` from hyper, such as in a client response, the method `Body::content_length()` now returns a value if the header was present. Closes #1545
This commit is contained in:
		
				
					committed by
					
						 Sean McArthur
						Sean McArthur
					
				
			
			
				
	
			
			
			
						parent
						
							396fe80e76
						
					
				
				
					commit
					a0a0fcdd9b
				
			| @@ -114,7 +114,7 @@ where I: AsyncRead + AsyncWrite, | ||||
|         read_buf.len() >= 24 && read_buf[..24] == *H2_PREFACE | ||||
|     } | ||||
|  | ||||
|     pub fn read_head(&mut self) -> Poll<Option<(MessageHead<T::Incoming>, bool)>, ::Error> { | ||||
|     pub fn read_head(&mut self) -> Poll<Option<(MessageHead<T::Incoming>, Option<BodyLength>)>, ::Error> { | ||||
|         debug_assert!(self.can_read_head()); | ||||
|         trace!("Conn::read_head"); | ||||
|  | ||||
| @@ -162,7 +162,6 @@ where I: AsyncRead + AsyncWrite, | ||||
|                     continue; | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             debug!("incoming body is {}", decoder); | ||||
|  | ||||
|             self.state.busy(); | ||||
| @@ -172,20 +171,23 @@ where I: AsyncRead + AsyncWrite, | ||||
|             } | ||||
|             let wants_keep_alive = msg.keep_alive; | ||||
|             self.state.keep_alive &= wants_keep_alive; | ||||
|             let (body, reading) = if decoder.is_eof() { | ||||
|                 (false, Reading::KeepAlive) | ||||
|             } else { | ||||
|                 (true, Reading::Body(decoder)) | ||||
|             }; | ||||
|  | ||||
|             let content_length = decoder.content_length(); | ||||
|  | ||||
|             if let Reading::Closed = self.state.reading { | ||||
|                 // actually want an `if not let ...` | ||||
|             } else { | ||||
|                 self.state.reading = reading; | ||||
|                 self.state.reading = if content_length.is_none() { | ||||
|                     Reading::KeepAlive | ||||
|                 } else { | ||||
|                     Reading::Body(decoder) | ||||
|                 }; | ||||
|             } | ||||
|             if !body { | ||||
|             if content_length.is_none() { | ||||
|                 self.try_keep_alive(); | ||||
|             } | ||||
|             return Ok(Async::Ready(Some((head, body)))); | ||||
|  | ||||
|             return Ok(Async::Ready(Some((head, content_length)))); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ use futures::{Async, Poll}; | ||||
| use bytes::Bytes; | ||||
|  | ||||
| use super::io::MemRead; | ||||
| use super::BodyLength; | ||||
|  | ||||
| use self::Kind::{Length, Chunked, Eof}; | ||||
|  | ||||
| @@ -84,6 +85,16 @@ impl Decoder { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn content_length(&self) -> Option<BodyLength> { | ||||
|         match self.kind { | ||||
|             Length(0) | | ||||
|             Chunked(ChunkedState::End, _) | | ||||
|             Eof(true) => None, | ||||
|             Length(len) => Some(BodyLength::Known(len)), | ||||
|             _ => Some(BodyLength::Unknown), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn decode<R: MemRead>(&mut self, body: &mut R) -> Poll<Bytes, io::Error> { | ||||
|         trace!("decode; state={:?}", self.kind); | ||||
|         match self.kind { | ||||
|   | ||||
| @@ -190,9 +190,14 @@ where | ||||
|         } | ||||
|         // dispatch is ready for a message, try to read one | ||||
|         match self.conn.read_head() { | ||||
|             Ok(Async::Ready(Some((head, has_body)))) => { | ||||
|                 let body = if has_body { | ||||
|                     let (mut tx, rx) = Body::channel(); | ||||
|             Ok(Async::Ready(Some((head, body_len)))) => { | ||||
|                 let body = if let Some(body_len) = body_len { | ||||
|                     let (mut tx, rx) = | ||||
|                         Body::new_channel(if let BodyLength::Known(len) = body_len { | ||||
|                             Some(len) | ||||
|                         } else { | ||||
|                             None | ||||
|                         }); | ||||
|                     let _ = tx.poll_ready(); // register this task if rx is dropped | ||||
|                     self.body_tx = Some(tx); | ||||
|                     rx | ||||
| @@ -201,7 +206,7 @@ where | ||||
|                 }; | ||||
|                 self.dispatch.recv_msg(Ok((head, body)))?; | ||||
|                 Ok(Async::Ready(())) | ||||
|             }, | ||||
|             } | ||||
|             Ok(Async::Ready(None)) => { | ||||
|                 // read eof, conn will start to shutdown automatically | ||||
|                 Ok(Async::Ready(())) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user