# an XML-RPC client interface for Python.
# the marshalling and response parser code can also be used to
# implement XML-RPC servers.
# this version is designed to work with Python 2.1 or newer.
# 1999-01-15 fl Changed dateTime to use localtime
# 1999-01-16 fl Added Binary/base64 element, default to RPC2 service
# 1999-01-19 fl Fixed array data element (from Skip Montanaro)
# 1999-01-21 fl Fixed dateTime constructor, etc.
# 1999-02-02 fl Added fault handling, handle empty sequences, etc.
# 1999-02-10 fl Fixed problem with empty responses (from Skip Montanaro)
# 1999-06-20 fl Speed improvements, pluggable parsers/transports (0.9.8)
# 2000-11-28 fl Changed boolean to check the truth value of its argument
# 2001-02-24 fl Added encoding/Unicode/SafeTransport patches
# 2001-02-26 fl Added compare support to wrappers (0.9.9/1.0b1)
# 2001-03-28 fl Make sure response tuple is a singleton
# 2001-03-29 fl Don't require empty params element (from Nicholas Riley)
# 2001-06-10 fl Folded in _xmlrpclib accelerator support (1.0b2)
# 2001-08-20 fl Base xmlrpclib.Error on built-in Exception (from Paul Prescod)
# 2001-09-03 fl Allow Transport subclass to override getparser
# 2001-09-10 fl Lazy import of urllib, cgi, xmllib (20x import speedup)
# 2001-10-01 fl Remove containers from memo cache when done with them
# 2001-10-01 fl Use faster escape method (80% dumps speedup)
# 2001-10-02 fl More dumps microtuning
# 2001-10-04 fl Make sure import expat gets a parser (from Guido van Rossum)
# 2001-10-10 sm Allow long ints to be passed as ints if they don't overflow
# 2001-10-17 sm Test for int and long overflow (allows use on 64-bit systems)
# 2001-11-12 fl Use repr() to marshal doubles (from Paul Felix)
# 2002-03-17 fl Avoid buffered read when possible (from James Rucker)
# 2002-04-07 fl Added pythondoc comments
# 2002-04-16 fl Added __str__ methods to datetime/binary wrappers
# 2002-05-15 fl Added error constants (from Andrew Kuchling)
# 2002-06-27 fl Merged with Python CVS version
# 2002-10-22 fl Added basic authentication (based on code from Phillip Eby)
# 2003-01-22 sm Add support for the bool type
# 2003-02-27 gvr Remove apply calls
# 2003-04-24 sm Use cStringIO if available
# 2003-04-25 ak Add support for nil
# 2003-06-15 gn Add support for time.struct_time
# 2003-07-12 gp Correct marshalling of Faults
# 2003-10-31 mvl Add multicall support
# 2004-08-20 mvl Bump minimum supported Python version to 2.1
# 2014-12-02 ch/doko Add workaround for gzip bomb vulnerability
# Copyright (c) 1999-2002 by Secret Labs AB.
# Copyright (c) 1999-2002 by Fredrik Lundh.
# http://www.pythonware.com
# --------------------------------------------------------------------
# The XML-RPC client interface is
# Copyright (c) 1999-2002 by Secret Labs AB
# Copyright (c) 1999-2002 by Fredrik Lundh
# By obtaining, using, and/or copying this software and/or its
# associated documentation, you agree that you have read, understood,
# and will comply with the following terms and conditions:
# Permission to use, copy, modify, and distribute this software and
# its associated documentation for any purpose and without fee is
# hereby granted, provided that the above copyright notice appears in
# all copies, and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of
# Secret Labs AB or the author not be used in advertising or publicity
# pertaining to distribution of the software without specific, written
# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# --------------------------------------------------------------------
# things to look into some day:
# TODO: sort out True/False/boolean issues for Python 2.3
An XML-RPC client interface for Python.
The marshalling and response parser code can also be used to
implement XML-RPC servers.
Error Base class for client errors
ProtocolError Indicates an HTTP protocol error
ResponseError Indicates a broken response package
Fault Indicates an XML-RPC fault package
ServerProxy Represents a logical connection to an XML-RPC server
MultiCall Executor of boxcared xmlrpc requests
Boolean boolean wrapper to generate a "boolean" XML-RPC value
DateTime dateTime wrapper for an ISO 8601 string or time tuple or
localtime integer value to generate a "dateTime.iso8601"
Binary binary data wrapper
SlowParser Slow but safe standard parser (based on xmllib)
Marshaller Generate an XML-RPC params chunk from a Python data structure
Unmarshaller Unmarshal an XML-RPC response from incoming XML event message
Transport Handles an HTTP transaction to an XML-RPC server
SafeTransport Handles an HTTPS transaction to an XML-RPC server
boolean Convert any Python value to an XML-RPC boolean
getparser Create instance of the fastest available parser & attach
to an unmarshalling object
dumps Convert an argument tuple or a Fault instance to an XML-RPC
request (or response, if the methodresponse option is used).
loads Convert an XML-RPC packet to unmarshalled data plus a method
name (None if not present).
import re, string, time, operator
gzip = None #python can be built without zlib/gzip support
# --------------------------------------------------------------------
unicode = None # unicode support not available
_bool_is_builtin = False.__class__.__name__ == "bool"
def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
# decode non-ascii string (if possible)
if unicode and encoding and is8bit(data):
data = unicode(data, encoding)
def escape(s, replace=string.replace):
s = replace(s, "&", "&")
s = replace(s, "<", "<")
return replace(s, ">", ">",)
# convert to 7-bit ascii if possible
return string.encode("ascii")
# --------------------------------------------------------------------
# Error constants (from Dan Libby's specification at
# http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
APPLICATION_ERROR = -32500
NOT_WELLFORMED_ERROR = -32700
UNSUPPORTED_ENCODING = -32701
INVALID_ENCODING_CHAR = -32702
METHOD_NOT_FOUND = -32601
INVALID_METHOD_PARAMS = -32602
# --------------------------------------------------------------------
# Base class for all kinds of client-side errors.
"""Base class for client errors."""
# Indicates an HTTP-level protocol error. This is raised by the HTTP
# transport layer, if the server returns an error code other than 200
# @param url The target URL.
# @param errcode The HTTP error code.
# @param errmsg The HTTP error message.
# @param headers The HTTP header dictionary.
class ProtocolError(Error):
"""Indicates an HTTP protocol error."""
def __init__(self, url, errcode, errmsg, headers):
"<ProtocolError for %s: %s %s>" %
(self.url, self.errcode, self.errmsg)
# Indicates a broken XML-RPC response package. This exception is
# raised by the unmarshalling layer, if the XML-RPC response is
class ResponseError(Error):
"""Indicates a broken response package."""
# Indicates an XML-RPC fault response package. This exception is
# raised by the unmarshalling layer, if the XML-RPC response contains
# a fault string. This exception can also used as a class, to
# generate a fault XML-RPC message.
# @param faultCode The XML-RPC fault code.
# @param faultString The XML-RPC fault string.
"""Indicates an XML-RPC fault package."""
def __init__(self, faultCode, faultString, **extra):
self.faultCode = faultCode
self.faultString = faultString
(self.faultCode, repr(self.faultString))
# --------------------------------------------------------------------
# Wrapper for XML-RPC boolean values. Use the xmlrpclib.True and
# xmlrpclib.False constants, or the xmlrpclib.boolean() function, to
# generate boolean XML-RPC values.
# @param value A boolean value. Any true value is interpreted as True,
# all other values are interpreted as False.
mod_dict = modules[__name__].__dict__
# to avoid breaking code which references xmlrpclib.{True,False}
mod_dict['False'] = False
"""Boolean-value wrapper.
Use True or False to generate a "boolean" XML-RPC value.
def __init__(self, value = 0):
self.value = operator.truth(value)
out.write("<value><boolean>%d</boolean></value>\n" % self.value)
def __cmp__(self, other):
if isinstance(other, Boolean):
return cmp(self.value, other)
return "<Boolean True at %x>" % id(self)
return "<Boolean False at %x>" % id(self)
mod_dict['True'] = Boolean(1)
mod_dict['False'] = Boolean(0)
# Map true or false value to XML-RPC boolean values.
# @param value A boolean value. Any true value is mapped to True,
# all other values are mapped to False.
# @return xmlrpclib.True or xmlrpclib.False.
def boolean(value, _truefalse=(False, True)):
"""Convert any Python value to XML-RPC 'boolean'."""
return _truefalse[operator.truth(value)]
# Wrapper for XML-RPC DateTime values. This converts a time value to
# the format used by XML-RPC.
# The value can be given as a string in the format
# "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by
# time.localtime()), or an integer value (as returned by time.time()).
# The wrapper uses time.localtime() to convert an integer to a time
# @param value The time, given as an ISO 8601 string, a time
# tuple, or an integer time value.
if isinstance(value, datetime.datetime):
return "%04d%02d%02dT%02d:%02d:%02d" % (
value.year, value.month, value.day,
value.hour, value.minute, value.second)
if not isinstance(value, (TupleType, time.struct_time)):
value = time.localtime(value)
return "%04d%02d%02dT%02d:%02d:%02d" % value[:6]
"""DateTime wrapper for an ISO 8601 string or time tuple or
localtime integer value to generate 'dateTime.iso8601' XML-RPC
def __init__(self, value=0):
if isinstance(value, StringType):
self.value = _strftime(value)
def make_comparable(self, other):
if isinstance(other, DateTime):
elif datetime and isinstance(other, datetime.datetime):
o = other.strftime("%Y%m%dT%H:%M:%S")
elif isinstance(other, basestring):
elif hasattr(other, "timetuple"):
otype = (hasattr(other, "__class__")
and other.__class__.__name__
raise TypeError("Can't compare %s and %s" %
(self.__class__.__name__, otype))
s, o = self.make_comparable(other)
s, o = self.make_comparable(other)
s, o = self.make_comparable(other)
s, o = self.make_comparable(other)
s, o = self.make_comparable(other)
s, o = self.make_comparable(other)
return time.strptime(self.value, "%Y%m%dT%H:%M:%S")
def __cmp__(self, other):
s, o = self.make_comparable(other)
# @return Date/time value, as an ISO 8601 string.
return "<DateTime %s at %x>" % (repr(self.value), id(self))
self.value = string.strip(data)
out.write("<value><dateTime.iso8601>")
out.write("</dateTime.iso8601></value>\n")
# decode xml element contents into a DateTime structure.
def _datetime_type(data):
t = time.strptime(data, "%Y%m%dT%H:%M:%S")
return datetime.datetime(*tuple(t)[:6])
# Wrapper for binary data. This can be used to transport any kind
# of binary data over XML-RPC, using BASE64 encoding.
# @param data An 8-bit string containing arbitrary data.
import cStringIO as StringIO
"""Wrapper for binary data."""
def __init__(self, data=None):
# @return Buffer contents, as an 8-bit string.
def __cmp__(self, other):
if isinstance(other, Binary):
return cmp(self.data, other)