Merged revisions 67442 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r67442 | jeremy.hylton | 2008-11-28 19:09:35 -0600 (Fri, 28 Nov 2008) | 18 lines

  Send HTTP headers and message body in a single send() call.

  This change addresses part of issue 4336.

  Change endheaders() to take an optional message_body argument
  that is sent along with the headers.  Change xmlrpclib and
  httplib's other methods to use this new interface.

  It is more efficient to make a single send() call, which should
  get the entire client request into one packet (assuming it is
  smaller than the MTU) and will avoid the long pause for delayed
  ack following timeout.

  Also:
  - Add a comment about the buffer size for makefile().
  - Extract _set_content_length() method and fix whitespace issues there.
........
This commit is contained in:
Benjamin Peterson 2008-11-30 22:15:29 +00:00
parent 45a6b9f7e5
commit 1742e401c4
1 changed files with 40 additions and 25 deletions

View File

@ -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."""