summaryrefslogtreecommitdiffstats
path: root/Lib/http/client.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/http/client.py')
-rw-r--r--Lib/http/client.py65
1 files changed, 40 insertions, 25 deletions
diff --git a/Lib/http/client.py b/Lib/http/client.py
index a4ec8e5..99d560e 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -693,7 +693,7 @@ class HTTPConnection:
"""
self._buffer.append(s)
- def _send_output(self):
+ def _send_output(self, message_body=None):
"""Send the currently buffered request and clear the buffer.
Appends an extra \\r\\n to the buffer.
@@ -701,6 +701,11 @@ class HTTPConnection:
self._buffer.extend((b"", b""))
msg = b"\r\n".join(self._buffer)
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 algorithim.
+ if message_body is not None:
+ msg += message_body
self.send(msg)
def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0):
@@ -830,15 +835,20 @@ class HTTPConnection:
header = header + b': ' + value
self._output(header)
- def endheaders(self):
- """Indicate that the last header line has been sent to the server."""
+ def endheaders(self, message_body=None):
+ """Indicate that the last header line has been sent to the server.
+ This method sends the request to the server. The optional
+ message_body argument can be used to pass message body
+ associated with the request. The message body will be sent in
+ the same packet as the message headers if possible. The
+ message_body should be a string.
+ """
if self.__state == _CS_REQ_STARTED:
self.__state = _CS_REQ_SENT
else:
raise CannotSendHeader()
-
- self._send_output()
+ self._send_output(message_body)
def request(self, method, url, body=None, headers={}):
"""Send a complete request to the server."""
@@ -851,6 +861,24 @@ class HTTPConnection:
# try one more time
self._send_request(method, url, body, headers)
+ def _set_content_length(self, body):
+ # Set the content-length based on the body.
+ thelen = None
+ try:
+ thelen = str(len(body))
+ 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):
+ # Don't send a length if this failed
+ if self.debuglevel > 0: print("Cannot stat!!")
+
+ if thelen is not None:
+ self.putheader('Content-Length', thelen)
+
def _send_request(self, method, url, body, headers):
# honour explicitly requested Host: and Accept-Encoding headers
header_names = dict.fromkeys([k.lower() for k in headers])
@@ -863,28 +891,15 @@ class HTTPConnection:
self.putrequest(method, url, **skips)
if body and ('content-length' not in header_names):
- thelen = None
- try:
- thelen = str(len(body))
- 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):
- # Don't send a length if this failed
- if self.debuglevel > 0: print("Cannot stat!!")
-
- if thelen is not None:
- self.putheader('Content-Length',thelen)
+ self._set_content_length(body)
for hdr, value in headers.items():
self.putheader(hdr, value)
- self.endheaders()
-
- if body:
- if isinstance(body, str): body = body.encode('ascii')
- self.send(body)
+ if isinstance(body, str):
+ self.endheaders(body.encode('ascii'))
+ else:
+ self.endheaders()
+ if body: # when body is a file rather than a string
+ self.send(body)
def getresponse(self):
"""Get the response from the server."""