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
						Sean McArthur
					
				
			
			
				
	
			
			
			
						parent
						
							f77ec53e59
						
					
				
				
					commit
					d62f8c2bbd
				
			
							
								
								
									
										46
									
								
								src/body.rs
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								src/body.rs
									
									
									
									
									
								
							| @@ -237,27 +237,32 @@ impl Sender { | ||||
|                 return Ok(().into()); | ||||
|             } | ||||
|  | ||||
|             try_ready!(tx | ||||
|                 .as_mut() | ||||
|                 .expect("tx only taken on error") | ||||
|                 .poll_ready() | ||||
|                 .map_err(::error::from)); | ||||
|  | ||||
|             // 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) => { | ||||
|                     return Ok(().into()) | ||||
|                 }, | ||||
|                         // The buffer was empty and nothing's left to | ||||
|                         // read. Return. | ||||
|                         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()); | ||||
| @@ -268,6 +273,21 @@ impl Sender { | ||||
|                         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