Skip to content

Upstream: flushing of event pipe on upstream timeouts. - #2

Open
climagabriel wants to merge 1 commit into
masterfrom
pipe-flush-raw-bufs-on-read-timeout
Open

Upstream: flushing of event pipe on upstream timeouts.#2
climagabriel wants to merge 1 commit into
masterfrom
pipe-flush-raw-bufs-on-read-timeout

Conversation

@climagabriel

@climagabriel climagabriel commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Port of freenginx da1b5ee651c3 (Maxim Dounin, 2026-08-28): on an upstream read timeout, data already read from the upstream is flushed to the client, as on a read error. Candidate for an nginx upstream PR; review before opening one. Tests: climagabriel/nginx-tests PR.

Deviation from freenginx: this port does not flush a timed-out 101 response when the client did not request an upgrade. freenginx rejects such responses at header parsing, freenginx 101-response validation; nginx passes them through as regular responses, so the unguarded port fails the "handshake noupgrade" and "log - bytes noupgrade" assertions in proxy_upgrade.t.

Verified against nginx 231a60ee3, the 1.31.5 release, versus this branch:

  • proxy_timeout.t: the four timeout assertions fail on 1.31.5 and pass on this branch, ten consecutive runs.
  • proxy_noclose.t: the TODO "bad backend - no content length" passes on this branch.
  • proxy_upgrade.t: passes on both.
  • 135-file sweep (proxy, slice, fastcgi, uwsgi, scgi, grpc, ssi, limit_rate): failure sets matched.

Prior art: nginx/nginx has no issue or PR for this; the freenginx backport set nginx#1696 stops at freenginx 1.31.4. Angie, Tengine and OpenResty keep the unmodified timeout path. The original failure occurred in a sliced proxy chain, reported in nginx-gcdn#501, which guards differently: it skips the flush when p->length is -1. Not taken; it leaves the proxy_noclose.t no-content-length case unfixed and disables the fix for FastCGI without keep_conn.

https://claude.ai/code/session_01BERKTkJd6r3FPviAuD9SyE

Previously, on upstream read timeouts data already read from the
upstream were not flushed: buffers already passed to the input filter
were not written to the client, and the partially filled buffer at the
head of p->free_raw_bufs was only processed on an eof or error seen by
ngx_event_pipe_read_upstream() itself.  With this change, similarly to
the handling of upstream read errors (see 4e8a73a), the data that
were previously read are processed and sent to the client, minimizing
the difference from the response as returned by the upstream server.

Unrequested 101 responses are excluded: they are passed as regular
responses, and what follows their headers is protocol data of an
upgrade the client did not request.

Based on freenginx changeset da1b5ee651c3 by Maxim Dounin.

Claude-Session: https://claude.ai/code/session_01BERKTkJd6r3FPviAuD9SyE
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