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.
This commit is contained in:
Martin Panter 2016-02-25 11:53:40 +00:00
parent f828218d65
commit eae3336e42
3 changed files with 44 additions and 3 deletions

View File

@ -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):
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")

View File

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

View File

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