Commit eae3336e authored by Martin Panter's avatar Martin Panter

Issue #26402: Fix XML-RPC client retrying after server disconnection

This is a regression introduced in 3.5 by revision eba80326ba53. Fix by Jelte
Fennema, test case by me.
parent f828218d
...@@ -7,6 +7,7 @@ from unittest import mock ...@@ -7,6 +7,7 @@ from unittest import mock
import xmlrpc.client as xmlrpclib import xmlrpc.client as xmlrpclib
import xmlrpc.server import xmlrpc.server
import http.client import http.client
import http, http.server
import socket import socket
import os import os
import re import re
...@@ -244,6 +245,42 @@ class XMLRPCTestCase(unittest.TestCase): ...@@ -244,6 +245,42 @@ class XMLRPCTestCase(unittest.TestCase):
except OSError: except OSError:
self.assertTrue(has_ssl) 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): class HelperTestCase(unittest.TestCase):
def test_escape(self): def test_escape(self):
self.assertEqual(xmlrpclib.escape("a&b"), "a&b") self.assertEqual(xmlrpclib.escape("a&b"), "a&b")
......
...@@ -1129,13 +1129,13 @@ class Transport: ...@@ -1129,13 +1129,13 @@ class Transport:
for i in (0, 1): for i in (0, 1):
try: try:
return self.single_request(host, handler, request_body, verbose) return self.single_request(host, handler, request_body, verbose)
except http.client.RemoteDisconnected:
if i:
raise
except OSError as e: except OSError as e:
if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED, if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED,
errno.EPIPE): errno.EPIPE):
raise raise
except http.client.RemoteDisconnected:
if i:
raise
def single_request(self, host, handler, request_body, verbose=False): def single_request(self, host, handler, request_body, verbose=False):
# issue XML-RPC request # issue XML-RPC request
......
...@@ -79,6 +79,10 @@ Core and Builtins ...@@ -79,6 +79,10 @@ Core and Builtins
Library 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 - Issue #25913: Leading ``<~`` is optional now in base64.a85decode() with
adobe=True. Patch by Swati Jaiswal. adobe=True. Patch by Swati Jaiswal.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment