improve error messages from gzip decoder
This commit is contained in:
		| @@ -217,28 +217,30 @@ impl Stream for Gzip { | ||||
|         // | ||||
|         // To be safe, this memory could be zeroed before passing to `flate2`. | ||||
|         // Otherwise we might need to deal with the case where `flate2` panics. | ||||
|         let read = { | ||||
|             let mut buf = unsafe { self.buf.bytes_mut() }; | ||||
|             self.inner.read(&mut buf) | ||||
|         }; | ||||
|         let read = try_io!(self.inner.read(unsafe { self.buf.bytes_mut() })); | ||||
|  | ||||
|         match read { | ||||
|             Ok(read) if read == 0 => match self.inner.get_mut().read(&mut [0]) { | ||||
|                 Ok(0) => Ok(Async::Ready(None)), | ||||
|                 Ok(_) => Err(error::from(io::Error::new(io::ErrorKind::InvalidData, "Unexpected Data"))), | ||||
|                 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(Async::NotReady), | ||||
|                 Err(e) => Err(error::from(e)) | ||||
|             }, | ||||
|             Ok(read) => { | ||||
|                 unsafe { self.buf.advance_mut(read) }; | ||||
|                 let chunk = Chunk::from_chunk(self.buf.split_to(read).freeze()); | ||||
|         if read == 0 { | ||||
|             // If GzDecoder reports EOF, it doesn't necessarily mean the | ||||
|             // underlying stream reached EOF (such as the `0\r\n\r\n` | ||||
|             // header meaning a chunked transfer has completed). If it | ||||
|             // isn't polled till EOF, the connection may not be able | ||||
|             // to be re-used. | ||||
|             // | ||||
|             // See https://github.com/seanmonstar/reqwest/issues/508. | ||||
|             let inner_read = try_io!(self.inner.get_mut().read(&mut [0])); | ||||
|             if inner_read == 0 { | ||||
|                 Ok(Async::Ready(None)) | ||||
|             } else { | ||||
|                 Err(error::from(io::Error::new( | ||||
|                     io::ErrorKind::InvalidData, | ||||
|                     "unexpected data after gzip decoder signaled end-of-file", | ||||
|                 ))) | ||||
|             } | ||||
|         } else { | ||||
|             unsafe { self.buf.advance_mut(read) }; | ||||
|             let chunk = Chunk::from_chunk(self.buf.split_to(read).freeze()); | ||||
|  | ||||
|                 Ok(Async::Ready(Some(chunk))) | ||||
|             }, | ||||
|             Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { | ||||
|                 Ok(Async::NotReady) | ||||
|             }, | ||||
|             Err(e) => Err(error::from(e)) | ||||
|             Ok(Async::Ready(Some(chunk))) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										40
									
								
								src/error.rs
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								src/error.rs
									
									
									
									
									
								
							| @@ -484,6 +484,18 @@ pub(crate) fn into_io(e: Error) -> io::Error { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub(crate) fn from_io(e: io::Error) -> Error { | ||||
|     if e.get_ref().map(|r| r.is::<Error>()).unwrap_or(false) { | ||||
|         *e | ||||
|             .into_inner() | ||||
|             .expect("io::Error::get_ref was Some(_)") | ||||
|             .downcast::<Error>() | ||||
|             .expect("StdError::is() was true") | ||||
|     } else { | ||||
|         from(e) | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| macro_rules! try_ { | ||||
|     ($e:expr) => ( | ||||
| @@ -504,6 +516,20 @@ macro_rules! try_ { | ||||
|     ) | ||||
| } | ||||
|  | ||||
| macro_rules! try_io { | ||||
|     ($e:expr) => ( | ||||
|         match $e { | ||||
|             Ok(v) => v, | ||||
|             Err(ref err) if err.kind() == ::std::io::ErrorKind::WouldBlock => { | ||||
|                 return Ok(::futures::Async::NotReady); | ||||
|             } | ||||
|             Err(err) => { | ||||
|                 return Err(::error::from_io(err)); | ||||
|             } | ||||
|         } | ||||
|     ) | ||||
| } | ||||
|  | ||||
| pub(crate) fn loop_detected(url: Url) -> Error { | ||||
|     Error::new(Kind::RedirectLoop, Some(url)) | ||||
| } | ||||
| @@ -594,4 +620,18 @@ mod tests { | ||||
|         use std::mem::size_of; | ||||
|         assert_eq!(size_of::<Error>(), size_of::<usize>()); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn roundtrip_io_error() { | ||||
|         let orig = unknown_proxy_scheme(); | ||||
|         // Convert reqwest::Error into an io::Error... | ||||
|         let io = into_io(orig); | ||||
|         // Convert that io::Error back into a reqwest::Error... | ||||
|         let err = from_io(io); | ||||
|         // It should have pulled out the original, not nested it... | ||||
|         match err.inner.kind { | ||||
|             Kind::UnknownProxyScheme => (), | ||||
|             _ => panic!("{:?}", err), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user