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`. |         // To be safe, this memory could be zeroed before passing to `flate2`. | ||||||
|         // Otherwise we might need to deal with the case where `flate2` panics. |         // Otherwise we might need to deal with the case where `flate2` panics. | ||||||
|         let read = { |         let read = try_io!(self.inner.read(unsafe { self.buf.bytes_mut() })); | ||||||
|             let mut buf = unsafe { self.buf.bytes_mut() }; |  | ||||||
|             self.inner.read(&mut buf) |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         match read { |         if read == 0 { | ||||||
|             Ok(read) if read == 0 => match self.inner.get_mut().read(&mut [0]) { |             // If GzDecoder reports EOF, it doesn't necessarily mean the | ||||||
|                 Ok(0) => Ok(Async::Ready(None)), |             // underlying stream reached EOF (such as the `0\r\n\r\n` | ||||||
|                 Ok(_) => Err(error::from(io::Error::new(io::ErrorKind::InvalidData, "Unexpected Data"))), |             // header meaning a chunked transfer has completed). If it | ||||||
|                 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(Async::NotReady), |             // isn't polled till EOF, the connection may not be able | ||||||
|                 Err(e) => Err(error::from(e)) |             // to be re-used. | ||||||
|             }, |             // | ||||||
|             Ok(read) => { |             // See https://github.com/seanmonstar/reqwest/issues/508. | ||||||
|                 unsafe { self.buf.advance_mut(read) }; |             let inner_read = try_io!(self.inner.get_mut().read(&mut [0])); | ||||||
|                 let chunk = Chunk::from_chunk(self.buf.split_to(read).freeze()); |             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))) |             Ok(Async::Ready(Some(chunk))) | ||||||
|             }, |  | ||||||
|             Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { |  | ||||||
|                 Ok(Async::NotReady) |  | ||||||
|             }, |  | ||||||
|             Err(e) => Err(error::from(e)) |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										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_ { | macro_rules! try_ { | ||||||
|     ($e:expr) => ( |     ($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 { | pub(crate) fn loop_detected(url: Url) -> Error { | ||||||
|     Error::new(Kind::RedirectLoop, Some(url)) |     Error::new(Kind::RedirectLoop, Some(url)) | ||||||
| } | } | ||||||
| @@ -594,4 +620,18 @@ mod tests { | |||||||
|         use std::mem::size_of; |         use std::mem::size_of; | ||||||
|         assert_eq!(size_of::<Error>(), size_of::<usize>()); |         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