Home | History | Annotate | Download | only in Lib
      1 #
      2 # XML-RPC CLIENT LIBRARY
      3 # $Id$
      4 #
      5 # an XML-RPC client interface for Python.
      6 #
      7 # the marshalling and response parser code can also be used to
      8 # implement XML-RPC servers.
      9 #
     10 # Notes:
     11 # this version is designed to work with Python 2.1 or newer.
     12 #
     13 # History:
     14 # 1999-01-14 fl  Created
     15 # 1999-01-15 fl  Changed dateTime to use localtime
     16 # 1999-01-16 fl  Added Binary/base64 element, default to RPC2 service
     17 # 1999-01-19 fl  Fixed array data element (from Skip Montanaro)
     18 # 1999-01-21 fl  Fixed dateTime constructor, etc.
     19 # 1999-02-02 fl  Added fault handling, handle empty sequences, etc.
     20 # 1999-02-10 fl  Fixed problem with empty responses (from Skip Montanaro)
     21 # 1999-06-20 fl  Speed improvements, pluggable parsers/transports (0.9.8)
     22 # 2000-11-28 fl  Changed boolean to check the truth value of its argument
     23 # 2001-02-24 fl  Added encoding/Unicode/SafeTransport patches
     24 # 2001-02-26 fl  Added compare support to wrappers (0.9.9/1.0b1)
     25 # 2001-03-28 fl  Make sure response tuple is a singleton
     26 # 2001-03-29 fl  Don't require empty params element (from Nicholas Riley)
     27 # 2001-06-10 fl  Folded in _xmlrpclib accelerator support (1.0b2)
     28 # 2001-08-20 fl  Base xmlrpclib.Error on built-in Exception (from Paul Prescod)
     29 # 2001-09-03 fl  Allow Transport subclass to override getparser
     30 # 2001-09-10 fl  Lazy import of urllib, cgi, xmllib (20x import speedup)
     31 # 2001-10-01 fl  Remove containers from memo cache when done with them
     32 # 2001-10-01 fl  Use faster escape method (80% dumps speedup)
     33 # 2001-10-02 fl  More dumps microtuning
     34 # 2001-10-04 fl  Make sure import expat gets a parser (from Guido van Rossum)
     35 # 2001-10-10 sm  Allow long ints to be passed as ints if they don't overflow
     36 # 2001-10-17 sm  Test for int and long overflow (allows use on 64-bit systems)
     37 # 2001-11-12 fl  Use repr() to marshal doubles (from Paul Felix)
     38 # 2002-03-17 fl  Avoid buffered read when possible (from James Rucker)
     39 # 2002-04-07 fl  Added pythondoc comments
     40 # 2002-04-16 fl  Added __str__ methods to datetime/binary wrappers
     41 # 2002-05-15 fl  Added error constants (from Andrew Kuchling)
     42 # 2002-06-27 fl  Merged with Python CVS version
     43 # 2002-10-22 fl  Added basic authentication (based on code from Phillip Eby)
     44 # 2003-01-22 sm  Add support for the bool type
     45 # 2003-02-27 gvr Remove apply calls
     46 # 2003-04-24 sm  Use cStringIO if available
     47 # 2003-04-25 ak  Add support for nil
     48 # 2003-06-15 gn  Add support for time.struct_time
     49 # 2003-07-12 gp  Correct marshalling of Faults
     50 # 2003-10-31 mvl Add multicall support
     51 # 2004-08-20 mvl Bump minimum supported Python version to 2.1
     52 # 2014-12-02 ch/doko  Add workaround for gzip bomb vulnerability
     53 #
     54 # Copyright (c) 1999-2002 by Secret Labs AB.
     55 # Copyright (c) 1999-2002 by Fredrik Lundh.
     56 #
     57 # info (at] pythonware.com
     58 # http://www.pythonware.com
     59 #
     60 # --------------------------------------------------------------------
     61 # The XML-RPC client interface is
     62 #
     63 # Copyright (c) 1999-2002 by Secret Labs AB
     64 # Copyright (c) 1999-2002 by Fredrik Lundh
     65 #
     66 # By obtaining, using, and/or copying this software and/or its
     67 # associated documentation, you agree that you have read, understood,
     68 # and will comply with the following terms and conditions:
     69 #
     70 # Permission to use, copy, modify, and distribute this software and
     71 # its associated documentation for any purpose and without fee is
     72 # hereby granted, provided that the above copyright notice appears in
     73 # all copies, and that both that copyright notice and this permission
     74 # notice appear in supporting documentation, and that the name of
     75 # Secret Labs AB or the author not be used in advertising or publicity
     76 # pertaining to distribution of the software without specific, written
     77 # prior permission.
     78 #
     79 # SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
     80 # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
     81 # ABILITY AND FITNESS.  IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
     82 # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
     83 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     84 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
     85 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     86 # OF THIS SOFTWARE.
     87 # --------------------------------------------------------------------
     88 
     89 #
     90 # things to look into some day:
     91 
     92 # TODO: sort out True/False/boolean issues for Python 2.3
     93 
     94 """
     95 An XML-RPC client interface for Python.
     96 
     97 The marshalling and response parser code can also be used to
     98 implement XML-RPC servers.
     99 
    100 Exported exceptions:
    101 
    102   Error          Base class for client errors
    103   ProtocolError  Indicates an HTTP protocol error
    104   ResponseError  Indicates a broken response package
    105   Fault          Indicates an XML-RPC fault package
    106 
    107 Exported classes:
    108 
    109   ServerProxy    Represents a logical connection to an XML-RPC server
    110 
    111   MultiCall      Executor of boxcared xmlrpc requests
    112   Boolean        boolean wrapper to generate a "boolean" XML-RPC value
    113   DateTime       dateTime wrapper for an ISO 8601 string or time tuple or
    114                  localtime integer value to generate a "dateTime.iso8601"
    115                  XML-RPC value
    116   Binary         binary data wrapper
    117 
    118   SlowParser     Slow but safe standard parser (based on xmllib)
    119   Marshaller     Generate an XML-RPC params chunk from a Python data structure
    120   Unmarshaller   Unmarshal an XML-RPC response from incoming XML event message
    121   Transport      Handles an HTTP transaction to an XML-RPC server
    122   SafeTransport  Handles an HTTPS transaction to an XML-RPC server
    123 
    124 Exported constants:
    125 
    126   True
    127   False
    128 
    129 Exported functions:
    130 
    131   boolean        Convert any Python value to an XML-RPC boolean
    132   getparser      Create instance of the fastest available parser & attach
    133                  to an unmarshalling object
    134   dumps          Convert an argument tuple or a Fault instance to an XML-RPC
    135                  request (or response, if the methodresponse option is used).
    136   loads          Convert an XML-RPC packet to unmarshalled data plus a method
    137                  name (None if not present).
    138 """
    139 
    140 import re, string, time, operator
    141 
    142 from types import *
    143 import socket
    144 import errno
    145 import httplib
    146 try:
    147     import gzip
    148 except ImportError:
    149     gzip = None #python can be built without zlib/gzip support
    150 
    151 # --------------------------------------------------------------------
    152 # Internal stuff
    153 
    154 try:
    155     unicode
    156 except NameError:
    157     unicode = None # unicode support not available
    158 
    159 try:
    160     import datetime
    161 except ImportError:
    162     datetime = None
    163 
    164 try:
    165     _bool_is_builtin = False.__class__.__name__ == "bool"
    166 except NameError:
    167     _bool_is_builtin = 0
    168 
    169 def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
    170     # decode non-ascii string (if possible)
    171     if unicode and encoding and is8bit(data):
    172         data = unicode(data, encoding)
    173     return data
    174 
    175 def escape(s, replace=string.replace):
    176     s = replace(s, "&", "&")
    177     s = replace(s, "<", "&lt;")
    178     return replace(s, ">", "&gt;",)
    179 
    180 if unicode:
    181     def _stringify(string):
    182         # convert to 7-bit ascii if possible
    183         try:
    184             return string.encode("ascii")
    185         except UnicodeError:
    186             return string
    187 else:
    188     def _stringify(string):
    189         return string
    190 
    191 __version__ = "1.0.1"
    192 
    193 # xmlrpc integer limits
    194 MAXINT =  2L**31-1
    195 MININT = -2L**31
    196 
    197 # --------------------------------------------------------------------
    198 # Error constants (from Dan Libby's specification at
    199 # http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
    200 
    201 # Ranges of errors
    202 PARSE_ERROR       = -32700
    203 SERVER_ERROR      = -32600
    204 APPLICATION_ERROR = -32500
    205 SYSTEM_ERROR      = -32400
    206 TRANSPORT_ERROR   = -32300
    207 
    208 # Specific errors
    209 NOT_WELLFORMED_ERROR  = -32700
    210 UNSUPPORTED_ENCODING  = -32701
    211 INVALID_ENCODING_CHAR = -32702
    212 INVALID_XMLRPC        = -32600
    213 METHOD_NOT_FOUND      = -32601
    214 INVALID_METHOD_PARAMS = -32602
    215 INTERNAL_ERROR        = -32603
    216 
    217 # --------------------------------------------------------------------
    218 # Exceptions
    219 
    220 ##
    221 # Base class for all kinds of client-side errors.
    222 
    223 class Error(Exception):
    224     """Base class for client errors."""
    225     def __str__(self):
    226         return repr(self)
    227 
    228 ##
    229 # Indicates an HTTP-level protocol error.  This is raised by the HTTP
    230 # transport layer, if the server returns an error code other than 200
    231 # (OK).
    232 #
    233 # @param url The target URL.
    234 # @param errcode The HTTP error code.
    235 # @param errmsg The HTTP error message.
    236 # @param headers The HTTP header dictionary.
    237 
    238 class ProtocolError(Error):
    239     """Indicates an HTTP protocol error."""
    240     def __init__(self, url, errcode, errmsg, headers):
    241         Error.__init__(self)
    242         self.url = url
    243         self.errcode = errcode
    244         self.errmsg = errmsg
    245         self.headers = headers
    246     def __repr__(self):
    247         return (
    248             "<ProtocolError for %s: %s %s>" %
    249             (self.url, self.errcode, self.errmsg)
    250             )
    251 
    252 ##
    253 # Indicates a broken XML-RPC response package.  This exception is
    254 # raised by the unmarshalling layer, if the XML-RPC response is
    255 # malformed.
    256 
    257 class ResponseError(Error):
    258     """Indicates a broken response package."""
    259     pass
    260 
    261 ##
    262 # Indicates an XML-RPC fault response package.  This exception is
    263 # raised by the unmarshalling layer, if the XML-RPC response contains
    264 # a fault string.  This exception can also used as a class, to
    265 # generate a fault XML-RPC message.
    266 #
    267 # @param faultCode The XML-RPC fault code.
    268 # @param faultString The XML-RPC fault string.
    269 
    270 class Fault(Error):
    271     """Indicates an XML-RPC fault package."""
    272     def __init__(self, faultCode, faultString, **extra):
    273         Error.__init__(self)
    274         self.faultCode = faultCode
    275         self.faultString = faultString
    276     def __repr__(self):
    277         return (
    278             "<Fault %s: %s>" %
    279             (self.faultCode, repr(self.faultString))
    280             )
    281 
    282 # --------------------------------------------------------------------
    283 # Special values
    284 
    285 ##
    286 # Wrapper for XML-RPC boolean values.  Use the xmlrpclib.True and
    287 # xmlrpclib.False constants, or the xmlrpclib.boolean() function, to
    288 # generate boolean XML-RPC values.
    289 #
    290 # @param value A boolean value.  Any true value is interpreted as True,
    291 #              all other values are interpreted as False.
    292 
    293 from sys import modules
    294 mod_dict = modules[__name__].__dict__
    295 if _bool_is_builtin:
    296     boolean = Boolean = bool
    297     # to avoid breaking code which references xmlrpclib.{True,False}
    298     mod_dict['True'] = True
    299     mod_dict['False'] = False
    300 else:
    301     class Boolean:
    302         """Boolean-value wrapper.
    303 
    304         Use True or False to generate a "boolean" XML-RPC value.
    305         """
    306 
    307         def __init__(self, value = 0):
    308             self.value = operator.truth(value)
    309 
    310         def encode(self, out):
    311             out.write("<value><boolean>%d</boolean></value>\n" % self.value)
    312 
    313         def __cmp__(self, other):
    314             if isinstance(other, Boolean):
    315                 other = other.value
    316             return cmp(self.value, other)
    317 
    318         def __repr__(self):
    319             if self.value:
    320                 return "<Boolean True at %x>" % id(self)
    321             else:
    322                 return "<Boolean False at %x>" % id(self)
    323 
    324         def __int__(self):
    325             return self.value
    326 
    327         def __nonzero__(self):
    328             return self.value
    329 
    330     mod_dict['True'] = Boolean(1)
    331     mod_dict['False'] = Boolean(0)
    332 
    333     ##
    334     # Map true or false value to XML-RPC boolean values.
    335     #
    336     # @def boolean(value)
    337     # @param value A boolean value.  Any true value is mapped to True,
    338     #              all other values are mapped to False.
    339     # @return xmlrpclib.True or xmlrpclib.False.
    340     # @see Boolean
    341     # @see True
    342     # @see False
    343 
    344     def boolean(value, _truefalse=(False, True)):
    345         """Convert any Python value to XML-RPC 'boolean'."""
    346         return _truefalse[operator.truth(value)]
    347 
    348 del modules, mod_dict
    349 
    350 ##
    351 # Wrapper for XML-RPC DateTime values.  This converts a time value to
    352 # the format used by XML-RPC.
    353 # <p>
    354 # The value can be given as a string in the format
    355 # "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by
    356 # time.localtime()), or an integer value (as returned by time.time()).
    357 # The wrapper uses time.localtime() to convert an integer to a time
    358 # tuple.
    359 #
    360 # @param value The time, given as an ISO 8601 string, a time
    361 #              tuple, or an integer time value.
    362 
    363 def _strftime(value):
    364     if datetime:
    365         if isinstance(value, datetime.datetime):
    366             return "%04d%02d%02dT%02d:%02d:%02d" % (
    367                 value.year, value.month, value.day,
    368                 value.hour, value.minute, value.second)
    369 
    370     if not isinstance(value, (TupleType, time.struct_time)):
    371         if value == 0:
    372             value = time.time()
    373         value = time.localtime(value)
    374 
    375     return "%04d%02d%02dT%02d:%02d:%02d" % value[:6]
    376 
    377 class DateTime:
    378     """DateTime wrapper for an ISO 8601 string or time tuple or
    379     localtime integer value to generate 'dateTime.iso8601' XML-RPC
    380     value.
    381     """
    382 
    383     def __init__(self, value=0):
    384         if isinstance(value, StringType):
    385             self.value = value
    386         else:
    387             self.value = _strftime(value)
    388 
    389     def make_comparable(self, other):
    390         if isinstance(other, DateTime):
    391             s = self.value
    392             o = other.value
    393         elif datetime and isinstance(other, datetime.datetime):
    394             s = self.value
    395             o = other.strftime("%Y%m%dT%H:%M:%S")
    396         elif isinstance(other, basestring):
    397             s = self.value
    398             o = other
    399         elif hasattr(other, "timetuple"):
    400             s = self.timetuple()
    401             o = other.timetuple()
    402         else:
    403             otype = (hasattr(other, "__class__")
    404                      and other.__class__.__name__
    405                      or type(other))
    406             raise TypeError("Can't compare %s and %s" %
    407                             (self.__class__.__name__, otype))
    408         return s, o
    409 
    410     def __lt__(self, other):
    411         s, o = self.make_comparable(other)
    412         return s < o
    413 
    414     def __le__(self, other):
    415         s, o = self.make_comparable(other)
    416         return s <= o
    417 
    418     def __gt__(self, other):
    419         s, o = self.make_comparable(other)
    420         return s > o
    421 
    422     def __ge__(self, other):
    423         s, o = self.make_comparable(other)
    424         return s >= o
    425 
    426     def __eq__(self, other):
    427         s, o = self.make_comparable(other)
    428         return s == o
    429 
    430     def __ne__(self, other):
    431         s, o = self.make_comparable(other)
    432         return s != o
    433 
    434     def timetuple(self):
    435         return time.strptime(self.value, "%Y%m%dT%H:%M:%S")
    436 
    437     def __cmp__(self, other):
    438         s, o = self.make_comparable(other)
    439         return cmp(s, o)
    440 
    441     ##
    442     # Get date/time value.
    443     #
    444     # @return Date/time value, as an ISO 8601 string.
    445 
    446     def __str__(self):
    447         return self.value
    448 
    449     def __repr__(self):
    450         return "<DateTime %s at %x>" % (repr(self.value), id(self))
    451 
    452     def decode(self, data):
    453         data = str(data)
    454         self.value = string.strip(data)
    455 
    456     def encode(self, out):
    457         out.write("<value><dateTime.iso8601>")
    458         out.write(self.value)
    459         out.write("</dateTime.iso8601></value>\n")
    460 
    461 def _datetime(data):
    462     # decode xml element contents into a DateTime structure.
    463     value = DateTime()
    464     value.decode(data)
    465     return value
    466 
    467 def _datetime_type(data):
    468     t = time.strptime(data, "%Y%m%dT%H:%M:%S")
    469     return datetime.datetime(*tuple(t)[:6])
    470 
    471 ##
    472 # Wrapper for binary data.  This can be used to transport any kind
    473 # of binary data over XML-RPC, using BASE64 encoding.
    474 #
    475 # @param data An 8-bit string containing arbitrary data.
    476 
    477 import base64
    478 try:
    479     import cStringIO as StringIO
    480 except ImportError:
    481     import StringIO
    482 
    483 class Binary:
    484     """Wrapper for binary data."""
    485 
    486     def __init__(self, data=None):
    487         self.data = data
    488 
    489     ##
    490     # Get buffer contents.
    491     #
    492     # @return Buffer contents, as an 8-bit string.
    493 
    494     def __str__(self):
    495         return self.data or ""
    496 
    497     def __cmp__(self, other):
    498         if isinstance(other, Binary):
    499             other = other.data
    500         return cmp(self.data, other)
    501 
    502     def decode(self, data):
    503         self.data = base64.decodestring(data)
    504 
    505     def encode(self, out):
    506         out.write("<value><base64>\n")
    507         base64.encode(StringIO.StringIO(self.data), out)
    508         out.write("</base64></value>\n")
    509 
    510 def _binary(data):
    511     # decode xml element contents into a Binary structure
    512     value = Binary()
    513     value.decode(data)
    514     return value
    515 
    516 WRAPPERS = (DateTime, Binary)
    517 if not _bool_is_builtin:
    518     WRAPPERS = WRAPPERS + (Boolean,)
    519 
    520 # --------------------------------------------------------------------
    521 # XML parsers
    522 
    523 try:
    524     # optional xmlrpclib accelerator
    525     import _xmlrpclib
    526     FastParser = _xmlrpclib.Parser
    527     FastUnmarshaller = _xmlrpclib.Unmarshaller
    528 except (AttributeError, ImportError):
    529     FastParser = FastUnmarshaller = None
    530 
    531 try:
    532     import _xmlrpclib
    533     FastMarshaller = _xmlrpclib.Marshaller
    534 except (AttributeError, ImportError):
    535     FastMarshaller = None
    536 
    537 try:
    538     from xml.parsers import expat
    539     if not hasattr(expat, "ParserCreate"):
    540         raise ImportError
    541 except ImportError:
    542     ExpatParser = None # expat not available
    543 else:
    544     class ExpatParser:
    545         # fast expat parser for Python 2.0 and later.
    546         def __init__(self, target):
    547             self._parser = parser = expat.ParserCreate(None, None)
    548             self._target = target
    549             parser.StartElementHandler = target.start
    550             parser.EndElementHandler = target.end
    551             parser.CharacterDataHandler = target.data
    552             encoding = None
    553             if not parser.returns_unicode:
    554                 encoding = "utf-8"
    555             target.xml(encoding, None)
    556 
    557         def feed(self, data):
    558             self._parser.Parse(data, 0)
    559 
    560         def close(self):
    561             try:
    562                 parser = self._parser
    563             except AttributeError:
    564                 pass
    565             else:
    566                 del self._target, self._parser # get rid of circular references
    567                 parser.Parse("", 1) # end of data
    568 
    569 class SlowParser:
    570     """Default XML parser (based on xmllib.XMLParser)."""
    571     # this is the slowest parser.
    572     def __init__(self, target):
    573         import xmllib # lazy subclassing (!)
    574         if xmllib.XMLParser not in SlowParser.__bases__:
    575             SlowParser.__bases__ = (xmllib.XMLParser,)
    576         self.handle_xml = target.xml
    577         self.unknown_starttag = target.start
    578         self.handle_data = target.data
    579         self.handle_cdata = target.data
    580         self.unknown_endtag = target.end
    581         try:
    582             xmllib.XMLParser.__init__(self, accept_utf8=1)
    583         except TypeError:
    584             xmllib.XMLParser.__init__(self) # pre-2.0
    585 
    586 # --------------------------------------------------------------------
    587 # XML-RPC marshalling and unmarshalling code
    588 
    589 ##
    590 # XML-RPC marshaller.
    591 #
    592 # @param encoding Default encoding for 8-bit strings.  The default
    593 #     value is None (interpreted as UTF-8).
    594 # @see dumps
    595 
    596 class Marshaller:
    597     """Generate an XML-RPC params chunk from a Python data structure.
    598 
    599     Create a Marshaller instance for each set of parameters, and use
    600     the "dumps" method to convert your data (represented as a tuple)
    601     to an XML-RPC params chunk.  To write a fault response, pass a
    602     Fault instance instead.  You may prefer to use the "dumps" module
    603     function for this purpose.
    604     """
    605 
    606     # by the way, if you don't understand what's going on in here,
    607     # that's perfectly ok.
    608 
    609     def __init__(self, encoding=None, allow_none=0):
    610         self.memo = {}
    611         self.data = None
    612         self.encoding = encoding
    613         self.allow_none = allow_none
    614 
    615     dispatch = {}
    616 
    617     def dumps(self, values):
    618         out = []
    619         write = out.append
    620         dump = self.__dump
    621         if isinstance(values, Fault):
    622             # fault instance
    623             write("<fault>\n")
    624             dump({'faultCode': values.faultCode,
    625                   'faultString': values.faultString},
    626                  write)
    627             write("</fault>\n")
    628         else:
    629             # parameter block
    630             # FIXME: the xml-rpc specification allows us to leave out
    631             # the entire <params> block if there are no parameters.
    632             # however, changing this may break older code (including
    633             # old versions of xmlrpclib.py), so this is better left as
    634             # is for now.  See @XMLRPC3 for more information. /F
    635             write("<params>\n")
    636             for v in values:
    637                 write("<param>\n")
    638                 dump(v, write)
    639                 write("</param>\n")
    640             write("</params>\n")
    641         result = string.join(out, "")
    642         return result
    643 
    644     def __dump(self, value, write):
    645         try:
    646             f = self.dispatch[type(value)]
    647         except KeyError:
    648             # check if this object can be marshalled as a structure
    649             try:
    650                 value.__dict__
    651             except:
    652                 raise TypeError, "cannot marshal %s objects" % type(value)
    653             # check if this class is a sub-class of a basic type,
    654             # because we don't know how to marshal these types
    655             # (e.g. a string sub-class)
    656             for type_ in type(value).__mro__:
    657                 if type_ in self.dispatch.keys():
    658                     raise TypeError, "cannot marshal %s objects" % type(value)
    659             f = self.dispatch[InstanceType]
    660         f(self, value, write)
    661 
    662     def dump_nil (self, value, write):
    663         if not self.allow_none:
    664             raise TypeError, "cannot marshal None unless allow_none is enabled"
    665         write("<value><nil/></value>")
    666     dispatch[NoneType] = dump_nil
    667 
    668     def dump_int(self, value, write):
    669         # in case ints are > 32 bits
    670         if value > MAXINT or value < MININT:
    671             raise OverflowError, "int exceeds XML-RPC limits"
    672         write("<value><int>")
    673         write(str(value))
    674         write("</int></value>\n")
    675     dispatch[IntType] = dump_int
    676 
    677     if _bool_is_builtin:
    678         def dump_bool(self, value, write):
    679             write("<value><boolean>")
    680             write(value and "1" or "0")
    681             write("</boolean></value>\n")
    682         dispatch[bool] = dump_bool
    683 
    684     def dump_long(self, value, write):
    685         if value > MAXINT or value < MININT:
    686             raise OverflowError, "long int exceeds XML-RPC limits"
    687         write("<value><int>")
    688         write(str(int(value)))
    689         write("</int></value>\n")
    690     dispatch[LongType] = dump_long
    691 
    692     def dump_double(self, value, write):
    693         write("<value><double>")
    694         write(repr(value))
    695         write("</double></value>\n")
    696     dispatch[FloatType] = dump_double
    697 
    698     def dump_string(self, value, write, escape=escape):
    699         write("<value><string>")
    700         write(escape(value))
    701         write("</string></value>\n")
    702     dispatch[StringType] = dump_string
    703 
    704     if unicode:
    705         def dump_unicode(self, value, write, escape=escape):
    706             write("<value><string>")
    707             write(escape(value).encode(self.encoding, 'xmlcharrefreplace'))
    708             write("</string></value>\n")
    709         dispatch[UnicodeType] = dump_unicode
    710 
    711     def dump_array(self, value, write):
    712         i = id(value)
    713         if i in self.memo:
    714             raise TypeError, "cannot marshal recursive sequences"
    715         self.memo[i] = None
    716         dump = self.__dump
    717         write("<value><array><data>\n")
    718         for v in value:
    719             dump(v, write)
    720         write("</data></array></value>\n")
    721         del self.memo[i]
    722     dispatch[TupleType] = dump_array
    723     dispatch[ListType] = dump_array
    724 
    725     def dump_struct(self, value, write, escape=escape):
    726         i = id(value)
    727         if i in self.memo:
    728             raise TypeError, "cannot marshal recursive dictionaries"
    729         self.memo[i] = None
    730         dump = self.__dump
    731         write("<value><struct>\n")
    732         for k, v in value.items():
    733             write("<member>\n")
    734             if type(k) is StringType:
    735                 k = escape(k)
    736             elif unicode and type(k) is UnicodeType:
    737                 k = escape(k).encode(self.encoding, 'xmlcharrefreplace')
    738             else:
    739                 raise TypeError, "dictionary key must be string"
    740             write("<name>%s</name>\n" % k)
    741             dump(v, write)
    742             write("</member>\n")
    743         write("</struct></value>\n")
    744         del self.memo[i]
    745     dispatch[DictType] = dump_struct
    746 
    747     if datetime:
    748         def dump_datetime(self, value, write):
    749             write("<value><dateTime.iso8601>")
    750             write(_strftime(value))
    751             write("</dateTime.iso8601></value>\n")
    752         dispatch[datetime.datetime] = dump_datetime
    753 
    754     def dump_instance(self, value, write):
    755         # check for special wrappers
    756         if value.__class__ in WRAPPERS:
    757             self.write = write
    758             value.encode(self)
    759             del self.write
    760         else:
    761             # store instance attributes as a struct (really?)
    762             self.dump_struct(value.__dict__, write)
    763     dispatch[InstanceType] = dump_instance
    764 
    765 ##
    766 # XML-RPC unmarshaller.
    767 #
    768 # @see loads
    769 
    770 class Unmarshaller:
    771     """Unmarshal an XML-RPC response, based on incoming XML event
    772     messages (start, data, end).  Call close() to get the resulting
    773     data structure.
    774 
    775     Note that this reader is fairly tolerant, and gladly accepts bogus
    776     XML-RPC data without complaining (but not bogus XML).
    777     """
    778 
    779     # and again, if you don't understand what's going on in here,
    780     # that's perfectly ok.
    781 
    782     def __init__(self, use_datetime=0):
    783         self._type = None
    784         self._stack = []
    785         self._marks = []
    786         self._data = []
    787         self._value = False
    788         self._methodname = None
    789         self._encoding = "utf-8"
    790         self.append = self._stack.append
    791         self._use_datetime = use_datetime
    792         if use_datetime and not datetime:
    793             raise ValueError, "the datetime module is not available"
    794 
    795     def close(self):
    796         # return response tuple and target method
    797         if self._type is None or self._marks:
    798             raise ResponseError()
    799         if self._type == "fault":
    800             raise Fault(**self._stack[0])
    801         return tuple(self._stack)
    802 
    803     def getmethodname(self):
    804         return self._methodname
    805 
    806     #
    807     # event handlers
    808 
    809     def xml(self, encoding, standalone):
    810         self._encoding = encoding
    811         # FIXME: assert standalone == 1 ???
    812 
    813     def start(self, tag, attrs):
    814         # prepare to handle this element
    815         if tag == "array" or tag == "struct":
    816             self._marks.append(len(self._stack))
    817         self._data = []
    818         if self._value and tag not in self.dispatch:
    819             raise ResponseError("unknown tag %r" % tag)
    820         self._value = (tag == "value")
    821 
    822     def data(self, text):
    823         self._data.append(text)
    824 
    825     def end(self, tag, join=string.join):
    826         # call the appropriate end tag handler
    827         try:
    828             f = self.dispatch[tag]
    829         except KeyError:
    830             pass # unknown tag ?
    831         else:
    832             return f(self, join(self._data, ""))
    833 
    834     #
    835     # accelerator support
    836 
    837     def end_dispatch(self, tag, data):
    838         # dispatch data
    839         try:
    840             f = self.dispatch[tag]
    841         except KeyError:
    842             pass # unknown tag ?
    843         else:
    844             return f(self, data)
    845 
    846     #
    847     # element decoders
    848 
    849     dispatch = {}
    850 
    851     def end_nil (self, data):
    852         self.append(None)
    853         self._value = 0
    854     dispatch["nil"] = end_nil
    855 
    856     def end_boolean(self, data):
    857         if data == "0":
    858             self.append(False)
    859         elif data == "1":
    860             self.append(True)
    861         else:
    862             raise TypeError, "bad boolean value"
    863         self._value = 0
    864     dispatch["boolean"] = end_boolean
    865 
    866     def end_int(self, data):
    867         self.append(int(data))
    868         self._value = 0
    869     dispatch["i4"] = end_int
    870     dispatch["i8"] = end_int
    871     dispatch["int"] = end_int
    872 
    873     def end_double(self, data):
    874         self.append(float(data))
    875         self._value = 0
    876     dispatch["double"] = end_double
    877 
    878     def end_string(self, data):
    879         if self._encoding:
    880             data = _decode(data, self._encoding)
    881         self.append(_stringify(data))
    882         self._value = 0
    883     dispatch["string"] = end_string
    884     dispatch["name"] = end_string # struct keys are always strings
    885 
    886     def end_array(self, data):
    887         mark = self._marks.pop()
    888         # map arrays to Python lists
    889         self._stack[mark:] = [self._stack[mark:]]
    890         self._value = 0
    891     dispatch["array"] = end_array
    892 
    893     def end_struct(self, data):
    894         mark = self._marks.pop()
    895         # map structs to Python dictionaries
    896         dict = {}
    897         items = self._stack[mark:]
    898         for i in range(0, len(items), 2):
    899             dict[_stringify(items[i])] = items[i+1]
    900         self._stack[mark:] = [dict]
    901         self._value = 0
    902     dispatch["struct"] = end_struct
    903 
    904     def end_base64(self, data):
    905         value = Binary()
    906         value.decode(data)
    907         self.append(value)
    908         self._value = 0
    909     dispatch["base64"] = end_base64
    910 
    911     def end_dateTime(self, data):
    912         value = DateTime()
    913         value.decode(data)
    914         if self._use_datetime:
    915             value = _datetime_type(data)
    916         self.append(value)
    917     dispatch["dateTime.iso8601"] = end_dateTime
    918 
    919     def end_value(self, data):
    920         # if we stumble upon a value element with no internal
    921         # elements, treat it as a string element
    922         if self._value:
    923             self.end_string(data)
    924     dispatch["value"] = end_value
    925 
    926     def end_params(self, data):
    927         self._type = "params"
    928     dispatch["params"] = end_params
    929 
    930     def end_fault(self, data):
    931         self._type = "fault"
    932     dispatch["fault"] = end_fault
    933 
    934     def end_methodName(self, data):
    935         if self._encoding:
    936             data = _decode(data, self._encoding)
    937         self._methodname = data
    938         self._type = "methodName" # no params
    939     dispatch["methodName"] = end_methodName
    940 
    941 ## Multicall support
    942 #
    943 
    944 class _MultiCallMethod:
    945     # some lesser magic to store calls made to a MultiCall object
    946     # for batch execution
    947     def __init__(self, call_list, name):
    948         self.__call_list = call_list
    949         self.__name = name
    950     def __getattr__(self, name):
    951         return _MultiCallMethod(self.__call_list, "%s.%s" % (self.__name, name))
    952     def __call__(self, *args):
    953         self.__call_list.append((self.__name, args))
    954 
    955 class MultiCallIterator:
    956     """Iterates over the results of a multicall. Exceptions are
    957     raised in response to xmlrpc faults."""
    958 
    959     def __init__(self, results):
    960         self.results = results
    961 
    962     def __getitem__(self, i):
    963         item = self.results[i]
    964         if type(item) == type({}):
    965             raise Fault(item['faultCode'], item['faultString'])
    966         elif type(item) == type([]):
    967             return item[0]
    968         else:
    969             raise ValueError,\
    970                   "unexpected type in multicall result"
    971 
    972 class MultiCall:
    973     """server -> an object used to boxcar method calls
    974 
    975     server should be a ServerProxy object.
    976 
    977     Methods can be added to the MultiCall using normal
    978     method call syntax e.g.:
    979 
    980     multicall = MultiCall(server_proxy)
    981     multicall.add(2,3)
    982     multicall.get_address("Guido")
    983 
    984     To execute the multicall, call the MultiCall object e.g.:
    985 
    986     add_result, address = multicall()
    987     """
    988 
    989     def __init__(self, server):
    990         self.__server = server
    991         self.__call_list = []
    992 
    993     def __repr__(self):
    994         return "<MultiCall at %x>" % id(self)
    995 
    996     __str__ = __repr__
    997 
    998     def __getattr__(self, name):
    999         return _MultiCallMethod(self.__call_list, name)
   1000 
   1001     def __call__(self):
   1002         marshalled_list = []
   1003         for name, args in self.__call_list:
   1004             marshalled_list.append({'methodName' : name, 'params' : args})
   1005 
   1006         return MultiCallIterator(self.__server.system.multicall(marshalled_list))
   1007 
   1008 # --------------------------------------------------------------------
   1009 # convenience functions
   1010 
   1011 ##
   1012 # Create a parser object, and connect it to an unmarshalling instance.
   1013 # This function picks the fastest available XML parser.
   1014 #
   1015 # return A (parser, unmarshaller) tuple.
   1016 
   1017 def getparser(use_datetime=0):
   1018     """getparser() -> parser, unmarshaller
   1019 
   1020     Create an instance of the fastest available parser, and attach it
   1021     to an unmarshalling object.  Return both objects.
   1022     """
   1023     if use_datetime and not datetime:
   1024         raise ValueError, "the datetime module is not available"
   1025     if FastParser and FastUnmarshaller:
   1026         if use_datetime:
   1027             mkdatetime = _datetime_type
   1028         else:
   1029             mkdatetime = _datetime
   1030         target = FastUnmarshaller(True, False, _binary, mkdatetime, Fault)
   1031         parser = FastParser(target)
   1032     else:
   1033         target = Unmarshaller(use_datetime=use_datetime)
   1034         if FastParser:
   1035             parser = FastParser(target)
   1036         elif ExpatParser:
   1037             parser = ExpatParser(target)
   1038         else:
   1039             parser = SlowParser(target)
   1040     return parser, target
   1041 
   1042 ##
   1043 # Convert a Python tuple or a Fault instance to an XML-RPC packet.
   1044 #
   1045 # @def dumps(params, **options)
   1046 # @param params A tuple or Fault instance.
   1047 # @keyparam methodname If given, create a methodCall request for
   1048 #     this method name.
   1049 # @keyparam methodresponse If given, create a methodResponse packet.
   1050 #     If used with a tuple, the tuple must be a singleton (that is,
   1051 #     it must contain exactly one element).
   1052 # @keyparam encoding The packet encoding.
   1053 # @return A string containing marshalled data.
   1054 
   1055 def dumps(params, methodname=None, methodresponse=None, encoding=None,
   1056           allow_none=0):
   1057     """data [,options] -> marshalled data
   1058 
   1059     Convert an argument tuple or a Fault instance to an XML-RPC
   1060     request (or response, if the methodresponse option is used).
   1061 
   1062     In addition to the data object, the following options can be given
   1063     as keyword arguments:
   1064 
   1065         methodname: the method name for a methodCall packet
   1066 
   1067         methodresponse: true to create a methodResponse packet.
   1068         If this option is used with a tuple, the tuple must be
   1069         a singleton (i.e. it can contain only one element).
   1070 
   1071         encoding: the packet encoding (default is UTF-8)
   1072 
   1073     All 8-bit strings in the data structure are assumed to use the
   1074     packet encoding.  Unicode strings are automatically converted,
   1075     where necessary.
   1076     """
   1077 
   1078     assert isinstance(params, TupleType) or isinstance(params, Fault),\
   1079            "argument must be tuple or Fault instance"
   1080 
   1081     if isinstance(params, Fault):
   1082         methodresponse = 1
   1083     elif methodresponse and isinstance(params, TupleType):
   1084         assert len(params) == 1, "response tuple must be a singleton"
   1085 
   1086     if not encoding:
   1087         encoding = "utf-8"
   1088 
   1089     if FastMarshaller:
   1090         m = FastMarshaller(encoding)
   1091     else:
   1092         m = Marshaller(encoding, allow_none)
   1093 
   1094     data = m.dumps(params)
   1095 
   1096     if encoding != "utf-8":
   1097         xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding)
   1098     else:
   1099         xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
   1100 
   1101     # standard XML-RPC wrappings
   1102     if methodname:
   1103         # a method call
   1104         if not isinstance(methodname, StringType):
   1105             methodname = methodname.encode(encoding, 'xmlcharrefreplace')
   1106         data = (
   1107             xmlheader,
   1108             "<methodCall>\n"
   1109             "<methodName>", methodname, "</methodName>\n",
   1110             data,
   1111             "</methodCall>\n"
   1112             )
   1113     elif methodresponse:
   1114         # a method response, or a fault structure
   1115         data = (
   1116             xmlheader,
   1117             "<methodResponse>\n",
   1118             data,
   1119             "</methodResponse>\n"
   1120             )
   1121     else:
   1122         return data # return as is
   1123     return string.join(data, "")
   1124 
   1125 ##
   1126 # Convert an XML-RPC packet to a Python object.  If the XML-RPC packet
   1127 # represents a fault condition, this function raises a Fault exception.
   1128 #
   1129 # @param data An XML-RPC packet, given as an 8-bit string.
   1130 # @return A tuple containing the unpacked data, and the method name
   1131 #     (None if not present).
   1132 # @see Fault
   1133 
   1134 def loads(data, use_datetime=0):
   1135     """data -> unmarshalled data, method name
   1136 
   1137     Convert an XML-RPC packet to unmarshalled data plus a method
   1138     name (None if not present).
   1139 
   1140     If the XML-RPC packet represents a fault condition, this function
   1141     raises a Fault exception.
   1142     """
   1143     p, u = getparser(use_datetime=use_datetime)
   1144     p.feed(data)
   1145     p.close()
   1146     return u.close(), u.getmethodname()
   1147 
   1148 ##
   1149 # Encode a string using the gzip content encoding such as specified by the
   1150 # Content-Encoding: gzip
   1151 # in the HTTP header, as described in RFC 1952
   1152 #
   1153 # @param data the unencoded data
   1154 # @return the encoded data
   1155 
   1156 def gzip_encode(data):
   1157     """data -> gzip encoded data
   1158 
   1159     Encode data using the gzip content encoding as described in RFC 1952
   1160     """
   1161     if not gzip:
   1162         raise NotImplementedError
   1163     f = StringIO.StringIO()
   1164     gzf = gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1)
   1165     gzf.write(data)
   1166     gzf.close()
   1167     encoded = f.getvalue()
   1168     f.close()
   1169     return encoded
   1170 
   1171 ##
   1172 # Decode a string using the gzip content encoding such as specified by the
   1173 # Content-Encoding: gzip
   1174 # in the HTTP header, as described in RFC 1952
   1175 #
   1176 # @param data The encoded data
   1177 # @keyparam max_decode Maximum bytes to decode (20MB default), use negative
   1178 #    values for unlimited decoding
   1179 # @return the unencoded data
   1180 # @raises ValueError if data is not correctly coded.
   1181 # @raises ValueError if max gzipped payload length exceeded
   1182 
   1183 def gzip_decode(data, max_decode=20971520):
   1184     """gzip encoded data -> unencoded data
   1185 
   1186     Decode data using the gzip content encoding as described in RFC 1952
   1187     """
   1188     if not gzip:
   1189         raise NotImplementedError
   1190     f = StringIO.StringIO(data)
   1191     gzf = gzip.GzipFile(mode="rb", fileobj=f)
   1192     try:
   1193         if max_decode < 0: # no limit
   1194             decoded = gzf.read()
   1195         else:
   1196             decoded = gzf.read(max_decode + 1)
   1197     except IOError:
   1198         raise ValueError("invalid data")
   1199     f.close()
   1200     gzf.close()
   1201     if max_decode >= 0 and len(decoded) > max_decode:
   1202         raise ValueError("max gzipped payload length exceeded")
   1203     return decoded
   1204 
   1205 ##
   1206 # Return a decoded file-like object for the gzip encoding
   1207 # as described in RFC 1952.
   1208 #
   1209 # @param response A stream supporting a read() method
   1210 # @return a file-like object that the decoded data can be read() from
   1211 
   1212 class GzipDecodedResponse(gzip.GzipFile if gzip else object):
   1213     """a file-like object to decode a response encoded with the gzip
   1214     method, as described in RFC 1952.
   1215     """
   1216     def __init__(self, response):
   1217         #response doesn't support tell() and read(), required by
   1218         #GzipFile
   1219         if not gzip:
   1220             raise NotImplementedError
   1221         self.stringio = StringIO.StringIO(response.read())
   1222         gzip.GzipFile.__init__(self, mode="rb", fileobj=self.stringio)
   1223 
   1224     def close(self):
   1225         try:
   1226             gzip.GzipFile.close(self)
   1227         finally:
   1228             self.stringio.close()
   1229 
   1230 
   1231 # --------------------------------------------------------------------
   1232 # request dispatcher
   1233 
   1234 class _Method:
   1235     # some magic to bind an XML-RPC method to an RPC server.
   1236     # supports "nested" methods (e.g. examples.getStateName)
   1237     def __init__(self, send, name):
   1238         self.__send = send
   1239         self.__name = name
   1240     def __getattr__(self, name):
   1241         return _Method(self.__send, "%s.%s" % (self.__name, name))
   1242     def __call__(self, *args):
   1243         return self.__send(self.__name, args)
   1244 
   1245 ##
   1246 # Standard transport class for XML-RPC over HTTP.
   1247 # <p>
   1248 # You can create custom transports by subclassing this method, and
   1249 # overriding selected methods.
   1250 
   1251 class Transport:
   1252     """Handles an HTTP transaction to an XML-RPC server."""
   1253 
   1254     # client identifier (may be overridden)
   1255     user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__
   1256 
   1257     #if true, we'll request gzip encoding
   1258     accept_gzip_encoding = True
   1259 
   1260     # if positive, encode request using gzip if it exceeds this threshold
   1261     # note that many server will get confused, so only use it if you know
   1262     # that they can decode such a request
   1263     encode_threshold = None #None = don't encode
   1264 
   1265     def __init__(self, use_datetime=0):
   1266         self._use_datetime = use_datetime
   1267         self._connection = (None, None)
   1268         self._extra_headers = []
   1269     ##
   1270     # Send a complete request, and parse the response.
   1271     # Retry request if a cached connection has disconnected.
   1272     #
   1273     # @param host Target host.
   1274     # @param handler Target PRC handler.
   1275     # @param request_body XML-RPC request body.
   1276     # @param verbose Debugging flag.
   1277     # @return Parsed response.
   1278 
   1279     def request(self, host, handler, request_body, verbose=0):
   1280         #retry request once if cached connection has gone cold
   1281         for i in (0, 1):
   1282             try:
   1283                 return self.single_request(host, handler, request_body, verbose)
   1284             except socket.error, e:
   1285                 if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE):
   1286                     raise
   1287             except httplib.BadStatusLine: #close after we sent request
   1288                 if i:
   1289                     raise
   1290 
   1291     ##
   1292     # Send a complete request, and parse the response.
   1293     #
   1294     # @param host Target host.
   1295     # @param handler Target PRC handler.
   1296     # @param request_body XML-RPC request body.
   1297     # @param verbose Debugging flag.
   1298     # @return Parsed response.
   1299 
   1300     def single_request(self, host, handler, request_body, verbose=0):
   1301         # issue XML-RPC request
   1302 
   1303         h = self.make_connection(host)
   1304         if verbose:
   1305             h.set_debuglevel(1)
   1306 
   1307         try:
   1308             self.send_request(h, handler, request_body)
   1309             self.send_host(h, host)
   1310             self.send_user_agent(h)
   1311             self.send_content(h, request_body)
   1312 
   1313             response = h.getresponse(buffering=True)
   1314             if response.status == 200:
   1315                 self.verbose = verbose
   1316                 return self.parse_response(response)
   1317         except Fault:
   1318             raise
   1319         except Exception:
   1320             # All unexpected errors leave connection in
   1321             # a strange state, so we clear it.
   1322             self.close()
   1323             raise
   1324 
   1325         #discard any response data and raise exception
   1326         if (response.getheader("content-length", 0)):
   1327             response.read()
   1328         raise ProtocolError(
   1329             host + handler,
   1330             response.status, response.reason,
   1331             response.msg,
   1332             )
   1333 
   1334     ##
   1335     # Create parser.
   1336     #
   1337     # @return A 2-tuple containing a parser and an unmarshaller.
   1338 
   1339     def getparser(self):
   1340         # get parser and unmarshaller
   1341         return getparser(use_datetime=self._use_datetime)
   1342 
   1343     ##
   1344     # Get authorization info from host parameter
   1345     # Host may be a string, or a (host, x509-dict) tuple; if a string,
   1346     # it is checked for a "user:pw@host" format, and a "Basic
   1347     # Authentication" header is added if appropriate.
   1348     #
   1349     # @param host Host descriptor (URL or (URL, x509 info) tuple).
   1350     # @return A 3-tuple containing (actual host, extra headers,
   1351     #     x509 info).  The header and x509 fields may be None.
   1352 
   1353     def get_host_info(self, host):
   1354 
   1355         x509 = {}
   1356         if isinstance(host, TupleType):
   1357             host, x509 = host
   1358 
   1359         import urllib
   1360         auth, host = urllib.splituser(host)
   1361 
   1362         if auth:
   1363             import base64
   1364             auth = base64.encodestring(urllib.unquote(auth))
   1365             auth = string.join(string.split(auth), "") # get rid of whitespace
   1366             extra_headers = [
   1367                 ("Authorization", "Basic " + auth)
   1368                 ]
   1369         else:
   1370             extra_headers = None
   1371 
   1372         return host, extra_headers, x509
   1373 
   1374     ##
   1375     # Connect to server.
   1376     #
   1377     # @param host Target host.
   1378     # @return A connection handle.
   1379 
   1380     def make_connection(self, host):
   1381         #return an existing connection if possible.  This allows
   1382         #HTTP/1.1 keep-alive.
   1383         if self._connection and host == self._connection[0]:
   1384             return self._connection[1]
   1385 
   1386         # create a HTTP connection object from a host descriptor
   1387         chost, self._extra_headers, x509 = self.get_host_info(host)
   1388         #store the host argument along with the connection object
   1389         self._connection = host, httplib.HTTPConnection(chost)
   1390         return self._connection[1]
   1391 
   1392     ##
   1393     # Clear any cached connection object.
   1394     # Used in the event of socket errors.
   1395     #
   1396     def close(self):
   1397         host, connection = self._connection
   1398         if connection:
   1399             self._connection = (None, None)
   1400             connection.close()
   1401 
   1402     ##
   1403     # Send request header.
   1404     #
   1405     # @param connection Connection handle.
   1406     # @param handler Target RPC handler.
   1407     # @param request_body XML-RPC body.
   1408 
   1409     def send_request(self, connection, handler, request_body):
   1410         if (self.accept_gzip_encoding and gzip):
   1411             connection.putrequest("POST", handler, skip_accept_encoding=True)
   1412             connection.putheader("Accept-Encoding", "gzip")
   1413         else:
   1414             connection.putrequest("POST", handler)
   1415 
   1416     ##
   1417     # Send host name.
   1418     #
   1419     # @param connection Connection handle.
   1420     # @param host Host name.
   1421     #
   1422     # Note: This function doesn't actually add the "Host"
   1423     # header anymore, it is done as part of the connection.putrequest() in
   1424     # send_request() above.
   1425 
   1426     def send_host(self, connection, host):
   1427         extra_headers = self._extra_headers
   1428         if extra_headers:
   1429             if isinstance(extra_headers, DictType):
   1430                 extra_headers = extra_headers.items()
   1431             for key, value in extra_headers:
   1432                 connection.putheader(key, value)
   1433 
   1434     ##
   1435     # Send user-agent identifier.
   1436     #
   1437     # @param connection Connection handle.
   1438 
   1439     def send_user_agent(self, connection):
   1440         connection.putheader("User-Agent", self.user_agent)
   1441 
   1442     ##
   1443     # Send request body.
   1444     #
   1445     # @param connection Connection handle.
   1446     # @param request_body XML-RPC request body.
   1447 
   1448     def send_content(self, connection, request_body):
   1449         connection.putheader("Content-Type", "text/xml")
   1450 
   1451         #optionally encode the request
   1452         if (self.encode_threshold is not None and
   1453             self.encode_threshold < len(request_body) and
   1454             gzip):
   1455             connection.putheader("Content-Encoding", "gzip")
   1456             request_body = gzip_encode(request_body)
   1457 
   1458         connection.putheader("Content-Length", str(len(request_body)))
   1459         connection.endheaders(request_body)
   1460 
   1461     ##
   1462     # Parse response.
   1463     #
   1464     # @param file Stream.
   1465     # @return Response tuple and target method.
   1466 
   1467     def parse_response(self, response):
   1468         # read response data from httpresponse, and parse it
   1469 
   1470         # Check for new http response object, else it is a file object
   1471         if hasattr(response,'getheader'):
   1472             if response.getheader("Content-Encoding", "") == "gzip":
   1473                 stream = GzipDecodedResponse(response)
   1474             else:
   1475                 stream = response
   1476         else:
   1477             stream = response
   1478 
   1479         p, u = self.getparser()
   1480 
   1481         while 1:
   1482             data = stream.read(1024)
   1483             if not data:
   1484                 break
   1485             if self.verbose:
   1486                 print "body:", repr(data)
   1487             p.feed(data)
   1488 
   1489         if stream is not response:
   1490             stream.close()
   1491         p.close()
   1492 
   1493         return u.close()
   1494 
   1495 ##
   1496 # Standard transport class for XML-RPC over HTTPS.
   1497 
   1498 class SafeTransport(Transport):
   1499     """Handles an HTTPS transaction to an XML-RPC server."""
   1500 
   1501     def __init__(self, use_datetime=0, context=None):
   1502         Transport.__init__(self, use_datetime=use_datetime)
   1503         self.context = context
   1504 
   1505     # FIXME: mostly untested
   1506 
   1507     def make_connection(self, host):
   1508         if self._connection and host == self._connection[0]:
   1509             return self._connection[1]
   1510         # create a HTTPS connection object from a host descriptor
   1511         # host may be a string, or a (host, x509-dict) tuple
   1512         try:
   1513             HTTPS = httplib.HTTPSConnection
   1514         except AttributeError:
   1515             raise NotImplementedError(
   1516                 "your version of httplib doesn't support HTTPS"
   1517                 )
   1518         else:
   1519             chost, self._extra_headers, x509 = self.get_host_info(host)
   1520             self._connection = host, HTTPS(chost, None, context=self.context, **(x509 or {}))
   1521             return self._connection[1]
   1522 
   1523 ##
   1524 # Standard server proxy.  This class establishes a virtual connection
   1525 # to an XML-RPC server.
   1526 # <p>
   1527 # This class is available as ServerProxy and Server.  New code should
   1528 # use ServerProxy, to avoid confusion.
   1529 #
   1530 # @def ServerProxy(uri, **options)
   1531 # @param uri The connection point on the server.
   1532 # @keyparam transport A transport factory, compatible with the
   1533 #    standard transport class.
   1534 # @keyparam encoding The default encoding used for 8-bit strings
   1535 #    (default is UTF-8).
   1536 # @keyparam verbose Use a true value to enable debugging output.
   1537 #    (printed to standard output).
   1538 # @see Transport
   1539 
   1540 class ServerProxy:
   1541     """uri [,options] -> a logical connection to an XML-RPC server
   1542 
   1543     uri is the connection point on the server, given as
   1544     scheme://host/target.
   1545 
   1546     The standard implementation always supports the "http" scheme.  If
   1547     SSL socket support is available (Python 2.0), it also supports
   1548     "https".
   1549 
   1550     If the target part and the slash preceding it are both omitted,
   1551     "/RPC2" is assumed.
   1552 
   1553     The following options can be given as keyword arguments:
   1554 
   1555         transport: a transport factory
   1556         encoding: the request encoding (default is UTF-8)
   1557 
   1558     All 8-bit strings passed to the server proxy are assumed to use
   1559     the given encoding.
   1560     """
   1561 
   1562     def __init__(self, uri, transport=None, encoding=None, verbose=0,
   1563                  allow_none=0, use_datetime=0, context=None):
   1564         # establish a "logical" server connection
   1565 
   1566         if unicode and isinstance(uri, unicode):
   1567             uri = uri.encode('ISO-8859-1')
   1568 
   1569         # get the url
   1570         import urllib
   1571         type, uri = urllib.splittype(uri)
   1572         if type not in ("http", "https"):
   1573             raise IOError, "unsupported XML-RPC protocol"
   1574         self.__host, self.__handler = urllib.splithost(uri)
   1575         if not self.__handler:
   1576             self.__handler = "/RPC2"
   1577 
   1578         if transport is None:
   1579             if type == "https":
   1580                 transport = SafeTransport(use_datetime=use_datetime, context=context)
   1581             else:
   1582                 transport = Transport(use_datetime=use_datetime)
   1583         self.__transport = transport
   1584 
   1585         self.__encoding = encoding
   1586         self.__verbose = verbose
   1587         self.__allow_none = allow_none
   1588 
   1589     def __close(self):
   1590         self.__transport.close()
   1591 
   1592     def __request(self, methodname, params):
   1593         # call a method on the remote server
   1594 
   1595         request = dumps(params, methodname, encoding=self.__encoding,
   1596                         allow_none=self.__allow_none)
   1597 
   1598         response = self.__transport.request(
   1599             self.__host,
   1600             self.__handler,
   1601             request,
   1602             verbose=self.__verbose
   1603             )
   1604 
   1605         if len(response) == 1:
   1606             response = response[0]
   1607 
   1608         return response
   1609 
   1610     def __repr__(self):
   1611         return (
   1612             "<ServerProxy for %s%s>" %
   1613             (self.__host, self.__handler)
   1614             )
   1615 
   1616     __str__ = __repr__
   1617 
   1618     def __getattr__(self, name):
   1619         # magic method dispatcher
   1620         return _Method(self.__request, name)
   1621 
   1622     # note: to call a remote object with a non-standard name, use
   1623     # result getattr(server, "strange-python-name")(args)
   1624 
   1625     def __call__(self, attr):
   1626         """A workaround to get special attributes on the ServerProxy
   1627            without interfering with the magic __getattr__
   1628         """
   1629         if attr == "close":
   1630             return self.__close
   1631         elif attr == "transport":
   1632             return self.__transport
   1633         raise AttributeError("Attribute %r not found" % (attr,))
   1634 
   1635 # compatibility
   1636 
   1637 Server = ServerProxy
   1638 
   1639 # --------------------------------------------------------------------
   1640 # test code
   1641 
   1642 if __name__ == "__main__":
   1643 
   1644     server = ServerProxy("http://localhost:8000")
   1645 
   1646     print server
   1647 
   1648     multi = MultiCall(server)
   1649     multi.pow(2, 9)
   1650     multi.add(5, 1)
   1651     multi.add(24, 11)
   1652     try:
   1653         for response in multi():
   1654             print response
   1655     except Error, v:
   1656         print "ERROR", v
   1657