Index: Lib/httplib.py =================================================================== --- Lib/httplib.py (revision 67120) +++ Lib/httplib.py (working copy) @@ -734,10 +734,17 @@ Appends an extra \\r\\n to the buffer. """ + self.send(self._get_output()) + + def _get_output(self): + """Get the currently buffered request and clear the buffer. + + Appends an extra \\r\\n to the buffer. + """ self._buffer.extend(("", "")) msg = "\r\n".join(self._buffer) del self._buffer[:] - self.send(msg) + return msg def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0): """Send a request to the server. @@ -857,16 +864,29 @@ str = '%s: %s' % (header, value) self._output(str) - def endheaders(self): - """Indicate that the last header line has been sent to the server.""" - + def endheaders(self, extra_data=None): + """Indicate that the last header line has been sent to the server. + The optional extra_data is data that is sent afther the headers, and + can be either a string or a file-like object. It will be appended + to the header data and all sent in one chunk if possible. + This helps avoid the dreaded Nagle/delayed-ACK TCP performance + problem that can be caused by two send operations in a row. + """ if self.__state == _CS_REQ_STARTED: self.__state = _CS_REQ_SENT else: raise CannotSendHeader() + if extra_data is not None: + if isinstance(extra_data, str): + self.send(self._get_output() + extra_data) + else: + #if extra_data is a file, we have to live with risking + #the Nagle problem + self._send_output() + self.send(extra_data) + else: + self._send_output() - self._send_output() - def request(self, method, url, body=None, headers={}): """Send a complete request to the server.""" @@ -908,11 +928,8 @@ self.putheader('Content-Length',thelen) for hdr, value in headers.iteritems(): self.putheader(hdr, value) - self.endheaders() + self.endheaders(body) - if body: - self.send(body) - def getresponse(self): "Get the response from the server." Index: Lib/test/test_xmlrpc.py =================================================================== --- Lib/test/test_xmlrpc.py (revision 67120) +++ Lib/test/test_xmlrpc.py (working copy) @@ -405,6 +405,9 @@ # protocol error; provide additional information in test output self.fail("%s\n%s" % (e, getattr(e, "headers", ""))) + + + def test_introspection2(self): try: # test _methodHelp() @@ -647,7 +650,9 @@ # 10035 (WSAEWOULDBLOCK) in the server thread handle_request call when # run on Windows. This only happens on the first test to run, but it # fails every time and so these tests are skipped on win32 platforms. - if sys.platform != 'win32': + # Update, nov 2008: This appears no longer to be the case, so they + # are included regardless + if True or sys.platform != 'win32': xmlrpc_tests.append(SimpleServerTestCase) xmlrpc_tests.append(FailingServerTestCase) xmlrpc_tests.append(CGIHandlerTestCase) Index: Lib/xmlrpclib.py =================================================================== --- Lib/xmlrpclib.py (revision 67120) +++ Lib/xmlrpclib.py (working copy) @@ -1234,6 +1234,8 @@ self.send_user_agent(h) self.send_content(h, request_body) + #we will perform readline() on the h.getfile() so we need + #default buffering errcode, errmsg, headers = h.getreply() if errcode != 200: @@ -1249,7 +1251,6 @@ sock = h._conn.sock except AttributeError: sock = None - return self._parse_response(h.getfile(), sock) ## @@ -1346,9 +1347,7 @@ def send_content(self, connection, request_body): connection.putheader("Content-Type", "text/xml") connection.putheader("Content-Length", str(len(request_body))) - connection.endheaders() - if request_body: - connection.send(request_body) + connection.endheaders(request_body) ## # Parse response.