summaryrefslogtreecommitdiffstats
path: root/Lib/http
diff options
context:
space:
mode:
authorR David Murray <rdmurray@bitdance.com>2015-04-05 23:26:29 (GMT)
committerR David Murray <rdmurray@bitdance.com>2015-04-05 23:26:29 (GMT)
commitcae7bdb4241b928f9da025dce48ec98f1b63d576 (patch)
tree9aff2370b4a06f84fda13e48448023cc6506af17 /Lib/http
parent142bf565b4e095cfdf59dcb07f6480a7368f1d33 (diff)
downloadcpython-cae7bdb4241b928f9da025dce48ec98f1b63d576.zip
cpython-cae7bdb4241b928f9da025dce48ec98f1b63d576.tar.gz
cpython-cae7bdb4241b928f9da025dce48ec98f1b63d576.tar.bz2
#3566: Clean up handling of remote server disconnects.
This changeset does two things: introduces a new RemoteDisconnected exception (that subclasses ConnectionResetError and BadStatusLine) so that a remote server disconnection can be detected by client code (and provides a better error message for debugging purposes), and ensures that the client socket is closed if a ConnectionError happens, so that the automatic re-connection code can work if the application handles the error and continues on. Tests are added that confirm that a connection is re-used or not re-used as appropriate to the various combinations of protocol version and headers. Patch by Martin Panter, reviewed by Demian Brecht. (Tweaked only slightly by me.)
Diffstat (limited to 'Lib/http')
-rw-r--r--Lib/http/client.py27
1 files changed, 20 insertions, 7 deletions
diff --git a/Lib/http/client.py b/Lib/http/client.py
index f5889ed..ac120e7 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -20,10 +20,12 @@ request. This diagram details these state transitions:
| ( putheader() )* endheaders()
v
Request-sent
- |
- | response = getresponse()
- v
- Unread-response [Response-headers-read]
+ |\_____________________________
+ | | getresponse() raises
+ | response = getresponse() | ConnectionError
+ v v
+ Unread-response Idle
+ [Response-headers-read]
|\____________________
| |
| response.read() | putrequest()
@@ -83,7 +85,8 @@ __all__ = ["HTTPResponse", "HTTPConnection",
"UnknownTransferEncoding", "UnimplementedFileMode",
"IncompleteRead", "InvalidURL", "ImproperConnectionState",
"CannotSendRequest", "CannotSendHeader", "ResponseNotReady",
- "BadStatusLine", "LineTooLong", "error", "responses"]
+ "BadStatusLine", "LineTooLong", "RemoteDisconnected", "error",
+ "responses"]
HTTP_PORT = 80
HTTPS_PORT = 443
@@ -245,7 +248,8 @@ class HTTPResponse(io.BufferedIOBase):
if not line:
# Presumably, the server closed the connection before
# sending a valid response.
- raise BadStatusLine(line)
+ raise RemoteDisconnected("Remote end closed connection without"
+ " response")
try:
version, status, reason = line.split(None, 2)
except ValueError:
@@ -1160,7 +1164,11 @@ class HTTPConnection:
response = self.response_class(self.sock, method=self._method)
try:
- response.begin()
+ try:
+ response.begin()
+ except ConnectionError:
+ self.close()
+ raise
assert response.will_close != _UNKNOWN
self.__state = _CS_IDLE
@@ -1292,5 +1300,10 @@ class LineTooLong(HTTPException):
HTTPException.__init__(self, "got more than %d bytes when reading %s"
% (_MAXLINE, line_type))
+class RemoteDisconnected(ConnectionResetError, BadStatusLine):
+ def __init__(self, *pos, **kw):
+ BadStatusLine.__init__(self, "")
+ ConnectionResetError.__init__(self, *pos, **kw)
+
# for backwards compatibility
error = HTTPException