Skip to content

Close the WSGI application-returned iterable #192

Description

@kentbull

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.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions