summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2009-03-28 04:34:21 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2009-03-28 04:34:21 (GMT)
commit636950f925d50763537d40342ec622808c9b7e9d (patch)
treeffd2880a6d118f374af24da66f435c6027eddca8
parent7c1692d587b62bbb0657d6c049e320e37c53e711 (diff)
downloadcpython-636950f925d50763537d40342ec622808c9b7e9d.zip
cpython-636950f925d50763537d40342ec622808c9b7e9d.tar.gz
cpython-636950f925d50763537d40342ec622808c9b7e9d.tar.bz2
Remove special logic that closes HTTPConnection socket on EPIPE.
http://bugs.python.org/issue5542 If the socket is closed, the client has no chance to read the response from the server. EPIPE means that it isn't possible to write more data from the socket, but not that it is impossible to read. Also, various formatting changes.
-rw-r--r--Lib/http/client.py59
-rw-r--r--Lib/test/test_httplib.py32
2 files changed, 55 insertions, 36 deletions
diff --git a/Lib/http/client.py b/Lib/http/client.py
index 0ea15ab..6547f85 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -66,10 +66,11 @@ Req-started-unread-response _CS_REQ_STARTED <response_class>
Req-sent-unread-response _CS_REQ_SENT <response_class>
"""
-import io
-import socket
import email.parser
import email.message
+import io
+import os
+import socket
from urllib.parse import urlsplit
import warnings
@@ -673,29 +674,24 @@ class HTTPConnection:
# ignore the error... the caller will know if they can retry.
if self.debuglevel > 0:
print("send:", repr(str))
- try:
- blocksize = 8192
- if hasattr(str, "read") :
+ blocksize = 8192
+ if hasattr(str, "read") :
+ if self.debuglevel > 0:
+ print("sendIng a read()able")
+ encode = False
+ if "b" not in str.mode:
+ encode = True
if self.debuglevel > 0:
- print("sendIng a read()able")
- encode = False
- if "b" not in str.mode:
- encode = True
- if self.debuglevel > 0:
- print("encoding file using iso-8859-1")
- while 1:
- data = str.read(blocksize)
- if not data:
- break
- if encode:
- data = data.encode("iso-8859-1")
- self.sock.sendall(data)
- else:
- self.sock.sendall(str)
- except socket.error as v:
- if v.args[0] == 32: # Broken pipe
- self.close()
- raise
+ print("encoding file using iso-8859-1")
+ while 1:
+ data = str.read(blocksize)
+ if not data:
+ break
+ if encode:
+ data = data.encode("iso-8859-1")
+ self.sock.sendall(data)
+ else:
+ self.sock.sendall(str)
def _output(self, s):
"""Add a line of output to the current request buffer.
@@ -869,14 +865,7 @@ class HTTPConnection:
def request(self, method, url, body=None, headers={}):
"""Send a complete request to the server."""
- try:
- self._send_request(method, url, body, headers)
- except socket.error as v:
- # trap 'Broken pipe' if we're allowed to automatically reconnect
- if v.args[0] != 32 or not self.auto_open:
- raise
- # try one more time
- self._send_request(method, url, body, headers)
+ self._send_request(method, url, body, headers)
def _set_content_length(self, body):
# Set the content-length based on the body.
@@ -886,7 +875,6 @@ class HTTPConnection:
except TypeError as te:
# If this is a file-like object, try to
# fstat its file descriptor
- import os
try:
thelen = str(os.fstat(body.fileno()).st_size)
except (AttributeError, OSError):
@@ -897,7 +885,7 @@ class HTTPConnection:
self.putheader('Content-Length', thelen)
def _send_request(self, method, url, body, headers):
- # honour explicitly requested Host: and Accept-Encoding headers
+ # Honor explicitly requested Host: and Accept-Encoding: headers.
header_names = dict.fromkeys([k.lower() for k in headers])
skips = {}
if 'host' in header_names:
@@ -983,7 +971,8 @@ else:
def connect(self):
"Connect to a host on a given (SSL) port."
- sock = socket.create_connection((self.host, self.port), self.timeout)
+ sock = socket.create_connection((self.host, self.port),
+ self.timeout)
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index 89413a5..d43c82d 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -1,3 +1,4 @@
+import errno
from http import client
import io
import socket
@@ -24,6 +25,21 @@ class FakeSocket:
raise client.UnimplementedFileMode()
return self.fileclass(self.text)
+class EPipeSocket(FakeSocket):
+
+ def __init__(self, text, pipe_trigger):
+ # When sendall() is called with pipe_trigger, raise EPIPE.
+ FakeSocket.__init__(self, text)
+ self.pipe_trigger = pipe_trigger
+
+ def sendall(self, data):
+ if self.pipe_trigger in data:
+ raise socket.error(errno.EPIPE, "gotcha")
+ self.data += data
+
+ def close(self):
+ pass
+
class NoEOFStringIO(io.BytesIO):
"""Like StringIO, but raises AssertionError on EOF.
@@ -213,6 +229,20 @@ class BasicTest(TestCase):
finally:
resp.close()
+ def test_epipe(self):
+ sock = EPipeSocket(
+ "HTTP/1.0 401 Authorization Required\r\n"
+ "Content-type: text/html\r\n"
+ "WWW-Authenticate: Basic realm=\"example\"\r\n",
+ b"Content-Length")
+ conn = client.HTTPConnection("example.com")
+ conn.sock = sock
+ self.assertRaises(socket.error,
+ lambda: conn.request("PUT", "/url", "body"))
+ resp = conn.getresponse()
+ self.assertEqual(401, resp.status)
+ self.assertEqual("Basic realm=\"example\"",
+ resp.getheader("www-authenticate"))
class OfflineTest(TestCase):
def test_responses(self):
@@ -277,7 +307,7 @@ class RequestBodyTest(TestCase):
def setUp(self):
self.conn = client.HTTPConnection('example.com')
- self.sock = FakeSocket("")
+ self.conn.sock = self.sock = FakeSocket("")
self.conn.sock = self.sock
def get_headers_and_fp(self):