]> granicus.if.org Git - python/commitdiff
Issue #26402: Fix XML-RPC client retrying after server disconnection
authorMartin Panter <vadmium+py@gmail.com>
Thu, 25 Feb 2016 11:53:40 +0000 (11:53 +0000)
committerMartin Panter <vadmium+py@gmail.com>
Thu, 25 Feb 2016 11:53:40 +0000 (11:53 +0000)
This is a regression introduced in 3.5 by revision eba80326ba53. Fix by Jelte
Fennema, test case by me.

Lib/test/test_xmlrpc.py
Lib/xmlrpc/client.py
Misc/NEWS

index d142a15b6f9bb3f9d8e4d39839755a67af9a8119..831a5a5aaed5fc546375f4e71888e24228f4467d 100644 (file)
@@ -7,6 +7,7 @@ from unittest import mock
 import xmlrpc.client as xmlrpclib
 import xmlrpc.server
 import http.client
+import http, http.server
 import socket
 import os
 import re
@@ -244,6 +245,42 @@ class XMLRPCTestCase(unittest.TestCase):
         except OSError:
             self.assertTrue(has_ssl)
 
+    @unittest.skipUnless(threading, "Threading required for this test.")
+    def test_keepalive_disconnect(self):
+        class RequestHandler(http.server.BaseHTTPRequestHandler):
+            protocol_version = "HTTP/1.1"
+            handled = False
+
+            def do_POST(self):
+                length = int(self.headers.get("Content-Length"))
+                self.rfile.read(length)
+                if self.handled:
+                    self.close_connection = True
+                    return
+                response = xmlrpclib.dumps((5,), methodresponse=True)
+                response = response.encode()
+                self.send_response(http.HTTPStatus.OK)
+                self.send_header("Content-Length", len(response))
+                self.end_headers()
+                self.wfile.write(response)
+                self.handled = True
+                self.close_connection = False
+
+        def run_server():
+            server.socket.settimeout(float(1))  # Don't hang if client fails
+            server.handle_request()  # First request and attempt at second
+            server.handle_request()  # Retried second request
+
+        server = http.server.HTTPServer((support.HOST, 0), RequestHandler)
+        self.addCleanup(server.server_close)
+        thread = threading.Thread(target=run_server)
+        thread.start()
+        self.addCleanup(thread.join)
+        url = "http://{}:{}/".format(*server.server_address)
+        with xmlrpclib.ServerProxy(url) as p:
+            self.assertEqual(p.method(), 5)
+            self.assertEqual(p.method(), 5)
+
 class HelperTestCase(unittest.TestCase):
     def test_escape(self):
         self.assertEqual(xmlrpclib.escape("a&b"), "a&amp;b")
index bf428358439fc9887ed176900c180eea942279bd..e7daa0793b7fbe5a9a655bbd40742fb8993738ac 100644 (file)
@@ -1129,13 +1129,13 @@ class Transport:
         for i in (0, 1):
             try:
                 return self.single_request(host, handler, request_body, verbose)
+            except http.client.RemoteDisconnected:
+                if i:
+                    raise
             except OSError as e:
                 if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED,
                                         errno.EPIPE):
                     raise
-            except http.client.RemoteDisconnected:
-                if i:
-                    raise
 
     def single_request(self, host, handler, request_body, verbose=False):
         # issue XML-RPC request
index 56f771fc763995ccbcd0e0eef365f8d40c2c2358..029b334e5689cf1f88cb05838e0d0bf61f3c0176 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -79,6 +79,10 @@ Core and Builtins
 Library
 -------
 
+- Issue #26402: Fix XML-RPC client to retry when the server shuts down a
+  persistent connection.  This was a regression related to the new
+  http.client.RemoteDisconnected exception in 3.5.0a4.
+
 - Issue #25913: Leading ``<~`` is optional now in base64.a85decode() with
   adobe=True.  Patch by Swati Jaiswal.