From 52a2f2dd191fa3609039e175cb717c44ad29d8d8 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 18 Feb 2026 20:44:27 +0100 Subject: [PATCH] detect/http2: use ThreadCtx for http.header_names Instead of custom inefficient "escaped" Vec Ticket: 8291 --- rust/src/http2/detect.rs | 35 ++++++++++++++++++++++++---------- src/detect-http-header-names.c | 10 +++++++++- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/rust/src/http2/detect.rs b/rust/src/http2/detect.rs index 0212ec33cb..c439f81570 100644 --- a/rust/src/http2/detect.rs +++ b/rust/src/http2/detect.rs @@ -700,11 +700,29 @@ fn http2_escape_header(blocks: &[parser::HTTP2FrameHeaderBlock], i: u32) -> Vec< return vec; } +#[derive(Default)] +struct Http2ThreadBuf { + data: Vec, +} + +#[no_mangle] +pub unsafe extern "C" fn SCHttp2ThreadBufDataInit(_cfg: *mut c_void) -> *mut c_void { + let boxed = Box::new(Http2ThreadBuf::default()); + return Box::into_raw(boxed) as *mut c_void; +} + +#[no_mangle] +pub unsafe extern "C" fn SCHttp2ThreadBufDataFree(ctx: *mut c_void) { + std::mem::drop(Box::from_raw(ctx as *mut Http2ThreadBuf)); +} + #[no_mangle] pub unsafe extern "C" fn SCHttp2TxGetHeaderNames( tx: &mut HTTP2Transaction, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, + tbuf: *mut c_void, ) -> u8 { - let mut vec = vec![b'\r', b'\n']; + let tbuf = cast_pointer!(tbuf, Http2ThreadBuf); + tbuf.data = vec![b'\r', b'\n']; let frames = if direction & Direction::ToServer as u8 != 0 { &tx.frames_ts } else { @@ -714,18 +732,15 @@ pub unsafe extern "C" fn SCHttp2TxGetHeaderNames( if let Some(blocks) = http2_header_blocks(frame) { for block in blocks.iter() { // we do not escape linefeeds in headers names - vec.extend_from_slice(&block.name); - vec.extend_from_slice(b"\r\n"); + tbuf.data.extend_from_slice(&block.name); + tbuf.data.extend_from_slice(b"\r\n"); } } } - if vec.len() > 2 { - vec.extend_from_slice(b"\r\n"); - tx.escaped.push(vec); - let idx = tx.escaped.len() - 1; - let value = &tx.escaped[idx]; - *buffer = value.as_ptr(); //unsafe - *buffer_len = value.len() as u32; + if tbuf.data.len() > 2 { + tbuf.data.extend_from_slice(b"\r\n"); + *buffer = tbuf.data.as_ptr(); //unsafe + *buffer_len = tbuf.data.len() as u32; return 1; } return 0; diff --git a/src/detect-http-header-names.c b/src/detect-http-header-names.c index 1a96fb4a93..ff2338890e 100644 --- a/src/detect-http-header-names.c +++ b/src/detect-http-header-names.c @@ -71,6 +71,7 @@ #define BUFFER_DESC "http header names" static int g_buffer_id = 0; static int g_keyword_thread_id = 0; +static int g_http2_thread_id = 0; #define BUFFER_SIZE_STEP 256 static HttpHeaderThreadDataConfig g_td_config = { BUFFER_SIZE_STEP }; @@ -169,7 +170,11 @@ static InspectionBuffer *GetBuffer2ForTX(DetectEngineThreadCtx *det_ctx, uint32_t b_len = 0; const uint8_t *b = NULL; - if (SCHttp2TxGetHeaderNames(txv, flow_flags, &b, &b_len) != 1) + void *thread_buf = DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, g_http2_thread_id); + if (thread_buf == NULL) + return NULL; + + if (SCHttp2TxGetHeaderNames(txv, flow_flags, &b, &b_len, thread_buf) != 1) return NULL; if (b == NULL || b_len == 0) return NULL; @@ -247,6 +252,9 @@ void DetectHttpHeaderNamesRegister(void) g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs(KEYWORD_NAME, HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); + g_http2_thread_id = DetectRegisterThreadCtxGlobalFuncs( + "http2.header_names", SCHttp2ThreadBufDataInit, NULL, SCHttp2ThreadBufDataFree); + SCLogDebug("keyword %s registered. Thread id %d. " "Buffer %s registered. Buffer id %d", KEYWORD_NAME, g_keyword_thread_id,