Skip to content

Fix POST/PUT request bodies being lost server-side#10

Open
sclaiborne wants to merge 6 commits into
mainfrom
fix/server-request-body
Open

Fix POST/PUT request bodies being lost server-side#10
sclaiborne wants to merge 6 commits into
mainfrom
fix/server-request-body

Conversation

@sclaiborne

Copy link
Copy Markdown
Member

Problem

LLHttpParse() only sets contentPresent / partialContent in the HTTP response parsing branch. The request parsing branch never sets them, so LLHttpServer''s dispatch (if(client->parser.contentPresent)) always copied an empty body into LLHttpResponse handlers. POST/PUT bodies were silently lost server-side: requestLength reported the Content-Length, but pRequest received only '\0'. Reproduced against ARsim with LLHttpServer + LLHttpResponse.

On top of that, the partial-content accumulation path in HttpServer.c was broken for multi-segment requests: after HttpShiftReceivePointer(), the parser was given the receive buffer base pointer but only the latest segment''s ReceivedDataLength, so a request whose headers and body arrive in separate TCP segments (which is what .NET HttpClient sends - headers and body in separate writes) never parsed completely. The appended null terminator was also written one byte past the received data.

Fix

  • HttpParse.c: mirror the response-branch logic at the end of the request branch - if header.contentLength != 0, set contentPresent = 1 and partialContent = (returnValue + contentLength > dataLength).
  • HttpServer.c:
    • Parse over the full accumulated buffer: recvLength = shift offset + newly received length (matching the client''s accumulation in HttpClient.c), and shift the receive pointer by the new segment length only.
    • Append the null terminator at data[recvLength] instead of data[recvLength+1], and reserve one byte of the receive buffer for it (as the client does).
    • Zero-initialize the TMP_alloc''d client array in LLHttpServerInit() - TMP_alloc memory is not initialized, so TCP stream state/FUB statuses started as garbage.

Tests

Added under test/:

  • Parser: request with body sets contentPresent/content, request with partial body sets partialContent.
  • Server: a POSTed JSON body split across two TCP segments (headers first, body second) is accumulated, parsed, and dispatched to a registered handler with the full body. Verified the new tests fail (empty body, exactly the reported symptom) with the parse fix reverted.

Test-infra repairs (needed to build/run the suite at all)

  • CMakeLists.txt: the src/Ar restructure broke the CMake build - add_subdirectory(example) pointed at a directory with no CMakeLists, and the library target had no include dirs. Fixed paths and stale ../LLHttpH.h-style includes in tests.cpp/example.cpp.
  • Bumped Catch2 v3.0.0-preview3 -> v3.4.0 (preview3 does not compile with current GCC) and renamed Contains -> ContainsSubstring per Catch2 v3 API.
  • Added brsstrlen fallback macro for non-AR builds (used by the chunked-encoding path).
  • Create the report/ directory at configure time so ctest passes on a clean checkout.

Verified per TestJenkinsfile: CMake + MinGW (32-bit, matching UDINT pointer width) build, full Catch2 suite green via ctest - 7/7 test cases, 139 assertions.

🤖 Generated with Claude Code

sclaiborne and others added 6 commits June 11, 2026 14:52
LLHttpParse only set contentPresent/partialContent in the HTTP
response parsing branch. The request parsing branch never set them,
so LLHttpServer dispatched POST/PUT requests with an empty body even
though header.contentLength was correct.

Also fix the partial-content accumulation in LLHttpServer: the parser
was given the receive buffer base pointer but only the length of the
latest TCP segment, so requests whose headers and body arrive in
separate segments (e.g. from .NET HttpClient) never parsed completely.
The null terminator was also being appended one byte past the received
data, and the receive pointer shift now matches the accumulated length
semantics. Reserve one byte of the receive buffer for the terminator.

Repair the CMake test build after the src/Ar restructure (library
include dirs, example subdirectory path, stale relative includes) and
add tests covering request bodies and a POSTed JSON body split across
two TCP segments.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TMP_alloc memory is not initialized, so the internal client state
(TCP stream state, FUB statuses, receive lengths) started as garbage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ection manager

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant