Skip to content

http.client Possible Improvement: Using shutdown() Before close() in HTTPConnection.close()Β #130902

@allrob23

Description

@allrob23

Description

While reviewing the close method in (

cpython/Lib/http/client.py

Lines 1015 to 1028 in 5e73ece

def close(self):
"""Close the connection to the HTTP server."""
self.__state = _CS_IDLE
try:
sock = self.sock
if sock:
self.sock = None
sock.close() # close it manually... there may be other refs
finally:
response = self.__response
if response:
self.__response = None
response.close()
I noticed that the socket is directly closed using close() (line 1022), without first calling shutdown().

This is similar to what I previously reported in issue #130850, where _close_self_pipe in asyncio.selector_events also closes sockets without calling shutdown() first.

Code Reference

Currently, the code is as follows:

def close(self):
    """Close the connection to the HTTP server."""
    self.__state = _CS_IDLE
    try:
        sock = self.sock
        if sock:
            self.sock = None
            sock.close()   # close it manually... there may be other refs
    finally:
        response = self.__response
        if response:
            self.__response = None
            response.close()

Question

Would there be any potential downsides or benefits to adding a shutdown(socket.SHUT_RDWR) call before close() in this case?

Possible Benefits

  • Ensures that all pending data is properly discarded before closing, particularly in scenarios where data might still be buffered.
  • Prevents potential issues with lingering resources in some edge cases.
  • Aligns with best practices for socket cleanup.
  • Can help avoid RST (reset by peer) issues in some network conditions.

Possible Change

def close(self):
    """Close the connection to the HTTP server."""
    self.__state = _CS_IDLE
    try:
        sock = self.sock
        if sock:
            self.sock = None
            try:
                sock.shutdown(socket.SHUT_RDWR)  # Gracefully terminate the connection
            except OSError:
                pass  # Ignore errors if the socket is already closed
            sock.close()   # Close it manually... there may be other refs
    finally:
        response = self.__response
        if response:
            self.__response = None
            response.close()

Reference

The Python socket documentation states:

"close() releases the resource associated with a connection but does not necessarily close the connection immediately. If you want to close the connection in a timely fashion, call shutdown() before close()."
πŸ“Œ Python socket documentation

Since a similar discussion is happening in #130850, I wanted to bring attention to this case in http.client as well.

Looking forward to your thoughts!

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions