mirror of
https://github.com/OISF/suricata.git
synced 2026-06-11 01:42:01 -04:00
http1: brotli decompression
Ticket: 5692 http2 already used brotli crate for decompression
This commit is contained in:
parent
128ee9ba46
commit
a1ff7424e4
5 changed files with 52 additions and 0 deletions
|
|
@ -1585,6 +1585,7 @@ name = "suricata-htp"
|
|||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"brotli",
|
||||
"bstr",
|
||||
"cdylib-link-lines",
|
||||
"flate2",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ libc = "0.2"
|
|||
nom = "7.1.1"
|
||||
lzma-rs = { version = "0.2.0", features = ["stream"] }
|
||||
flate2 = { version = "~1.0.35", features = ["zlib-default"], default-features = false }
|
||||
brotli = "~3.4.0"
|
||||
lazy_static = "1.4.0"
|
||||
time = "=0.3.36"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use brotli;
|
||||
use std::{
|
||||
io::{Cursor, Write},
|
||||
time::Instant,
|
||||
|
|
@ -194,6 +195,8 @@ pub(crate) enum HtpContentEncoding {
|
|||
Zlib,
|
||||
/// LZMA compression.
|
||||
Lzma,
|
||||
/// Brotli compression.
|
||||
Brotli,
|
||||
}
|
||||
|
||||
/// The outer decompressor tracks the number of callbacks and time spent
|
||||
|
|
@ -240,6 +243,7 @@ impl Decompressor {
|
|||
HtpContentEncoding::Gzip
|
||||
| HtpContentEncoding::Deflate
|
||||
| HtpContentEncoding::Zlib
|
||||
| HtpContentEncoding::Brotli
|
||||
| HtpContentEncoding::Lzma => Ok(Decompressor::new(Box::new(InnerDecompressor::new(
|
||||
encoding, self.inner, options,
|
||||
)?))),
|
||||
|
|
@ -660,6 +664,35 @@ impl BufWriter for LzmaBufWriter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Simple wrapper around an lzma implementation
|
||||
struct BrotliBufWriter(brotli::DecompressorWriter<Cursor<Box<[u8]>>>);
|
||||
|
||||
impl Write for BrotliBufWriter {
|
||||
fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
|
||||
self.0.write(data)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.0.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl BufWriter for BrotliBufWriter {
|
||||
fn get_mut(&mut self) -> Option<&mut Cursor<Box<[u8]>>> {
|
||||
Some(self.0.get_mut())
|
||||
}
|
||||
|
||||
fn finish(self: Box<Self>) -> std::io::Result<Cursor<Box<[u8]>>> {
|
||||
self.0
|
||||
.into_inner()
|
||||
.map_err(|_e| std::io::Error::new(std::io::ErrorKind::Other, "brotli"))
|
||||
}
|
||||
|
||||
fn try_finish(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Structure that represents each decompressor in the chain.
|
||||
struct InnerDecompressor {
|
||||
/// Decoder implementation that will write to a temporary buffer.
|
||||
|
|
@ -693,6 +726,13 @@ impl InnerDecompressor {
|
|||
Box::new(ZlibBufWriter(flate2::write::ZlibDecoder::new(buf))),
|
||||
false,
|
||||
)),
|
||||
HtpContentEncoding::Brotli => Ok((
|
||||
Box::new(BrotliBufWriter(brotli::DecompressorWriter::new(
|
||||
buf,
|
||||
ENCODING_CHUNK_SIZE,
|
||||
))),
|
||||
false,
|
||||
)),
|
||||
HtpContentEncoding::Lzma => {
|
||||
if let Some(options) = options.lzma {
|
||||
Ok((
|
||||
|
|
@ -896,7 +936,9 @@ impl Decompress for InnerDecompressor {
|
|||
HtpContentEncoding::Gzip => HtpContentEncoding::Deflate,
|
||||
HtpContentEncoding::Deflate => HtpContentEncoding::Zlib,
|
||||
HtpContentEncoding::Zlib => HtpContentEncoding::Gzip,
|
||||
// For other encodings, we retry with deflate, zlib and gzip
|
||||
HtpContentEncoding::Lzma => HtpContentEncoding::Deflate,
|
||||
HtpContentEncoding::Brotli => HtpContentEncoding::Deflate,
|
||||
HtpContentEncoding::None => {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
|
|
|
|||
|
|
@ -1043,6 +1043,7 @@ impl ConnectionParser {
|
|||
HtpContentEncoding::Gzip
|
||||
| HtpContentEncoding::Deflate
|
||||
| HtpContentEncoding::Zlib
|
||||
| HtpContentEncoding::Brotli
|
||||
| HtpContentEncoding::Lzma => {
|
||||
// Send data buffer to the decompressor if it exists
|
||||
if req.request_decompressor.is_none() && data.is_none() {
|
||||
|
|
@ -1125,6 +1126,8 @@ impl ConnectionParser {
|
|||
HtpContentEncoding::Gzip
|
||||
} else if ce.cmp_nocase_nozero(b"deflate") || ce.cmp_nocase_nozero(b"x-deflate") {
|
||||
HtpContentEncoding::Deflate
|
||||
} else if ce.cmp_nocase_nozero(b"br") {
|
||||
HtpContentEncoding::Brotli
|
||||
} else if ce.cmp_nocase_nozero(b"lzma") {
|
||||
HtpContentEncoding::Lzma
|
||||
} else if ce.cmp_nocase_nozero(b"inflate") || ce.cmp_nocase_nozero(b"none") {
|
||||
|
|
@ -1154,6 +1157,7 @@ impl ConnectionParser {
|
|||
HtpContentEncoding::Gzip
|
||||
| HtpContentEncoding::Deflate
|
||||
| HtpContentEncoding::Zlib
|
||||
| HtpContentEncoding::Brotli
|
||||
| HtpContentEncoding::Lzma => {
|
||||
self.request_prepend_decompressor(request_content_encoding_processing)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1062,6 +1062,7 @@ impl ConnectionParser {
|
|||
HtpContentEncoding::Gzip
|
||||
| HtpContentEncoding::Deflate
|
||||
| HtpContentEncoding::Zlib
|
||||
| HtpContentEncoding::Brotli
|
||||
| HtpContentEncoding::Lzma => {
|
||||
// Send data buffer to the decompressor if it exists
|
||||
if resp.response_decompressor.is_none() && data.is_none() {
|
||||
|
|
@ -1141,6 +1142,8 @@ impl ConnectionParser {
|
|||
HtpContentEncoding::Deflate
|
||||
} else if ce.cmp_nocase_nozero(b"lzma") {
|
||||
HtpContentEncoding::Lzma
|
||||
} else if ce.cmp_nocase_nozero(b"br") {
|
||||
HtpContentEncoding::Brotli
|
||||
} else if ce.cmp_nocase_nozero(b"inflate") || ce.cmp_nocase_nozero(b"none") {
|
||||
HtpContentEncoding::None
|
||||
} else {
|
||||
|
|
@ -1160,6 +1163,7 @@ impl ConnectionParser {
|
|||
HtpContentEncoding::Gzip
|
||||
| HtpContentEncoding::Deflate
|
||||
| HtpContentEncoding::Zlib
|
||||
| HtpContentEncoding::Brotli
|
||||
| HtpContentEncoding::Lzma => {
|
||||
self.response_prepend_decompressor(response_content_encoding_processing)?;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue