Problem
Responder.service() currently collapses two potentially different WSGI objects into one:
self.iterator = iter(self.app(self.environ, start_response=self.start))
The application-returned iterable is discarded, while HIO retains only the iterator produced by iter(iterable). Those objects are often identical for generators, but Python permits iter(iterable) to return a distinct object.
PEP 3333 requires the server to call close() on the iterable returned by the application, when present, on normal completion or early termination: https://peps.python.org/pep-3333/#the-application-framework-side
Closing only the derived iterator can therefore miss the application or middleware object that owns files, database sessions, cursors, or other request-scoped resources. It may also close the wrong object when both expose different cleanup contracts.
Expected behavior
- Retain the application-returned iterable separately from the iterator used by
next().
- Close the returned iterable exactly once on normal exhaustion, exact
Content-Length termination, explicit abort, connection closure, or defensive reset.
- Clear both retained references before invoking
close() so repeated terminal signals, including a cleanup method that raises, cannot repeat resource release.
- If cleanup fails during a successful terminal transition, retain that failure and do not emit terminal chunk framing or claim normal completion.
Regression coverage
Use a real Responder and Remoter with a protocol-conforming application result whose __iter__() returns a separately constructed closeable iterator. Verify that HIO closes the returned iterable—not the iterator—exactly once across exhaustion, early Content-Length completion, abort followed by administrative close, repeated close, and cleanup failure.
Scope and dependency
This issue fixes cleanup ownership on HIO's existing normal and explicit-abort terminal paths. It does not claim complete exception-path coverage: application invocation, iter(), next(), and HTTPError settlement are a separate follow-up, as are body and terminal-frame enqueue failures.
The behavior is generic PEP 3333 compliance, but the code port should wait for #179 and #181 plus the upstream implementation of #191, whose response settlement states this cleanup relies on.
Problem
Responder.service()currently collapses two potentially different WSGI objects into one:The application-returned iterable is discarded, while HIO retains only the iterator produced by
iter(iterable). Those objects are often identical for generators, but Python permitsiter(iterable)to return a distinct object.PEP 3333 requires the server to call
close()on the iterable returned by the application, when present, on normal completion or early termination: https://peps.python.org/pep-3333/#the-application-framework-sideClosing only the derived iterator can therefore miss the application or middleware object that owns files, database sessions, cursors, or other request-scoped resources. It may also close the wrong object when both expose different cleanup contracts.
Expected behavior
next().Content-Lengthtermination, explicit abort, connection closure, or defensive reset.close()so repeated terminal signals, including a cleanup method that raises, cannot repeat resource release.Regression coverage
Use a real
ResponderandRemoterwith a protocol-conforming application result whose__iter__()returns a separately constructed closeable iterator. Verify that HIO closes the returned iterable—not the iterator—exactly once across exhaustion, earlyContent-Lengthcompletion, abort followed by administrative close, repeated close, and cleanup failure.Scope and dependency
This issue fixes cleanup ownership on HIO's existing normal and explicit-abort terminal paths. It does not claim complete exception-path coverage: application invocation,
iter(),next(), andHTTPErrorsettlement are a separate follow-up, as are body and terminal-frame enqueue failures.The behavior is generic PEP 3333 compliance, but the code port should wait for #179 and #181 plus the upstream implementation of #191, whose response settlement states this cleanup relies on.