Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 636950f

Browse files
committed
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.
1 parent 7c1692d commit 636950f

2 files changed

Lines changed: 55 additions & 36 deletions

File tree

Lib/http/client.py

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,11 @@
6666
Req-sent-unread-response _CS_REQ_SENT <response_class>
6767
"""
6868

69-
import io
70-
import socket
7169
import email.parser
7270
import email.message
71+
import io
72+
import os
73+
import socket
7374
from urllib.parse import urlsplit
7475
import warnings
7576

@@ -673,29 +674,24 @@ def send(self, str):
673674
# ignore the error... the caller will know if they can retry.
674675
if self.debuglevel > 0:
675676
print("send:", repr(str))
676-
try:
677-
blocksize = 8192
678-
if hasattr(str, "read") :
677+
blocksize = 8192
678+
if hasattr(str, "read") :
679+
if self.debuglevel > 0:
680+
print("sendIng a read()able")
681+
encode = False
682+
if "b" not in str.mode:
683+
encode = True
679684
if self.debuglevel > 0:
680-
print("sendIng a read()able")
681-
encode = False
682-
if "b" not in str.mode:
683-
encode = True
684-
if self.debuglevel > 0:
685-
print("encoding file using iso-8859-1")
686-
while 1:
687-
data = str.read(blocksize)
688-
if not data:
689-
break
690-
if encode:
691-
data = data.encode("iso-8859-1")
692-
self.sock.sendall(data)
693-
else:
694-
self.sock.sendall(str)
695-
except socket.error as v:
696-
if v.args[0] == 32: # Broken pipe
697-
self.close()
698-
raise
685+
print("encoding file using iso-8859-1")
686+
while 1:
687+
data = str.read(blocksize)
688+
if not data:
689+
break
690+
if encode:
691+
data = data.encode("iso-8859-1")
692+
self.sock.sendall(data)
693+
else:
694+
self.sock.sendall(str)
699695

700696
def _output(self, s):
701697
"""Add a line of output to the current request buffer.
@@ -869,14 +865,7 @@ def endheaders(self, message_body=None):
869865

870866
def request(self, method, url, body=None, headers={}):
871867
"""Send a complete request to the server."""
872-
try:
873-
self._send_request(method, url, body, headers)
874-
except socket.error as v:
875-
# trap 'Broken pipe' if we're allowed to automatically reconnect
876-
if v.args[0] != 32 or not self.auto_open:
877-
raise
878-
# try one more time
879-
self._send_request(method, url, body, headers)
868+
self._send_request(method, url, body, headers)
880869

881870
def _set_content_length(self, body):
882871
# Set the content-length based on the body.
@@ -886,7 +875,6 @@ def _set_content_length(self, body):
886875
except TypeError as te:
887876
# If this is a file-like object, try to
888877
# fstat its file descriptor
889-
import os
890878
try:
891879
thelen = str(os.fstat(body.fileno()).st_size)
892880
except (AttributeError, OSError):
@@ -897,7 +885,7 @@ def _set_content_length(self, body):
897885
self.putheader('Content-Length', thelen)
898886

899887
def _send_request(self, method, url, body, headers):
900-
# honour explicitly requested Host: and Accept-Encoding headers
888+
# Honor explicitly requested Host: and Accept-Encoding: headers.
901889
header_names = dict.fromkeys([k.lower() for k in headers])
902890
skips = {}
903891
if 'host' in header_names:
@@ -983,7 +971,8 @@ def __init__(self, host, port=None, key_file=None, cert_file=None,
983971
def connect(self):
984972
"Connect to a host on a given (SSL) port."
985973

986-
sock = socket.create_connection((self.host, self.port), self.timeout)
974+
sock = socket.create_connection((self.host, self.port),
975+
self.timeout)
987976
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
988977

989978

Lib/test/test_httplib.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import errno
12
from http import client
23
import io
34
import socket
@@ -24,6 +25,21 @@ def makefile(self, mode, bufsize=None):
2425
raise client.UnimplementedFileMode()
2526
return self.fileclass(self.text)
2627

28+
class EPipeSocket(FakeSocket):
29+
30+
def __init__(self, text, pipe_trigger):
31+
# When sendall() is called with pipe_trigger, raise EPIPE.
32+
FakeSocket.__init__(self, text)
33+
self.pipe_trigger = pipe_trigger
34+
35+
def sendall(self, data):
36+
if self.pipe_trigger in data:
37+
raise socket.error(errno.EPIPE, "gotcha")
38+
self.data += data
39+
40+
def close(self):
41+
pass
42+
2743
class NoEOFStringIO(io.BytesIO):
2844
"""Like StringIO, but raises AssertionError on EOF.
2945
@@ -213,6 +229,20 @@ def test_incomplete_read(self):
213229
finally:
214230
resp.close()
215231

232+
def test_epipe(self):
233+
sock = EPipeSocket(
234+
"HTTP/1.0 401 Authorization Required\r\n"
235+
"Content-type: text/html\r\n"
236+
"WWW-Authenticate: Basic realm=\"example\"\r\n",
237+
b"Content-Length")
238+
conn = client.HTTPConnection("example.com")
239+
conn.sock = sock
240+
self.assertRaises(socket.error,
241+
lambda: conn.request("PUT", "/url", "body"))
242+
resp = conn.getresponse()
243+
self.assertEqual(401, resp.status)
244+
self.assertEqual("Basic realm=\"example\"",
245+
resp.getheader("www-authenticate"))
216246

217247
class OfflineTest(TestCase):
218248
def test_responses(self):
@@ -277,7 +307,7 @@ class RequestBodyTest(TestCase):
277307

278308
def setUp(self):
279309
self.conn = client.HTTPConnection('example.com')
280-
self.sock = FakeSocket("")
310+
self.conn.sock = self.sock = FakeSocket("")
281311
self.conn.sock = self.sock
282312

283313
def get_headers_and_fp(self):

0 commit comments

Comments
 (0)