1use futures_core::Stream;
4use http::{header, Response, StatusCode, Version};
5
6use super::{
7 coder::{Coder, FeaturedCode},
8 coding::ContentEncoding,
9};
10
11pub fn encoder<S, T, E>(response: Response<S>, mut encoding: ContentEncoding) -> Response<Coder<S, FeaturedCode>>
13where
14 S: Stream<Item = Result<T, E>>,
15 T: AsRef<[u8]> + 'static,
16{
17 #[allow(unused_mut)]
18 let (mut parts, body) = response.into_parts();
19
20 if parts.headers.contains_key(&header::CONTENT_ENCODING)
21 || parts.status == StatusCode::SWITCHING_PROTOCOLS
22 || parts.status == StatusCode::NO_CONTENT
23 {
24 encoding = ContentEncoding::NoOp
25 }
26
27 let encoder = {
28 match encoding {
29 #[cfg(feature = "de")]
30 ContentEncoding::Deflate => {
31 update_header(&mut parts.headers, "deflate", parts.version);
32 FeaturedCode::EncodeDe(super::deflate::Encoder::new(
33 super::writer::BytesMutWriter::new(),
34 flate2::Compression::fast(),
35 ))
36 }
37 #[cfg(feature = "gz")]
38 ContentEncoding::Gzip => {
39 update_header(&mut parts.headers, "gzip", parts.version);
40 FeaturedCode::EncodeGz(super::gzip::Encoder::new(
41 super::writer::BytesMutWriter::new(),
42 flate2::Compression::fast(),
43 ))
44 }
45 #[cfg(feature = "br")]
46 ContentEncoding::Br => {
47 update_header(&mut parts.headers, "br", parts.version);
48 FeaturedCode::EncodeBr(super::brotli::Encoder::new(3))
49 }
50 _ => FeaturedCode::default(),
51 }
52 };
53
54 let body = Coder::new(body, encoder);
55 Response::from_parts(parts, body)
56}
57
58#[cfg(any(feature = "br", feature = "gz", feature = "de"))]
59fn update_header(headers: &mut header::HeaderMap, value: &'static str, version: Version) {
60 headers.insert(header::CONTENT_ENCODING, header::HeaderValue::from_static(value));
61 headers.remove(header::CONTENT_LENGTH);
62
63 if version < Version::HTTP_2 {
66 headers.insert(header::TRANSFER_ENCODING, header::HeaderValue::from_static("chunked"));
67 }
68}