blob: ff931e758792afa0ea564a79de15f70c8783a5da [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
Fred Drake1b410792001-09-04 18:55:03 +000088"""
89An XML-RPC client interface for Python.
90
91The marshalling and response parser code can also be used to
92implement XML-RPC servers.
93
Fred Drake1b410792001-09-04 18:55:03 +000094Exported exceptions:
95
Fredrik Lundhc4c062f2001-09-10 19:45:02 +000096 Error Base class for client errors
97 ProtocolError Indicates an HTTP protocol error
98 ResponseError Indicates a broken response package
99 Fault Indicates an XML-RPC fault package
Fred Drake1b410792001-09-04 18:55:03 +0000100
101Exported classes:
102
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000103 ServerProxy Represents a logical connection to an XML-RPC server
Fred Drake1b410792001-09-04 18:55:03 +0000104
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000105 MultiCall Executor of boxcared xmlrpc requests
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000106 DateTime dateTime wrapper for an ISO 8601 string or time tuple or
107 localtime integer value to generate a "dateTime.iso8601"
108 XML-RPC value
109 Binary binary data wrapper
Fred Drake1b410792001-09-04 18:55:03 +0000110
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000111 Marshaller Generate an XML-RPC params chunk from a Python data structure
112 Unmarshaller Unmarshal an XML-RPC response from incoming XML event message
113 Transport Handles an HTTP transaction to an XML-RPC server
114 SafeTransport Handles an HTTPS transaction to an XML-RPC server
Fred Drake1b410792001-09-04 18:55:03 +0000115
116Exported constants:
117
Florent Xiclunac4fec932011-10-30 20:19:32 +0100118 (none)
Fred Drake1b410792001-09-04 18:55:03 +0000119
120Exported functions:
121
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000122 getparser Create instance of the fastest available parser & attach
123 to an unmarshalling object
124 dumps Convert an argument tuple or a Fault instance to an XML-RPC
125 request (or response, if the methodresponse option is used).
126 loads Convert an XML-RPC packet to unmarshalled data plus a method
127 name (None if not present).
Fred Drake1b410792001-09-04 18:55:03 +0000128"""
129
Florent Xiclunac4fec932011-10-30 20:19:32 +0100130import base64
Florent Xicluna75861df2011-10-30 20:39:24 +0100131import sys
Florent Xiclunac4fec932011-10-30 20:19:32 +0100132import time
Florent Xiclunab6f019a2011-10-30 23:54:17 +0100133from datetime import datetime
Georg Brandl24420152008-05-26 16:32:26 +0000134import http.client
Georg Brandlcef803f2009-06-04 09:04:53 +0000135from xml.parsers import expat
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000136import socket
137import errno
138from io import BytesIO
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +0000139try:
140 import gzip
141except ImportError:
142 gzip = None #python can be built without zlib/gzip support
Fredrik Lundh1538c232001-10-01 19:42:03 +0000143
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000144# --------------------------------------------------------------------
145# Internal stuff
146
Neal Norwitzff113342007-04-17 08:42:15 +0000147def escape(s):
148 s = s.replace("&", "&")
149 s = s.replace("<", "&lt;")
150 return s.replace(">", "&gt;",)
Fredrik Lundh1538c232001-10-01 19:42:03 +0000151
Florent Xicluna75861df2011-10-30 20:39:24 +0100152# used in User-Agent header sent
153__version__ = sys.version[:3]
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000154
155# xmlrpc integer limits
Guido van Rossume2a383d2007-01-15 16:59:06 +0000156MAXINT = 2**31-1
157MININT = -2**31
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000158
159# --------------------------------------------------------------------
160# Error constants (from Dan Libby's specification at
161# http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
162
163# Ranges of errors
164PARSE_ERROR = -32700
165SERVER_ERROR = -32600
166APPLICATION_ERROR = -32500
167SYSTEM_ERROR = -32400
168TRANSPORT_ERROR = -32300
169
170# Specific errors
171NOT_WELLFORMED_ERROR = -32700
172UNSUPPORTED_ENCODING = -32701
173INVALID_ENCODING_CHAR = -32702
174INVALID_XMLRPC = -32600
175METHOD_NOT_FOUND = -32601
176INVALID_METHOD_PARAMS = -32602
177INTERNAL_ERROR = -32603
Fredrik Lundhb9056332001-07-11 17:42:21 +0000178
179# --------------------------------------------------------------------
180# Exceptions
181
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000182##
183# Base class for all kinds of client-side errors.
184
Fredrik Lundh78eedce2001-08-23 20:04:33 +0000185class Error(Exception):
Fred Drake1b410792001-09-04 18:55:03 +0000186 """Base class for client errors."""
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000187 def __str__(self):
188 return repr(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000189
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000190##
191# Indicates an HTTP-level protocol error. This is raised by the HTTP
192# transport layer, if the server returns an error code other than 200
193# (OK).
194#
195# @param url The target URL.
196# @param errcode The HTTP error code.
197# @param errmsg The HTTP error message.
198# @param headers The HTTP header dictionary.
199
Fredrik Lundhb9056332001-07-11 17:42:21 +0000200class ProtocolError(Error):
Fred Drake1b410792001-09-04 18:55:03 +0000201 """Indicates an HTTP protocol error."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000202 def __init__(self, url, errcode, errmsg, headers):
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000203 Error.__init__(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000204 self.url = url
205 self.errcode = errcode
206 self.errmsg = errmsg
207 self.headers = headers
208 def __repr__(self):
209 return (
210 "<ProtocolError for %s: %s %s>" %
211 (self.url, self.errcode, self.errmsg)
212 )
213
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000214##
215# Indicates a broken XML-RPC response package. This exception is
216# raised by the unmarshalling layer, if the XML-RPC response is
217# malformed.
218
Fredrik Lundhb9056332001-07-11 17:42:21 +0000219class ResponseError(Error):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000220 """Indicates a broken response package."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000221 pass
222
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000223##
224# Indicates an XML-RPC fault response package. This exception is
225# raised by the unmarshalling layer, if the XML-RPC response contains
Florent Xiclunac4fec932011-10-30 20:19:32 +0100226# a fault string. This exception can also be used as a class, to
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000227# generate a fault XML-RPC message.
228#
229# @param faultCode The XML-RPC fault code.
230# @param faultString The XML-RPC fault string.
231
Fredrik Lundhb9056332001-07-11 17:42:21 +0000232class Fault(Error):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000233 """Indicates an XML-RPC fault package."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000234 def __init__(self, faultCode, faultString, **extra):
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000235 Error.__init__(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000236 self.faultCode = faultCode
237 self.faultString = faultString
238 def __repr__(self):
Florent Xiclunac4fec932011-10-30 20:19:32 +0100239 return "<Fault %s: %r>" % (self.faultCode, self.faultString)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000240
241# --------------------------------------------------------------------
242# Special values
243
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000244##
Georg Brandl38eceaa2008-05-26 11:14:17 +0000245# Backwards compatibility
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000246
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000247boolean = Boolean = bool
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000248
249##
250# Wrapper for XML-RPC DateTime values. This converts a time value to
251# the format used by XML-RPC.
252# <p>
Florent Xicluna2738a642011-11-01 00:06:58 +0100253# The value can be given as a datetime object, as a string in the
254# format "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000255# time.localtime()), or an integer value (as returned by time.time()).
256# The wrapper uses time.localtime() to convert an integer to a time
257# tuple.
258#
Florent Xicluna2738a642011-11-01 00:06:58 +0100259# @param value The time, given as a datetime object, an ISO 8601 string,
260# a time tuple, or an integer time value.
261
262
263# Issue #13305: different format codes across platforms
264_day0 = datetime(1, 1, 1)
265if _day0.strftime('%Y') == '0001': # Mac OS X
266 def _iso8601_format(value):
267 return value.strftime("%Y%m%dT%H:%M:%S")
268elif _day0.strftime('%4Y') == '0001': # Linux
269 def _iso8601_format(value):
270 return value.strftime("%4Y%m%dT%H:%M:%S")
271else:
272 def _iso8601_format(value):
273 return value.strftime("%Y%m%dT%H:%M:%S").zfill(17)
274del _day0
275
Fredrik Lundhb9056332001-07-11 17:42:21 +0000276
Christian Heimesdae2a892008-04-19 00:55:37 +0000277def _strftime(value):
Florent Xiclunab6f019a2011-10-30 23:54:17 +0100278 if isinstance(value, datetime):
Florent Xicluna2738a642011-11-01 00:06:58 +0100279 return _iso8601_format(value)
Christian Heimesdae2a892008-04-19 00:55:37 +0000280
281 if not isinstance(value, (tuple, time.struct_time)):
282 if value == 0:
283 value = time.time()
284 value = time.localtime(value)
285
286 return "%04d%02d%02dT%02d:%02d:%02d" % value[:6]
287
Fredrik Lundhb9056332001-07-11 17:42:21 +0000288class DateTime:
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000289 """DateTime wrapper for an ISO 8601 string or time tuple or
290 localtime integer value to generate 'dateTime.iso8601' XML-RPC
291 value.
292 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000293
294 def __init__(self, value=0):
Christian Heimesdae2a892008-04-19 00:55:37 +0000295 if isinstance(value, str):
296 self.value = value
297 else:
298 self.value = _strftime(value)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000299
Christian Heimes05e8be12008-02-23 18:30:17 +0000300 def make_comparable(self, other):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000301 if isinstance(other, DateTime):
Christian Heimes05e8be12008-02-23 18:30:17 +0000302 s = self.value
303 o = other.value
Florent Xiclunab6f019a2011-10-30 23:54:17 +0100304 elif isinstance(other, datetime):
Christian Heimes05e8be12008-02-23 18:30:17 +0000305 s = self.value
Florent Xicluna2738a642011-11-01 00:06:58 +0100306 o = _iso8601_format(other)
Florent Xicluna3fa29f72011-10-30 20:18:50 +0100307 elif isinstance(other, str):
Christian Heimes05e8be12008-02-23 18:30:17 +0000308 s = self.value
309 o = other
310 elif hasattr(other, "timetuple"):
311 s = self.timetuple()
312 o = other.timetuple()
313 else:
314 otype = (hasattr(other, "__class__")
315 and other.__class__.__name__
316 or type(other))
317 raise TypeError("Can't compare %s and %s" %
318 (self.__class__.__name__, otype))
319 return s, o
320
321 def __lt__(self, other):
322 s, o = self.make_comparable(other)
323 return s < o
324
325 def __le__(self, other):
326 s, o = self.make_comparable(other)
327 return s <= o
328
329 def __gt__(self, other):
330 s, o = self.make_comparable(other)
331 return s > o
332
333 def __ge__(self, other):
334 s, o = self.make_comparable(other)
335 return s >= o
336
337 def __eq__(self, other):
338 s, o = self.make_comparable(other)
339 return s == o
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000340
341 def __ne__(self, other):
Christian Heimes05e8be12008-02-23 18:30:17 +0000342 s, o = self.make_comparable(other)
343 return s != o
344
345 def timetuple(self):
346 return time.strptime(self.value, "%Y%m%dT%H:%M:%S")
347
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000348 ##
349 # Get date/time value.
350 #
351 # @return Date/time value, as an ISO 8601 string.
352
353 def __str__(self):
354 return self.value
355
Fredrik Lundhb9056332001-07-11 17:42:21 +0000356 def __repr__(self):
Florent Xiclunac4fec932011-10-30 20:19:32 +0100357 return "<DateTime %r at %x>" % (self.value, id(self))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000358
359 def decode(self, data):
Neal Norwitzff113342007-04-17 08:42:15 +0000360 self.value = str(data).strip()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000361
362 def encode(self, out):
363 out.write("<value><dateTime.iso8601>")
364 out.write(self.value)
365 out.write("</dateTime.iso8601></value>\n")
366
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000367def _datetime(data):
368 # decode xml element contents into a DateTime structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000369 value = DateTime()
370 value.decode(data)
371 return value
372
Skip Montanaro174dd222005-05-14 20:54:16 +0000373def _datetime_type(data):
Florent Xiclunab6f019a2011-10-30 23:54:17 +0100374 return datetime.strptime(data, "%Y%m%dT%H:%M:%S")
Skip Montanaro174dd222005-05-14 20:54:16 +0000375
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000376##
377# Wrapper for binary data. This can be used to transport any kind
378# of binary data over XML-RPC, using BASE64 encoding.
379#
380# @param data An 8-bit string containing arbitrary data.
381
Fredrik Lundhb9056332001-07-11 17:42:21 +0000382class Binary:
Fred Drake1b410792001-09-04 18:55:03 +0000383 """Wrapper for binary data."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000384
385 def __init__(self, data=None):
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000386 if data is None:
387 data = b""
388 else:
389 if not isinstance(data, bytes):
390 raise TypeError("expected bytes, not %s" %
391 data.__class__.__name__)
392 data = bytes(data) # Make a copy of the bytes!
Fredrik Lundhb9056332001-07-11 17:42:21 +0000393 self.data = data
394
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000395 ##
396 # Get buffer contents.
397 #
398 # @return Buffer contents, as an 8-bit string.
399
400 def __str__(self):
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000401 return str(self.data, "latin-1") # XXX encoding?!
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000402
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000403 def __eq__(self, other):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000404 if isinstance(other, Binary):
405 other = other.data
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000406 return self.data == other
407
408 def __ne__(self, other):
409 if isinstance(other, Binary):
410 other = other.data
411 return self.data != other
Fredrik Lundhb9056332001-07-11 17:42:21 +0000412
413 def decode(self, data):
Georg Brandlb54d8012009-06-04 09:11:51 +0000414 self.data = base64.decodebytes(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000415
416 def encode(self, out):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000417 out.write("<value><base64>\n")
Georg Brandlb54d8012009-06-04 09:11:51 +0000418 encoded = base64.encodebytes(self.data)
Brett Cannon2dbde5e2007-07-30 03:50:35 +0000419 out.write(encoded.decode('ascii'))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000420 out.write("</base64></value>\n")
421
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000422def _binary(data):
423 # decode xml element contents into a Binary structure
Fredrik Lundhb9056332001-07-11 17:42:21 +0000424 value = Binary()
425 value.decode(data)
426 return value
427
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000428WRAPPERS = (DateTime, Binary)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000429
430# --------------------------------------------------------------------
431# XML parsers
432
Georg Brandlcef803f2009-06-04 09:04:53 +0000433class ExpatParser:
434 # fast expat parser for Python 2.0 and later.
435 def __init__(self, target):
436 self._parser = parser = expat.ParserCreate(None, None)
437 self._target = target
438 parser.StartElementHandler = target.start
439 parser.EndElementHandler = target.end
440 parser.CharacterDataHandler = target.data
441 encoding = None
442 target.xml(encoding, None)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000443
Georg Brandlcef803f2009-06-04 09:04:53 +0000444 def feed(self, data):
445 self._parser.Parse(data, 0)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000446
Georg Brandlcef803f2009-06-04 09:04:53 +0000447 def close(self):
448 self._parser.Parse("", 1) # end of data
449 del self._target, self._parser # get rid of circular references
Fredrik Lundhb9056332001-07-11 17:42:21 +0000450
Fredrik Lundhb9056332001-07-11 17:42:21 +0000451# --------------------------------------------------------------------
452# XML-RPC marshalling and unmarshalling code
453
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000454##
455# XML-RPC marshaller.
456#
457# @param encoding Default encoding for 8-bit strings. The default
458# value is None (interpreted as UTF-8).
459# @see dumps
460
Fredrik Lundhb9056332001-07-11 17:42:21 +0000461class Marshaller:
Fred Drake1b410792001-09-04 18:55:03 +0000462 """Generate an XML-RPC params chunk from a Python data structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000463
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000464 Create a Marshaller instance for each set of parameters, and use
465 the "dumps" method to convert your data (represented as a tuple)
466 to an XML-RPC params chunk. To write a fault response, pass a
467 Fault instance instead. You may prefer to use the "dumps" module
468 function for this purpose.
Fred Drake1b410792001-09-04 18:55:03 +0000469 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000470
471 # by the way, if you don't understand what's going on in here,
472 # that's perfectly ok.
473
Georg Brandlfe991052009-09-16 15:54:04 +0000474 def __init__(self, encoding=None, allow_none=False):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000475 self.memo = {}
476 self.data = None
477 self.encoding = encoding
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000478 self.allow_none = allow_none
Tim Petersc2659cf2003-05-12 20:19:37 +0000479
Fredrik Lundhb9056332001-07-11 17:42:21 +0000480 dispatch = {}
481
482 def dumps(self, values):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000483 out = []
484 write = out.append
485 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000486 if isinstance(values, Fault):
487 # fault instance
488 write("<fault>\n")
Martin v. Löwis541342f2003-07-12 07:53:04 +0000489 dump({'faultCode': values.faultCode,
490 'faultString': values.faultString},
491 write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000492 write("</fault>\n")
493 else:
494 # parameter block
Fredrik Lundhc266bb02001-08-23 20:13:08 +0000495 # FIXME: the xml-rpc specification allows us to leave out
496 # the entire <params> block if there are no parameters.
497 # however, changing this may break older code (including
498 # old versions of xmlrpclib.py), so this is better left as
499 # is for now. See @XMLRPC3 for more information. /F
Fredrik Lundhb9056332001-07-11 17:42:21 +0000500 write("<params>\n")
501 for v in values:
502 write("<param>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000503 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000504 write("</param>\n")
505 write("</params>\n")
Neal Norwitzff113342007-04-17 08:42:15 +0000506 result = "".join(out)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000507 return result
508
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000509 def __dump(self, value, write):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000510 try:
511 f = self.dispatch[type(value)]
512 except KeyError:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000513 # check if this object can be marshalled as a structure
Florent Xicluna93dfee12011-10-30 20:22:25 +0100514 if not hasattr(value, '__dict__'):
Collin Winterce36ad82007-08-30 01:19:48 +0000515 raise TypeError("cannot marshal %s objects" % type(value))
Thomas Wouters89f507f2006-12-13 04:49:30 +0000516 # check if this class is a sub-class of a basic type,
517 # because we don't know how to marshal these types
518 # (e.g. a string sub-class)
519 for type_ in type(value).__mro__:
520 if type_ in self.dispatch.keys():
Collin Winterce36ad82007-08-30 01:19:48 +0000521 raise TypeError("cannot marshal %s objects" % type(value))
Thomas Wouters89f507f2006-12-13 04:49:30 +0000522 # XXX(twouters): using "_arbitrary_instance" as key as a quick-fix
523 # for the p3yk merge, this should probably be fixed more neatly.
524 f = self.dispatch["_arbitrary_instance"]
525 f(self, value, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000526
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000527 def dump_nil (self, value, write):
528 if not self.allow_none:
Collin Winterce36ad82007-08-30 01:19:48 +0000529 raise TypeError("cannot marshal None unless allow_none is enabled")
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000530 write("<value><nil/></value>")
Guido van Rossum13257902007-06-07 23:15:56 +0000531 dispatch[type(None)] = dump_nil
Tim Petersc2659cf2003-05-12 20:19:37 +0000532
Georg Brandl38eceaa2008-05-26 11:14:17 +0000533 def dump_bool(self, value, write):
534 write("<value><boolean>")
535 write(value and "1" or "0")
536 write("</boolean></value>\n")
537 dispatch[bool] = dump_bool
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000538
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000539 def dump_long(self, value, write):
Skip Montanaro5449e082001-10-17 22:53:33 +0000540 if value > MAXINT or value < MININT:
Collin Winterce36ad82007-08-30 01:19:48 +0000541 raise OverflowError("long int exceeds XML-RPC limits")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000542 write("<value><int>")
543 write(str(int(value)))
544 write("</int></value>\n")
Guido van Rossum13257902007-06-07 23:15:56 +0000545 dispatch[int] = dump_long
Skip Montanaro5e9c71b2001-10-10 15:56:34 +0000546
Florent Xicluna2bb96f52011-10-23 22:11:00 +0200547 # backward compatible
548 dump_int = dump_long
549
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000550 def dump_double(self, value, write):
551 write("<value><double>")
552 write(repr(value))
553 write("</double></value>\n")
Guido van Rossum13257902007-06-07 23:15:56 +0000554 dispatch[float] = dump_double
Fredrik Lundhb9056332001-07-11 17:42:21 +0000555
Guido van Rossum54ad5232007-05-27 09:17:48 +0000556 def dump_unicode(self, value, write, escape=escape):
Guido van Rossum54ad5232007-05-27 09:17:48 +0000557 write("<value><string>")
558 write(escape(value))
559 write("</string></value>\n")
560 dispatch[str] = dump_unicode
Fredrik Lundhb9056332001-07-11 17:42:21 +0000561
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000562 def dump_array(self, value, write):
563 i = id(value)
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000564 if i in self.memo:
Collin Winterce36ad82007-08-30 01:19:48 +0000565 raise TypeError("cannot marshal recursive sequences")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000566 self.memo[i] = None
Fredrik Lundh1538c232001-10-01 19:42:03 +0000567 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000568 write("<value><array><data>\n")
569 for v in value:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000570 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000571 write("</data></array></value>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000572 del self.memo[i]
Guido van Rossum13257902007-06-07 23:15:56 +0000573 dispatch[tuple] = dump_array
574 dispatch[list] = dump_array
Fredrik Lundhb9056332001-07-11 17:42:21 +0000575
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000576 def dump_struct(self, value, write, escape=escape):
577 i = id(value)
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000578 if i in self.memo:
Collin Winterce36ad82007-08-30 01:19:48 +0000579 raise TypeError("cannot marshal recursive dictionaries")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000580 self.memo[i] = None
Fredrik Lundh1538c232001-10-01 19:42:03 +0000581 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000582 write("<value><struct>\n")
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000583 for k, v in value.items():
Fredrik Lundhb9056332001-07-11 17:42:21 +0000584 write("<member>\n")
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000585 if not isinstance(k, str):
Collin Winterce36ad82007-08-30 01:19:48 +0000586 raise TypeError("dictionary key must be string")
Fredrik Lundh1538c232001-10-01 19:42:03 +0000587 write("<name>%s</name>\n" % escape(k))
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000588 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000589 write("</member>\n")
590 write("</struct></value>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000591 del self.memo[i]
Guido van Rossum13257902007-06-07 23:15:56 +0000592 dispatch[dict] = dump_struct
Fredrik Lundhb9056332001-07-11 17:42:21 +0000593
Florent Xiclunab6f019a2011-10-30 23:54:17 +0100594 def dump_datetime(self, value, write):
595 write("<value><dateTime.iso8601>")
596 write(_strftime(value))
597 write("</dateTime.iso8601></value>\n")
598 dispatch[datetime] = dump_datetime
Fred Drakeba613c32005-02-10 18:33:30 +0000599
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000600 def dump_instance(self, value, write):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000601 # check for special wrappers
602 if value.__class__ in WRAPPERS:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000603 self.write = write
Fredrik Lundhb9056332001-07-11 17:42:21 +0000604 value.encode(self)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000605 del self.write
Fredrik Lundhb9056332001-07-11 17:42:21 +0000606 else:
607 # store instance attributes as a struct (really?)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000608 self.dump_struct(value.__dict__, write)
Guido van Rossume4dea982006-04-21 13:45:00 +0000609 dispatch[DateTime] = dump_instance
610 dispatch[Binary] = dump_instance
Thomas Wouters89f507f2006-12-13 04:49:30 +0000611 # XXX(twouters): using "_arbitrary_instance" as key as a quick-fix
612 # for the p3yk merge, this should probably be fixed more neatly.
613 dispatch["_arbitrary_instance"] = dump_instance
Fredrik Lundhb9056332001-07-11 17:42:21 +0000614
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000615##
616# XML-RPC unmarshaller.
617#
618# @see loads
619
Fredrik Lundhb9056332001-07-11 17:42:21 +0000620class Unmarshaller:
Fred Drake1b410792001-09-04 18:55:03 +0000621 """Unmarshal an XML-RPC response, based on incoming XML event
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000622 messages (start, data, end). Call close() to get the resulting
Fred Drake1b410792001-09-04 18:55:03 +0000623 data structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000624
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000625 Note that this reader is fairly tolerant, and gladly accepts bogus
626 XML-RPC data without complaining (but not bogus XML).
Fred Drake1b410792001-09-04 18:55:03 +0000627 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000628
629 # and again, if you don't understand what's going on in here,
630 # that's perfectly ok.
631
Georg Brandlfe991052009-09-16 15:54:04 +0000632 def __init__(self, use_datetime=False):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000633 self._type = None
634 self._stack = []
635 self._marks = []
636 self._data = []
637 self._methodname = None
638 self._encoding = "utf-8"
639 self.append = self._stack.append
Skip Montanaro174dd222005-05-14 20:54:16 +0000640 self._use_datetime = use_datetime
Fredrik Lundhb9056332001-07-11 17:42:21 +0000641
642 def close(self):
643 # return response tuple and target method
644 if self._type is None or self._marks:
645 raise ResponseError()
646 if self._type == "fault":
Guido van Rossum68468eb2003-02-27 20:14:51 +0000647 raise Fault(**self._stack[0])
Fredrik Lundhb9056332001-07-11 17:42:21 +0000648 return tuple(self._stack)
649
650 def getmethodname(self):
651 return self._methodname
652
653 #
654 # event handlers
655
656 def xml(self, encoding, standalone):
657 self._encoding = encoding
658 # FIXME: assert standalone == 1 ???
659
660 def start(self, tag, attrs):
661 # prepare to handle this element
662 if tag == "array" or tag == "struct":
663 self._marks.append(len(self._stack))
664 self._data = []
665 self._value = (tag == "value")
666
667 def data(self, text):
668 self._data.append(text)
669
Neal Norwitzff113342007-04-17 08:42:15 +0000670 def end(self, tag):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000671 # call the appropriate end tag handler
672 try:
673 f = self.dispatch[tag]
674 except KeyError:
675 pass # unknown tag ?
676 else:
Neal Norwitzff113342007-04-17 08:42:15 +0000677 return f(self, "".join(self._data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000678
679 #
680 # accelerator support
681
682 def end_dispatch(self, tag, data):
683 # dispatch data
684 try:
685 f = self.dispatch[tag]
686 except KeyError:
687 pass # unknown tag ?
688 else:
689 return f(self, data)
690
691 #
692 # element decoders
693
694 dispatch = {}
695
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000696 def end_nil (self, data):
697 self.append(None)
698 self._value = 0
699 dispatch["nil"] = end_nil
Tim Petersc2659cf2003-05-12 20:19:37 +0000700
Fredrik Lundh1538c232001-10-01 19:42:03 +0000701 def end_boolean(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000702 if data == "0":
703 self.append(False)
704 elif data == "1":
705 self.append(True)
706 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000707 raise TypeError("bad boolean value")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000708 self._value = 0
709 dispatch["boolean"] = end_boolean
710
Fredrik Lundh1538c232001-10-01 19:42:03 +0000711 def end_int(self, data):
712 self.append(int(data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000713 self._value = 0
714 dispatch["i4"] = end_int
Georg Brandlf08a9dd2008-06-10 16:57:31 +0000715 dispatch["i8"] = end_int
Fredrik Lundhb9056332001-07-11 17:42:21 +0000716 dispatch["int"] = end_int
717
Fredrik Lundh1538c232001-10-01 19:42:03 +0000718 def end_double(self, data):
719 self.append(float(data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000720 self._value = 0
721 dispatch["double"] = end_double
722
Fredrik Lundh1538c232001-10-01 19:42:03 +0000723 def end_string(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000724 if self._encoding:
Alexandre Vassalottie671fd22009-07-22 02:32:34 +0000725 data = data.decode(self._encoding)
726 self.append(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000727 self._value = 0
728 dispatch["string"] = end_string
729 dispatch["name"] = end_string # struct keys are always strings
730
731 def end_array(self, data):
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000732 mark = self._marks.pop()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000733 # map arrays to Python lists
734 self._stack[mark:] = [self._stack[mark:]]
735 self._value = 0
736 dispatch["array"] = end_array
737
738 def end_struct(self, data):
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000739 mark = self._marks.pop()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000740 # map structs to Python dictionaries
741 dict = {}
742 items = self._stack[mark:]
743 for i in range(0, len(items), 2):
Alexandre Vassalottie671fd22009-07-22 02:32:34 +0000744 dict[items[i]] = items[i+1]
Fredrik Lundhb9056332001-07-11 17:42:21 +0000745 self._stack[mark:] = [dict]
746 self._value = 0
747 dispatch["struct"] = end_struct
748
Fredrik Lundh1538c232001-10-01 19:42:03 +0000749 def end_base64(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000750 value = Binary()
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000751 value.decode(data.encode("ascii"))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000752 self.append(value)
753 self._value = 0
754 dispatch["base64"] = end_base64
755
Fredrik Lundh1538c232001-10-01 19:42:03 +0000756 def end_dateTime(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000757 value = DateTime()
Fredrik Lundh1538c232001-10-01 19:42:03 +0000758 value.decode(data)
Skip Montanaro174dd222005-05-14 20:54:16 +0000759 if self._use_datetime:
760 value = _datetime_type(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000761 self.append(value)
762 dispatch["dateTime.iso8601"] = end_dateTime
763
764 def end_value(self, data):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000765 # if we stumble upon a value element with no internal
Fredrik Lundhb9056332001-07-11 17:42:21 +0000766 # elements, treat it as a string element
767 if self._value:
768 self.end_string(data)
769 dispatch["value"] = end_value
770
771 def end_params(self, data):
772 self._type = "params"
773 dispatch["params"] = end_params
774
775 def end_fault(self, data):
776 self._type = "fault"
777 dispatch["fault"] = end_fault
778
Fredrik Lundh1538c232001-10-01 19:42:03 +0000779 def end_methodName(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000780 if self._encoding:
Alexandre Vassalottie671fd22009-07-22 02:32:34 +0000781 data = data.decode(self._encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000782 self._methodname = data
783 self._type = "methodName" # no params
784 dispatch["methodName"] = end_methodName
785
Martin v. Löwis45394c22003-10-31 13:49:36 +0000786## Multicall support
787#
Fredrik Lundhb9056332001-07-11 17:42:21 +0000788
Martin v. Löwis45394c22003-10-31 13:49:36 +0000789class _MultiCallMethod:
790 # some lesser magic to store calls made to a MultiCall object
791 # for batch execution
792 def __init__(self, call_list, name):
793 self.__call_list = call_list
794 self.__name = name
795 def __getattr__(self, name):
796 return _MultiCallMethod(self.__call_list, "%s.%s" % (self.__name, name))
797 def __call__(self, *args):
798 self.__call_list.append((self.__name, args))
799
Martin v. Löwis12237b32004-08-22 16:04:50 +0000800class MultiCallIterator:
Martin v. Löwis45394c22003-10-31 13:49:36 +0000801 """Iterates over the results of a multicall. Exceptions are
802 thrown in response to xmlrpc faults."""
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000803
Martin v. Löwis12237b32004-08-22 16:04:50 +0000804 def __init__(self, results):
805 self.results = results
806
807 def __getitem__(self, i):
808 item = self.results[i]
809 if type(item) == type({}):
810 raise Fault(item['faultCode'], item['faultString'])
811 elif type(item) == type([]):
812 return item[0]
Martin v. Löwis45394c22003-10-31 13:49:36 +0000813 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000814 raise ValueError("unexpected type in multicall result")
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000815
Martin v. Löwis45394c22003-10-31 13:49:36 +0000816class MultiCall:
817 """server -> a object used to boxcar method calls
818
819 server should be a ServerProxy object.
820
821 Methods can be added to the MultiCall using normal
822 method call syntax e.g.:
823
824 multicall = MultiCall(server_proxy)
825 multicall.add(2,3)
826 multicall.get_address("Guido")
827
828 To execute the multicall, call the MultiCall object e.g.:
829
830 add_result, address = multicall()
831 """
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000832
Martin v. Löwis45394c22003-10-31 13:49:36 +0000833 def __init__(self, server):
834 self.__server = server
835 self.__call_list = []
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000836
Martin v. Löwis45394c22003-10-31 13:49:36 +0000837 def __repr__(self):
838 return "<MultiCall at %x>" % id(self)
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000839
Martin v. Löwis45394c22003-10-31 13:49:36 +0000840 __str__ = __repr__
841
842 def __getattr__(self, name):
843 return _MultiCallMethod(self.__call_list, name)
844
845 def __call__(self):
846 marshalled_list = []
847 for name, args in self.__call_list:
848 marshalled_list.append({'methodName' : name, 'params' : args})
849
850 return MultiCallIterator(self.__server.system.multicall(marshalled_list))
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000851
Fredrik Lundhb9056332001-07-11 17:42:21 +0000852# --------------------------------------------------------------------
853# convenience functions
854
Georg Brandl38eceaa2008-05-26 11:14:17 +0000855FastMarshaller = FastParser = FastUnmarshaller = None
856
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000857##
858# Create a parser object, and connect it to an unmarshalling instance.
859# This function picks the fastest available XML parser.
860#
861# return A (parser, unmarshaller) tuple.
862
Georg Brandlfe991052009-09-16 15:54:04 +0000863def getparser(use_datetime=False):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000864 """getparser() -> parser, unmarshaller
865
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000866 Create an instance of the fastest available parser, and attach it
867 to an unmarshalling object. Return both objects.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000868 """
869 if FastParser and FastUnmarshaller:
Skip Montanaro174dd222005-05-14 20:54:16 +0000870 if use_datetime:
871 mkdatetime = _datetime_type
872 else:
873 mkdatetime = _datetime
874 target = FastUnmarshaller(True, False, _binary, mkdatetime, Fault)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000875 parser = FastParser(target)
876 else:
Skip Montanaro174dd222005-05-14 20:54:16 +0000877 target = Unmarshaller(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000878 if FastParser:
879 parser = FastParser(target)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000880 else:
Georg Brandlcef803f2009-06-04 09:04:53 +0000881 parser = ExpatParser(target)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000882 return parser, target
883
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000884##
885# Convert a Python tuple or a Fault instance to an XML-RPC packet.
886#
887# @def dumps(params, **options)
888# @param params A tuple or Fault instance.
889# @keyparam methodname If given, create a methodCall request for
890# this method name.
891# @keyparam methodresponse If given, create a methodResponse packet.
892# If used with a tuple, the tuple must be a singleton (that is,
893# it must contain exactly one element).
894# @keyparam encoding The packet encoding.
895# @return A string containing marshalled data.
896
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000897def dumps(params, methodname=None, methodresponse=None, encoding=None,
Georg Brandlfe991052009-09-16 15:54:04 +0000898 allow_none=False):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000899 """data [,options] -> marshalled data
900
901 Convert an argument tuple or a Fault instance to an XML-RPC
902 request (or response, if the methodresponse option is used).
903
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000904 In addition to the data object, the following options can be given
905 as keyword arguments:
Fredrik Lundhb9056332001-07-11 17:42:21 +0000906
907 methodname: the method name for a methodCall packet
908
909 methodresponse: true to create a methodResponse packet.
910 If this option is used with a tuple, the tuple must be
911 a singleton (i.e. it can contain only one element).
912
913 encoding: the packet encoding (default is UTF-8)
914
915 All 8-bit strings in the data structure are assumed to use the
916 packet encoding. Unicode strings are automatically converted,
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000917 where necessary.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000918 """
919
Guido van Rossum13257902007-06-07 23:15:56 +0000920 assert isinstance(params, (tuple, Fault)), "argument must be tuple or Fault instance"
Fredrik Lundhb9056332001-07-11 17:42:21 +0000921 if isinstance(params, Fault):
922 methodresponse = 1
Guido van Rossum13257902007-06-07 23:15:56 +0000923 elif methodresponse and isinstance(params, tuple):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000924 assert len(params) == 1, "response tuple must be a singleton"
925
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000926 if not encoding:
Fredrik Lundhb9056332001-07-11 17:42:21 +0000927 encoding = "utf-8"
928
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000929 if FastMarshaller:
930 m = FastMarshaller(encoding)
931 else:
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000932 m = Marshaller(encoding, allow_none)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000933
Fredrik Lundhb9056332001-07-11 17:42:21 +0000934 data = m.dumps(params)
935
936 if encoding != "utf-8":
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000937 xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000938 else:
939 xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
940
941 # standard XML-RPC wrappings
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000942 if methodname:
Fredrik Lundhb9056332001-07-11 17:42:21 +0000943 # a method call
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000944 if not isinstance(methodname, str):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000945 methodname = methodname.encode(encoding)
946 data = (
947 xmlheader,
948 "<methodCall>\n"
949 "<methodName>", methodname, "</methodName>\n",
950 data,
951 "</methodCall>\n"
952 )
953 elif methodresponse:
954 # a method response, or a fault structure
955 data = (
956 xmlheader,
957 "<methodResponse>\n",
958 data,
959 "</methodResponse>\n"
960 )
961 else:
962 return data # return as is
Neal Norwitzff113342007-04-17 08:42:15 +0000963 return "".join(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000964
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000965##
966# Convert an XML-RPC packet to a Python object. If the XML-RPC packet
967# represents a fault condition, this function raises a Fault exception.
968#
969# @param data An XML-RPC packet, given as an 8-bit string.
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +0000970# @return A tuple containing the unpacked data, and the method name
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000971# (None if not present).
972# @see Fault
973
Georg Brandlfe991052009-09-16 15:54:04 +0000974def loads(data, use_datetime=False):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000975 """data -> unmarshalled data, method name
976
977 Convert an XML-RPC packet to unmarshalled data plus a method
978 name (None if not present).
979
980 If the XML-RPC packet represents a fault condition, this function
981 raises a Fault exception.
982 """
Skip Montanaro174dd222005-05-14 20:54:16 +0000983 p, u = getparser(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000984 p.feed(data)
985 p.close()
986 return u.close(), u.getmethodname()
987
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000988##
989# Encode a string using the gzip content encoding such as specified by the
990# Content-Encoding: gzip
991# in the HTTP header, as described in RFC 1952
992#
993# @param data the unencoded data
994# @return the encoded data
995
996def gzip_encode(data):
997 """data -> gzip encoded data
998
999 Encode data using the gzip content encoding as described in RFC 1952
1000 """
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +00001001 if not gzip:
1002 raise NotImplementedError
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001003 f = BytesIO()
1004 gzf = gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1)
1005 gzf.write(data)
1006 gzf.close()
1007 encoded = f.getvalue()
1008 f.close()
1009 return encoded
1010
1011##
1012# Decode a string using the gzip content encoding such as specified by the
1013# Content-Encoding: gzip
1014# in the HTTP header, as described in RFC 1952
1015#
1016# @param data The encoded data
1017# @return the unencoded data
1018# @raises ValueError if data is not correctly coded.
1019
1020def gzip_decode(data):
1021 """gzip encoded data -> unencoded data
1022
1023 Decode data using the gzip content encoding as described in RFC 1952
1024 """
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +00001025 if not gzip:
1026 raise NotImplementedError
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001027 f = BytesIO(data)
1028 gzf = gzip.GzipFile(mode="rb", fileobj=f)
1029 try:
1030 decoded = gzf.read()
1031 except IOError:
1032 raise ValueError("invalid data")
1033 f.close()
1034 gzf.close()
1035 return decoded
1036
1037##
1038# Return a decoded file-like object for the gzip encoding
1039# as described in RFC 1952.
1040#
1041# @param response A stream supporting a read() method
1042# @return a file-like object that the decoded data can be read() from
1043
Kristján Valur Jónsson9ab07312009-07-19 22:38:38 +00001044class GzipDecodedResponse(gzip.GzipFile if gzip else object):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001045 """a file-like object to decode a response encoded with the gzip
1046 method, as described in RFC 1952.
1047 """
1048 def __init__(self, response):
1049 #response doesn't support tell() and read(), required by
1050 #GzipFile
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +00001051 if not gzip:
1052 raise NotImplementedError
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001053 self.io = BytesIO(response.read())
1054 gzip.GzipFile.__init__(self, mode="rb", fileobj=self.io)
1055
1056 def close(self):
1057 gzip.GzipFile.close(self)
1058 self.io.close()
1059
Fredrik Lundhb9056332001-07-11 17:42:21 +00001060
1061# --------------------------------------------------------------------
1062# request dispatcher
1063
1064class _Method:
1065 # some magic to bind an XML-RPC method to an RPC server.
1066 # supports "nested" methods (e.g. examples.getStateName)
1067 def __init__(self, send, name):
1068 self.__send = send
1069 self.__name = name
1070 def __getattr__(self, name):
1071 return _Method(self.__send, "%s.%s" % (self.__name, name))
1072 def __call__(self, *args):
1073 return self.__send(self.__name, args)
1074
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001075##
1076# Standard transport class for XML-RPC over HTTP.
1077# <p>
1078# You can create custom transports by subclassing this method, and
1079# overriding selected methods.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001080
1081class Transport:
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001082 """Handles an HTTP transaction to an XML-RPC server."""
Fredrik Lundhb9056332001-07-11 17:42:21 +00001083
1084 # client identifier (may be overridden)
Florent Xicluna75861df2011-10-30 20:39:24 +01001085 user_agent = "Python-xmlrpc/%s" % __version__
Fredrik Lundhb9056332001-07-11 17:42:21 +00001086
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001087 #if true, we'll request gzip encoding
1088 accept_gzip_encoding = True
1089
1090 # if positive, encode request using gzip if it exceeds this threshold
1091 # note that many server will get confused, so only use it if you know
1092 # that they can decode such a request
1093 encode_threshold = None #None = don't encode
1094
Georg Brandlfe991052009-09-16 15:54:04 +00001095 def __init__(self, use_datetime=False):
Skip Montanaro174dd222005-05-14 20:54:16 +00001096 self._use_datetime = use_datetime
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001097 self._connection = (None, None)
1098 self._extra_headers = []
Skip Montanaro174dd222005-05-14 20:54:16 +00001099
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001100 ##
1101 # Send a complete request, and parse the response.
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001102 # Retry request if a cached connection has disconnected.
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001103 #
1104 # @param host Target host.
1105 # @param handler Target PRC handler.
1106 # @param request_body XML-RPC request body.
1107 # @param verbose Debugging flag.
1108 # @return Parsed response.
1109
Georg Brandlfe991052009-09-16 15:54:04 +00001110 def request(self, host, handler, request_body, verbose=False):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001111 #retry request once if cached connection has gone cold
1112 for i in (0, 1):
1113 try:
1114 return self.single_request(host, handler, request_body, verbose)
Kristján Valur Jónsson43535d92009-07-03 23:23:50 +00001115 except socket.error as e:
Victor Stinner756f5472010-07-24 02:24:55 +00001116 if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE):
Kristján Valur Jónsson43535d92009-07-03 23:23:50 +00001117 raise
1118 except http.client.BadStatusLine: #close after we sent request
1119 if i:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001120 raise
1121
Georg Brandlfe991052009-09-16 15:54:04 +00001122 def single_request(self, host, handler, request_body, verbose=False):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001123 # issue XML-RPC request
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001124 try:
1125 http_conn = self.send_request(host, handler, request_body, verbose)
1126 resp = http_conn.getresponse()
1127 if resp.status == 200:
1128 self.verbose = verbose
1129 return self.parse_response(resp)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001130
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001131 except Fault:
1132 raise
1133 except Exception:
1134 #All unexpected errors leave connection in
1135 # a strange state, so we clear it.
1136 self.close()
1137 raise
Fredrik Lundhb9056332001-07-11 17:42:21 +00001138
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001139 #We got an error response.
1140 #Discard any response data and raise exception
1141 if resp.getheader("content-length", ""):
1142 resp.read()
1143 raise ProtocolError(
1144 host + handler,
1145 resp.status, resp.reason,
1146 dict(resp.getheaders())
1147 )
Fredrik Lundhb9056332001-07-11 17:42:21 +00001148
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001149
1150 ##
1151 # Create parser.
1152 #
1153 # @return A 2-tuple containing a parser and a unmarshaller.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001154
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001155 def getparser(self):
1156 # get parser and unmarshaller
Skip Montanaro174dd222005-05-14 20:54:16 +00001157 return getparser(use_datetime=self._use_datetime)
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001158
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001159 ##
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001160 # Get authorization info from host parameter
1161 # Host may be a string, or a (host, x509-dict) tuple; if a string,
1162 # it is checked for a "user:pw@host" format, and a "Basic
1163 # Authentication" header is added if appropriate.
1164 #
1165 # @param host Host descriptor (URL or (URL, x509 info) tuple).
1166 # @return A 3-tuple containing (actual host, extra headers,
1167 # x509 info). The header and x509 fields may be None.
1168
1169 def get_host_info(self, host):
1170
1171 x509 = {}
Guido van Rossum13257902007-06-07 23:15:56 +00001172 if isinstance(host, tuple):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001173 host, x509 = host
1174
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001175 import urllib.parse
1176 auth, host = urllib.parse.splituser(host)
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001177
1178 if auth:
Georg Brandlc8dcfb62009-02-13 10:50:01 +00001179 auth = urllib.parse.unquote_to_bytes(auth)
Georg Brandlb54d8012009-06-04 09:11:51 +00001180 auth = base64.encodebytes(auth).decode("utf-8")
Neal Norwitzff113342007-04-17 08:42:15 +00001181 auth = "".join(auth.split()) # get rid of whitespace
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001182 extra_headers = [
1183 ("Authorization", "Basic " + auth)
1184 ]
1185 else:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001186 extra_headers = []
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001187
1188 return host, extra_headers, x509
1189
1190 ##
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001191 # Connect to server.
1192 #
1193 # @param host Target host.
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001194 # @return An HTTPConnection object
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001195
Fredrik Lundhb9056332001-07-11 17:42:21 +00001196 def make_connection(self, host):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001197 #return an existing connection if possible. This allows
1198 #HTTP/1.1 keep-alive.
1199 if self._connection and host == self._connection[0]:
1200 return self._connection[1]
Fredrik Lundhb9056332001-07-11 17:42:21 +00001201 # create a HTTP connection object from a host descriptor
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001202 chost, self._extra_headers, x509 = self.get_host_info(host)
1203 self._connection = host, http.client.HTTPConnection(chost)
1204 return self._connection[1]
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001205
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001206 ##
1207 # Clear any cached connection object.
1208 # Used in the event of socket errors.
1209 #
1210 def close(self):
1211 if self._connection[1]:
1212 self._connection[1].close()
1213 self._connection = (None, None)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001214
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001215 ##
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001216 # Send HTTP request.
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001217 #
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001218 # @param host Host descriptor (URL or (URL, x509 info) tuple).
1219 # @param handler Targer RPC handler (a path relative to host)
1220 # @param request_body The XML-RPC request body
1221 # @param debug Enable debugging if debug is true.
1222 # @return An HTTPConnection.
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001223
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001224 def send_request(self, host, handler, request_body, debug):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001225 connection = self.make_connection(host)
1226 headers = self._extra_headers[:]
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001227 if debug:
1228 connection.set_debuglevel(1)
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +00001229 if self.accept_gzip_encoding and gzip:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001230 connection.putrequest("POST", handler, skip_accept_encoding=True)
1231 headers.append(("Accept-Encoding", "gzip"))
1232 else:
1233 connection.putrequest("POST", handler)
1234 headers.append(("Content-Type", "text/xml"))
1235 headers.append(("User-Agent", self.user_agent))
1236 self.send_headers(connection, headers)
1237 self.send_content(connection, request_body)
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001238 return connection
Fredrik Lundhb9056332001-07-11 17:42:21 +00001239
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001240 ##
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001241 # Send request headers.
1242 # This function provides a useful hook for subclassing
1243 #
1244 # @param connection httpConnection.
1245 # @param headers list of key,value pairs for HTTP headers
1246
1247 def send_headers(self, connection, headers):
1248 for key, val in headers:
1249 connection.putheader(key, val)
1250
1251 ##
1252 # Send request body.
1253 # This function provides a useful hook for subclassing
1254 #
1255 # @param connection httpConnection.
1256 # @param request_body XML-RPC request body.
1257
1258 def send_content(self, connection, request_body):
1259 #optionally encode the request
1260 if (self.encode_threshold is not None and
Kristján Valur Jónssonaefde242009-07-19 22:29:24 +00001261 self.encode_threshold < len(request_body) and
1262 gzip):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001263 connection.putheader("Content-Encoding", "gzip")
1264 request_body = gzip_encode(request_body)
1265
1266 connection.putheader("Content-Length", str(len(request_body)))
1267 connection.endheaders(request_body)
1268
1269 ##
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001270 # Parse response.
1271 #
1272 # @param file Stream.
1273 # @return Response tuple and target method.
1274
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001275 def parse_response(self, response):
1276 # read response data from httpresponse, and parse it
Senthil Kumaranf34445f2010-12-08 08:04:49 +00001277 # Check for new http response object, otherwise it is a file object.
1278 if hasattr(response, 'getheader'):
1279 if response.getheader("Content-Encoding", "") == "gzip":
1280 stream = GzipDecodedResponse(response)
1281 else:
1282 stream = response
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001283 else:
1284 stream = response
Fredrik Lundhb9056332001-07-11 17:42:21 +00001285
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001286 p, u = self.getparser()
Fredrik Lundhb9056332001-07-11 17:42:21 +00001287
1288 while 1:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001289 data = stream.read(1024)
1290 if not data:
Fredrik Lundhb9056332001-07-11 17:42:21 +00001291 break
1292 if self.verbose:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001293 print("body:", repr(data))
1294 p.feed(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001295
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001296 if stream is not response:
1297 stream.close()
Fredrik Lundhb9056332001-07-11 17:42:21 +00001298 p.close()
1299
1300 return u.close()
1301
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001302##
1303# Standard transport class for XML-RPC over HTTPS.
1304
Fredrik Lundhb9056332001-07-11 17:42:21 +00001305class SafeTransport(Transport):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001306 """Handles an HTTPS transaction to an XML-RPC server."""
Fredrik Lundhb9056332001-07-11 17:42:21 +00001307
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001308 # FIXME: mostly untested
1309
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001310 def make_connection(self, host):
1311 if self._connection and host == self._connection[0]:
1312 return self._connection[1]
1313
Senthil Kumaran6a0b5c42010-11-18 17:08:48 +00001314 if not hasattr(http.client, "HTTPSConnection"):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001315 raise NotImplementedError(
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001316 "your version of http.client doesn't support HTTPS")
1317 # create a HTTPS connection object from a host descriptor
1318 # host may be a string, or a (host, x509-dict) tuple
1319 chost, self._extra_headers, x509 = self.get_host_info(host)
1320 self._connection = host, http.client.HTTPSConnection(chost,
1321 None, **(x509 or {}))
1322 return self._connection[1]
Fredrik Lundhb9056332001-07-11 17:42:21 +00001323
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001324##
1325# Standard server proxy. This class establishes a virtual connection
1326# to an XML-RPC server.
1327# <p>
1328# This class is available as ServerProxy and Server. New code should
1329# use ServerProxy, to avoid confusion.
1330#
1331# @def ServerProxy(uri, **options)
1332# @param uri The connection point on the server.
1333# @keyparam transport A transport factory, compatible with the
1334# standard transport class.
1335# @keyparam encoding The default encoding used for 8-bit strings
1336# (default is UTF-8).
1337# @keyparam verbose Use a true value to enable debugging output.
1338# (printed to standard output).
1339# @see Transport
1340
Fredrik Lundhb9056332001-07-11 17:42:21 +00001341class ServerProxy:
1342 """uri [,options] -> a logical connection to an XML-RPC server
1343
1344 uri is the connection point on the server, given as
1345 scheme://host/target.
1346
1347 The standard implementation always supports the "http" scheme. If
1348 SSL socket support is available (Python 2.0), it also supports
1349 "https".
1350
1351 If the target part and the slash preceding it are both omitted,
1352 "/RPC2" is assumed.
1353
1354 The following options can be given as keyword arguments:
1355
1356 transport: a transport factory
1357 encoding: the request encoding (default is UTF-8)
1358
1359 All 8-bit strings passed to the server proxy are assumed to use
1360 the given encoding.
1361 """
1362
Georg Brandlfe991052009-09-16 15:54:04 +00001363 def __init__(self, uri, transport=None, encoding=None, verbose=False,
1364 allow_none=False, use_datetime=False):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001365 # establish a "logical" server connection
1366
1367 # get the url
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001368 import urllib.parse
1369 type, uri = urllib.parse.splittype(uri)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001370 if type not in ("http", "https"):
Collin Winterce36ad82007-08-30 01:19:48 +00001371 raise IOError("unsupported XML-RPC protocol")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001372 self.__host, self.__handler = urllib.parse.splithost(uri)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001373 if not self.__handler:
1374 self.__handler = "/RPC2"
1375
1376 if transport is None:
1377 if type == "https":
Skip Montanaro174dd222005-05-14 20:54:16 +00001378 transport = SafeTransport(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001379 else:
Skip Montanaro174dd222005-05-14 20:54:16 +00001380 transport = Transport(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001381 self.__transport = transport
1382
Senthil Kumaranb3af08f2009-04-01 20:20:43 +00001383 self.__encoding = encoding or 'utf-8'
Fredrik Lundhb9056332001-07-11 17:42:21 +00001384 self.__verbose = verbose
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001385 self.__allow_none = allow_none
Tim Petersc2659cf2003-05-12 20:19:37 +00001386
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001387 def __close(self):
1388 self.__transport.close()
1389
Fredrik Lundhb9056332001-07-11 17:42:21 +00001390 def __request(self, methodname, params):
1391 # call a method on the remote server
1392
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001393 request = dumps(params, methodname, encoding=self.__encoding,
Senthil Kumaranb3af08f2009-04-01 20:20:43 +00001394 allow_none=self.__allow_none).encode(self.__encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001395
1396 response = self.__transport.request(
1397 self.__host,
1398 self.__handler,
1399 request,
1400 verbose=self.__verbose
1401 )
1402
1403 if len(response) == 1:
1404 response = response[0]
1405
1406 return response
1407
1408 def __repr__(self):
1409 return (
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001410 "<ServerProxy for %s%s>" %
Fredrik Lundhb9056332001-07-11 17:42:21 +00001411 (self.__host, self.__handler)
1412 )
1413
1414 __str__ = __repr__
Raymond Hettingercc523fc2003-11-02 09:47:05 +00001415
Fredrik Lundhb9056332001-07-11 17:42:21 +00001416 def __getattr__(self, name):
1417 # magic method dispatcher
1418 return _Method(self.__request, name)
1419
1420 # note: to call a remote object with an non-standard name, use
1421 # result getattr(server, "strange-python-name")(args)
1422
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001423 def __call__(self, attr):
1424 """A workaround to get special attributes on the ServerProxy
1425 without interfering with the magic __getattr__
1426 """
1427 if attr == "close":
1428 return self.__close
1429 elif attr == "transport":
1430 return self.__transport
1431 raise AttributeError("Attribute %r not found" % (attr,))
1432
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001433# compatibility
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001434
Fredrik Lundhb9056332001-07-11 17:42:21 +00001435Server = ServerProxy
1436
1437# --------------------------------------------------------------------
1438# test code
1439
1440if __name__ == "__main__":
1441
1442 # simple test program (from the XML-RPC specification)
1443
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001444 # server = ServerProxy("http://localhost:8000") # local server
Martin v. Löwis12237b32004-08-22 16:04:50 +00001445 server = ServerProxy("http://time.xmlrpc.com/RPC2")
Fredrik Lundhb9056332001-07-11 17:42:21 +00001446
Fredrik Lundhb9056332001-07-11 17:42:21 +00001447 try:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001448 print(server.currentTime.getCurrentTime())
Guido van Rossumb940e112007-01-10 16:19:56 +00001449 except Error as v:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001450 print("ERROR", v)
Martin v. Löwis12237b32004-08-22 16:04:50 +00001451
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001452 # The server at xmlrpc.com doesn't seem to support multicall anymore.
Martin v. Löwis12237b32004-08-22 16:04:50 +00001453 multi = MultiCall(server)
1454 multi.currentTime.getCurrentTime()
1455 multi.currentTime.getCurrentTime()
1456 try:
1457 for response in multi():
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001458 print(response)
Guido van Rossumb940e112007-01-10 16:19:56 +00001459 except Error as v:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001460 print("ERROR", v)