This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author martin.panter
Recipients WildCard65, berker.peksag, martin.panter, paul.moore, steve.dower, terry.reedy, tim.golden, vstinner, zach.ware
Date 2018-08-01.04:32:14
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1533097935.12.0.56676864532.issue25095@psf.upfronthosting.co.za>
In-reply-to
Content
I reproduced the problem on a Windows computer, and now understand why my "Content-Length: 0" suggestion isn't good enough on its own. It does solve the initial deadlock, but there is a further deadlock. The main thread is waiting for the server to shut down while it is holding the HTTP connection open, and the server is still trying to read a second request on that connection.

Setting "self.close_connection = True" in the server (or using "Connection: close") solves both deadlocks. But it seems cleaner for the client to close the connection and response objects anyway, before shutting down the server. I would modify the "test_get" method:

with support.captured_stderr() as err:
    self.con.request('GET', '/')
    res = self.con.getresponse()
    res.close()  # Not needed but cleans up socket if no Content-Length
self.con.close()  # Needed to shut down connection with Content-Length

I think my Windows computer has a firewall that holds TCP data if it looks like an unfinished HTTP request or response. I suspect Terry and William had a similar firewall. Here is a demonstration of the socket behaviour it causes:

>>> from socket import *
>>> listener = socket()
>>> listener.bind(("127.1", 0))
>>> listener.listen()
>>> outgoing = create_connection(listener.getsockname())
>>> [incoming, address] = listener.accept()
>>> outgoing.sendall(b"GET / HTTP/1.1\r\n")  # Unfinished HTTP request
>>> incoming.settimeout(3)
>>> incoming.recv(300)  # Partial request should normally be received
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
socket.timeout: timed out
>>> outgoing.sendall(b"\r\n")  # Complete the request
>>> incoming.recv(300)  # Only now is the request received
b'GET / HTTP/1.1\r\n\r\n'
>>> incoming.sendall(b"HTTP/1.1 200 OK\r\n")  # Unfinished response
>>> outgoing.settimeout(3)
>>> outgoing.recv(300)  # Should normally be received
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
socket.timeout: timed out
>>> incoming.sendall(b"Content-Length: 0\r\n\r\n")  # Complete the response
>>> outgoing.recv(300)  # Only now received
b'HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n'
History
Date User Action Args
2018-08-01 04:32:15martin.pantersetrecipients: + martin.panter, terry.reedy, paul.moore, vstinner, tim.golden, berker.peksag, zach.ware, steve.dower, WildCard65
2018-08-01 04:32:15martin.pantersetmessageid: <1533097935.12.0.56676864532.issue25095@psf.upfronthosting.co.za>
2018-08-01 04:32:15martin.panterlinkissue25095 messages
2018-08-01 04:32:14martin.pantercreate