|
|
|
|
@ -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<DeflateDecoder<HTTP2cursor>>),
|
|
|
|
|
|
|
|
|
|
// usage of 'static, alternative could be trait instead of enum
|
|
|
|
|
Zstd(Box<zstd::stream::read::Decoder<'static, BufReader<HTTP2cursor>>>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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<HTTP2cursor>> {
|
|
|
|
|
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<u8>,
|
|
|
|
|
) -> 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 {
|
|
|
|
|
|