Problem
Responder.close() currently conflates administrative connection teardown with successful WSGI response completion. If a response has started but not ended, close() calls write(b''); for a chunked response this enqueues the terminal zero chunk. It then unconditionally sets ended = True.
Server.closeConnection() invokes this method for remote cutoff, timeout, request parsing failure, server shutdown, and normal nonpersistent cleanup. Normal completion is already established earlier by Responder.service() through iterator exhaustion or exact Content-Length emission. Therefore, reaching close() with ended = False means completion was never observed.
Impact
- A partially produced chunked response can receive
0\r\n\r\n, making a truncated representation look complete to the client.
- A partial fixed-length or not-yet-started response is still recorded internally as successful.
- Later connection lifecycle logic cannot distinguish producer success from forced teardown.
Cleanup may follow completion, but cleanup cannot prove completion.
Expected behavior
- Closing an already-ended responder should preserve success and only mark it closed.
- Closing an incomplete responder should record a retained failure, mark it closed, leave
ended = False, and enqueue no completion framing.
- Repeated abort/close should preserve the first cause and byte boundary.
- A failed responder generation must not be reset for persistent reuse.
Regression coverage
Exercise a real Responder over a real Remoter transmit queue before response start and after partial body output. Verify incomplete close records failure without appending a terminal chunk, first-cause retention is idempotent, failed reset is rejected, and normal iterator exhaustion still emits exactly one terminal chunk.
Scope and dependency
This issue is generic WSGI/HTTP settlement behavior and does not require the GLEIF transport changes. The code port should wait for #179 and #181 because it depends on their Content-Length producer settlement and responder-reset behavior. Returned-iterable cleanup and application/iterator exception handling are separate follow-up concerns.
Problem
Responder.close()currently conflates administrative connection teardown with successful WSGI response completion. If a response has started but not ended,close()callswrite(b''); for a chunked response this enqueues the terminal zero chunk. It then unconditionally setsended = True.Server.closeConnection()invokes this method for remote cutoff, timeout, request parsing failure, server shutdown, and normal nonpersistent cleanup. Normal completion is already established earlier byResponder.service()through iterator exhaustion or exactContent-Lengthemission. Therefore, reachingclose()withended = Falsemeans completion was never observed.Impact
0\r\n\r\n, making a truncated representation look complete to the client.Cleanup may follow completion, but cleanup cannot prove completion.
Expected behavior
ended = False, and enqueue no completion framing.Regression coverage
Exercise a real
Responderover a realRemotertransmit queue before response start and after partial body output. Verify incomplete close records failure without appending a terminal chunk, first-cause retention is idempotent, failed reset is rejected, and normal iterator exhaustion still emits exactly one terminal chunk.Scope and dependency
This issue is generic WSGI/HTTP settlement behavior and does not require the GLEIF transport changes. The code port should wait for #179 and #181 because it depends on their Content-Length producer settlement and responder-reset behavior. Returned-iterable cleanup and application/iterator exception handling are separate follow-up concerns.