diff --git a/rust/src/http2/decompression.rs b/rust/src/http2/decompression.rs index 4c266e2a62..f6f225d967 100644 --- a/rust/src/http2/decompression.rs +++ b/rust/src/http2/decompression.rs @@ -21,7 +21,8 @@ use brotli::{BrotliDecompressStream, BrotliResult, BrotliState, HeapAlloc, Huffm use flate2::read::{DeflateDecoder, GzDecoder}; use std; use std::io; -use std::io::{Cursor, Read, Write}; +use std::io::{BufReader, Cursor, Read, Write}; +use zstd; pub const HTTP2_DECOMPRESSION_CHUNK_SIZE: usize = 0x1000; // 4096 @@ -34,7 +35,8 @@ pub enum HTTP2ContentEncoding { Gzip = 1, Br = 2, Deflate = 3, - Unrecognized = 4, + Zstd = 4, + Unrecognized = 5, } //a cursor turning EOF into blocking errors @@ -148,6 +150,9 @@ pub enum HTTP2Decompresser { // This one is not so large, at 88 bytes as of doing this, but box // for consistency. Deflate(Box>), + + // usage of 'static, alternative could be trait instead of enum + Zstd(Box>>), } impl std::fmt::Debug for HTTP2Decompresser { @@ -157,6 +162,7 @@ impl std::fmt::Debug for HTTP2Decompresser { HTTP2Decompresser::Gzip(_) => write!(f, "GZIP"), HTTP2Decompresser::Brotli(_) => write!(f, "BROTLI"), HTTP2Decompresser::Deflate(_) => write!(f, "DEFLATE"), + HTTP2Decompresser::Zstd(_) => write!(f, "ZSTD"), } } } @@ -191,6 +197,12 @@ impl GetMutCursor for BrotliDecompressor { } } +impl GetMutCursor for zstd::stream::read::Decoder<'_, BufReader> { + fn get_mut(&mut self) -> &mut HTTP2cursor { + return self.get_mut().get_mut(); + } +} + fn http2_decompress<'a>( decoder: &mut (impl Read + GetMutCursor), input: &'a [u8], output: &'a mut Vec, ) -> io::Result<&'a [u8]> { @@ -259,6 +271,19 @@ impl HTTP2DecoderHalf { self.decoder = HTTP2Decompresser::Brotli(Box::new(BrotliDecompressor::new( HTTP2cursor::new(), ))); + } else if input.eq_ignore_ascii_case(b"zstd") { + self.encoding = HTTP2ContentEncoding::Zstd; + if let Ok(mut z) = zstd::stream::read::Decoder::new(HTTP2cursor::new()) { + if z.window_log_max(23).is_ok() { + self.decoder = HTTP2Decompresser::Zstd(Box::new(z)); + } else { + SCLogWarning!("Failed to set zstd window log max"); + self.decoder = HTTP2Decompresser::Unassigned; + } + } else { + SCLogWarning!("Failed to create zstd decoder"); + self.decoder = HTTP2Decompresser::Unassigned; + } } else { self.encoding = HTTP2ContentEncoding::Unrecognized; } @@ -295,6 +320,19 @@ impl HTTP2DecoderHalf { self.input_len += input.len() as u64; return r; } + HTTP2Decompresser::Zstd(ref mut zstd_decoder) => { + let r = http2_decompress(&mut *zstd_decoder.as_mut(), input, output); + match r { + Err(_) => { + self.decoder = HTTP2Decompresser::Unassigned; + } + Ok(o) => { + self.output_len += o.len() as u64; + } + } + self.input_len += input.len() as u64; + return r; + } HTTP2Decompresser::Deflate(ref mut df_decoder) => { let r = http2_decompress(&mut *df_decoder.as_mut(), input, output); match r {