Index: Lib/xmlrpclib.py |
=================================================================== |
--- Lib/xmlrpclib.py (revision 73271) |
+++ Lib/xmlrpclib.py (working copy) |
@@ -140,6 +140,9 @@ |
from types import * |
+import socket |
+import errno |
+ |
# -------------------------------------------------------------------- |
# Internal stuff |
@@ -1158,7 +1161,27 @@ |
def __init__(self, use_datetime=0): |
self._use_datetime = use_datetime |
+ self._connection = None |
+ self._extra_headers = [] |
+ ## |
+ # Send a complete request, and parse the response. |
+ # Retry request if a cached connection has disconnected. |
+ # |
+ # @param host Target host. |
+ # @param handler Target PRC handler. |
+ # @param request_body XML-RPC request body. |
+ # @param verbose Debugging flag. |
+ # @return Parsed response. |
+ def request(self, host, handler, request_body, verbose=0): |
+ #retry request if cached connection has gone cold |
+ for i in (0, 1): |
+ try: |
+ return self.single_request(host, handler, request_body, verbose) |
+ except socket.error, e: |
+ if not (i == 0 and e[0] == errno.ECONNRESET): |
+ raise |
+ |
## |
# Send a complete request, and parse the response. |
# |
@@ -1168,31 +1191,38 @@ |
# @param verbose Debugging flag. |
# @return Parsed response. |
- def request(self, host, handler, request_body, verbose=0): |
+ def single_request(self, host, handler, request_body, verbose=0): |
# issue XML-RPC request |
h = self.make_connection(host) |
if verbose: |
h.set_debuglevel(1) |
- self.send_request(h, handler, request_body) |
- self.send_host(h, host) |
- self.send_user_agent(h) |
- self.send_content(h, request_body) |
+ try: |
+ self.send_request(h, handler, request_body) |
+ self.send_extra_headers(h) |
+ self.send_user_agent(h) |
+ self.send_content(h, request_body) |
- errcode, errmsg, headers = h.getreply(buffering=True) |
+ response = h.getresponse(buffering=True) |
+ if response.status == 200: |
+ self.verbose = verbose |
+ return self.parse_response(response) |
+ except Fault: |
+ raise |
+ except Exception: |
+ # All unexpected errors leave connection in |
+ # a strange state, so we clear it. |
+ self.clear_connection() |
+ raise |
- if errcode != 200: |
- raise ProtocolError( |
- host + handler, |
- errcode, errmsg, |
- headers |
- ) |
+ response.read() #discard any response data |
+ raise ProtocolError( |
+ host + handler, |
+ response.status, response.reason, |
+ response.msg, |
+ ) |
- self.verbose = verbose |
- |
- return self.parse_response(h.getfile()) |
- |
## |
# Create parser. |
# |
@@ -1240,12 +1270,24 @@ |
# @return A connection handle. |
def make_connection(self, host): |
+ if self._connection: |
+ return self._connection |
# create a HTTP connection object from a host descriptor |
import httplib |
- host, extra_headers, x509 = self.get_host_info(host) |
- return httplib.HTTP(host) |
+ host, self._extra_headers, x509 = self.get_host_info(host) |
+ self._connection = httplib.HTTPConnection(host) |
+ return self._connection |
## |
+ # Clear any cached connection object. |
+ # Used in the event of socket errors. |
+ # |
+ def clear_connection(self): |
+ if self._connection: |
+ self._connection.close() |
+ self._connection = None |
+ |
+ ## |
# Send request header. |
# |
# @param connection Connection handle. |
@@ -1256,14 +1298,12 @@ |
connection.putrequest("POST", handler) |
## |
- # Send host name. |
+ # Send extra headers. |
# |
# @param connection Connection handle. |
- # @param host Host name. |
- def send_host(self, connection, host): |
- host, extra_headers, x509 = self.get_host_info(host) |
- connection.putheader("Host", host) |
+ def send_extra_headers(self, connection): |
+ extra_headers = self._extra_headers |
if extra_headers: |
if isinstance(extra_headers, DictType): |
extra_headers = extra_headers.items() |
@@ -1295,20 +1335,19 @@ |
# @param file Stream. |
# @return Response tuple and target method. |
- def parse_response(self, file): |
- # read response from input file/socket, and parse it |
+ def parse_response(self, response): |
+ # read response data from httpresponse, and parse it |
p, u = self.getparser() |
while 1: |
- response = file.read(1024) |
- if not response: |
+ data = response.read(1024) |
+ if not data: |
break |
if self.verbose: |
- print "body:", repr(response) |
- p.feed(response) |
+ print "body:", repr(data) |
+ p.feed(data) |
- file.close() |
p.close() |
return u.close() |
@@ -1322,18 +1361,14 @@ |
# FIXME: mostly untested |
def make_connection(self, host): |
+ if self._connection: |
+ return self._connection |
# create a HTTPS connection object from a host descriptor |
# host may be a string, or a (host, x509-dict) tuple |
import httplib |
- host, extra_headers, x509 = self.get_host_info(host) |
- try: |
- HTTPS = httplib.HTTPS |
- except AttributeError: |
- raise NotImplementedError( |
- "your version of httplib doesn't support HTTPS" |
- ) |
- else: |
- return HTTPS(host, None, **(x509 or {})) |
+ host, self._extra_headers, x509 = self.get_host_info(host) |
+ self._connection = httplib.HTTPSConnection(host, None, **(x509 or {})) |
+ return self._connection |
## |
# Standard server proxy. This class establishes a virtual connection |