Defer HTTP parser callback errors
Issue
HTTP parser callbacks could report errors synchronously while llhttp was still executing inside HttpCodecFilter::dispatch().
That is unsafe because the error path can disconnect MCP state, close transports, and destroy filter-owned objects while the parser callback stack is still unwinding. In practice, malformed or oversized body callbacks could trigger teardown from inside the parser itself, creating a use-after-free or crash risk on the transport read path.
How to reproduce
- Build the SDK with HTTP transport enabled.
- Create an HTTP client or server path using
HttpCodecFilter.
- Feed an HTTP message that causes a parser callback error while
dispatch() is processing input. One practical trigger is an invalid body callback condition from the oversized-body guard path:
body callback data = null and length > 0
or
body callback length > codec body chunk limit
- Make the registered message error callback close the MCP connection or transport.
Before the fix, the parser callback could call the error path immediately. That allowed connection shutdown and object destruction to run before llhttp_execute() and HttpCodecFilter::dispatch() finished unwinding.
Expected fixed behavior
Parser callback errors are stored in pending_parser_error_ instead of reported directly from the callback.
After parser execution returns and the input buffer is drained, dispatch() checks pending_parser_error_, clears it, and then calls the parser error handling path. This keeps parser callbacks from tearing down the connection while the parser is still active on the stack.
Regression check
A regression test should trigger a parser callback failure and assert that:
- the callback returns parser error;
- the user-facing error callback is not invoked synchronously from inside the parser body callback;
- the error is reported after
dispatch() regains control;
- connection teardown from the error callback does not destroy objects still active in the parser callback stack.
Defer HTTP parser callback errors
Issue
HTTP parser callbacks could report errors synchronously while
llhttpwas still executing insideHttpCodecFilter::dispatch().That is unsafe because the error path can disconnect MCP state, close transports, and destroy filter-owned objects while the parser callback stack is still unwinding. In practice, malformed or oversized body callbacks could trigger teardown from inside the parser itself, creating a use-after-free or crash risk on the transport read path.
How to reproduce
HttpCodecFilter.dispatch()is processing input. One practical trigger is an invalid body callback condition from the oversized-body guard path:or
Before the fix, the parser callback could call the error path immediately. That allowed connection shutdown and object destruction to run before
llhttp_execute()andHttpCodecFilter::dispatch()finished unwinding.Expected fixed behavior
Parser callback errors are stored in
pending_parser_error_instead of reported directly from the callback.After parser execution returns and the input buffer is drained,
dispatch()checkspending_parser_error_, clears it, and then calls the parser error handling path. This keeps parser callbacks from tearing down the connection while the parser is still active on the stack.Regression check
A regression test should trigger a parser callback failure and assert that:
dispatch()regains control;