Body: don't call poll_ready on tx when 0 bytes remaining. (#479)
Some web servers (if IIS is a web server) may close their request stream early when they consider the input is complete. That leads to poll_ready returning an error of kind "Closed" which is legitimate as the receiver disappeared. So this change ignores the case when the body has been fully transmitted.
This commit is contained in:
committed by
Sean McArthur
parent
f77ec53e59
commit
d62f8c2bbd
46
src/body.rs
46
src/body.rs
@@ -237,27 +237,32 @@ impl Sender {
|
|||||||
return Ok(().into());
|
return Ok(().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
try_ready!(tx
|
// The input stream is read only if the buffer is empty so
|
||||||
.as_mut()
|
// that there is only one read in the buffer at any time.
|
||||||
.expect("tx only taken on error")
|
//
|
||||||
.poll_ready()
|
// We need to know whether there is any data to send before
|
||||||
.map_err(::error::from));
|
// we check the transmission channel (with poll_ready below)
|
||||||
|
// because somestimes the receiver disappears as soon as is
|
||||||
|
// considers the data is completely transmitted, which may
|
||||||
|
// be true.
|
||||||
|
//
|
||||||
|
// The use case is a web server that closes its
|
||||||
|
// input stream as soon as the data received is valid JSON.
|
||||||
|
// This behaviour is questionable, but it exists and the
|
||||||
|
// fact is that there is actually no remaining data to read.
|
||||||
|
if buf.len() == 0 {
|
||||||
if buf.remaining_mut() == 0 {
|
if buf.remaining_mut() == 0 {
|
||||||
buf.reserve(8192);
|
buf.reserve(8192);
|
||||||
}
|
}
|
||||||
|
|
||||||
match body.read(unsafe { buf.bytes_mut() }) {
|
match body.read(unsafe { buf.bytes_mut() }) {
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
return Ok(().into())
|
// The buffer was empty and nothing's left to
|
||||||
},
|
// read. Return.
|
||||||
|
return Ok(().into());
|
||||||
|
}
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
unsafe { buf.advance_mut(n); }
|
unsafe { buf.advance_mut(n); }
|
||||||
written += n as u64;
|
|
||||||
let tx = tx.as_mut().expect("tx only taken on error");
|
|
||||||
if let Err(_) = tx.send_data(buf.take().freeze().into()) {
|
|
||||||
return Err(::error::timedout(None));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let ret = io::Error::new(e.kind(), e.to_string());
|
let ret = io::Error::new(e.kind(), e.to_string());
|
||||||
@@ -268,6 +273,21 @@ impl Sender {
|
|||||||
return Err(::error::from(ret));
|
return Err(::error::from(ret));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The only way to get here is when the buffer is not empty.
|
||||||
|
// We can check the transmission channel
|
||||||
|
try_ready!(tx
|
||||||
|
.as_mut()
|
||||||
|
.expect("tx only taken on error")
|
||||||
|
.poll_ready()
|
||||||
|
.map_err(::error::from));
|
||||||
|
|
||||||
|
written += buf.len() as u64;
|
||||||
|
let tx = tx.as_mut().expect("tx only taken on error");
|
||||||
|
if let Err(_) = tx.send_data(buf.take().freeze().into()) {
|
||||||
|
return Err(::error::timedout(None));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user