(root)/
Python-3.11.7/
Lib/
xmlrpc/
client.py
       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@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  An XML-RPC client interface for Python.
      91  
      92  The marshalling and response parser code can also be used to
      93  implement XML-RPC servers.
      94  
      95  Exported exceptions:
      96  
      97    Error          Base class for client errors
      98    ProtocolError  Indicates an HTTP protocol error
      99    ResponseError  Indicates a broken response package
     100    Fault          Indicates an XML-RPC fault package
     101  
     102  Exported classes:
     103  
     104    ServerProxy    Represents a logical connection to an XML-RPC server
     105  
     106    MultiCall      Executor of boxcared xmlrpc requests
     107    DateTime       dateTime wrapper for an ISO 8601 string or time tuple or
     108                   localtime integer value to generate a "dateTime.iso8601"
     109                   XML-RPC value
     110    Binary         binary data wrapper
     111  
     112    Marshaller     Generate an XML-RPC params chunk from a Python data structure
     113    Unmarshaller   Unmarshal an XML-RPC response from incoming XML event message
     114    Transport      Handles an HTTP transaction to an XML-RPC server
     115    SafeTransport  Handles an HTTPS transaction to an XML-RPC server
     116  
     117  Exported constants:
     118  
     119    (none)
     120  
     121  Exported functions:
     122  
     123    getparser      Create instance of the fastest available parser & attach
     124                   to an unmarshalling object
     125    dumps          Convert an argument tuple or a Fault instance to an XML-RPC
     126                   request (or response, if the methodresponse option is used).
     127    loads          Convert an XML-RPC packet to unmarshalled data plus a method
     128                   name (None if not present).
     129  """
     130  
     131  import base64
     132  import sys
     133  import time
     134  from datetime import datetime
     135  from decimal import Decimal
     136  import http.client
     137  import urllib.parse
     138  from xml.parsers import expat
     139  import errno
     140  from io import BytesIO
     141  try:
     142      import gzip
     143  except ImportError:
     144      gzip = None #python can be built without zlib/gzip support
     145  
     146  # --------------------------------------------------------------------
     147  # Internal stuff
     148  
     149  def escape(s):
     150      s = s.replace("&", "&")
     151      s = s.replace("<", "&lt;")
     152      return s.replace(">", "&gt;",)
     153  
     154  # used in User-Agent header sent
     155  __version__ = '%d.%d' % sys.version_info[:2]
     156  
     157  # xmlrpc integer limits
     158  MAXINT =  2**31-1
     159  MININT = -2**31
     160  
     161  # --------------------------------------------------------------------
     162  # Error constants (from Dan Libby's specification at
     163  # http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
     164  
     165  # Ranges of errors
     166  PARSE_ERROR       = -32700
     167  SERVER_ERROR      = -32600
     168  APPLICATION_ERROR = -32500
     169  SYSTEM_ERROR      = -32400
     170  TRANSPORT_ERROR   = -32300
     171  
     172  # Specific errors
     173  NOT_WELLFORMED_ERROR  = -32700
     174  UNSUPPORTED_ENCODING  = -32701
     175  INVALID_ENCODING_CHAR = -32702
     176  INVALID_XMLRPC        = -32600
     177  METHOD_NOT_FOUND      = -32601
     178  INVALID_METHOD_PARAMS = -32602
     179  INTERNAL_ERROR        = -32603
     180  
     181  # --------------------------------------------------------------------
     182  # Exceptions
     183  
     184  ##
     185  # Base class for all kinds of client-side errors.
     186  
     187  class ESC[4;38;5;81mError(ESC[4;38;5;149mException):
     188      """Base class for client errors."""
     189      __str__ = object.__str__
     190  
     191  ##
     192  # Indicates an HTTP-level protocol error.  This is raised by the HTTP
     193  # transport layer, if the server returns an error code other than 200
     194  # (OK).
     195  #
     196  # @param url The target URL.
     197  # @param errcode The HTTP error code.
     198  # @param errmsg The HTTP error message.
     199  # @param headers The HTTP header dictionary.
     200  
     201  class ESC[4;38;5;81mProtocolError(ESC[4;38;5;149mError):
     202      """Indicates an HTTP protocol error."""
     203      def __init__(self, url, errcode, errmsg, headers):
     204          Error.__init__(self)
     205          self.url = url
     206          self.errcode = errcode
     207          self.errmsg = errmsg
     208          self.headers = headers
     209      def __repr__(self):
     210          return (
     211              "<%s for %s: %s %s>" %
     212              (self.__class__.__name__, self.url, self.errcode, self.errmsg)
     213              )
     214  
     215  ##
     216  # Indicates a broken XML-RPC response package.  This exception is
     217  # raised by the unmarshalling layer, if the XML-RPC response is
     218  # malformed.
     219  
     220  class ESC[4;38;5;81mResponseError(ESC[4;38;5;149mError):
     221      """Indicates a broken response package."""
     222      pass
     223  
     224  ##
     225  # Indicates an XML-RPC fault response package.  This exception is
     226  # raised by the unmarshalling layer, if the XML-RPC response contains
     227  # a fault string.  This exception can also be used as a class, to
     228  # generate a fault XML-RPC message.
     229  #
     230  # @param faultCode The XML-RPC fault code.
     231  # @param faultString The XML-RPC fault string.
     232  
     233  class ESC[4;38;5;81mFault(ESC[4;38;5;149mError):
     234      """Indicates an XML-RPC fault package."""
     235      def __init__(self, faultCode, faultString, **extra):
     236          Error.__init__(self)
     237          self.faultCode = faultCode
     238          self.faultString = faultString
     239      def __repr__(self):
     240          return "<%s %s: %r>" % (self.__class__.__name__,
     241                                  self.faultCode, self.faultString)
     242  
     243  # --------------------------------------------------------------------
     244  # Special values
     245  
     246  ##
     247  # Backwards compatibility
     248  
     249  boolean = Boolean = bool
     250  
     251  ##
     252  # Wrapper for XML-RPC DateTime values.  This converts a time value to
     253  # the format used by XML-RPC.
     254  # <p>
     255  # The value can be given as a datetime object, as a string in the
     256  # format "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by
     257  # time.localtime()), or an integer value (as returned by time.time()).
     258  # The wrapper uses time.localtime() to convert an integer to a time
     259  # tuple.
     260  #
     261  # @param value The time, given as a datetime object, an ISO 8601 string,
     262  #              a time tuple, or an integer time value.
     263  
     264  
     265  # Issue #13305: different format codes across platforms
     266  _day0 = datetime(1, 1, 1)
     267  def _try(fmt):
     268      try:
     269          return _day0.strftime(fmt) == '0001'
     270      except ValueError:
     271          return False
     272  if _try('%Y'):      # Mac OS X
     273      def _iso8601_format(value):
     274          return value.strftime("%Y%m%dT%H:%M:%S")
     275  elif _try('%4Y'):   # Linux
     276      def _iso8601_format(value):
     277          return value.strftime("%4Y%m%dT%H:%M:%S")
     278  else:
     279      def _iso8601_format(value):
     280          return value.strftime("%Y%m%dT%H:%M:%S").zfill(17)
     281  del _day0
     282  del _try
     283  
     284  
     285  def _strftime(value):
     286      if isinstance(value, datetime):
     287          return _iso8601_format(value)
     288  
     289      if not isinstance(value, (tuple, time.struct_time)):
     290          if value == 0:
     291              value = time.time()
     292          value = time.localtime(value)
     293  
     294      return "%04d%02d%02dT%02d:%02d:%02d" % value[:6]
     295  
     296  class ESC[4;38;5;81mDateTime:
     297      """DateTime wrapper for an ISO 8601 string or time tuple or
     298      localtime integer value to generate 'dateTime.iso8601' XML-RPC
     299      value.
     300      """
     301  
     302      def __init__(self, value=0):
     303          if isinstance(value, str):
     304              self.value = value
     305          else:
     306              self.value = _strftime(value)
     307  
     308      def make_comparable(self, other):
     309          if isinstance(other, DateTime):
     310              s = self.value
     311              o = other.value
     312          elif isinstance(other, datetime):
     313              s = self.value
     314              o = _iso8601_format(other)
     315          elif isinstance(other, str):
     316              s = self.value
     317              o = other
     318          elif hasattr(other, "timetuple"):
     319              s = self.timetuple()
     320              o = other.timetuple()
     321          else:
     322              s = self
     323              o = NotImplemented
     324          return s, o
     325  
     326      def __lt__(self, other):
     327          s, o = self.make_comparable(other)
     328          if o is NotImplemented:
     329              return NotImplemented
     330          return s < o
     331  
     332      def __le__(self, other):
     333          s, o = self.make_comparable(other)
     334          if o is NotImplemented:
     335              return NotImplemented
     336          return s <= o
     337  
     338      def __gt__(self, other):
     339          s, o = self.make_comparable(other)
     340          if o is NotImplemented:
     341              return NotImplemented
     342          return s > o
     343  
     344      def __ge__(self, other):
     345          s, o = self.make_comparable(other)
     346          if o is NotImplemented:
     347              return NotImplemented
     348          return s >= o
     349  
     350      def __eq__(self, other):
     351          s, o = self.make_comparable(other)
     352          if o is NotImplemented:
     353              return NotImplemented
     354          return s == o
     355  
     356      def timetuple(self):
     357          return time.strptime(self.value, "%Y%m%dT%H:%M:%S")
     358  
     359      ##
     360      # Get date/time value.
     361      #
     362      # @return Date/time value, as an ISO 8601 string.
     363  
     364      def __str__(self):
     365          return self.value
     366  
     367      def __repr__(self):
     368          return "<%s %r at %#x>" % (self.__class__.__name__, self.value, id(self))
     369  
     370      def decode(self, data):
     371          self.value = str(data).strip()
     372  
     373      def encode(self, out):
     374          out.write("<value><dateTime.iso8601>")
     375          out.write(self.value)
     376          out.write("</dateTime.iso8601></value>\n")
     377  
     378  def _datetime(data):
     379      # decode xml element contents into a DateTime structure.
     380      value = DateTime()
     381      value.decode(data)
     382      return value
     383  
     384  def _datetime_type(data):
     385      return datetime.strptime(data, "%Y%m%dT%H:%M:%S")
     386  
     387  ##
     388  # Wrapper for binary data.  This can be used to transport any kind
     389  # of binary data over XML-RPC, using BASE64 encoding.
     390  #
     391  # @param data An 8-bit string containing arbitrary data.
     392  
     393  class ESC[4;38;5;81mBinary:
     394      """Wrapper for binary data."""
     395  
     396      def __init__(self, data=None):
     397          if data is None:
     398              data = b""
     399          else:
     400              if not isinstance(data, (bytes, bytearray)):
     401                  raise TypeError("expected bytes or bytearray, not %s" %
     402                                  data.__class__.__name__)
     403              data = bytes(data)  # Make a copy of the bytes!
     404          self.data = data
     405  
     406      ##
     407      # Get buffer contents.
     408      #
     409      # @return Buffer contents, as an 8-bit string.
     410  
     411      def __str__(self):
     412          return str(self.data, "latin-1")  # XXX encoding?!
     413  
     414      def __eq__(self, other):
     415          if isinstance(other, Binary):
     416              other = other.data
     417          return self.data == other
     418  
     419      def decode(self, data):
     420          self.data = base64.decodebytes(data)
     421  
     422      def encode(self, out):
     423          out.write("<value><base64>\n")
     424          encoded = base64.encodebytes(self.data)
     425          out.write(encoded.decode('ascii'))
     426          out.write("</base64></value>\n")
     427  
     428  def _binary(data):
     429      # decode xml element contents into a Binary structure
     430      value = Binary()
     431      value.decode(data)
     432      return value
     433  
     434  WRAPPERS = (DateTime, Binary)
     435  
     436  # --------------------------------------------------------------------
     437  # XML parsers
     438  
     439  class ESC[4;38;5;81mExpatParser:
     440      # fast expat parser for Python 2.0 and later.
     441      def __init__(self, target):
     442          self._parser = parser = expat.ParserCreate(None, None)
     443          self._target = target
     444          parser.StartElementHandler = target.start
     445          parser.EndElementHandler = target.end
     446          parser.CharacterDataHandler = target.data
     447          encoding = None
     448          target.xml(encoding, None)
     449  
     450      def feed(self, data):
     451          self._parser.Parse(data, False)
     452  
     453      def close(self):
     454          try:
     455              parser = self._parser
     456          except AttributeError:
     457              pass
     458          else:
     459              del self._target, self._parser # get rid of circular references
     460              parser.Parse(b"", True) # end of data
     461  
     462  # --------------------------------------------------------------------
     463  # XML-RPC marshalling and unmarshalling code
     464  
     465  ##
     466  # XML-RPC marshaller.
     467  #
     468  # @param encoding Default encoding for 8-bit strings.  The default
     469  #     value is None (interpreted as UTF-8).
     470  # @see dumps
     471  
     472  class ESC[4;38;5;81mMarshaller:
     473      """Generate an XML-RPC params chunk from a Python data structure.
     474  
     475      Create a Marshaller instance for each set of parameters, and use
     476      the "dumps" method to convert your data (represented as a tuple)
     477      to an XML-RPC params chunk.  To write a fault response, pass a
     478      Fault instance instead.  You may prefer to use the "dumps" module
     479      function for this purpose.
     480      """
     481  
     482      # by the way, if you don't understand what's going on in here,
     483      # that's perfectly ok.
     484  
     485      def __init__(self, encoding=None, allow_none=False):
     486          self.memo = {}
     487          self.data = None
     488          self.encoding = encoding
     489          self.allow_none = allow_none
     490  
     491      dispatch = {}
     492  
     493      def dumps(self, values):
     494          out = []
     495          write = out.append
     496          dump = self.__dump
     497          if isinstance(values, Fault):
     498              # fault instance
     499              write("<fault>\n")
     500              dump({'faultCode': values.faultCode,
     501                    'faultString': values.faultString},
     502                   write)
     503              write("</fault>\n")
     504          else:
     505              # parameter block
     506              # FIXME: the xml-rpc specification allows us to leave out
     507              # the entire <params> block if there are no parameters.
     508              # however, changing this may break older code (including
     509              # old versions of xmlrpclib.py), so this is better left as
     510              # is for now.  See @XMLRPC3 for more information. /F
     511              write("<params>\n")
     512              for v in values:
     513                  write("<param>\n")
     514                  dump(v, write)
     515                  write("</param>\n")
     516              write("</params>\n")
     517          result = "".join(out)
     518          return result
     519  
     520      def __dump(self, value, write):
     521          try:
     522              f = self.dispatch[type(value)]
     523          except KeyError:
     524              # check if this object can be marshalled as a structure
     525              if not hasattr(value, '__dict__'):
     526                  raise TypeError("cannot marshal %s objects" % type(value))
     527              # check if this class is a sub-class of a basic type,
     528              # because we don't know how to marshal these types
     529              # (e.g. a string sub-class)
     530              for type_ in type(value).__mro__:
     531                  if type_ in self.dispatch.keys():
     532                      raise TypeError("cannot marshal %s objects" % type(value))
     533              # XXX(twouters): using "_arbitrary_instance" as key as a quick-fix
     534              # for the p3yk merge, this should probably be fixed more neatly.
     535              f = self.dispatch["_arbitrary_instance"]
     536          f(self, value, write)
     537  
     538      def dump_nil (self, value, write):
     539          if not self.allow_none:
     540              raise TypeError("cannot marshal None unless allow_none is enabled")
     541          write("<value><nil/></value>")
     542      dispatch[type(None)] = dump_nil
     543  
     544      def dump_bool(self, value, write):
     545          write("<value><boolean>")
     546          write(value and "1" or "0")
     547          write("</boolean></value>\n")
     548      dispatch[bool] = dump_bool
     549  
     550      def dump_long(self, value, write):
     551          if value > MAXINT or value < MININT:
     552              raise OverflowError("int exceeds XML-RPC limits")
     553          write("<value><int>")
     554          write(str(int(value)))
     555          write("</int></value>\n")
     556      dispatch[int] = dump_long
     557  
     558      # backward compatible
     559      dump_int = dump_long
     560  
     561      def dump_double(self, value, write):
     562          write("<value><double>")
     563          write(repr(value))
     564          write("</double></value>\n")
     565      dispatch[float] = dump_double
     566  
     567      def dump_unicode(self, value, write, escape=escape):
     568          write("<value><string>")
     569          write(escape(value))
     570          write("</string></value>\n")
     571      dispatch[str] = dump_unicode
     572  
     573      def dump_bytes(self, value, write):
     574          write("<value><base64>\n")
     575          encoded = base64.encodebytes(value)
     576          write(encoded.decode('ascii'))
     577          write("</base64></value>\n")
     578      dispatch[bytes] = dump_bytes
     579      dispatch[bytearray] = dump_bytes
     580  
     581      def dump_array(self, value, write):
     582          i = id(value)
     583          if i in self.memo:
     584              raise TypeError("cannot marshal recursive sequences")
     585          self.memo[i] = None
     586          dump = self.__dump
     587          write("<value><array><data>\n")
     588          for v in value:
     589              dump(v, write)
     590          write("</data></array></value>\n")
     591          del self.memo[i]
     592      dispatch[tuple] = dump_array
     593      dispatch[list] = dump_array
     594  
     595      def dump_struct(self, value, write, escape=escape):
     596          i = id(value)
     597          if i in self.memo:
     598              raise TypeError("cannot marshal recursive dictionaries")
     599          self.memo[i] = None
     600          dump = self.__dump
     601          write("<value><struct>\n")
     602          for k, v in value.items():
     603              write("<member>\n")
     604              if not isinstance(k, str):
     605                  raise TypeError("dictionary key must be string")
     606              write("<name>%s</name>\n" % escape(k))
     607              dump(v, write)
     608              write("</member>\n")
     609          write("</struct></value>\n")
     610          del self.memo[i]
     611      dispatch[dict] = dump_struct
     612  
     613      def dump_datetime(self, value, write):
     614          write("<value><dateTime.iso8601>")
     615          write(_strftime(value))
     616          write("</dateTime.iso8601></value>\n")
     617      dispatch[datetime] = dump_datetime
     618  
     619      def dump_instance(self, value, write):
     620          # check for special wrappers
     621          if value.__class__ in WRAPPERS:
     622              self.write = write
     623              value.encode(self)
     624              del self.write
     625          else:
     626              # store instance attributes as a struct (really?)
     627              self.dump_struct(value.__dict__, write)
     628      dispatch[DateTime] = dump_instance
     629      dispatch[Binary] = dump_instance
     630      # XXX(twouters): using "_arbitrary_instance" as key as a quick-fix
     631      # for the p3yk merge, this should probably be fixed more neatly.
     632      dispatch["_arbitrary_instance"] = dump_instance
     633  
     634  ##
     635  # XML-RPC unmarshaller.
     636  #
     637  # @see loads
     638  
     639  class ESC[4;38;5;81mUnmarshaller:
     640      """Unmarshal an XML-RPC response, based on incoming XML event
     641      messages (start, data, end).  Call close() to get the resulting
     642      data structure.
     643  
     644      Note that this reader is fairly tolerant, and gladly accepts bogus
     645      XML-RPC data without complaining (but not bogus XML).
     646      """
     647  
     648      # and again, if you don't understand what's going on in here,
     649      # that's perfectly ok.
     650  
     651      def __init__(self, use_datetime=False, use_builtin_types=False):
     652          self._type = None
     653          self._stack = []
     654          self._marks = []
     655          self._data = []
     656          self._value = False
     657          self._methodname = None
     658          self._encoding = "utf-8"
     659          self.append = self._stack.append
     660          self._use_datetime = use_builtin_types or use_datetime
     661          self._use_bytes = use_builtin_types
     662  
     663      def close(self):
     664          # return response tuple and target method
     665          if self._type is None or self._marks:
     666              raise ResponseError()
     667          if self._type == "fault":
     668              raise Fault(**self._stack[0])
     669          return tuple(self._stack)
     670  
     671      def getmethodname(self):
     672          return self._methodname
     673  
     674      #
     675      # event handlers
     676  
     677      def xml(self, encoding, standalone):
     678          self._encoding = encoding
     679          # FIXME: assert standalone == 1 ???
     680  
     681      def start(self, tag, attrs):
     682          # prepare to handle this element
     683          if ':' in tag:
     684              tag = tag.split(':')[-1]
     685          if tag == "array" or tag == "struct":
     686              self._marks.append(len(self._stack))
     687          self._data = []
     688          if self._value and tag not in self.dispatch:
     689              raise ResponseError("unknown tag %r" % tag)
     690          self._value = (tag == "value")
     691  
     692      def data(self, text):
     693          self._data.append(text)
     694  
     695      def end(self, tag):
     696          # call the appropriate end tag handler
     697          try:
     698              f = self.dispatch[tag]
     699          except KeyError:
     700              if ':' not in tag:
     701                  return # unknown tag ?
     702              try:
     703                  f = self.dispatch[tag.split(':')[-1]]
     704              except KeyError:
     705                  return # unknown tag ?
     706          return f(self, "".join(self._data))
     707  
     708      #
     709      # accelerator support
     710  
     711      def end_dispatch(self, tag, data):
     712          # dispatch data
     713          try:
     714              f = self.dispatch[tag]
     715          except KeyError:
     716              if ':' not in tag:
     717                  return # unknown tag ?
     718              try:
     719                  f = self.dispatch[tag.split(':')[-1]]
     720              except KeyError:
     721                  return # unknown tag ?
     722          return f(self, data)
     723  
     724      #
     725      # element decoders
     726  
     727      dispatch = {}
     728  
     729      def end_nil (self, data):
     730          self.append(None)
     731          self._value = 0
     732      dispatch["nil"] = end_nil
     733  
     734      def end_boolean(self, data):
     735          if data == "0":
     736              self.append(False)
     737          elif data == "1":
     738              self.append(True)
     739          else:
     740              raise TypeError("bad boolean value")
     741          self._value = 0
     742      dispatch["boolean"] = end_boolean
     743  
     744      def end_int(self, data):
     745          self.append(int(data))
     746          self._value = 0
     747      dispatch["i1"] = end_int
     748      dispatch["i2"] = end_int
     749      dispatch["i4"] = end_int
     750      dispatch["i8"] = end_int
     751      dispatch["int"] = end_int
     752      dispatch["biginteger"] = end_int
     753  
     754      def end_double(self, data):
     755          self.append(float(data))
     756          self._value = 0
     757      dispatch["double"] = end_double
     758      dispatch["float"] = end_double
     759  
     760      def end_bigdecimal(self, data):
     761          self.append(Decimal(data))
     762          self._value = 0
     763      dispatch["bigdecimal"] = end_bigdecimal
     764  
     765      def end_string(self, data):
     766          if self._encoding:
     767              data = data.decode(self._encoding)
     768          self.append(data)
     769          self._value = 0
     770      dispatch["string"] = end_string
     771      dispatch["name"] = end_string # struct keys are always strings
     772  
     773      def end_array(self, data):
     774          mark = self._marks.pop()
     775          # map arrays to Python lists
     776          self._stack[mark:] = [self._stack[mark:]]
     777          self._value = 0
     778      dispatch["array"] = end_array
     779  
     780      def end_struct(self, data):
     781          mark = self._marks.pop()
     782          # map structs to Python dictionaries
     783          dict = {}
     784          items = self._stack[mark:]
     785          for i in range(0, len(items), 2):
     786              dict[items[i]] = items[i+1]
     787          self._stack[mark:] = [dict]
     788          self._value = 0
     789      dispatch["struct"] = end_struct
     790  
     791      def end_base64(self, data):
     792          value = Binary()
     793          value.decode(data.encode("ascii"))
     794          if self._use_bytes:
     795              value = value.data
     796          self.append(value)
     797          self._value = 0
     798      dispatch["base64"] = end_base64
     799  
     800      def end_dateTime(self, data):
     801          value = DateTime()
     802          value.decode(data)
     803          if self._use_datetime:
     804              value = _datetime_type(data)
     805          self.append(value)
     806      dispatch["dateTime.iso8601"] = end_dateTime
     807  
     808      def end_value(self, data):
     809          # if we stumble upon a value element with no internal
     810          # elements, treat it as a string element
     811          if self._value:
     812              self.end_string(data)
     813      dispatch["value"] = end_value
     814  
     815      def end_params(self, data):
     816          self._type = "params"
     817      dispatch["params"] = end_params
     818  
     819      def end_fault(self, data):
     820          self._type = "fault"
     821      dispatch["fault"] = end_fault
     822  
     823      def end_methodName(self, data):
     824          if self._encoding:
     825              data = data.decode(self._encoding)
     826          self._methodname = data
     827          self._type = "methodName" # no params
     828      dispatch["methodName"] = end_methodName
     829  
     830  ## Multicall support
     831  #
     832  
     833  class ESC[4;38;5;81m_MultiCallMethod:
     834      # some lesser magic to store calls made to a MultiCall object
     835      # for batch execution
     836      def __init__(self, call_list, name):
     837          self.__call_list = call_list
     838          self.__name = name
     839      def __getattr__(self, name):
     840          return _MultiCallMethod(self.__call_list, "%s.%s" % (self.__name, name))
     841      def __call__(self, *args):
     842          self.__call_list.append((self.__name, args))
     843  
     844  class ESC[4;38;5;81mMultiCallIterator:
     845      """Iterates over the results of a multicall. Exceptions are
     846      raised in response to xmlrpc faults."""
     847  
     848      def __init__(self, results):
     849          self.results = results
     850  
     851      def __getitem__(self, i):
     852          item = self.results[i]
     853          if type(item) == type({}):
     854              raise Fault(item['faultCode'], item['faultString'])
     855          elif type(item) == type([]):
     856              return item[0]
     857          else:
     858              raise ValueError("unexpected type in multicall result")
     859  
     860  class ESC[4;38;5;81mMultiCall:
     861      """server -> an object used to boxcar method calls
     862  
     863      server should be a ServerProxy object.
     864  
     865      Methods can be added to the MultiCall using normal
     866      method call syntax e.g.:
     867  
     868      multicall = MultiCall(server_proxy)
     869      multicall.add(2,3)
     870      multicall.get_address("Guido")
     871  
     872      To execute the multicall, call the MultiCall object e.g.:
     873  
     874      add_result, address = multicall()
     875      """
     876  
     877      def __init__(self, server):
     878          self.__server = server
     879          self.__call_list = []
     880  
     881      def __repr__(self):
     882          return "<%s at %#x>" % (self.__class__.__name__, id(self))
     883  
     884      def __getattr__(self, name):
     885          return _MultiCallMethod(self.__call_list, name)
     886  
     887      def __call__(self):
     888          marshalled_list = []
     889          for name, args in self.__call_list:
     890              marshalled_list.append({'methodName' : name, 'params' : args})
     891  
     892          return MultiCallIterator(self.__server.system.multicall(marshalled_list))
     893  
     894  # --------------------------------------------------------------------
     895  # convenience functions
     896  
     897  FastMarshaller = FastParser = FastUnmarshaller = None
     898  
     899  ##
     900  # Create a parser object, and connect it to an unmarshalling instance.
     901  # This function picks the fastest available XML parser.
     902  #
     903  # return A (parser, unmarshaller) tuple.
     904  
     905  def getparser(use_datetime=False, use_builtin_types=False):
     906      """getparser() -> parser, unmarshaller
     907  
     908      Create an instance of the fastest available parser, and attach it
     909      to an unmarshalling object.  Return both objects.
     910      """
     911      if FastParser and FastUnmarshaller:
     912          if use_builtin_types:
     913              mkdatetime = _datetime_type
     914              mkbytes = base64.decodebytes
     915          elif use_datetime:
     916              mkdatetime = _datetime_type
     917              mkbytes = _binary
     918          else:
     919              mkdatetime = _datetime
     920              mkbytes = _binary
     921          target = FastUnmarshaller(True, False, mkbytes, mkdatetime, Fault)
     922          parser = FastParser(target)
     923      else:
     924          target = Unmarshaller(use_datetime=use_datetime, use_builtin_types=use_builtin_types)
     925          if FastParser:
     926              parser = FastParser(target)
     927          else:
     928              parser = ExpatParser(target)
     929      return parser, target
     930  
     931  ##
     932  # Convert a Python tuple or a Fault instance to an XML-RPC packet.
     933  #
     934  # @def dumps(params, **options)
     935  # @param params A tuple or Fault instance.
     936  # @keyparam methodname If given, create a methodCall request for
     937  #     this method name.
     938  # @keyparam methodresponse If given, create a methodResponse packet.
     939  #     If used with a tuple, the tuple must be a singleton (that is,
     940  #     it must contain exactly one element).
     941  # @keyparam encoding The packet encoding.
     942  # @return A string containing marshalled data.
     943  
     944  def dumps(params, methodname=None, methodresponse=None, encoding=None,
     945            allow_none=False):
     946      """data [,options] -> marshalled data
     947  
     948      Convert an argument tuple or a Fault instance to an XML-RPC
     949      request (or response, if the methodresponse option is used).
     950  
     951      In addition to the data object, the following options can be given
     952      as keyword arguments:
     953  
     954          methodname: the method name for a methodCall packet
     955  
     956          methodresponse: true to create a methodResponse packet.
     957          If this option is used with a tuple, the tuple must be
     958          a singleton (i.e. it can contain only one element).
     959  
     960          encoding: the packet encoding (default is UTF-8)
     961  
     962      All byte strings in the data structure are assumed to use the
     963      packet encoding.  Unicode strings are automatically converted,
     964      where necessary.
     965      """
     966  
     967      assert isinstance(params, (tuple, Fault)), "argument must be tuple or Fault instance"
     968      if isinstance(params, Fault):
     969          methodresponse = 1
     970      elif methodresponse and isinstance(params, tuple):
     971          assert len(params) == 1, "response tuple must be a singleton"
     972  
     973      if not encoding:
     974          encoding = "utf-8"
     975  
     976      if FastMarshaller:
     977          m = FastMarshaller(encoding)
     978      else:
     979          m = Marshaller(encoding, allow_none)
     980  
     981      data = m.dumps(params)
     982  
     983      if encoding != "utf-8":
     984          xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding)
     985      else:
     986          xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
     987  
     988      # standard XML-RPC wrappings
     989      if methodname:
     990          # a method call
     991          data = (
     992              xmlheader,
     993              "<methodCall>\n"
     994              "<methodName>", methodname, "</methodName>\n",
     995              data,
     996              "</methodCall>\n"
     997              )
     998      elif methodresponse:
     999          # a method response, or a fault structure
    1000          data = (
    1001              xmlheader,
    1002              "<methodResponse>\n",
    1003              data,
    1004              "</methodResponse>\n"
    1005              )
    1006      else:
    1007          return data # return as is
    1008      return "".join(data)
    1009  
    1010  ##
    1011  # Convert an XML-RPC packet to a Python object.  If the XML-RPC packet
    1012  # represents a fault condition, this function raises a Fault exception.
    1013  #
    1014  # @param data An XML-RPC packet, given as an 8-bit string.
    1015  # @return A tuple containing the unpacked data, and the method name
    1016  #     (None if not present).
    1017  # @see Fault
    1018  
    1019  def loads(data, use_datetime=False, use_builtin_types=False):
    1020      """data -> unmarshalled data, method name
    1021  
    1022      Convert an XML-RPC packet to unmarshalled data plus a method
    1023      name (None if not present).
    1024  
    1025      If the XML-RPC packet represents a fault condition, this function
    1026      raises a Fault exception.
    1027      """
    1028      p, u = getparser(use_datetime=use_datetime, use_builtin_types=use_builtin_types)
    1029      p.feed(data)
    1030      p.close()
    1031      return u.close(), u.getmethodname()
    1032  
    1033  ##
    1034  # Encode a string using the gzip content encoding such as specified by the
    1035  # Content-Encoding: gzip
    1036  # in the HTTP header, as described in RFC 1952
    1037  #
    1038  # @param data the unencoded data
    1039  # @return the encoded data
    1040  
    1041  def gzip_encode(data):
    1042      """data -> gzip encoded data
    1043  
    1044      Encode data using the gzip content encoding as described in RFC 1952
    1045      """
    1046      if not gzip:
    1047          raise NotImplementedError
    1048      f = BytesIO()
    1049      with gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1) as gzf:
    1050          gzf.write(data)
    1051      return f.getvalue()
    1052  
    1053  ##
    1054  # Decode a string using the gzip content encoding such as specified by the
    1055  # Content-Encoding: gzip
    1056  # in the HTTP header, as described in RFC 1952
    1057  #
    1058  # @param data The encoded data
    1059  # @keyparam max_decode Maximum bytes to decode (20 MiB default), use negative
    1060  #    values for unlimited decoding
    1061  # @return the unencoded data
    1062  # @raises ValueError if data is not correctly coded.
    1063  # @raises ValueError if max gzipped payload length exceeded
    1064  
    1065  def gzip_decode(data, max_decode=20971520):
    1066      """gzip encoded data -> unencoded data
    1067  
    1068      Decode data using the gzip content encoding as described in RFC 1952
    1069      """
    1070      if not gzip:
    1071          raise NotImplementedError
    1072      with gzip.GzipFile(mode="rb", fileobj=BytesIO(data)) as gzf:
    1073          try:
    1074              if max_decode < 0: # no limit
    1075                  decoded = gzf.read()
    1076              else:
    1077                  decoded = gzf.read(max_decode + 1)
    1078          except OSError:
    1079              raise ValueError("invalid data")
    1080      if max_decode >= 0 and len(decoded) > max_decode:
    1081          raise ValueError("max gzipped payload length exceeded")
    1082      return decoded
    1083  
    1084  ##
    1085  # Return a decoded file-like object for the gzip encoding
    1086  # as described in RFC 1952.
    1087  #
    1088  # @param response A stream supporting a read() method
    1089  # @return a file-like object that the decoded data can be read() from
    1090  
    1091  class ESC[4;38;5;81mGzipDecodedResponse(ESC[4;38;5;149mgzipESC[4;38;5;149m.ESC[4;38;5;149mGzipFile if gzip else object):
    1092      """a file-like object to decode a response encoded with the gzip
    1093      method, as described in RFC 1952.
    1094      """
    1095      def __init__(self, response):
    1096          #response doesn't support tell() and read(), required by
    1097          #GzipFile
    1098          if not gzip:
    1099              raise NotImplementedError
    1100          self.io = BytesIO(response.read())
    1101          gzip.GzipFile.__init__(self, mode="rb", fileobj=self.io)
    1102  
    1103      def close(self):
    1104          try:
    1105              gzip.GzipFile.close(self)
    1106          finally:
    1107              self.io.close()
    1108  
    1109  
    1110  # --------------------------------------------------------------------
    1111  # request dispatcher
    1112  
    1113  class ESC[4;38;5;81m_Method:
    1114      # some magic to bind an XML-RPC method to an RPC server.
    1115      # supports "nested" methods (e.g. examples.getStateName)
    1116      def __init__(self, send, name):
    1117          self.__send = send
    1118          self.__name = name
    1119      def __getattr__(self, name):
    1120          return _Method(self.__send, "%s.%s" % (self.__name, name))
    1121      def __call__(self, *args):
    1122          return self.__send(self.__name, args)
    1123  
    1124  ##
    1125  # Standard transport class for XML-RPC over HTTP.
    1126  # <p>
    1127  # You can create custom transports by subclassing this method, and
    1128  # overriding selected methods.
    1129  
    1130  class ESC[4;38;5;81mTransport:
    1131      """Handles an HTTP transaction to an XML-RPC server."""
    1132  
    1133      # client identifier (may be overridden)
    1134      user_agent = "Python-xmlrpc/%s" % __version__
    1135  
    1136      #if true, we'll request gzip encoding
    1137      accept_gzip_encoding = True
    1138  
    1139      # if positive, encode request using gzip if it exceeds this threshold
    1140      # note that many servers will get confused, so only use it if you know
    1141      # that they can decode such a request
    1142      encode_threshold = None #None = don't encode
    1143  
    1144      def __init__(self, use_datetime=False, use_builtin_types=False,
    1145                   *, headers=()):
    1146          self._use_datetime = use_datetime
    1147          self._use_builtin_types = use_builtin_types
    1148          self._connection = (None, None)
    1149          self._headers = list(headers)
    1150          self._extra_headers = []
    1151  
    1152      ##
    1153      # Send a complete request, and parse the response.
    1154      # Retry request if a cached connection has disconnected.
    1155      #
    1156      # @param host Target host.
    1157      # @param handler Target PRC handler.
    1158      # @param request_body XML-RPC request body.
    1159      # @param verbose Debugging flag.
    1160      # @return Parsed response.
    1161  
    1162      def request(self, host, handler, request_body, verbose=False):
    1163          #retry request once if cached connection has gone cold
    1164          for i in (0, 1):
    1165              try:
    1166                  return self.single_request(host, handler, request_body, verbose)
    1167              except http.client.RemoteDisconnected:
    1168                  if i:
    1169                      raise
    1170              except OSError as e:
    1171                  if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED,
    1172                                          errno.EPIPE):
    1173                      raise
    1174  
    1175      def single_request(self, host, handler, request_body, verbose=False):
    1176          # issue XML-RPC request
    1177          try:
    1178              http_conn = self.send_request(host, handler, request_body, verbose)
    1179              resp = http_conn.getresponse()
    1180              if resp.status == 200:
    1181                  self.verbose = verbose
    1182                  return self.parse_response(resp)
    1183  
    1184          except Fault:
    1185              raise
    1186          except Exception:
    1187              #All unexpected errors leave connection in
    1188              # a strange state, so we clear it.
    1189              self.close()
    1190              raise
    1191  
    1192          #We got an error response.
    1193          #Discard any response data and raise exception
    1194          if resp.getheader("content-length", ""):
    1195              resp.read()
    1196          raise ProtocolError(
    1197              host + handler,
    1198              resp.status, resp.reason,
    1199              dict(resp.getheaders())
    1200              )
    1201  
    1202  
    1203      ##
    1204      # Create parser.
    1205      #
    1206      # @return A 2-tuple containing a parser and an unmarshaller.
    1207  
    1208      def getparser(self):
    1209          # get parser and unmarshaller
    1210          return getparser(use_datetime=self._use_datetime,
    1211                           use_builtin_types=self._use_builtin_types)
    1212  
    1213      ##
    1214      # Get authorization info from host parameter
    1215      # Host may be a string, or a (host, x509-dict) tuple; if a string,
    1216      # it is checked for a "user:pw@host" format, and a "Basic
    1217      # Authentication" header is added if appropriate.
    1218      #
    1219      # @param host Host descriptor (URL or (URL, x509 info) tuple).
    1220      # @return A 3-tuple containing (actual host, extra headers,
    1221      #     x509 info).  The header and x509 fields may be None.
    1222  
    1223      def get_host_info(self, host):
    1224  
    1225          x509 = {}
    1226          if isinstance(host, tuple):
    1227              host, x509 = host
    1228  
    1229          auth, host = urllib.parse._splituser(host)
    1230  
    1231          if auth:
    1232              auth = urllib.parse.unquote_to_bytes(auth)
    1233              auth = base64.encodebytes(auth).decode("utf-8")
    1234              auth = "".join(auth.split()) # get rid of whitespace
    1235              extra_headers = [
    1236                  ("Authorization", "Basic " + auth)
    1237                  ]
    1238          else:
    1239              extra_headers = []
    1240  
    1241          return host, extra_headers, x509
    1242  
    1243      ##
    1244      # Connect to server.
    1245      #
    1246      # @param host Target host.
    1247      # @return An HTTPConnection object
    1248  
    1249      def make_connection(self, host):
    1250          #return an existing connection if possible.  This allows
    1251          #HTTP/1.1 keep-alive.
    1252          if self._connection and host == self._connection[0]:
    1253              return self._connection[1]
    1254          # create a HTTP connection object from a host descriptor
    1255          chost, self._extra_headers, x509 = self.get_host_info(host)
    1256          self._connection = host, http.client.HTTPConnection(chost)
    1257          return self._connection[1]
    1258  
    1259      ##
    1260      # Clear any cached connection object.
    1261      # Used in the event of socket errors.
    1262      #
    1263      def close(self):
    1264          host, connection = self._connection
    1265          if connection:
    1266              self._connection = (None, None)
    1267              connection.close()
    1268  
    1269      ##
    1270      # Send HTTP request.
    1271      #
    1272      # @param host Host descriptor (URL or (URL, x509 info) tuple).
    1273      # @param handler Target RPC handler (a path relative to host)
    1274      # @param request_body The XML-RPC request body
    1275      # @param debug Enable debugging if debug is true.
    1276      # @return An HTTPConnection.
    1277  
    1278      def send_request(self, host, handler, request_body, debug):
    1279          connection = self.make_connection(host)
    1280          headers = self._headers + self._extra_headers
    1281          if debug:
    1282              connection.set_debuglevel(1)
    1283          if self.accept_gzip_encoding and gzip:
    1284              connection.putrequest("POST", handler, skip_accept_encoding=True)
    1285              headers.append(("Accept-Encoding", "gzip"))
    1286          else:
    1287              connection.putrequest("POST", handler)
    1288          headers.append(("Content-Type", "text/xml"))
    1289          headers.append(("User-Agent", self.user_agent))
    1290          self.send_headers(connection, headers)
    1291          self.send_content(connection, request_body)
    1292          return connection
    1293  
    1294      ##
    1295      # Send request headers.
    1296      # This function provides a useful hook for subclassing
    1297      #
    1298      # @param connection httpConnection.
    1299      # @param headers list of key,value pairs for HTTP headers
    1300  
    1301      def send_headers(self, connection, headers):
    1302          for key, val in headers:
    1303              connection.putheader(key, val)
    1304  
    1305      ##
    1306      # Send request body.
    1307      # This function provides a useful hook for subclassing
    1308      #
    1309      # @param connection httpConnection.
    1310      # @param request_body XML-RPC request body.
    1311  
    1312      def send_content(self, connection, request_body):
    1313          #optionally encode the request
    1314          if (self.encode_threshold is not None and
    1315              self.encode_threshold < len(request_body) and
    1316              gzip):
    1317              connection.putheader("Content-Encoding", "gzip")
    1318              request_body = gzip_encode(request_body)
    1319  
    1320          connection.putheader("Content-Length", str(len(request_body)))
    1321          connection.endheaders(request_body)
    1322  
    1323      ##
    1324      # Parse response.
    1325      #
    1326      # @param file Stream.
    1327      # @return Response tuple and target method.
    1328  
    1329      def parse_response(self, response):
    1330          # read response data from httpresponse, and parse it
    1331          # Check for new http response object, otherwise it is a file object.
    1332          if hasattr(response, 'getheader'):
    1333              if response.getheader("Content-Encoding", "") == "gzip":
    1334                  stream = GzipDecodedResponse(response)
    1335              else:
    1336                  stream = response
    1337          else:
    1338              stream = response
    1339  
    1340          p, u = self.getparser()
    1341  
    1342          while 1:
    1343              data = stream.read(1024)
    1344              if not data:
    1345                  break
    1346              if self.verbose:
    1347                  print("body:", repr(data))
    1348              p.feed(data)
    1349  
    1350          if stream is not response:
    1351              stream.close()
    1352          p.close()
    1353  
    1354          return u.close()
    1355  
    1356  ##
    1357  # Standard transport class for XML-RPC over HTTPS.
    1358  
    1359  class ESC[4;38;5;81mSafeTransport(ESC[4;38;5;149mTransport):
    1360      """Handles an HTTPS transaction to an XML-RPC server."""
    1361  
    1362      def __init__(self, use_datetime=False, use_builtin_types=False,
    1363                   *, headers=(), context=None):
    1364          super().__init__(use_datetime=use_datetime,
    1365                           use_builtin_types=use_builtin_types,
    1366                           headers=headers)
    1367          self.context = context
    1368  
    1369      # FIXME: mostly untested
    1370  
    1371      def make_connection(self, host):
    1372          if self._connection and host == self._connection[0]:
    1373              return self._connection[1]
    1374  
    1375          if not hasattr(http.client, "HTTPSConnection"):
    1376              raise NotImplementedError(
    1377              "your version of http.client doesn't support HTTPS")
    1378          # create a HTTPS connection object from a host descriptor
    1379          # host may be a string, or a (host, x509-dict) tuple
    1380          chost, self._extra_headers, x509 = self.get_host_info(host)
    1381          self._connection = host, http.client.HTTPSConnection(chost,
    1382              None, context=self.context, **(x509 or {}))
    1383          return self._connection[1]
    1384  
    1385  ##
    1386  # Standard server proxy.  This class establishes a virtual connection
    1387  # to an XML-RPC server.
    1388  # <p>
    1389  # This class is available as ServerProxy and Server.  New code should
    1390  # use ServerProxy, to avoid confusion.
    1391  #
    1392  # @def ServerProxy(uri, **options)
    1393  # @param uri The connection point on the server.
    1394  # @keyparam transport A transport factory, compatible with the
    1395  #    standard transport class.
    1396  # @keyparam encoding The default encoding used for 8-bit strings
    1397  #    (default is UTF-8).
    1398  # @keyparam verbose Use a true value to enable debugging output.
    1399  #    (printed to standard output).
    1400  # @see Transport
    1401  
    1402  class ESC[4;38;5;81mServerProxy:
    1403      """uri [,options] -> a logical connection to an XML-RPC server
    1404  
    1405      uri is the connection point on the server, given as
    1406      scheme://host/target.
    1407  
    1408      The standard implementation always supports the "http" scheme.  If
    1409      SSL socket support is available (Python 2.0), it also supports
    1410      "https".
    1411  
    1412      If the target part and the slash preceding it are both omitted,
    1413      "/RPC2" is assumed.
    1414  
    1415      The following options can be given as keyword arguments:
    1416  
    1417          transport: a transport factory
    1418          encoding: the request encoding (default is UTF-8)
    1419  
    1420      All 8-bit strings passed to the server proxy are assumed to use
    1421      the given encoding.
    1422      """
    1423  
    1424      def __init__(self, uri, transport=None, encoding=None, verbose=False,
    1425                   allow_none=False, use_datetime=False, use_builtin_types=False,
    1426                   *, headers=(), context=None):
    1427          # establish a "logical" server connection
    1428  
    1429          # get the url
    1430          p = urllib.parse.urlsplit(uri)
    1431          if p.scheme not in ("http", "https"):
    1432              raise OSError("unsupported XML-RPC protocol")
    1433          self.__host = p.netloc
    1434          self.__handler = urllib.parse.urlunsplit(["", "", *p[2:]])
    1435          if not self.__handler:
    1436              self.__handler = "/RPC2"
    1437  
    1438          if transport is None:
    1439              if p.scheme == "https":
    1440                  handler = SafeTransport
    1441                  extra_kwargs = {"context": context}
    1442              else:
    1443                  handler = Transport
    1444                  extra_kwargs = {}
    1445              transport = handler(use_datetime=use_datetime,
    1446                                  use_builtin_types=use_builtin_types,
    1447                                  headers=headers,
    1448                                  **extra_kwargs)
    1449          self.__transport = transport
    1450  
    1451          self.__encoding = encoding or 'utf-8'
    1452          self.__verbose = verbose
    1453          self.__allow_none = allow_none
    1454  
    1455      def __close(self):
    1456          self.__transport.close()
    1457  
    1458      def __request(self, methodname, params):
    1459          # call a method on the remote server
    1460  
    1461          request = dumps(params, methodname, encoding=self.__encoding,
    1462                          allow_none=self.__allow_none).encode(self.__encoding, 'xmlcharrefreplace')
    1463  
    1464          response = self.__transport.request(
    1465              self.__host,
    1466              self.__handler,
    1467              request,
    1468              verbose=self.__verbose
    1469              )
    1470  
    1471          if len(response) == 1:
    1472              response = response[0]
    1473  
    1474          return response
    1475  
    1476      def __repr__(self):
    1477          return (
    1478              "<%s for %s%s>" %
    1479              (self.__class__.__name__, self.__host, self.__handler)
    1480              )
    1481  
    1482      def __getattr__(self, name):
    1483          # magic method dispatcher
    1484          return _Method(self.__request, name)
    1485  
    1486      # note: to call a remote object with a non-standard name, use
    1487      # result getattr(server, "strange-python-name")(args)
    1488  
    1489      def __call__(self, attr):
    1490          """A workaround to get special attributes on the ServerProxy
    1491             without interfering with the magic __getattr__
    1492          """
    1493          if attr == "close":
    1494              return self.__close
    1495          elif attr == "transport":
    1496              return self.__transport
    1497          raise AttributeError("Attribute %r not found" % (attr,))
    1498  
    1499      def __enter__(self):
    1500          return self
    1501  
    1502      def __exit__(self, *args):
    1503          self.__close()
    1504  
    1505  # compatibility
    1506  
    1507  Server = ServerProxy
    1508  
    1509  # --------------------------------------------------------------------
    1510  # test code
    1511  
    1512  if __name__ == "__main__":
    1513  
    1514      # simple test program (from the XML-RPC specification)
    1515  
    1516      # local server, available from Lib/xmlrpc/server.py
    1517      server = ServerProxy("http://localhost:8000")
    1518  
    1519      try:
    1520          print(server.currentTime.getCurrentTime())
    1521      except Error as v:
    1522          print("ERROR", v)
    1523  
    1524      multi = MultiCall(server)
    1525      multi.getData()
    1526      multi.pow(2,9)
    1527      multi.add(1,2)
    1528      try:
    1529          for response in multi():
    1530              print(response)
    1531      except Error as v:
    1532          print("ERROR", v)