Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions Doc/library/http.client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ HTTPS protocols. It is normally not used directly --- the module
The module provides the following classes:


.. class:: HTTPConnection(host, port=None[, timeout], source_address=None)
.. class:: HTTPConnection(host, port=None[, timeout], source_address=None, \
blocksize=8192)

An :class:`HTTPConnection` instance represents one transaction with an HTTP
server. It should be instantiated passing it a host and optional port
Expand All @@ -42,6 +43,8 @@ The module provides the following classes:
(if it is not given, the global default timeout setting is used).
The optional *source_address* parameter may be a tuple of a (host, port)
to use as the source address the HTTP connection is made from.
The optional *blocksize* parameter sets the buffer size in bytes for
sending a file-like message body.

For example, the following calls all create instances that connect to the server
at the same host and port::
Expand All @@ -58,11 +61,14 @@ The module provides the following classes:
The *strict* parameter was removed. HTTP 0.9-style "Simple Responses" are
not longer supported.

.. versionchanged:: 3.7
*blocksize* parameter was added.


.. class:: HTTPSConnection(host, port=None, key_file=None, \
cert_file=None[, timeout], \
source_address=None, *, context=None, \
check_hostname=None)
check_hostname=None, blocksize=8192)

A subclass of :class:`HTTPConnection` that uses SSL for communication with
secure servers. Default port is ``443``. If *context* is specified, it
Expand Down Expand Up @@ -338,6 +344,14 @@ HTTPConnection Objects

Close the connection to the server.


.. attribute:: HTTPConnection.blocksize

Buffer size in bytes for sending a file-like message body.

.. versionadded:: 3.7


As an alternative to using the :meth:`request` method described above, you can
also send your request step by step, by using the four functions below.

Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,13 @@ README.rst is now included in the list of distutils standard READMEs and
therefore included in source distributions.
(Contributed by Ryan Gonzalez in :issue:`11913`.)

http.client
-----------

Add Configurable *blocksize* to ``HTTPConnection`` and
``HTTPSConnection`` for improved upload throughput.
(Contributed by Nir Soffer in :issue:`31945`.)

http.server
-----------

Expand Down
14 changes: 7 additions & 7 deletions Lib/http/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -825,9 +825,10 @@ def _get_content_length(body, method):
return None

def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
source_address=None):
source_address=None, blocksize=8192):
self.timeout = timeout
self.source_address = source_address
self.blocksize = blocksize

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest either name the attribute with an underscore (“_blocksize”) or document it as a public attribute.

@nirs nirs Nov 6, 2017

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll document that this is a public attribute, since a user of the connection may like to modify it.

For example, user code may want to check if a connection supports changing the block size, and hasattr(conn, "blocksize") is nicer to use compared with checking __init__ signature.

self.sock = None
self._buffer = []
self.__response = None
Expand Down Expand Up @@ -958,15 +959,14 @@ def send(self, data):

if self.debuglevel > 0:
print("send:", repr(data))
blocksize = 8192
if hasattr(data, "read") :
if self.debuglevel > 0:
print("sendIng a read()able")
encode = self._is_textIO(data)
if encode and self.debuglevel > 0:
print("encoding file using iso-8859-1")
while 1:
datablock = data.read(blocksize)
datablock = data.read(self.blocksize)
if not datablock:
break
if encode:
Expand All @@ -991,14 +991,13 @@ def _output(self, s):
self._buffer.append(s)

def _read_readable(self, readable):
blocksize = 8192
if self.debuglevel > 0:
print("sendIng a read()able")
encode = self._is_textIO(readable)
if encode and self.debuglevel > 0:
print("encoding file using iso-8859-1")
while True:
datablock = readable.read(blocksize)
datablock = readable.read(self.blocksize)
if not datablock:
break
if encode:
Expand Down Expand Up @@ -1353,9 +1352,10 @@ class HTTPSConnection(HTTPConnection):
def __init__(self, host, port=None, key_file=None, cert_file=None,
timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
source_address=None, *, context=None,
check_hostname=None):
check_hostname=None, blocksize=8192):
super(HTTPSConnection, self).__init__(host, port, timeout,
source_address)
source_address,
blocksize=blocksize)
if (key_file is not None or cert_file is not None or
check_hostname is not None):
import warnings
Expand Down
23 changes: 23 additions & 0 deletions Lib/test/test_httplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,29 @@ def body():
conn.request('GET', '/foo', body(), {'Content-Length': '11'})
self.assertEqual(sock.data, expected)

def test_blocksize_request(self):
"""Check that request() respects the configured block size."""
blocksize = 8 # For easy debugging.
conn = client.HTTPConnection('example.com', blocksize=blocksize)
sock = FakeSocket(None)
conn.sock = sock
expected = b"a" * blocksize + b"b"
conn.request("PUT", "/", io.BytesIO(expected), {"Content-Length": "9"})
self.assertEqual(sock.sendall_calls, 3)
body = sock.data.split(b"\r\n\r\n", 1)[1]
self.assertEqual(body, expected)

def test_blocksize_send(self):
"""Check that send() respects the configured block size."""
blocksize = 8 # For easy debugging.
conn = client.HTTPConnection('example.com', blocksize=blocksize)
sock = FakeSocket(None)
conn.sock = sock
expected = b"a" * blocksize + b"b"
conn.send(io.BytesIO(expected))
self.assertEqual(sock.sendall_calls, 2)
self.assertEqual(sock.data, expected)

def test_send_type_error(self):
# See: Issue #12676
conn = client.HTTPConnection('example.com')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add Configurable *blocksize* to ``HTTPConnection`` and
``HTTPSConnection`` for improved upload throughput. Patch by Nir
Soffer.