Skip to content

Quietly end FastAGI request when a client disconnects during the handshake#64

Merged
itg-karthicr merged 2 commits into
masterfrom
fix/fastagi-handshake-disconnect
Jun 25, 2026
Merged

Quietly end FastAGI request when a client disconnects during the handshake#64
itg-karthicr merged 2 commits into
masterfrom
fix/fastagi-handshake-disconnect

Conversation

@itg-karthicr

Copy link
Copy Markdown
Contributor

Closes #49.

Problem

When a FastAGI client connection closes before the AGI environment handshake completes, _AGIClientHandler.handle() constructs FastAGI(...) as its first action, which reads the environment block. If the connection is already gone, _read_line raises AGISIGPIPEHangup. handle() did not catch it, so the default socketserver error handling printed a full traceback to stderr for a routine, expected condition.

Common triggers, all benign:

  • A caller hangs up just as the call reaches the AGI() step.
  • Asterisk aborts the AGI leg (dialplan hangup or timeout).
  • A bare TCP probe (health check or scanner) connects and closes without sending AGI data.

No in-flight call is affected. The only problem is the alarming traceback noise.

Fix

Wrap only the FastAGI(...) handshake construction in except AGIHangup and return early (option A from the issue). The suppression is scoped to the environment read, so it cannot hide handler-time failures: errors raised by the script handler, which runs after this guard, still propagate. AGIHangup is the base of the handshake hangup (AGISIGPIPEHangup), so the guard covers the disconnect category without swallowing protocol or handler errors.

I left the optional debug log line out. The module has no logger and the issue lists it as optional, so the surgical change is to simply end the request quietly. Easy to add later if a disconnect log is wanted.

Tests

New tests/test_fastagi_handler.py:

  • A client that closes during the handshake makes handle() return without raising (no traceback). Fails against the old code, passes against the fix.
  • A script handler that raises still propagates, proving the guard is scoped to the handshake and does not swallow genuine handler errors.

Full suite: 52 passing, ruff clean.

Out of scope

Disconnects after the handshake (mid-call, inside a handler) are a separate path, typically a SIGPIPE on the next channel write. Not covered here, per the issue.

itg-karthicr and others added 2 commits June 24, 2026 22:09
When a FastAGI client closes before sending the full AGI environment, the
handshake read raises AGISIGPIPEHangup from inside _AGIClientHandler.handle().
It propagated uncaught, so socketserver printed a full traceback to stderr for
a routine event (caller hung up, Asterisk aborted the leg, or a bare TCP
probe).

Wrap only the FastAGI(...) handshake construction in except AGIHangup and
return early. The suppression is scoped to the environment read, so genuine
errors from the script handler, which runs after this guard, still propagate.

Add regression tests: a client that closes during the handshake makes handle()
return without raising, and a handler that raises still propagates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…iew)

Review panel convergence:
- Narrow the handler guard from the AGIHangup base to AGISIGPIPEHangup, the
  only hangup reachable during the environment read (no command is sent, so
  AGIResultHangup cannot arise). This documents intent precisely, makes the
  code match the comment/CHANGELOG/test which already name AGISIGPIPEHangup,
  and avoids silently swallowing a future non-disconnect hangup introduced
  into construction.
- Strengthen the disconnect test: assert the script handler is never invoked
  and nothing is written back on the quiet path.
- Add a mid-handshake disconnect test (partial environment then EOF) covering
  the parse-loop EOF path, distinct from the first-read EOF case.
- CHANGELOG: say the traceback is printed to stderr rather than "logged",
  since socketserver writes directly to stderr.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@itg-karthicr itg-karthicr merged commit 19f1b82 into master Jun 25, 2026
8 checks passed
@itg-karthicr itg-karthicr deleted the fix/fastagi-handshake-disconnect branch June 25, 2026 02:33
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.

FastAGI server logs an unhandled traceback when a client disconnects during the AGI handshake

1 participant