summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_xmlrpc.py37
-rw-r--r--Lib/xmlrpc/client.py6
-rw-r--r--Misc/NEWS4
3 files changed, 44 insertions, 3 deletions
diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py
index d142a15..831a5a5 100644
--- a/Lib/test/test_xmlrpc.py
+++ b/Lib/test/test_xmlrpc.py
@@ -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&b")
diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py
index bf42835..e7daa07 100644
--- a/Lib/xmlrpc/client.py
+++ b/Lib/xmlrpc/client.py
@@ -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
diff --git a/Misc/NEWS b/Misc/NEWS
index 56f771f..029b334 100644
--- 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.