Skip to content

fix(proxy): ignore empty body payloads in HTTP/1 upstream writes - #976

Open
Curious-r wants to merge 1 commit into
cloudflare:mainfrom
Curious-r:fix/h1-ignore-empty-body
Open

fix(proxy): ignore empty body payloads in HTTP/1 upstream writes#976
Curious-r wants to merge 1 commit into
cloudflare:mainfrom
Curious-r:fix/h1-ignore-empty-body

Conversation

@Curious-r

Copy link
Copy Markdown

Summary

Fix a spurious HTTP/1 warning when an empty final body task follows a fully written Content-Length body. The upstream sink now skips empty payloads in both Body and UpgradedBody, while finish_body() still handles final framing and Content-Length validation. Non-empty data after the body is finished continues to trigger the warning.

Added regression tests for Content-Length and chunked bodies to ensure empty final tasks don't affect wire framing or produce duplicate chunk terminators.

Validated with cargo test -p pingora-proxy --lib, cargo clippy -p pingora-proxy --lib --tests -- -D warnings, and cargo fmt --all -- --check.

Background:

When using a Pingora-based reverse proxy for my Matrix homeserver, I noticed that it produced a large number of warnings like:

WARN pingora_proxy::proxy_h1: Upstream body is already finished. Nothing to write

After enabling DEBUG logging, the warning could be reproduced on normal Matrix federation requests. The relevant sequence was:

DEBUG pingora_proxy::proxy_h1: Read 208 bytes body from downstream
DEBUG pingora_proxy::proxy_h1: Read 0 bytes body from downstream
DEBUG pingora_proxy::proxy_h1: Write 208 bytes body to upstream
WARN  pingora_proxy::proxy_h1: Upstream body is already finished. Nothing to write
DEBUG pingora_proxy::proxy_h1: finish sending body to upstream

This shows that the warning is triggered by an empty body event arriving after the complete Content-Length body has already been written. Since empty payloads do not carry any data and finish_body() already handles the end-of-body framing, the empty buffer should be ignored rather than passed to write_body().

@Curious-r
Curious-r force-pushed the fix/h1-ignore-empty-body branch from ba4de7b to 8650d51 Compare August 24, 2026 19:08
@Curious-r

Copy link
Copy Markdown
Author

Sorry, I missed #936 before opening this. Looking at the patches, though, I don't think this is a duplicate — they seem complementary.

#936 hardens BodyWriter at the codec layer by making zero-length writes no-ops in chunked mode, ensuring finish() remains the only place that emits the terminator.

This PR works at the HTTP/1 proxy adapter instead: send_body_to1() skips empty payload buffers before calling the upstream body writer, while still using finish_body() for end-of-stream framing. That covers both Body and UpgradedBody tasks, avoids the spurious "Upstream body is already finished" warning for fully written Content-Length bodies, and includes wire-level regression tests for Content-Length and chunked bodies.

Given the different layers, I think it may make sense to land both: #936 protects the writer API more broadly, while this change keeps the generic proxy task-to-H1 translation from treating an empty EOS signal as application data.

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