Add support for gzip and brotli
Automatically sends the Accept-Encoding header on requests. Not runtime-configurable, only with Cargo features.
This commit is contained in:
committed by
Martin Algesten
parent
0f0dec5f32
commit
873e6066f3
@@ -18,6 +18,12 @@ use serde::de::DeserializeOwned;
|
||||
#[cfg(feature = "charset")]
|
||||
use encoding_rs::Encoding;
|
||||
|
||||
#[cfg(feature = "gzip")]
|
||||
use flate2::read::GzDecoder;
|
||||
|
||||
#[cfg(feature = "brotli")]
|
||||
use brotli_decompressor::Decompressor;
|
||||
|
||||
pub const DEFAULT_CONTENT_TYPE: &str = "text/plain";
|
||||
pub const DEFAULT_CHARACTER_SET: &str = "utf-8";
|
||||
const INTO_STRING_LIMIT: usize = 10 * 1_024 * 1_024;
|
||||
@@ -281,6 +287,11 @@ impl Response {
|
||||
.and_then(|l| l.parse::<usize>().ok())
|
||||
};
|
||||
|
||||
let compression = self
|
||||
.header("content-encoding")
|
||||
.map(Compression::from_header_value)
|
||||
.flatten();
|
||||
|
||||
let stream = self.stream;
|
||||
let unit = self.unit;
|
||||
if let Some(unit) = &unit {
|
||||
@@ -292,12 +303,17 @@ impl Response {
|
||||
let deadline = unit.as_ref().and_then(|u| u.deadline);
|
||||
let stream = DeadlineStream::new(*stream, deadline);
|
||||
|
||||
match (use_chunked, limit_bytes) {
|
||||
let body_reader: Box<dyn Read + Send> = match (use_chunked, limit_bytes) {
|
||||
(true, _) => Box::new(PoolReturnRead::new(unit, ChunkDecoder::new(stream))),
|
||||
(false, Some(len)) => {
|
||||
Box::new(PoolReturnRead::new(unit, LimitedRead::new(stream, len)))
|
||||
}
|
||||
(false, None) => Box::new(stream),
|
||||
};
|
||||
|
||||
match compression {
|
||||
None => body_reader,
|
||||
Some(c) => c.wrap_reader(body_reader),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,6 +524,38 @@ impl Response {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum Compression {
|
||||
#[cfg(feature = "brotli")]
|
||||
Brotli,
|
||||
#[cfg(feature = "gzip")]
|
||||
Gzip,
|
||||
}
|
||||
|
||||
impl Compression {
|
||||
/// Convert a string like "br" to an enum value
|
||||
fn from_header_value(value: &str) -> Option<Compression> {
|
||||
match value {
|
||||
#[cfg(feature = "brotli")]
|
||||
"br" => Some(Compression::Brotli),
|
||||
#[cfg(feature = "gzip")]
|
||||
"gzip" | "x-gzip" => Some(Compression::Gzip),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrap the raw reader with a decompressing reader
|
||||
#[allow(unused_variables)] // when no features enabled, reader is unused (unreachable)
|
||||
fn wrap_reader(self, reader: Box<dyn Read + Send>) -> Box<dyn Read + Send> {
|
||||
match self {
|
||||
#[cfg(feature = "brotli")]
|
||||
Compression::Brotli => Box::new(Decompressor::new(reader, 4096)),
|
||||
#[cfg(feature = "gzip")]
|
||||
Compression::Gzip => Box::new(GzDecoder::new(reader)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// parse a line like: HTTP/1.1 200 OK\r\n
|
||||
fn parse_status_line(line: &str) -> Result<(ResponseStatusIndex, u16), Error> {
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user