1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-07-01 00:44:26 +02:00

Add zstd ContentEncoding support (#2244)

Co-authored-by: Igor Aleksanov <popzxc@yandex.ru>
Co-authored-by: Rob Ede <robjtede@icloud.com>
This commit is contained in:
Arthur Le Moigne
2021-06-03 22:32:52 +02:00
committed by GitHub
parent 136dac1352
commit 3479293416
7 changed files with 189 additions and 1 deletions

View File

@ -12,6 +12,7 @@ use brotli2::write::BrotliDecoder;
use bytes::Bytes;
use flate2::write::{GzDecoder, ZlibDecoder};
use futures_core::{ready, Stream};
use zstd::stream::write::Decoder as ZstdDecoder;
use crate::{
encoding::Writer,
@ -45,6 +46,12 @@ where
ContentEncoding::Gzip => Some(ContentDecoder::Gzip(Box::new(
GzDecoder::new(Writer::new()),
))),
ContentEncoding::Zstd => Some(ContentDecoder::Zstd(Box::new(
ZstdDecoder::new(Writer::new()).expect(
"Failed to create zstd decoder. This is a bug. \
Please report it to the actix-web repository.",
),
))),
_ => None,
};
@ -144,6 +151,9 @@ enum ContentDecoder {
Deflate(Box<ZlibDecoder<Writer>>),
Gzip(Box<GzDecoder<Writer>>),
Br(Box<BrotliDecoder<Writer>>),
// 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`
Zstd(Box<ZstdDecoder<'static, Writer>>),
}
impl ContentDecoder {
@ -186,6 +196,18 @@ impl ContentDecoder {
}
Err(e) => Err(e),
},
ContentDecoder::Zstd(ref mut decoder) => match decoder.flush() {
Ok(_) => {
let b = decoder.get_mut().take();
if !b.is_empty() {
Ok(Some(b))
} else {
Ok(None)
}
}
Err(e) => Err(e),
},
}
}
@ -232,6 +254,20 @@ impl ContentDecoder {
}
Err(e) => Err(e),
},
ContentDecoder::Zstd(ref mut decoder) => match decoder.write_all(&data) {
Ok(_) => {
decoder.flush()?;
let b = decoder.get_mut().take();
if !b.is_empty() {
Ok(Some(b))
} else {
Ok(None)
}
}
Err(e) => Err(e),
},
}
}
}

View File

@ -15,6 +15,7 @@ use derive_more::Display;
use flate2::write::{GzEncoder, ZlibEncoder};
use futures_core::ready;
use pin_project::pin_project;
use zstd::stream::write::Encoder as ZstdEncoder;
use crate::{
body::{Body, BodySize, BoxAnyBody, MessageBody, ResponseBody},
@ -237,6 +238,9 @@ enum ContentEncoder {
Deflate(ZlibEncoder<Writer>),
Gzip(GzEncoder<Writer>),
Br(BrotliEncoder<Writer>),
// We need explicit 'static lifetime here because ZstdEncoder need lifetime
// argument, and we use `spawn_blocking` in `Encoder::poll_next` that require `FnOnce() -> R + Send + 'static`
Zstd(ZstdEncoder<'static, Writer>),
}
impl ContentEncoder {
@ -253,6 +257,10 @@ impl ContentEncoder {
ContentEncoding::Br => {
Some(ContentEncoder::Br(BrotliEncoder::new(Writer::new(), 3)))
}
ContentEncoding::Zstd => {
let encoder = ZstdEncoder::new(Writer::new(), 3).ok()?;
Some(ContentEncoder::Zstd(encoder))
}
_ => None,
}
}
@ -263,6 +271,7 @@ impl ContentEncoder {
ContentEncoder::Br(ref mut encoder) => encoder.get_mut().take(),
ContentEncoder::Deflate(ref mut encoder) => encoder.get_mut().take(),
ContentEncoder::Gzip(ref mut encoder) => encoder.get_mut().take(),
ContentEncoder::Zstd(ref mut encoder) => encoder.get_mut().take(),
}
}
@ -280,6 +289,10 @@ impl ContentEncoder {
Ok(writer) => Ok(writer.buf.freeze()),
Err(err) => Err(err),
},
ContentEncoder::Zstd(encoder) => match encoder.finish() {
Ok(writer) => Ok(writer.buf.freeze()),
Err(err) => Err(err),
},
}
}
@ -306,6 +319,13 @@ impl ContentEncoder {
Err(err)
}
},
ContentEncoder::Zstd(ref mut encoder) => match encoder.write_all(data) {
Ok(_) => Ok(()),
Err(err) => {
trace!("Error decoding ztsd encoding: {}", err);
Err(err)
}
},
}
}
}