]> granicus.if.org Git - python/commitdiff
Issue #16833: In http.client.HTTPConnection, do not concatenate the request headers...
authorAntoine Pitrou <solipsis@pitrou.net>
Wed, 2 Jan 2013 21:10:47 +0000 (22:10 +0100)
committerAntoine Pitrou <solipsis@pitrou.net>
Wed, 2 Jan 2013 21:10:47 +0000 (22:10 +0100)
Patch by Benno Leslie.

Lib/http/client.py
Lib/test/test_httplib.py
Misc/ACKS
Misc/NEWS

index 5e5b3a382eeae8260e0590e8b193ca0385c549bd..7db79b3f2134f9fe61e47460f293544ffd349f51 100644 (file)
@@ -719,6 +719,14 @@ class HTTPConnection:
     default_port = HTTP_PORT
     auto_open = 1
     debuglevel = 0
+    # TCP Maximum Segment Size (MSS) is determined by the TCP stack on
+    # a per-connection basis.  There is no simple and efficient
+    # platform independent mechanism for determining the MSS, so
+    # instead a reasonable estimate is chosen.  The getsockopt()
+    # interface using the TCP_MAXSEG parameter may be a suitable
+    # approach on some operating systems. A value of 16KiB is chosen
+    # as a reasonable estimate of the maximum MSS.
+    mss = 16384
 
     def __init__(self, host, port=None, strict=_strict_sentinel,
                  timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None):
@@ -886,8 +894,11 @@ class HTTPConnection:
         del self._buffer[:]
         # If msg and message_body are sent in a single send() call,
         # it will avoid performance problems caused by the interaction
-        # between delayed ack and the Nagle algorithm.
-        if isinstance(message_body, bytes):
+        # between delayed ack and the Nagle algorithm. However,
+        # there is no performance gain if the message is larger
+        # than MSS (and there is a memory penalty for the message
+        # copy).
+        if isinstance(message_body, bytes) and len(message_body) < self.mss:
             msg += message_body
             message_body = None
         self.send(msg)
index 9c53e9c7ba766b6ac202d42ae115cb60b7170e80..e2d644d98c053881e974cd0c781f9bc9a59c9fc7 100644 (file)
@@ -27,8 +27,10 @@ class FakeSocket:
         self.text = text
         self.fileclass = fileclass
         self.data = b''
+        self.sendall_calls = 0
 
     def sendall(self, data):
+        self.sendall_calls += 1
         self.data += data
 
     def makefile(self, mode, bufsize=None):
@@ -558,6 +560,28 @@ class BasicTest(TestCase):
         self.assertEqual(resp.read(), b'')
         self.assertTrue(resp.isclosed())
 
+    def test_delayed_ack_opt(self):
+        # Test that Nagle/delayed_ack optimistaion works correctly.
+
+        # For small payloads, it should coalesce the body with
+        # headers, resulting in a single sendall() call
+        conn = client.HTTPConnection('example.com')
+        sock = FakeSocket(None)
+        conn.sock = sock
+        body = b'x' * (conn.mss - 1)
+        conn.request('POST', '/', body)
+        self.assertEqual(sock.sendall_calls, 1)
+
+        # For large payloads, it should send the headers and
+        # then the body, resulting in more than one sendall()
+        # call
+        conn = client.HTTPConnection('example.com')
+        sock = FakeSocket(None)
+        conn.sock = sock
+        body = b'x' * conn.mss
+        conn.request('POST', '/', body)
+        self.assertGreater(sock.sendall_calls, 1)
+
 class OfflineTest(TestCase):
     def test_responses(self):
         self.assertEqual(client.responses[client.NOT_FOUND], "Not Found")
index 1f0b1e0fa5a30ccce056e1365bdfa08a1981b8cb..9a7b3a7bf4095a3a4015263d5a9cad0aa5befda0 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -705,6 +705,7 @@ Luke Kenneth Casson Leighton
 Tshepang Lekhonkhobe
 Marc-AndrĂ© Lemburg
 John Lenton
+Benno Leslie
 Christopher Tur Lesniewski-Laas
 Alain Leufroy
 Mark Levinson
index 161d4fd3113ae739cc80997550f26d7937dfa8b1..eaa8cfc30dcdfa55e5657813e78c59cad3d8dc64 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -199,6 +199,10 @@ Core and Builtins
 Library
 -------
 
+- Issue #16833: In http.client.HTTPConnection, do not concatenate the request
+  headers and body when the payload exceeds 16 KB, since it can consume more
+  memory for no benefit.  Patch by Benno Leslie.
+
 - Issue #16541: tk_setPalette() now works with keyword arguments.
 
 - Issue #16820: In configparser, `parser.popitem()` no longer raises ValueError.