]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
http1: brotli decompression
authorPhilippe Antoine <pantoine@oisf.net>
Fri, 11 Apr 2025 19:56:19 +0000 (21:56 +0200)
committerVictor Julien <victor@inliniac.net>
Sat, 19 Apr 2025 16:20:01 +0000 (18:20 +0200)
Ticket: 5692

http2 already used brotli crate for decompression

rust/Cargo.lock.in
rust/htp/Cargo.toml
rust/htp/src/decompressors.rs
rust/htp/src/request.rs
rust/htp/src/response.rs

index ad150914534d47a823f415fbebd9c6378239bb2e..2cb1202ffe3679238d321fa4aeca14e0ba0e636e 100644 (file)
@@ -1585,6 +1585,7 @@ name = "suricata-htp"
 version = "2.0.0"
 dependencies = [
  "base64",
+ "brotli",
  "bstr",
  "cdylib-link-lines",
  "flate2",
index 0b928eb340b6fd8f0a0853c4150d468e76aba9e0..46b4c77784bfa14a09f6880cc522df0abe6591cc 100644 (file)
@@ -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"
 
index 6fe55ebce2dbdb71a3d137e3184c4c5d3f62474d..56ef36cfc2eef254ad2773593123c5799cb9f766 100644 (file)
@@ -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,
index 56fe02db118fec6352e0d0904271d5afc13e083a..0f518e77ac23dfbed6d9d98aa66a7a5691be18c8 100644 (file)
@@ -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)?;
             }
index 820f878bcc490abbdc0050ece3b905dd9920d612..cf1ed409a560518294765ce0f3c9e899a72cfe7c 100644 (file)
@@ -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)?;
             }