From 6beb7242dade01f826da9aeda9b2f574e6dc9830 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Wed, 22 Dec 2021 09:27:54 +0000 Subject: [PATCH] partially migrate to brotli crate --- Cargo.toml | 4 +++- actix-http/Cargo.toml | 4 ++-- actix-http/src/encoding/decoder.rs | 11 ++++------- actix-http/src/encoding/encoder.rs | 31 ++++++++++++++++++++---------- awc/Cargo.toml | 2 +- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d15f26172..c4f026566 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,7 +109,7 @@ url = "2.1" actix-test = { version = "0.1.0-beta.9", features = ["openssl", "rustls"] } awc = { version = "3.0.0-beta.14", features = ["openssl"] } -brotli2 = "0.3.2" +brotli = "3.3" criterion = { version = "0.3", features = ["html_reports"] } env_logger = "0.9" flate2 = "1.0.13" @@ -142,6 +142,8 @@ actix-web-actors = { path = "actix-web-actors" } actix-web-codegen = { path = "actix-web-codegen" } awc = { path = "awc" } +brotli = { path = "../rust-brotli" } + # uncomment for quick testing against local actix-net repo # actix-service = { path = "../actix-net/actix-service" } # actix-macros = { path = "../actix-net/actix-macros" } diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 2958a1c77..eaff0cb43 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -33,7 +33,7 @@ openssl = ["actix-tls/accept", "actix-tls/openssl"] rustls = ["actix-tls/accept", "actix-tls/rustls"] # enable compression support -compress-brotli = ["brotli2", "__compress"] +compress-brotli = ["brotli", "__compress"] compress-gzip = ["flate2", "__compress"] compress-zstd = ["zstd", "__compress"] @@ -75,7 +75,7 @@ smallvec = "1.6.1" actix-tls = { version = "3.0.0-rc.1", default-features = false, optional = true } # compression -brotli2 = { version="0.3.2", optional = true } +brotli = { version = "3.3", optional = true } flate2 = { version = "1.0.13", optional = true } zstd = { version = "0.9", optional = true } diff --git a/actix-http/src/encoding/decoder.rs b/actix-http/src/encoding/decoder.rs index a46e330c9..03c1944b6 100644 --- a/actix-http/src/encoding/decoder.rs +++ b/actix-http/src/encoding/decoder.rs @@ -11,9 +11,6 @@ use actix_rt::task::{spawn_blocking, JoinHandle}; use bytes::Bytes; use futures_core::{ready, Stream}; -#[cfg(feature = "compress-brotli")] -use brotli2::write::BrotliDecoder; - #[cfg(feature = "compress-gzip")] use flate2::write::{GzDecoder, ZlibDecoder}; @@ -44,9 +41,9 @@ where pub fn new(stream: S, encoding: ContentEncoding) -> Decoder { let decoder = match encoding { #[cfg(feature = "compress-brotli")] - ContentEncoding::Br => Some(ContentDecoder::Br(Box::new(BrotliDecoder::new( - Writer::new(), - )))), + ContentEncoding::Br => Some(ContentDecoder::Br(Box::new( + brotli::DecompressorWriter::new(Writer::new(), 8_096), + ))), #[cfg(feature = "compress-gzip")] ContentEncoding::Deflate => Some(ContentDecoder::Deflate(Box::new( ZlibDecoder::new(Writer::new()), @@ -160,7 +157,7 @@ enum ContentDecoder { #[cfg(feature = "compress-gzip")] Gzip(Box>), #[cfg(feature = "compress-brotli")] - Br(Box>), + Br(Box>), // We need explicit 'static lifetime here because ZstdDecoder need lifetime // argument, and we use `spawn_blocking` in `Decoder::poll_next` that require `FnOnce() -> R + Send + 'static` #[cfg(feature = "compress-zstd")] diff --git a/actix-http/src/encoding/encoder.rs b/actix-http/src/encoding/encoder.rs index b565bb2b5..0008a269e 100644 --- a/actix-http/src/encoding/encoder.rs +++ b/actix-http/src/encoding/encoder.rs @@ -4,6 +4,7 @@ use std::{ error::Error as StdError, future::Future, io::{self, Write as _}, + mem, pin::Pin, task::{Context, Poll}, }; @@ -14,9 +15,6 @@ use derive_more::Display; use futures_core::ready; use pin_project_lite::pin_project; -#[cfg(feature = "compress-brotli")] -use brotli2::write::BrotliEncoder; - #[cfg(feature = "compress-gzip")] use flate2::write::{GzEncoder, ZlibEncoder}; @@ -268,7 +266,7 @@ enum ContentEncoder { Gzip(GzEncoder), #[cfg(feature = "compress-brotli")] - Br(BrotliEncoder), + Br(Box>), // Wwe need explicit 'static lifetime here because ZstdEncoder needs a lifetime argument and we // use `spawn_blocking` in `Encoder::poll_next` that requires `FnOnce() -> R + Send + 'static`. @@ -292,9 +290,7 @@ impl ContentEncoder { ))), #[cfg(feature = "compress-brotli")] - ContentEncoding::Br => { - Some(ContentEncoder::Br(BrotliEncoder::new(Writer::new(), 3))) - } + ContentEncoding::Br => Some(ContentEncoder::Br(new_brotli_compressor())), #[cfg(feature = "compress-zstd")] ContentEncoding::Zstd => { @@ -310,7 +306,12 @@ impl ContentEncoder { pub(crate) fn take(&mut self) -> Bytes { match *self { #[cfg(feature = "compress-brotli")] - ContentEncoder::Br(ref mut encoder) => encoder.get_mut().take(), + // ContentEncoder::Br(ref mut encoder) => encoder.get_mut().take(), + ContentEncoder::Br(ref mut encoder) => { + // `CompressorWriter` has no `get_mut` (yet) + let prev = mem::replace(encoder, new_brotli_compressor()); + prev.into_inner().buf.freeze() + } #[cfg(feature = "compress-gzip")] ContentEncoder::Deflate(ref mut encoder) => encoder.get_mut().take(), @@ -326,8 +327,8 @@ impl ContentEncoder { fn finish(self) -> Result { match self { #[cfg(feature = "compress-brotli")] - ContentEncoder::Br(encoder) => match encoder.finish() { - Ok(writer) => Ok(writer.buf.freeze()), + ContentEncoder::Br(mut encoder) => match encoder.flush() { + Ok(()) => Ok(encoder.into_inner().buf.freeze()), Err(err) => Err(err), }, @@ -392,6 +393,16 @@ impl ContentEncoder { } } +#[cfg(feature = "compress-brotli")] +fn new_brotli_compressor() -> Box> { + Box::new(brotli::CompressorWriter::new( + Writer::new(), + 8 * 1024, // 32 KiB buffer + 3, // BROTLI_PARAM_QUALITY + 22, // BROTLI_PARAM_LGWIN + )) +} + #[derive(Debug, Display)] #[non_exhaustive] pub enum EncoderError { diff --git a/awc/Cargo.toml b/awc/Cargo.toml index 4b29aac16..ab1162778 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -101,7 +101,7 @@ actix-tls = { version = "3.0.0-rc.1", features = ["openssl", "rustls"] } actix-utils = "3.0.0" actix-web = { version = "4.0.0-beta.15", features = ["openssl"] } -brotli2 = "0.3.2" +brotli = "3.3" env_logger = "0.9" flate2 = "1.0.13" futures-util = { version = "0.3.7", default-features = false }