use std::io;
use flate2::read::MultiGzDecoder;
use crate::Error;
use crate::error::is_wrapped_ureq_error;
pub(crate) struct GzipDecoder<R>(MultiGzDecoder<R>);
impl<R: io::Read> GzipDecoder<R> {
pub fn new(reader: R) -> Self {
GzipDecoder(MultiGzDecoder::new(reader))
}
}
impl<R: io::Read> io::Read for GzipDecoder<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf).map_err(|e| {
if is_wrapped_ureq_error(&e) {
e
} else {
Error::Decompress("gzip", e).into_io()
}
})
}
}
#[cfg(all(test, feature = "_test"))]
mod test {
use crate::Agent;
use crate::test::init_test_log;
use crate::transport::set_handler;
#[test]
fn gz_internal_length() {
init_test_log();
let gz_body = vec![
b'E', b'\r', b'\n', 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xCB, 0x48, 0xCD, 0xC9,
b'\r', b'\n', b'E', b'\r', b'\n', 0xC9, 0x57, 0x28, 0xCF, 0x2F, 0xCA, 0x49, 0x51, 0xC8, 0x18, 0xBC, 0x6C, 0x00, 0xA5,
b'\r', b'\n', b'7', b'\r', b'\n', 0x5C, 0x7C, 0xEF, 0xA7, 0x00, 0x00, 0x00, b'\r', b'\n', b'0', b'\r', b'\n', b'\r', b'\n', ];
let agent = Agent::new_with_defaults();
assert_eq!(agent.pool_count(), 0);
set_handler(
"/gz_body",
200,
&[
("transfer-encoding", "chunked"),
("content-encoding", "gzip"),
],
&gz_body,
);
let mut res = agent.get("https://example.test/gz_body").call().unwrap();
res.body_mut().read_to_string().unwrap();
assert_eq!(agent.pool_count(), 1);
}
fn gzip_compress(data: &[u8]) -> Vec<u8> {
use flate2::Compression;
use flate2::write::GzEncoder;
use std::io::Write;
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
encoder.write_all(data).unwrap();
encoder.finish().unwrap()
}
#[test]
fn gz_strips_content_encoding_and_content_length() {
init_test_log();
let original = b"{\"hello\":\"world\"}";
let compressed = gzip_compress(original);
let compressed_len = compressed.len().to_string();
set_handler(
"/gz_strip",
200,
&[
("content-encoding", "gzip"),
("content-length", &compressed_len),
("content-type", "application/json"),
],
&compressed,
);
let mut res = crate::get("https://my.test/gz_strip").call().unwrap();
assert!(
res.headers().get("content-encoding").is_none(),
"Content-Encoding should be stripped after gzip decompression, got: {:?}",
res.headers().get("content-encoding"),
);
assert!(
res.headers().get("content-length").is_none(),
"Content-Length header should be stripped after gzip decompression, got: {:?}",
res.headers().get("content-length"),
);
assert!(
res.body().content_length().is_none(),
"Body::content_length() should return None after gzip decompression, got: {:?}",
res.body().content_length(),
);
assert_eq!(
res.headers().get("content-type").unwrap().to_str().unwrap(),
"application/json",
);
let body = res.body_mut().read_to_string().unwrap();
assert_eq!(body, "{\"hello\":\"world\"}");
}
}