diff --git a/Lib/httplib.py b/Lib/httplib.py index 60a8fb4e355f897..a132d316ec8075e 100644 --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -71,6 +71,7 @@ import re import socket from sys import py3kwarning +import collections from urlparse import urlsplit import warnings with warnings.catch_warnings(): @@ -855,7 +856,15 @@ def send(self, data): self.sock.sendall(datablock) datablock = data.read(blocksize) else: - self.sock.sendall(data) + try: + self.sock.sendall(data) + except TypeError: + if isinstance(data, collections.Iterable): + for d in data: + self.sock.sendall(d) + else: + raise TypeError("data should be a bytes-like object " + "or an iterable, got %r" % type(data)) def _output(self, s): """Add a line of output to the current request buffer. diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 44ffac7036886e2..56abe98d6fd2b53 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -545,6 +545,22 @@ def test_send(self): conn.send(StringIO.StringIO(expected)) self.assertEqual(expected, sock.data) + def test_send_iter(self): + expected = b'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \ + b'Accept-Encoding: identity\r\nContent-Length: 11\r\n' \ + b'\r\nonetwothree' + + def body(): + yield b"one" + yield b"two" + yield b"three" + + conn = httplib.HTTPConnection('example.com') + sock = FakeSocket("") + conn.sock = sock + conn.request('GET', '/foo', body(), {'Content-Length': '11'}) + self.assertEquals(sock.data, expected) + def test_chunked(self): chunked_start = ( 'HTTP/1.1 200 OK\r\n' diff --git a/Misc/NEWS.d/next/Library/2018-10-29-22-12-31.bpo-3243.-ytiRj.rst b/Misc/NEWS.d/next/Library/2018-10-29-22-12-31.bpo-3243.-ytiRj.rst new file mode 100644 index 000000000000000..86ec3b9d717035d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-10-29-22-12-31.bpo-3243.-ytiRj.rst @@ -0,0 +1 @@ +Support iterable bodies in httplib.