msc_add_n_request_header() and msc_add_n_response_header() signal
failure via their return value, but every call site discarded it --
both the resolver dispatch loop and the raw header_out/header_in list
loops. A failure (OOM inside libmodsecurity) meant that header simply
never reached the WAF, with no visibility into it. Log a warning on
failure. Unlike the request/response body phase, dropping a single
header is not equivalent to skipping inspection outright, so this
logs rather than fails the request closed.
ngx_str_to_char() returns NULL for a zero-length ngx_str_t (not an
error, just "empty"), and most callers check for it, but client_addr
and server_addr in the connection-info block didn't. An empty
addr_text (e.g. some unix-socket configurations) would pass NULL
straight into msc_process_connection(), which expects a C string.
The response-body loop in the body filter never broke out after
running msc_process_response_body() on the buffer carrying last_buf.
A filter upstream of us (sub_filter, gzip, ...) can append a trailing
buffer after the last_buf link in the same chain, which would loop
back around and call msc_append_response_body() again on an
already-finalized transaction. The full chain is still forwarded to
the next filter regardless of where this loop stops inspecting.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
Test plan