From d62f8c2bbd39d6cf5562c2f3c0aad32bad81d331 Mon Sep 17 00:00:00 2001 From: Arnaud de Bossoreille Date: Tue, 26 Mar 2019 21:09:08 +0100 Subject: [PATCH] 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. --- src/body.rs | 68 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/src/body.rs b/src/body.rs index 4933c51..17b7a0d 100644 --- a/src/body.rs +++ b/src/body.rs @@ -237,36 +237,56 @@ impl Sender { return Ok(().into()); } + // The input stream is read only if the buffer is empty so + // that there is only one read in the buffer at any time. + // + // We need to know whether there is any data to send before + // 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 { + buf.reserve(8192); + } + + match body.read(unsafe { buf.bytes_mut() }) { + Ok(0) => { + // The buffer was empty and nothing's left to + // read. Return. + return Ok(().into()); + } + Ok(n) => { + unsafe { buf.advance_mut(n); } + } + Err(e) => { + let ret = io::Error::new(e.kind(), e.to_string()); + tx + .take() + .expect("tx only taken on error") + .abort(); + 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)); - if buf.remaining_mut() == 0 { - buf.reserve(8192); - } - - match body.read(unsafe { buf.bytes_mut() }) { - Ok(0) => { - return Ok(().into()) - }, - Ok(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) => { - let ret = io::Error::new(e.kind(), e.to_string()); - tx - .take() - .expect("tx only taken on error") - .abort(); - return Err(::error::from(ret)); - } + 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)); } }) }