blob: 549006bc29976a39dbf19f14993b71365ef4ba1a [file] [log] [blame]
Fredrik Lundhb9056332001-07-11 17:42:21 +00001#
2# XML-RPC CLIENT LIBRARY
3# $Id$
4#
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00005# 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:
Martin v. Löwis37af9862004-08-20 07:31:37 +000011# this version is designed to work with Python 2.1 or newer.
Fredrik Lundhc4c062f2001-09-10 19:45:02 +000012#
Fredrik Lundhb9056332001-07-11 17:42:21 +000013# 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)
Fredrik Lundh78eedce2001-08-23 20:04:33 +000027# 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)
Fredrik Lundhc4c062f2001-09-10 19:45:02 +000029# 2001-09-03 fl Allow Transport subclass to override getparser
30# 2001-09-10 fl Lazy import of urllib, cgi, xmllib (20x import speedup)
Fredrik Lundh1538c232001-10-01 19:42:03 +000031# 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)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000033# 2001-10-02 fl More dumps microtuning
34# 2001-10-04 fl Make sure import expat gets a parser (from Guido van Rossum)
Skip Montanaro5e9c71b2001-10-10 15:56:34 +000035# 2001-10-10 sm Allow long ints to be passed as ints if they don't overflow
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000036# 2001-10-17 sm Test for int and long overflow (allows use on 64-bit systems)
Fredrik Lundhb6ab93f2001-12-19 21:40:04 +000037# 2001-11-12 fl Use repr() to marshal doubles (from Paul Felix)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000038# 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
Fredrik Lundh1303c7c2002-10-22 18:23:00 +000043# 2002-10-22 fl Added basic authentication (based on code from Phillip Eby)
Martin v. Löwis541342f2003-07-12 07:53:04 +000044# 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
Martin v. Löwis45394c22003-10-31 13:49:36 +000050# 2003-10-31 mvl Add multicall support
Martin v. Löwis37af9862004-08-20 07:31:37 +000051# 2004-08-20 mvl Bump minimum supported Python version to 2.1
Fredrik Lundhb9056332001-07-11 17:42:21 +000052#
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000053# Copyright (c) 1999-2002 by Secret Labs AB.
54# Copyright (c) 1999-2002 by Fredrik Lundh.
Fredrik Lundhb9056332001-07-11 17:42:21 +000055#
56# info@pythonware.com
57# http://www.pythonware.com
58#
59# --------------------------------------------------------------------
60# The XML-RPC client interface is
61#
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000062# Copyright (c) 1999-2002 by Secret Labs AB
63# Copyright (c) 1999-2002 by Fredrik Lundh
Fredrik Lundhb9056332001-07-11 17:42:21 +000064#
65# By obtaining, using, and/or copying this software and/or its
66# associated documentation, you agree that you have read, understood,
67# and will comply with the following terms and conditions:
68#
69# Permission to use, copy, modify, and distribute this software and
70# its associated documentation for any purpose and without fee is
71# hereby granted, provided that the above copyright notice appears in
72# all copies, and that both that copyright notice and this permission
73# notice appear in supporting documentation, and that the name of
74# Secret Labs AB or the author not be used in advertising or publicity
75# pertaining to distribution of the software without specific, written
76# prior permission.
77#
78# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
79# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
80# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
81# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
82# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
83# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
84# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
85# OF THIS SOFTWARE.
86# --------------------------------------------------------------------
87
88#
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000089# things to look into some day:
Fredrik Lundhb9056332001-07-11 17:42:21 +000090
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000091# TODO: sort out True/False/boolean issues for Python 2.3
Fredrik Lundhb9056332001-07-11 17:42:21 +000092
Fred Drake1b410792001-09-04 18:55:03 +000093"""
94An XML-RPC client interface for Python.
95
96The marshalling and response parser code can also be used to
97implement XML-RPC servers.
98
Fred Drake1b410792001-09-04 18:55:03 +000099Exported exceptions:
100
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000101 Error Base class for client errors
102 ProtocolError Indicates an HTTP protocol error
103 ResponseError Indicates a broken response package
104 Fault Indicates an XML-RPC fault package
Fred Drake1b410792001-09-04 18:55:03 +0000105
106Exported classes:
107
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000108 ServerProxy Represents a logical connection to an XML-RPC server
Fred Drake1b410792001-09-04 18:55:03 +0000109
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000110 MultiCall Executor of boxcared xmlrpc requests
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000111 DateTime dateTime wrapper for an ISO 8601 string or time tuple or
112 localtime integer value to generate a "dateTime.iso8601"
113 XML-RPC value
114 Binary binary data wrapper
Fred Drake1b410792001-09-04 18:55:03 +0000115
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000116 Marshaller Generate an XML-RPC params chunk from a Python data structure
117 Unmarshaller Unmarshal an XML-RPC response from incoming XML event message
118 Transport Handles an HTTP transaction to an XML-RPC server
119 SafeTransport Handles an HTTPS transaction to an XML-RPC server
Fred Drake1b410792001-09-04 18:55:03 +0000120
121Exported constants:
122
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000123 True
124 False
Fred Drake1b410792001-09-04 18:55:03 +0000125
126Exported functions:
127
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000128 getparser Create instance of the fastest available parser & attach
129 to an unmarshalling object
130 dumps Convert an argument tuple or a Fault instance to an XML-RPC
131 request (or response, if the methodresponse option is used).
132 loads Convert an XML-RPC packet to unmarshalled data plus a method
133 name (None if not present).
Fred Drake1b410792001-09-04 18:55:03 +0000134"""
135
Neal Norwitzff113342007-04-17 08:42:15 +0000136import re, time, operator
Georg Brandl24420152008-05-26 16:32:26 +0000137import http.client
Georg Brandlcef803f2009-06-04 09:04:53 +0000138from xml.parsers import expat
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000139import socket
140import errno
141from io import BytesIO
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +0000142try:
143 import gzip
144except ImportError:
145 gzip = None #python can be built without zlib/gzip support
Fredrik Lundh1538c232001-10-01 19:42:03 +0000146
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000147# --------------------------------------------------------------------
148# Internal stuff
149
Fredrik Lundhb9056332001-07-11 17:42:21 +0000150try:
Fred Drakeba613c32005-02-10 18:33:30 +0000151 import datetime
152except ImportError:
153 datetime = None
154
Fredrik Lundhb9056332001-07-11 17:42:21 +0000155def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
156 # decode non-ascii string (if possible)
Guido van Rossum54ad5232007-05-27 09:17:48 +0000157 if encoding and is8bit(data):
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000158 data = str(data, encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000159 return data
160
Neal Norwitzff113342007-04-17 08:42:15 +0000161def escape(s):
162 s = s.replace("&", "&")
163 s = s.replace("<", "&lt;")
164 return s.replace(">", "&gt;",)
Fredrik Lundh1538c232001-10-01 19:42:03 +0000165
Guido van Rossum54ad5232007-05-27 09:17:48 +0000166def _stringify(string):
167 # convert to 7-bit ascii if possible
168 try:
Brett Cannon2dbde5e2007-07-30 03:50:35 +0000169 return string.decode("ascii")
Guido van Rossum261f9df2007-08-31 14:07:27 +0000170 except (UnicodeError, TypeError, AttributeError):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000171 return string
172
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000173__version__ = "1.0.1"
174
175# xmlrpc integer limits
Guido van Rossume2a383d2007-01-15 16:59:06 +0000176MAXINT = 2**31-1
177MININT = -2**31
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000178
179# --------------------------------------------------------------------
180# Error constants (from Dan Libby's specification at
181# http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
182
183# Ranges of errors
184PARSE_ERROR = -32700
185SERVER_ERROR = -32600
186APPLICATION_ERROR = -32500
187SYSTEM_ERROR = -32400
188TRANSPORT_ERROR = -32300
189
190# Specific errors
191NOT_WELLFORMED_ERROR = -32700
192UNSUPPORTED_ENCODING = -32701
193INVALID_ENCODING_CHAR = -32702
194INVALID_XMLRPC = -32600
195METHOD_NOT_FOUND = -32601
196INVALID_METHOD_PARAMS = -32602
197INTERNAL_ERROR = -32603
Fredrik Lundhb9056332001-07-11 17:42:21 +0000198
199# --------------------------------------------------------------------
200# Exceptions
201
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000202##
203# Base class for all kinds of client-side errors.
204
Fredrik Lundh78eedce2001-08-23 20:04:33 +0000205class Error(Exception):
Fred Drake1b410792001-09-04 18:55:03 +0000206 """Base class for client errors."""
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000207 def __str__(self):
208 return repr(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000209
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000210##
211# Indicates an HTTP-level protocol error. This is raised by the HTTP
212# transport layer, if the server returns an error code other than 200
213# (OK).
214#
215# @param url The target URL.
216# @param errcode The HTTP error code.
217# @param errmsg The HTTP error message.
218# @param headers The HTTP header dictionary.
219
Fredrik Lundhb9056332001-07-11 17:42:21 +0000220class ProtocolError(Error):
Fred Drake1b410792001-09-04 18:55:03 +0000221 """Indicates an HTTP protocol error."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000222 def __init__(self, url, errcode, errmsg, headers):
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000223 Error.__init__(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000224 self.url = url
225 self.errcode = errcode
226 self.errmsg = errmsg
227 self.headers = headers
228 def __repr__(self):
229 return (
230 "<ProtocolError for %s: %s %s>" %
231 (self.url, self.errcode, self.errmsg)
232 )
233
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000234##
235# Indicates a broken XML-RPC response package. This exception is
236# raised by the unmarshalling layer, if the XML-RPC response is
237# malformed.
238
Fredrik Lundhb9056332001-07-11 17:42:21 +0000239class ResponseError(Error):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000240 """Indicates a broken response package."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000241 pass
242
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000243##
244# Indicates an XML-RPC fault response package. This exception is
245# raised by the unmarshalling layer, if the XML-RPC response contains
246# a fault string. This exception can also used as a class, to
247# generate a fault XML-RPC message.
248#
249# @param faultCode The XML-RPC fault code.
250# @param faultString The XML-RPC fault string.
251
Fredrik Lundhb9056332001-07-11 17:42:21 +0000252class Fault(Error):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000253 """Indicates an XML-RPC fault package."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000254 def __init__(self, faultCode, faultString, **extra):
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000255 Error.__init__(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000256 self.faultCode = faultCode
257 self.faultString = faultString
258 def __repr__(self):
259 return (
260 "<Fault %s: %s>" %
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000261 (self.faultCode, repr(self.faultString))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000262 )
263
264# --------------------------------------------------------------------
265# Special values
266
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000267##
Georg Brandl38eceaa2008-05-26 11:14:17 +0000268# Backwards compatibility
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000269
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000270boolean = Boolean = bool
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000271
272##
273# Wrapper for XML-RPC DateTime values. This converts a time value to
274# the format used by XML-RPC.
275# <p>
276# The value can be given as a string in the format
277# "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by
278# time.localtime()), or an integer value (as returned by time.time()).
279# The wrapper uses time.localtime() to convert an integer to a time
280# tuple.
281#
282# @param value The time, given as an ISO 8601 string, a time
283# tuple, or a integer time value.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000284
Christian Heimesdae2a892008-04-19 00:55:37 +0000285def _strftime(value):
286 if datetime:
287 if isinstance(value, datetime.datetime):
288 return "%04d%02d%02dT%02d:%02d:%02d" % (
289 value.year, value.month, value.day,
290 value.hour, value.minute, value.second)
291
292 if not isinstance(value, (tuple, time.struct_time)):
293 if value == 0:
294 value = time.time()
295 value = time.localtime(value)
296
297 return "%04d%02d%02dT%02d:%02d:%02d" % value[:6]
298
Fredrik Lundhb9056332001-07-11 17:42:21 +0000299class DateTime:
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000300 """DateTime wrapper for an ISO 8601 string or time tuple or
301 localtime integer value to generate 'dateTime.iso8601' XML-RPC
302 value.
303 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000304
305 def __init__(self, value=0):
Christian Heimesdae2a892008-04-19 00:55:37 +0000306 if isinstance(value, str):
307 self.value = value
308 else:
309 self.value = _strftime(value)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000310
Christian Heimes05e8be12008-02-23 18:30:17 +0000311 def make_comparable(self, other):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000312 if isinstance(other, DateTime):
Christian Heimes05e8be12008-02-23 18:30:17 +0000313 s = self.value
314 o = other.value
315 elif datetime and isinstance(other, datetime.datetime):
316 s = self.value
317 o = other.strftime("%Y%m%dT%H:%M:%S")
318 elif isinstance(other, (str, unicode)):
319 s = self.value
320 o = other
321 elif hasattr(other, "timetuple"):
322 s = self.timetuple()
323 o = other.timetuple()
324 else:
325 otype = (hasattr(other, "__class__")
326 and other.__class__.__name__
327 or type(other))
328 raise TypeError("Can't compare %s and %s" %
329 (self.__class__.__name__, otype))
330 return s, o
331
332 def __lt__(self, other):
333 s, o = self.make_comparable(other)
334 return s < o
335
336 def __le__(self, other):
337 s, o = self.make_comparable(other)
338 return s <= o
339
340 def __gt__(self, other):
341 s, o = self.make_comparable(other)
342 return s > o
343
344 def __ge__(self, other):
345 s, o = self.make_comparable(other)
346 return s >= o
347
348 def __eq__(self, other):
349 s, o = self.make_comparable(other)
350 return s == o
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000351
352 def __ne__(self, other):
Christian Heimes05e8be12008-02-23 18:30:17 +0000353 s, o = self.make_comparable(other)
354 return s != o
355
356 def timetuple(self):
357 return time.strptime(self.value, "%Y%m%dT%H:%M:%S")
358
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000359 ##
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
Fredrik Lundhb9056332001-07-11 17:42:21 +0000367 def __repr__(self):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000368 return "<DateTime %s at %x>" % (repr(self.value), id(self))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000369
370 def decode(self, data):
Neal Norwitzff113342007-04-17 08:42:15 +0000371 self.value = str(data).strip()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000372
373 def encode(self, out):
374 out.write("<value><dateTime.iso8601>")
375 out.write(self.value)
376 out.write("</dateTime.iso8601></value>\n")
377
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000378def _datetime(data):
379 # decode xml element contents into a DateTime structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000380 value = DateTime()
381 value.decode(data)
382 return value
383
Skip Montanaro174dd222005-05-14 20:54:16 +0000384def _datetime_type(data):
385 t = time.strptime(data, "%Y%m%dT%H:%M:%S")
386 return datetime.datetime(*tuple(t)[:6])
387
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000388##
389# Wrapper for binary data. This can be used to transport any kind
390# of binary data over XML-RPC, using BASE64 encoding.
391#
392# @param data An 8-bit string containing arbitrary data.
393
Skip Montanarobfcbfa72003-04-24 19:51:31 +0000394import base64
Guido van Rossum68937b42007-05-18 00:51:22 +0000395import io
Skip Montanarobfcbfa72003-04-24 19:51:31 +0000396
Fredrik Lundhb9056332001-07-11 17:42:21 +0000397class Binary:
Fred Drake1b410792001-09-04 18:55:03 +0000398 """Wrapper for binary data."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000399
400 def __init__(self, data=None):
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000401 if data is None:
402 data = b""
403 else:
404 if not isinstance(data, bytes):
405 raise TypeError("expected bytes, not %s" %
406 data.__class__.__name__)
407 data = bytes(data) # Make a copy of the bytes!
Fredrik Lundhb9056332001-07-11 17:42:21 +0000408 self.data = data
409
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000410 ##
411 # Get buffer contents.
412 #
413 # @return Buffer contents, as an 8-bit string.
414
415 def __str__(self):
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000416 return str(self.data, "latin-1") # XXX encoding?!
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000417
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000418 def __eq__(self, other):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000419 if isinstance(other, Binary):
420 other = other.data
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000421 return self.data == other
422
423 def __ne__(self, other):
424 if isinstance(other, Binary):
425 other = other.data
426 return self.data != other
Fredrik Lundhb9056332001-07-11 17:42:21 +0000427
428 def decode(self, data):
Georg Brandlb54d8012009-06-04 09:11:51 +0000429 self.data = base64.decodebytes(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000430
431 def encode(self, out):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000432 out.write("<value><base64>\n")
Georg Brandlb54d8012009-06-04 09:11:51 +0000433 encoded = base64.encodebytes(self.data)
Brett Cannon2dbde5e2007-07-30 03:50:35 +0000434 out.write(encoded.decode('ascii'))
435 out.write('\n')
Fredrik Lundhb9056332001-07-11 17:42:21 +0000436 out.write("</base64></value>\n")
437
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000438def _binary(data):
439 # decode xml element contents into a Binary structure
Fredrik Lundhb9056332001-07-11 17:42:21 +0000440 value = Binary()
441 value.decode(data)
442 return value
443
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000444WRAPPERS = (DateTime, Binary)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000445
446# --------------------------------------------------------------------
447# XML parsers
448
Georg Brandlcef803f2009-06-04 09:04:53 +0000449class ExpatParser:
450 # fast expat parser for Python 2.0 and later.
451 def __init__(self, target):
452 self._parser = parser = expat.ParserCreate(None, None)
453 self._target = target
454 parser.StartElementHandler = target.start
455 parser.EndElementHandler = target.end
456 parser.CharacterDataHandler = target.data
457 encoding = None
458 target.xml(encoding, None)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000459
Georg Brandlcef803f2009-06-04 09:04:53 +0000460 def feed(self, data):
461 self._parser.Parse(data, 0)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000462
Georg Brandlcef803f2009-06-04 09:04:53 +0000463 def close(self):
464 self._parser.Parse("", 1) # end of data
465 del self._target, self._parser # get rid of circular references
Fredrik Lundhb9056332001-07-11 17:42:21 +0000466
Fredrik Lundhb9056332001-07-11 17:42:21 +0000467# --------------------------------------------------------------------
468# XML-RPC marshalling and unmarshalling code
469
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000470##
471# XML-RPC marshaller.
472#
473# @param encoding Default encoding for 8-bit strings. The default
474# value is None (interpreted as UTF-8).
475# @see dumps
476
Fredrik Lundhb9056332001-07-11 17:42:21 +0000477class Marshaller:
Fred Drake1b410792001-09-04 18:55:03 +0000478 """Generate an XML-RPC params chunk from a Python data structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000479
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000480 Create a Marshaller instance for each set of parameters, and use
481 the "dumps" method to convert your data (represented as a tuple)
482 to an XML-RPC params chunk. To write a fault response, pass a
483 Fault instance instead. You may prefer to use the "dumps" module
484 function for this purpose.
Fred Drake1b410792001-09-04 18:55:03 +0000485 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000486
487 # by the way, if you don't understand what's going on in here,
488 # that's perfectly ok.
489
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000490 def __init__(self, encoding=None, allow_none=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000491 self.memo = {}
492 self.data = None
493 self.encoding = encoding
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000494 self.allow_none = allow_none
Tim Petersc2659cf2003-05-12 20:19:37 +0000495
Fredrik Lundhb9056332001-07-11 17:42:21 +0000496 dispatch = {}
497
498 def dumps(self, values):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000499 out = []
500 write = out.append
501 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000502 if isinstance(values, Fault):
503 # fault instance
504 write("<fault>\n")
Martin v. Löwis541342f2003-07-12 07:53:04 +0000505 dump({'faultCode': values.faultCode,
506 'faultString': values.faultString},
507 write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000508 write("</fault>\n")
509 else:
510 # parameter block
Fredrik Lundhc266bb02001-08-23 20:13:08 +0000511 # FIXME: the xml-rpc specification allows us to leave out
512 # the entire <params> block if there are no parameters.
513 # however, changing this may break older code (including
514 # old versions of xmlrpclib.py), so this is better left as
515 # is for now. See @XMLRPC3 for more information. /F
Fredrik Lundhb9056332001-07-11 17:42:21 +0000516 write("<params>\n")
517 for v in values:
518 write("<param>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000519 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000520 write("</param>\n")
521 write("</params>\n")
Neal Norwitzff113342007-04-17 08:42:15 +0000522 result = "".join(out)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000523 return result
524
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000525 def __dump(self, value, write):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000526 try:
527 f = self.dispatch[type(value)]
528 except KeyError:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000529 # check if this object can be marshalled as a structure
530 try:
531 value.__dict__
532 except:
Collin Winterce36ad82007-08-30 01:19:48 +0000533 raise TypeError("cannot marshal %s objects" % type(value))
Thomas Wouters89f507f2006-12-13 04:49:30 +0000534 # check if this class is a sub-class of a basic type,
535 # because we don't know how to marshal these types
536 # (e.g. a string sub-class)
537 for type_ in type(value).__mro__:
538 if type_ in self.dispatch.keys():
Collin Winterce36ad82007-08-30 01:19:48 +0000539 raise TypeError("cannot marshal %s objects" % type(value))
Thomas Wouters89f507f2006-12-13 04:49:30 +0000540 # XXX(twouters): using "_arbitrary_instance" as key as a quick-fix
541 # for the p3yk merge, this should probably be fixed more neatly.
542 f = self.dispatch["_arbitrary_instance"]
543 f(self, value, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000544
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000545 def dump_nil (self, value, write):
546 if not self.allow_none:
Collin Winterce36ad82007-08-30 01:19:48 +0000547 raise TypeError("cannot marshal None unless allow_none is enabled")
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000548 write("<value><nil/></value>")
Guido van Rossum13257902007-06-07 23:15:56 +0000549 dispatch[type(None)] = dump_nil
Tim Petersc2659cf2003-05-12 20:19:37 +0000550
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000551 def dump_int(self, value, write):
Skip Montanaro5449e082001-10-17 22:53:33 +0000552 # in case ints are > 32 bits
553 if value > MAXINT or value < MININT:
Collin Winterce36ad82007-08-30 01:19:48 +0000554 raise OverflowError("int exceeds XML-RPC limits")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000555 write("<value><int>")
556 write(str(value))
557 write("</int></value>\n")
Guido van Rossum13257902007-06-07 23:15:56 +0000558 #dispatch[int] = dump_int
Fredrik Lundhb9056332001-07-11 17:42:21 +0000559
Georg Brandl38eceaa2008-05-26 11:14:17 +0000560 def dump_bool(self, value, write):
561 write("<value><boolean>")
562 write(value and "1" or "0")
563 write("</boolean></value>\n")
564 dispatch[bool] = dump_bool
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000565
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000566 def dump_long(self, value, write):
Skip Montanaro5449e082001-10-17 22:53:33 +0000567 if value > MAXINT or value < MININT:
Collin Winterce36ad82007-08-30 01:19:48 +0000568 raise OverflowError("long int exceeds XML-RPC limits")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000569 write("<value><int>")
570 write(str(int(value)))
571 write("</int></value>\n")
Guido van Rossum13257902007-06-07 23:15:56 +0000572 dispatch[int] = dump_long
Skip Montanaro5e9c71b2001-10-10 15:56:34 +0000573
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000574 def dump_double(self, value, write):
575 write("<value><double>")
576 write(repr(value))
577 write("</double></value>\n")
Guido van Rossum13257902007-06-07 23:15:56 +0000578 dispatch[float] = dump_double
Fredrik Lundhb9056332001-07-11 17:42:21 +0000579
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000580 def dump_string(self, value, write, escape=escape):
581 write("<value><string>")
582 write(escape(value))
583 write("</string></value>\n")
Guido van Rossum98297ee2007-11-06 21:34:58 +0000584 dispatch[bytes] = dump_string
Fredrik Lundhb9056332001-07-11 17:42:21 +0000585
Guido van Rossum54ad5232007-05-27 09:17:48 +0000586 def dump_unicode(self, value, write, escape=escape):
Guido van Rossum54ad5232007-05-27 09:17:48 +0000587 write("<value><string>")
588 write(escape(value))
589 write("</string></value>\n")
590 dispatch[str] = dump_unicode
Fredrik Lundhb9056332001-07-11 17:42:21 +0000591
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000592 def dump_array(self, value, write):
593 i = id(value)
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000594 if i in self.memo:
Collin Winterce36ad82007-08-30 01:19:48 +0000595 raise TypeError("cannot marshal recursive sequences")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000596 self.memo[i] = None
Fredrik Lundh1538c232001-10-01 19:42:03 +0000597 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000598 write("<value><array><data>\n")
599 for v in value:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000600 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000601 write("</data></array></value>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000602 del self.memo[i]
Guido van Rossum13257902007-06-07 23:15:56 +0000603 dispatch[tuple] = dump_array
604 dispatch[list] = dump_array
Fredrik Lundhb9056332001-07-11 17:42:21 +0000605
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000606 def dump_struct(self, value, write, escape=escape):
607 i = id(value)
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000608 if i in self.memo:
Collin Winterce36ad82007-08-30 01:19:48 +0000609 raise TypeError("cannot marshal recursive dictionaries")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000610 self.memo[i] = None
Fredrik Lundh1538c232001-10-01 19:42:03 +0000611 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000612 write("<value><struct>\n")
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000613 for k, v in value.items():
Fredrik Lundhb9056332001-07-11 17:42:21 +0000614 write("<member>\n")
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000615 if not isinstance(k, str):
Collin Winterce36ad82007-08-30 01:19:48 +0000616 raise TypeError("dictionary key must be string")
Fredrik Lundh1538c232001-10-01 19:42:03 +0000617 write("<name>%s</name>\n" % escape(k))
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000618 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000619 write("</member>\n")
620 write("</struct></value>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000621 del self.memo[i]
Guido van Rossum13257902007-06-07 23:15:56 +0000622 dispatch[dict] = dump_struct
Fredrik Lundhb9056332001-07-11 17:42:21 +0000623
Fred Drakeba613c32005-02-10 18:33:30 +0000624 if datetime:
625 def dump_datetime(self, value, write):
626 write("<value><dateTime.iso8601>")
Christian Heimesdae2a892008-04-19 00:55:37 +0000627 write(_strftime(value))
Fred Drakeba613c32005-02-10 18:33:30 +0000628 write("</dateTime.iso8601></value>\n")
629 dispatch[datetime.datetime] = dump_datetime
630
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000631 def dump_instance(self, value, write):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000632 # check for special wrappers
633 if value.__class__ in WRAPPERS:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000634 self.write = write
Fredrik Lundhb9056332001-07-11 17:42:21 +0000635 value.encode(self)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000636 del self.write
Fredrik Lundhb9056332001-07-11 17:42:21 +0000637 else:
638 # store instance attributes as a struct (really?)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000639 self.dump_struct(value.__dict__, write)
Guido van Rossume4dea982006-04-21 13:45:00 +0000640 dispatch[DateTime] = dump_instance
641 dispatch[Binary] = dump_instance
Thomas Wouters89f507f2006-12-13 04:49:30 +0000642 # XXX(twouters): using "_arbitrary_instance" as key as a quick-fix
643 # for the p3yk merge, this should probably be fixed more neatly.
644 dispatch["_arbitrary_instance"] = dump_instance
Fredrik Lundhb9056332001-07-11 17:42:21 +0000645
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000646##
647# XML-RPC unmarshaller.
648#
649# @see loads
650
Fredrik Lundhb9056332001-07-11 17:42:21 +0000651class Unmarshaller:
Fred Drake1b410792001-09-04 18:55:03 +0000652 """Unmarshal an XML-RPC response, based on incoming XML event
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000653 messages (start, data, end). Call close() to get the resulting
Fred Drake1b410792001-09-04 18:55:03 +0000654 data structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000655
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000656 Note that this reader is fairly tolerant, and gladly accepts bogus
657 XML-RPC data without complaining (but not bogus XML).
Fred Drake1b410792001-09-04 18:55:03 +0000658 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000659
660 # and again, if you don't understand what's going on in here,
661 # that's perfectly ok.
662
Skip Montanaro174dd222005-05-14 20:54:16 +0000663 def __init__(self, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000664 self._type = None
665 self._stack = []
666 self._marks = []
667 self._data = []
668 self._methodname = None
669 self._encoding = "utf-8"
670 self.append = self._stack.append
Skip Montanaro174dd222005-05-14 20:54:16 +0000671 self._use_datetime = use_datetime
672 if use_datetime and not datetime:
Collin Winterce36ad82007-08-30 01:19:48 +0000673 raise ValueError("the datetime module is not available")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000674
675 def close(self):
676 # return response tuple and target method
677 if self._type is None or self._marks:
678 raise ResponseError()
679 if self._type == "fault":
Guido van Rossum68468eb2003-02-27 20:14:51 +0000680 raise Fault(**self._stack[0])
Fredrik Lundhb9056332001-07-11 17:42:21 +0000681 return tuple(self._stack)
682
683 def getmethodname(self):
684 return self._methodname
685
686 #
687 # event handlers
688
689 def xml(self, encoding, standalone):
690 self._encoding = encoding
691 # FIXME: assert standalone == 1 ???
692
693 def start(self, tag, attrs):
694 # prepare to handle this element
695 if tag == "array" or tag == "struct":
696 self._marks.append(len(self._stack))
697 self._data = []
698 self._value = (tag == "value")
699
700 def data(self, text):
701 self._data.append(text)
702
Neal Norwitzff113342007-04-17 08:42:15 +0000703 def end(self, tag):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000704 # call the appropriate end tag handler
705 try:
706 f = self.dispatch[tag]
707 except KeyError:
708 pass # unknown tag ?
709 else:
Neal Norwitzff113342007-04-17 08:42:15 +0000710 return f(self, "".join(self._data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000711
712 #
713 # accelerator support
714
715 def end_dispatch(self, tag, data):
716 # dispatch data
717 try:
718 f = self.dispatch[tag]
719 except KeyError:
720 pass # unknown tag ?
721 else:
722 return f(self, data)
723
724 #
725 # element decoders
726
727 dispatch = {}
728
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000729 def end_nil (self, data):
730 self.append(None)
731 self._value = 0
732 dispatch["nil"] = end_nil
Tim Petersc2659cf2003-05-12 20:19:37 +0000733
Fredrik Lundh1538c232001-10-01 19:42:03 +0000734 def end_boolean(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000735 if data == "0":
736 self.append(False)
737 elif data == "1":
738 self.append(True)
739 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000740 raise TypeError("bad boolean value")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000741 self._value = 0
742 dispatch["boolean"] = end_boolean
743
Fredrik Lundh1538c232001-10-01 19:42:03 +0000744 def end_int(self, data):
745 self.append(int(data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000746 self._value = 0
747 dispatch["i4"] = end_int
Georg Brandlf08a9dd2008-06-10 16:57:31 +0000748 dispatch["i8"] = end_int
Fredrik Lundhb9056332001-07-11 17:42:21 +0000749 dispatch["int"] = end_int
750
Fredrik Lundh1538c232001-10-01 19:42:03 +0000751 def end_double(self, data):
752 self.append(float(data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000753 self._value = 0
754 dispatch["double"] = end_double
755
Fredrik Lundh1538c232001-10-01 19:42:03 +0000756 def end_string(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000757 if self._encoding:
758 data = _decode(data, self._encoding)
759 self.append(_stringify(data))
760 self._value = 0
761 dispatch["string"] = end_string
762 dispatch["name"] = end_string # struct keys are always strings
763
764 def end_array(self, data):
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000765 mark = self._marks.pop()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000766 # map arrays to Python lists
767 self._stack[mark:] = [self._stack[mark:]]
768 self._value = 0
769 dispatch["array"] = end_array
770
771 def end_struct(self, data):
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000772 mark = self._marks.pop()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000773 # map structs to Python dictionaries
774 dict = {}
775 items = self._stack[mark:]
776 for i in range(0, len(items), 2):
777 dict[_stringify(items[i])] = items[i+1]
778 self._stack[mark:] = [dict]
779 self._value = 0
780 dispatch["struct"] = end_struct
781
Fredrik Lundh1538c232001-10-01 19:42:03 +0000782 def end_base64(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000783 value = Binary()
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000784 value.decode(data.encode("ascii"))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000785 self.append(value)
786 self._value = 0
787 dispatch["base64"] = end_base64
788
Fredrik Lundh1538c232001-10-01 19:42:03 +0000789 def end_dateTime(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000790 value = DateTime()
Fredrik Lundh1538c232001-10-01 19:42:03 +0000791 value.decode(data)
Skip Montanaro174dd222005-05-14 20:54:16 +0000792 if self._use_datetime:
793 value = _datetime_type(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000794 self.append(value)
795 dispatch["dateTime.iso8601"] = end_dateTime
796
797 def end_value(self, data):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000798 # if we stumble upon a value element with no internal
Fredrik Lundhb9056332001-07-11 17:42:21 +0000799 # elements, treat it as a string element
800 if self._value:
801 self.end_string(data)
802 dispatch["value"] = end_value
803
804 def end_params(self, data):
805 self._type = "params"
806 dispatch["params"] = end_params
807
808 def end_fault(self, data):
809 self._type = "fault"
810 dispatch["fault"] = end_fault
811
Fredrik Lundh1538c232001-10-01 19:42:03 +0000812 def end_methodName(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000813 if self._encoding:
814 data = _decode(data, self._encoding)
815 self._methodname = data
816 self._type = "methodName" # no params
817 dispatch["methodName"] = end_methodName
818
Martin v. Löwis45394c22003-10-31 13:49:36 +0000819## Multicall support
820#
Fredrik Lundhb9056332001-07-11 17:42:21 +0000821
Martin v. Löwis45394c22003-10-31 13:49:36 +0000822class _MultiCallMethod:
823 # some lesser magic to store calls made to a MultiCall object
824 # for batch execution
825 def __init__(self, call_list, name):
826 self.__call_list = call_list
827 self.__name = name
828 def __getattr__(self, name):
829 return _MultiCallMethod(self.__call_list, "%s.%s" % (self.__name, name))
830 def __call__(self, *args):
831 self.__call_list.append((self.__name, args))
832
Martin v. Löwis12237b32004-08-22 16:04:50 +0000833class MultiCallIterator:
Martin v. Löwis45394c22003-10-31 13:49:36 +0000834 """Iterates over the results of a multicall. Exceptions are
835 thrown in response to xmlrpc faults."""
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000836
Martin v. Löwis12237b32004-08-22 16:04:50 +0000837 def __init__(self, results):
838 self.results = results
839
840 def __getitem__(self, i):
841 item = self.results[i]
842 if type(item) == type({}):
843 raise Fault(item['faultCode'], item['faultString'])
844 elif type(item) == type([]):
845 return item[0]
Martin v. Löwis45394c22003-10-31 13:49:36 +0000846 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000847 raise ValueError("unexpected type in multicall result")
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000848
Martin v. Löwis45394c22003-10-31 13:49:36 +0000849class MultiCall:
850 """server -> a object used to boxcar method calls
851
852 server should be a ServerProxy object.
853
854 Methods can be added to the MultiCall using normal
855 method call syntax e.g.:
856
857 multicall = MultiCall(server_proxy)
858 multicall.add(2,3)
859 multicall.get_address("Guido")
860
861 To execute the multicall, call the MultiCall object e.g.:
862
863 add_result, address = multicall()
864 """
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000865
Martin v. Löwis45394c22003-10-31 13:49:36 +0000866 def __init__(self, server):
867 self.__server = server
868 self.__call_list = []
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000869
Martin v. Löwis45394c22003-10-31 13:49:36 +0000870 def __repr__(self):
871 return "<MultiCall at %x>" % id(self)
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000872
Martin v. Löwis45394c22003-10-31 13:49:36 +0000873 __str__ = __repr__
874
875 def __getattr__(self, name):
876 return _MultiCallMethod(self.__call_list, name)
877
878 def __call__(self):
879 marshalled_list = []
880 for name, args in self.__call_list:
881 marshalled_list.append({'methodName' : name, 'params' : args})
882
883 return MultiCallIterator(self.__server.system.multicall(marshalled_list))
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000884
Fredrik Lundhb9056332001-07-11 17:42:21 +0000885# --------------------------------------------------------------------
886# convenience functions
887
Georg Brandl38eceaa2008-05-26 11:14:17 +0000888FastMarshaller = FastParser = FastUnmarshaller = None
889
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000890##
891# Create a parser object, and connect it to an unmarshalling instance.
892# This function picks the fastest available XML parser.
893#
894# return A (parser, unmarshaller) tuple.
895
Skip Montanaro174dd222005-05-14 20:54:16 +0000896def getparser(use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000897 """getparser() -> parser, unmarshaller
898
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000899 Create an instance of the fastest available parser, and attach it
900 to an unmarshalling object. Return both objects.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000901 """
Skip Montanaro174dd222005-05-14 20:54:16 +0000902 if use_datetime and not datetime:
Collin Winterce36ad82007-08-30 01:19:48 +0000903 raise ValueError("the datetime module is not available")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000904 if FastParser and FastUnmarshaller:
Skip Montanaro174dd222005-05-14 20:54:16 +0000905 if use_datetime:
906 mkdatetime = _datetime_type
907 else:
908 mkdatetime = _datetime
909 target = FastUnmarshaller(True, False, _binary, mkdatetime, Fault)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000910 parser = FastParser(target)
911 else:
Skip Montanaro174dd222005-05-14 20:54:16 +0000912 target = Unmarshaller(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000913 if FastParser:
914 parser = FastParser(target)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000915 else:
Georg Brandlcef803f2009-06-04 09:04:53 +0000916 parser = ExpatParser(target)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000917 return parser, target
918
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000919##
920# Convert a Python tuple or a Fault instance to an XML-RPC packet.
921#
922# @def dumps(params, **options)
923# @param params A tuple or Fault instance.
924# @keyparam methodname If given, create a methodCall request for
925# this method name.
926# @keyparam methodresponse If given, create a methodResponse packet.
927# If used with a tuple, the tuple must be a singleton (that is,
928# it must contain exactly one element).
929# @keyparam encoding The packet encoding.
930# @return A string containing marshalled data.
931
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000932def dumps(params, methodname=None, methodresponse=None, encoding=None,
933 allow_none=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000934 """data [,options] -> marshalled data
935
936 Convert an argument tuple or a Fault instance to an XML-RPC
937 request (or response, if the methodresponse option is used).
938
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000939 In addition to the data object, the following options can be given
940 as keyword arguments:
Fredrik Lundhb9056332001-07-11 17:42:21 +0000941
942 methodname: the method name for a methodCall packet
943
944 methodresponse: true to create a methodResponse packet.
945 If this option is used with a tuple, the tuple must be
946 a singleton (i.e. it can contain only one element).
947
948 encoding: the packet encoding (default is UTF-8)
949
950 All 8-bit strings in the data structure are assumed to use the
951 packet encoding. Unicode strings are automatically converted,
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000952 where necessary.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000953 """
954
Guido van Rossum13257902007-06-07 23:15:56 +0000955 assert isinstance(params, (tuple, Fault)), "argument must be tuple or Fault instance"
Fredrik Lundhb9056332001-07-11 17:42:21 +0000956 if isinstance(params, Fault):
957 methodresponse = 1
Guido van Rossum13257902007-06-07 23:15:56 +0000958 elif methodresponse and isinstance(params, tuple):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000959 assert len(params) == 1, "response tuple must be a singleton"
960
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000961 if not encoding:
Fredrik Lundhb9056332001-07-11 17:42:21 +0000962 encoding = "utf-8"
963
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000964 if FastMarshaller:
965 m = FastMarshaller(encoding)
966 else:
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000967 m = Marshaller(encoding, allow_none)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000968
Fredrik Lundhb9056332001-07-11 17:42:21 +0000969 data = m.dumps(params)
970
971 if encoding != "utf-8":
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000972 xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000973 else:
974 xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
975
976 # standard XML-RPC wrappings
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000977 if methodname:
Fredrik Lundhb9056332001-07-11 17:42:21 +0000978 # a method call
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000979 if not isinstance(methodname, str):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000980 methodname = methodname.encode(encoding)
981 data = (
982 xmlheader,
983 "<methodCall>\n"
984 "<methodName>", methodname, "</methodName>\n",
985 data,
986 "</methodCall>\n"
987 )
988 elif methodresponse:
989 # a method response, or a fault structure
990 data = (
991 xmlheader,
992 "<methodResponse>\n",
993 data,
994 "</methodResponse>\n"
995 )
996 else:
997 return data # return as is
Neal Norwitzff113342007-04-17 08:42:15 +0000998 return "".join(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000999
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001000##
1001# Convert an XML-RPC packet to a Python object. If the XML-RPC packet
1002# represents a fault condition, this function raises a Fault exception.
1003#
1004# @param data An XML-RPC packet, given as an 8-bit string.
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +00001005# @return A tuple containing the unpacked data, and the method name
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001006# (None if not present).
1007# @see Fault
1008
Skip Montanaro174dd222005-05-14 20:54:16 +00001009def loads(data, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001010 """data -> unmarshalled data, method name
1011
1012 Convert an XML-RPC packet to unmarshalled data plus a method
1013 name (None if not present).
1014
1015 If the XML-RPC packet represents a fault condition, this function
1016 raises a Fault exception.
1017 """
Skip Montanaro174dd222005-05-14 20:54:16 +00001018 p, u = getparser(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001019 p.feed(data)
1020 p.close()
1021 return u.close(), u.getmethodname()
1022
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001023##
1024# Encode a string using the gzip content encoding such as specified by the
1025# Content-Encoding: gzip
1026# in the HTTP header, as described in RFC 1952
1027#
1028# @param data the unencoded data
1029# @return the encoded data
1030
1031def gzip_encode(data):
1032 """data -> gzip encoded data
1033
1034 Encode data using the gzip content encoding as described in RFC 1952
1035 """
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +00001036 if not gzip:
1037 raise NotImplementedError
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001038 f = BytesIO()
1039 gzf = gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1)
1040 gzf.write(data)
1041 gzf.close()
1042 encoded = f.getvalue()
1043 f.close()
1044 return encoded
1045
1046##
1047# Decode a string using the gzip content encoding such as specified by the
1048# Content-Encoding: gzip
1049# in the HTTP header, as described in RFC 1952
1050#
1051# @param data The encoded data
1052# @return the unencoded data
1053# @raises ValueError if data is not correctly coded.
1054
1055def gzip_decode(data):
1056 """gzip encoded data -> unencoded data
1057
1058 Decode data using the gzip content encoding as described in RFC 1952
1059 """
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +00001060 if not gzip:
1061 raise NotImplementedError
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001062 f = BytesIO(data)
1063 gzf = gzip.GzipFile(mode="rb", fileobj=f)
1064 try:
1065 decoded = gzf.read()
1066 except IOError:
1067 raise ValueError("invalid data")
1068 f.close()
1069 gzf.close()
1070 return decoded
1071
1072##
1073# Return a decoded file-like object for the gzip encoding
1074# as described in RFC 1952.
1075#
1076# @param response A stream supporting a read() method
1077# @return a file-like object that the decoded data can be read() from
1078
Kristján Valur Jónsson9ab07312009-07-19 22:38:38 +00001079class GzipDecodedResponse(gzip.GzipFile if gzip else object):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001080 """a file-like object to decode a response encoded with the gzip
1081 method, as described in RFC 1952.
1082 """
1083 def __init__(self, response):
1084 #response doesn't support tell() and read(), required by
1085 #GzipFile
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +00001086 if not gzip:
1087 raise NotImplementedError
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001088 self.io = BytesIO(response.read())
1089 gzip.GzipFile.__init__(self, mode="rb", fileobj=self.io)
1090
1091 def close(self):
1092 gzip.GzipFile.close(self)
1093 self.io.close()
1094
Fredrik Lundhb9056332001-07-11 17:42:21 +00001095
1096# --------------------------------------------------------------------
1097# request dispatcher
1098
1099class _Method:
1100 # some magic to bind an XML-RPC method to an RPC server.
1101 # supports "nested" methods (e.g. examples.getStateName)
1102 def __init__(self, send, name):
1103 self.__send = send
1104 self.__name = name
1105 def __getattr__(self, name):
1106 return _Method(self.__send, "%s.%s" % (self.__name, name))
1107 def __call__(self, *args):
1108 return self.__send(self.__name, args)
1109
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001110##
1111# Standard transport class for XML-RPC over HTTP.
1112# <p>
1113# You can create custom transports by subclassing this method, and
1114# overriding selected methods.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001115
1116class Transport:
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001117 """Handles an HTTP transaction to an XML-RPC server."""
Fredrik Lundhb9056332001-07-11 17:42:21 +00001118
1119 # client identifier (may be overridden)
1120 user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__
1121
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001122 #if true, we'll request gzip encoding
1123 accept_gzip_encoding = True
1124
1125 # if positive, encode request using gzip if it exceeds this threshold
1126 # note that many server will get confused, so only use it if you know
1127 # that they can decode such a request
1128 encode_threshold = None #None = don't encode
1129
Skip Montanaro174dd222005-05-14 20:54:16 +00001130 def __init__(self, use_datetime=0):
1131 self._use_datetime = use_datetime
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001132 self._connection = (None, None)
1133 self._extra_headers = []
Skip Montanaro174dd222005-05-14 20:54:16 +00001134
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001135 ##
1136 # Send a complete request, and parse the response.
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001137 # Retry request if a cached connection has disconnected.
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001138 #
1139 # @param host Target host.
1140 # @param handler Target PRC handler.
1141 # @param request_body XML-RPC request body.
1142 # @param verbose Debugging flag.
1143 # @return Parsed response.
1144
Fredrik Lundhb9056332001-07-11 17:42:21 +00001145 def request(self, host, handler, request_body, verbose=0):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001146 #retry request once if cached connection has gone cold
1147 for i in (0, 1):
1148 try:
1149 return self.single_request(host, handler, request_body, verbose)
Kristján Valur Jónsson43535d92009-07-03 23:23:50 +00001150 except socket.error as e:
1151 if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED):
1152 raise
1153 except http.client.BadStatusLine: #close after we sent request
1154 if i:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001155 raise
1156
1157 def single_request(self, host, handler, request_body, verbose=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001158 # issue XML-RPC request
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001159 try:
1160 http_conn = self.send_request(host, handler, request_body, verbose)
1161 resp = http_conn.getresponse()
1162 if resp.status == 200:
1163 self.verbose = verbose
1164 return self.parse_response(resp)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001165
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001166 except Fault:
1167 raise
1168 except Exception:
1169 #All unexpected errors leave connection in
1170 # a strange state, so we clear it.
1171 self.close()
1172 raise
Fredrik Lundhb9056332001-07-11 17:42:21 +00001173
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001174 #We got an error response.
1175 #Discard any response data and raise exception
1176 if resp.getheader("content-length", ""):
1177 resp.read()
1178 raise ProtocolError(
1179 host + handler,
1180 resp.status, resp.reason,
1181 dict(resp.getheaders())
1182 )
Fredrik Lundhb9056332001-07-11 17:42:21 +00001183
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001184
1185 ##
1186 # Create parser.
1187 #
1188 # @return A 2-tuple containing a parser and a unmarshaller.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001189
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001190 def getparser(self):
1191 # get parser and unmarshaller
Skip Montanaro174dd222005-05-14 20:54:16 +00001192 return getparser(use_datetime=self._use_datetime)
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001193
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001194 ##
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001195 # Get authorization info from host parameter
1196 # Host may be a string, or a (host, x509-dict) tuple; if a string,
1197 # it is checked for a "user:pw@host" format, and a "Basic
1198 # Authentication" header is added if appropriate.
1199 #
1200 # @param host Host descriptor (URL or (URL, x509 info) tuple).
1201 # @return A 3-tuple containing (actual host, extra headers,
1202 # x509 info). The header and x509 fields may be None.
1203
1204 def get_host_info(self, host):
1205
1206 x509 = {}
Guido van Rossum13257902007-06-07 23:15:56 +00001207 if isinstance(host, tuple):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001208 host, x509 = host
1209
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001210 import urllib.parse
1211 auth, host = urllib.parse.splituser(host)
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001212
1213 if auth:
1214 import base64
Georg Brandlc8dcfb62009-02-13 10:50:01 +00001215 auth = urllib.parse.unquote_to_bytes(auth)
Georg Brandlb54d8012009-06-04 09:11:51 +00001216 auth = base64.encodebytes(auth).decode("utf-8")
Neal Norwitzff113342007-04-17 08:42:15 +00001217 auth = "".join(auth.split()) # get rid of whitespace
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001218 extra_headers = [
1219 ("Authorization", "Basic " + auth)
1220 ]
1221 else:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001222 extra_headers = []
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001223
1224 return host, extra_headers, x509
1225
1226 ##
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001227 # Connect to server.
1228 #
1229 # @param host Target host.
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001230 # @return An HTTPConnection object
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001231
Fredrik Lundhb9056332001-07-11 17:42:21 +00001232 def make_connection(self, host):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001233 #return an existing connection if possible. This allows
1234 #HTTP/1.1 keep-alive.
1235 if self._connection and host == self._connection[0]:
1236 return self._connection[1]
Fredrik Lundhb9056332001-07-11 17:42:21 +00001237 # create a HTTP connection object from a host descriptor
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001238 chost, self._extra_headers, x509 = self.get_host_info(host)
1239 self._connection = host, http.client.HTTPConnection(chost)
1240 return self._connection[1]
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001241
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001242 ##
1243 # Clear any cached connection object.
1244 # Used in the event of socket errors.
1245 #
1246 def close(self):
1247 if self._connection[1]:
1248 self._connection[1].close()
1249 self._connection = (None, None)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001250
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001251 ##
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001252 # Send HTTP request.
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001253 #
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001254 # @param host Host descriptor (URL or (URL, x509 info) tuple).
1255 # @param handler Targer RPC handler (a path relative to host)
1256 # @param request_body The XML-RPC request body
1257 # @param debug Enable debugging if debug is true.
1258 # @return An HTTPConnection.
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001259
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001260 def send_request(self, host, handler, request_body, debug):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001261 connection = self.make_connection(host)
1262 headers = self._extra_headers[:]
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001263 if debug:
1264 connection.set_debuglevel(1)
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +00001265 if self.accept_gzip_encoding and gzip:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001266 connection.putrequest("POST", handler, skip_accept_encoding=True)
1267 headers.append(("Accept-Encoding", "gzip"))
1268 else:
1269 connection.putrequest("POST", handler)
1270 headers.append(("Content-Type", "text/xml"))
1271 headers.append(("User-Agent", self.user_agent))
1272 self.send_headers(connection, headers)
1273 self.send_content(connection, request_body)
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001274 return connection
Fredrik Lundhb9056332001-07-11 17:42:21 +00001275
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001276 ##
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001277 # Send request headers.
1278 # This function provides a useful hook for subclassing
1279 #
1280 # @param connection httpConnection.
1281 # @param headers list of key,value pairs for HTTP headers
1282
1283 def send_headers(self, connection, headers):
1284 for key, val in headers:
1285 connection.putheader(key, val)
1286
1287 ##
1288 # Send request body.
1289 # This function provides a useful hook for subclassing
1290 #
1291 # @param connection httpConnection.
1292 # @param request_body XML-RPC request body.
1293
1294 def send_content(self, connection, request_body):
1295 #optionally encode the request
1296 if (self.encode_threshold is not None and
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +00001297 self.encode_threshold < len(request_body) and
1298 gzip):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001299 connection.putheader("Content-Encoding", "gzip")
1300 request_body = gzip_encode(request_body)
1301
1302 connection.putheader("Content-Length", str(len(request_body)))
1303 connection.endheaders(request_body)
1304
1305 ##
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001306 # Parse response.
1307 #
1308 # @param file Stream.
1309 # @return Response tuple and target method.
1310
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001311 def parse_response(self, response):
1312 # read response data from httpresponse, and parse it
1313 if response.getheader("Content-Encoding", "") == "gzip":
1314 stream = GzipDecodedResponse(response)
1315 else:
1316 stream = response
Fredrik Lundhb9056332001-07-11 17:42:21 +00001317
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001318 p, u = self.getparser()
Fredrik Lundhb9056332001-07-11 17:42:21 +00001319
1320 while 1:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001321 data = stream.read(1024)
1322 if not data:
Fredrik Lundhb9056332001-07-11 17:42:21 +00001323 break
1324 if self.verbose:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001325 print("body:", repr(data))
1326 p.feed(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001327
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001328 if stream is not response:
1329 stream.close()
Fredrik Lundhb9056332001-07-11 17:42:21 +00001330 p.close()
1331
1332 return u.close()
1333
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001334##
1335# Standard transport class for XML-RPC over HTTPS.
1336
Fredrik Lundhb9056332001-07-11 17:42:21 +00001337class SafeTransport(Transport):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001338 """Handles an HTTPS transaction to an XML-RPC server."""
Fredrik Lundhb9056332001-07-11 17:42:21 +00001339
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001340 # FIXME: mostly untested
1341
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001342 def make_connection(self, host):
1343 if self._connection and host == self._connection[0]:
1344 return self._connection[1]
1345
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001346 if not hasattr(socket, "ssl"):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001347 raise NotImplementedError(
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001348 "your version of http.client doesn't support HTTPS")
1349 # create a HTTPS connection object from a host descriptor
1350 # host may be a string, or a (host, x509-dict) tuple
1351 chost, self._extra_headers, x509 = self.get_host_info(host)
1352 self._connection = host, http.client.HTTPSConnection(chost,
1353 None, **(x509 or {}))
1354 return self._connection[1]
Fredrik Lundhb9056332001-07-11 17:42:21 +00001355
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001356##
1357# Standard server proxy. This class establishes a virtual connection
1358# to an XML-RPC server.
1359# <p>
1360# This class is available as ServerProxy and Server. New code should
1361# use ServerProxy, to avoid confusion.
1362#
1363# @def ServerProxy(uri, **options)
1364# @param uri The connection point on the server.
1365# @keyparam transport A transport factory, compatible with the
1366# standard transport class.
1367# @keyparam encoding The default encoding used for 8-bit strings
1368# (default is UTF-8).
1369# @keyparam verbose Use a true value to enable debugging output.
1370# (printed to standard output).
1371# @see Transport
1372
Fredrik Lundhb9056332001-07-11 17:42:21 +00001373class ServerProxy:
1374 """uri [,options] -> a logical connection to an XML-RPC server
1375
1376 uri is the connection point on the server, given as
1377 scheme://host/target.
1378
1379 The standard implementation always supports the "http" scheme. If
1380 SSL socket support is available (Python 2.0), it also supports
1381 "https".
1382
1383 If the target part and the slash preceding it are both omitted,
1384 "/RPC2" is assumed.
1385
1386 The following options can be given as keyword arguments:
1387
1388 transport: a transport factory
1389 encoding: the request encoding (default is UTF-8)
1390
1391 All 8-bit strings passed to the server proxy are assumed to use
1392 the given encoding.
1393 """
1394
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001395 def __init__(self, uri, transport=None, encoding=None, verbose=0,
Skip Montanaro174dd222005-05-14 20:54:16 +00001396 allow_none=0, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001397 # establish a "logical" server connection
1398
1399 # get the url
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001400 import urllib.parse
1401 type, uri = urllib.parse.splittype(uri)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001402 if type not in ("http", "https"):
Collin Winterce36ad82007-08-30 01:19:48 +00001403 raise IOError("unsupported XML-RPC protocol")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001404 self.__host, self.__handler = urllib.parse.splithost(uri)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001405 if not self.__handler:
1406 self.__handler = "/RPC2"
1407
1408 if transport is None:
1409 if type == "https":
Skip Montanaro174dd222005-05-14 20:54:16 +00001410 transport = SafeTransport(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001411 else:
Skip Montanaro174dd222005-05-14 20:54:16 +00001412 transport = Transport(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001413 self.__transport = transport
1414
Senthil Kumaranb3af08f2009-04-01 20:20:43 +00001415 self.__encoding = encoding or 'utf-8'
Fredrik Lundhb9056332001-07-11 17:42:21 +00001416 self.__verbose = verbose
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001417 self.__allow_none = allow_none
Tim Petersc2659cf2003-05-12 20:19:37 +00001418
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001419 def __close(self):
1420 self.__transport.close()
1421
Fredrik Lundhb9056332001-07-11 17:42:21 +00001422 def __request(self, methodname, params):
1423 # call a method on the remote server
1424
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001425 request = dumps(params, methodname, encoding=self.__encoding,
Senthil Kumaranb3af08f2009-04-01 20:20:43 +00001426 allow_none=self.__allow_none).encode(self.__encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001427
1428 response = self.__transport.request(
1429 self.__host,
1430 self.__handler,
1431 request,
1432 verbose=self.__verbose
1433 )
1434
1435 if len(response) == 1:
1436 response = response[0]
1437
1438 return response
1439
1440 def __repr__(self):
1441 return (
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001442 "<ServerProxy for %s%s>" %
Fredrik Lundhb9056332001-07-11 17:42:21 +00001443 (self.__host, self.__handler)
1444 )
1445
1446 __str__ = __repr__
Raymond Hettingercc523fc2003-11-02 09:47:05 +00001447
Fredrik Lundhb9056332001-07-11 17:42:21 +00001448 def __getattr__(self, name):
1449 # magic method dispatcher
1450 return _Method(self.__request, name)
1451
1452 # note: to call a remote object with an non-standard name, use
1453 # result getattr(server, "strange-python-name")(args)
1454
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001455 def __call__(self, attr):
1456 """A workaround to get special attributes on the ServerProxy
1457 without interfering with the magic __getattr__
1458 """
1459 if attr == "close":
1460 return self.__close
1461 elif attr == "transport":
1462 return self.__transport
1463 raise AttributeError("Attribute %r not found" % (attr,))
1464
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001465# compatibility
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001466
Fredrik Lundhb9056332001-07-11 17:42:21 +00001467Server = ServerProxy
1468
1469# --------------------------------------------------------------------
1470# test code
1471
1472if __name__ == "__main__":
1473
1474 # simple test program (from the XML-RPC specification)
1475
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001476 # server = ServerProxy("http://localhost:8000") # local server
Martin v. Löwis12237b32004-08-22 16:04:50 +00001477 server = ServerProxy("http://time.xmlrpc.com/RPC2")
Fredrik Lundhb9056332001-07-11 17:42:21 +00001478
Fredrik Lundhb9056332001-07-11 17:42:21 +00001479 try:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001480 print(server.currentTime.getCurrentTime())
Guido van Rossumb940e112007-01-10 16:19:56 +00001481 except Error as v:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001482 print("ERROR", v)
Martin v. Löwis12237b32004-08-22 16:04:50 +00001483
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001484 # The server at xmlrpc.com doesn't seem to support multicall anymore.
Martin v. Löwis12237b32004-08-22 16:04:50 +00001485 multi = MultiCall(server)
1486 multi.currentTime.getCurrentTime()
1487 multi.currentTime.getCurrentTime()
1488 try:
1489 for response in multi():
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001490 print(response)
Guido van Rossumb940e112007-01-10 16:19:56 +00001491 except Error as v:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001492 print("ERROR", v)