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
parent
396fe80e76
commit
a0a0fcdd9b
@@ -35,6 +35,7 @@ pub struct Body {
|
||||
enum Kind {
|
||||
Once(Option<Chunk>),
|
||||
Chan {
|
||||
content_length: Option<u64>,
|
||||
abort_rx: oneshot::Receiver<()>,
|
||||
rx: mpsc::Receiver<Result<Chunk, ::Error>>,
|
||||
},
|
||||
@@ -85,6 +86,11 @@ impl Body {
|
||||
/// Useful when wanting to stream chunks from another thread.
|
||||
#[inline]
|
||||
pub fn channel() -> (Sender, Body) {
|
||||
Self::new_channel(None)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn new_channel(content_length: Option<u64>) -> (Sender, Body) {
|
||||
let (tx, rx) = mpsc::channel(0);
|
||||
let (abort_tx, abort_rx) = oneshot::channel();
|
||||
|
||||
@@ -93,8 +99,9 @@ impl Body {
|
||||
tx: tx,
|
||||
};
|
||||
let rx = Body::new(Kind::Chan {
|
||||
abort_rx: abort_rx,
|
||||
rx: rx,
|
||||
content_length,
|
||||
abort_rx,
|
||||
rx,
|
||||
});
|
||||
|
||||
(tx, rx)
|
||||
@@ -188,13 +195,19 @@ impl Body {
|
||||
fn poll_inner(&mut self) -> Poll<Option<Chunk>, ::Error> {
|
||||
match self.kind {
|
||||
Kind::Once(ref mut val) => Ok(Async::Ready(val.take())),
|
||||
Kind::Chan { ref mut rx, ref mut abort_rx } => {
|
||||
Kind::Chan { content_length: ref mut len, ref mut rx, ref mut abort_rx } => {
|
||||
if let Ok(Async::Ready(())) = abort_rx.poll() {
|
||||
return Err(::Error::new_body_write("body write aborted"));
|
||||
}
|
||||
|
||||
match rx.poll().expect("mpsc cannot error") {
|
||||
Async::Ready(Some(Ok(chunk))) => Ok(Async::Ready(Some(chunk))),
|
||||
Async::Ready(Some(Ok(chunk))) => {
|
||||
if let Some(ref mut len) = *len {
|
||||
debug_assert!(*len >= chunk.len() as u64);
|
||||
*len = *len - chunk.len() as u64;
|
||||
}
|
||||
Ok(Async::Ready(Some(chunk)))
|
||||
}
|
||||
Async::Ready(Some(Err(err))) => Err(err),
|
||||
Async::Ready(None) => Ok(Async::Ready(None)),
|
||||
Async::NotReady => Ok(Async::NotReady),
|
||||
@@ -243,7 +256,7 @@ impl Payload for Body {
|
||||
fn is_end_stream(&self) -> bool {
|
||||
match self.kind {
|
||||
Kind::Once(ref val) => val.is_none(),
|
||||
Kind::Chan { .. } => false,
|
||||
Kind::Chan { content_length: len, .. } => len == Some(0),
|
||||
Kind::H2(ref h2) => h2.is_end_stream(),
|
||||
Kind::Wrapped(..) => false,
|
||||
}
|
||||
@@ -253,7 +266,7 @@ impl Payload for Body {
|
||||
match self.kind {
|
||||
Kind::Once(Some(ref val)) => Some(val.len() as u64),
|
||||
Kind::Once(None) => Some(0),
|
||||
Kind::Chan { .. } => None,
|
||||
Kind::Chan { content_length: len, .. } => len,
|
||||
Kind::H2(..) => None,
|
||||
Kind::Wrapped(..) => None,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user