blob: 160b61c8e041da502d1ca8c2700cb7e85955640e [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 Boolean boolean wrapper to generate a "boolean" XML-RPC value
112 DateTime dateTime wrapper for an ISO 8601 string or time tuple or
113 localtime integer value to generate a "dateTime.iso8601"
114 XML-RPC value
115 Binary binary data wrapper
Fred Drake1b410792001-09-04 18:55:03 +0000116
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000117 SlowParser Slow but safe standard parser (based on xmllib)
118 Marshaller Generate an XML-RPC params chunk from a Python data structure
119 Unmarshaller Unmarshal an XML-RPC response from incoming XML event message
120 Transport Handles an HTTP transaction to an XML-RPC server
121 SafeTransport Handles an HTTPS transaction to an XML-RPC server
Fred Drake1b410792001-09-04 18:55:03 +0000122
123Exported constants:
124
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000125 True
126 False
Fred Drake1b410792001-09-04 18:55:03 +0000127
128Exported functions:
129
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000130 boolean Convert any Python value to an XML-RPC boolean
131 getparser Create instance of the fastest available parser & attach
132 to an unmarshalling object
133 dumps Convert an argument tuple or a Fault instance to an XML-RPC
134 request (or response, if the methodresponse option is used).
135 loads Convert an XML-RPC packet to unmarshalled data plus a method
136 name (None if not present).
Fred Drake1b410792001-09-04 18:55:03 +0000137"""
138
Fred Drake2a2d9702001-10-17 01:51:04 +0000139import re, string, time, operator
Fredrik Lundh1538c232001-10-01 19:42:03 +0000140
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000141from types import *
Kristján Valur Jónssone0078602009-06-28 21:04:17 +0000142import gzip
143import socket
144import errno
145import httplib
Fredrik Lundhb9056332001-07-11 17:42:21 +0000146
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000147# --------------------------------------------------------------------
148# Internal stuff
149
Fredrik Lundhb9056332001-07-11 17:42:21 +0000150try:
151 unicode
152except NameError:
153 unicode = None # unicode support not available
154
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000155try:
Fred Drakeba613c32005-02-10 18:33:30 +0000156 import datetime
157except ImportError:
158 datetime = None
159
160try:
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000161 _bool_is_builtin = False.__class__.__name__ == "bool"
162except NameError:
163 _bool_is_builtin = 0
164
Fredrik Lundhb9056332001-07-11 17:42:21 +0000165def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
166 # decode non-ascii string (if possible)
167 if unicode and encoding and is8bit(data):
168 data = unicode(data, encoding)
169 return data
170
Fredrik Lundh1538c232001-10-01 19:42:03 +0000171def escape(s, replace=string.replace):
172 s = replace(s, "&", "&")
173 s = replace(s, "<", "&lt;")
174 return replace(s, ">", "&gt;",)
175
Fredrik Lundhb9056332001-07-11 17:42:21 +0000176if unicode:
177 def _stringify(string):
178 # convert to 7-bit ascii if possible
179 try:
Fred Drake22c07062005-02-11 17:59:08 +0000180 return string.encode("ascii")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000181 except UnicodeError:
182 return string
183else:
184 def _stringify(string):
185 return string
186
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000187__version__ = "1.0.1"
188
189# xmlrpc integer limits
190MAXINT = 2L**31-1
191MININT = -2L**31
192
193# --------------------------------------------------------------------
194# Error constants (from Dan Libby's specification at
195# http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
196
197# Ranges of errors
198PARSE_ERROR = -32700
199SERVER_ERROR = -32600
200APPLICATION_ERROR = -32500
201SYSTEM_ERROR = -32400
202TRANSPORT_ERROR = -32300
203
204# Specific errors
205NOT_WELLFORMED_ERROR = -32700
206UNSUPPORTED_ENCODING = -32701
207INVALID_ENCODING_CHAR = -32702
208INVALID_XMLRPC = -32600
209METHOD_NOT_FOUND = -32601
210INVALID_METHOD_PARAMS = -32602
211INTERNAL_ERROR = -32603
Fredrik Lundhb9056332001-07-11 17:42:21 +0000212
213# --------------------------------------------------------------------
214# Exceptions
215
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000216##
217# Base class for all kinds of client-side errors.
218
Fredrik Lundh78eedce2001-08-23 20:04:33 +0000219class Error(Exception):
Fred Drake1b410792001-09-04 18:55:03 +0000220 """Base class for client errors."""
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000221 def __str__(self):
222 return repr(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000223
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000224##
225# Indicates an HTTP-level protocol error. This is raised by the HTTP
226# transport layer, if the server returns an error code other than 200
227# (OK).
228#
229# @param url The target URL.
230# @param errcode The HTTP error code.
231# @param errmsg The HTTP error message.
232# @param headers The HTTP header dictionary.
233
Fredrik Lundhb9056332001-07-11 17:42:21 +0000234class ProtocolError(Error):
Fred Drake1b410792001-09-04 18:55:03 +0000235 """Indicates an HTTP protocol error."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000236 def __init__(self, url, errcode, errmsg, headers):
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000237 Error.__init__(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000238 self.url = url
239 self.errcode = errcode
240 self.errmsg = errmsg
241 self.headers = headers
242 def __repr__(self):
243 return (
244 "<ProtocolError for %s: %s %s>" %
245 (self.url, self.errcode, self.errmsg)
246 )
247
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000248##
249# Indicates a broken XML-RPC response package. This exception is
250# raised by the unmarshalling layer, if the XML-RPC response is
251# malformed.
252
Fredrik Lundhb9056332001-07-11 17:42:21 +0000253class ResponseError(Error):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000254 """Indicates a broken response package."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000255 pass
256
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000257##
258# Indicates an XML-RPC fault response package. This exception is
259# raised by the unmarshalling layer, if the XML-RPC response contains
260# a fault string. This exception can also used as a class, to
261# generate a fault XML-RPC message.
262#
263# @param faultCode The XML-RPC fault code.
264# @param faultString The XML-RPC fault string.
265
Fredrik Lundhb9056332001-07-11 17:42:21 +0000266class Fault(Error):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000267 """Indicates an XML-RPC fault package."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000268 def __init__(self, faultCode, faultString, **extra):
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000269 Error.__init__(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000270 self.faultCode = faultCode
271 self.faultString = faultString
272 def __repr__(self):
273 return (
274 "<Fault %s: %s>" %
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000275 (self.faultCode, repr(self.faultString))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000276 )
277
278# --------------------------------------------------------------------
279# Special values
280
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000281##
282# Wrapper for XML-RPC boolean values. Use the xmlrpclib.True and
283# xmlrpclib.False constants, or the xmlrpclib.boolean() function, to
284# generate boolean XML-RPC values.
285#
286# @param value A boolean value. Any true value is interpreted as True,
287# all other values are interpreted as False.
288
Brett Cannon814820b2008-08-04 00:50:11 +0000289from sys import modules
290mod_dict = modules[__name__].__dict__
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000291if _bool_is_builtin:
292 boolean = Boolean = bool
293 # to avoid breaking code which references xmlrpclib.{True,False}
Brett Cannon814820b2008-08-04 00:50:11 +0000294 mod_dict['True'] = True
295 mod_dict['False'] = False
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000296else:
297 class Boolean:
298 """Boolean-value wrapper.
Fred Drake1b410792001-09-04 18:55:03 +0000299
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000300 Use True or False to generate a "boolean" XML-RPC value.
301 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000302
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000303 def __init__(self, value = 0):
304 self.value = operator.truth(value)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000305
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000306 def encode(self, out):
307 out.write("<value><boolean>%d</boolean></value>\n" % self.value)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000308
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000309 def __cmp__(self, other):
310 if isinstance(other, Boolean):
311 other = other.value
312 return cmp(self.value, other)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000313
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000314 def __repr__(self):
315 if self.value:
316 return "<Boolean True at %x>" % id(self)
317 else:
318 return "<Boolean False at %x>" % id(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000319
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000320 def __int__(self):
321 return self.value
Fredrik Lundhb9056332001-07-11 17:42:21 +0000322
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000323 def __nonzero__(self):
324 return self.value
Fredrik Lundhb9056332001-07-11 17:42:21 +0000325
Brett Cannon814820b2008-08-04 00:50:11 +0000326 mod_dict['True'] = Boolean(1)
327 mod_dict['False'] = Boolean(0)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000328
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000329 ##
330 # Map true or false value to XML-RPC boolean values.
331 #
332 # @def boolean(value)
333 # @param value A boolean value. Any true value is mapped to True,
334 # all other values are mapped to False.
335 # @return xmlrpclib.True or xmlrpclib.False.
336 # @see Boolean
337 # @see True
338 # @see False
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000339
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000340 def boolean(value, _truefalse=(False, True)):
341 """Convert any Python value to XML-RPC 'boolean'."""
342 return _truefalse[operator.truth(value)]
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000343
Brett Cannon814820b2008-08-04 00:50:11 +0000344del modules, mod_dict
345
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000346##
347# Wrapper for XML-RPC DateTime values. This converts a time value to
348# the format used by XML-RPC.
349# <p>
350# The value can be given as a string in the format
351# "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by
352# time.localtime()), or an integer value (as returned by time.time()).
353# The wrapper uses time.localtime() to convert an integer to a time
354# tuple.
355#
356# @param value The time, given as an ISO 8601 string, a time
357# tuple, or a integer time value.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000358
Skip Montanarob131f042008-04-18 20:35:46 +0000359def _strftime(value):
360 if datetime:
361 if isinstance(value, datetime.datetime):
362 return "%04d%02d%02dT%02d:%02d:%02d" % (
363 value.year, value.month, value.day,
364 value.hour, value.minute, value.second)
365
366 if not isinstance(value, (TupleType, time.struct_time)):
367 if value == 0:
368 value = time.time()
369 value = time.localtime(value)
370
371 return "%04d%02d%02dT%02d:%02d:%02d" % value[:6]
372
Fredrik Lundhb9056332001-07-11 17:42:21 +0000373class DateTime:
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000374 """DateTime wrapper for an ISO 8601 string or time tuple or
375 localtime integer value to generate 'dateTime.iso8601' XML-RPC
376 value.
377 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000378
379 def __init__(self, value=0):
Skip Montanarob131f042008-04-18 20:35:46 +0000380 if isinstance(value, StringType):
381 self.value = value
382 else:
383 self.value = _strftime(value)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000384
Andrew M. Kuchling085f75a2008-02-23 16:23:05 +0000385 def make_comparable(self, other):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000386 if isinstance(other, DateTime):
Andrew M. Kuchling085f75a2008-02-23 16:23:05 +0000387 s = self.value
388 o = other.value
389 elif datetime and isinstance(other, datetime.datetime):
390 s = self.value
391 o = other.strftime("%Y%m%dT%H:%M:%S")
392 elif isinstance(other, (str, unicode)):
393 s = self.value
394 o = other
395 elif hasattr(other, "timetuple"):
396 s = self.timetuple()
397 o = other.timetuple()
398 else:
399 otype = (hasattr(other, "__class__")
400 and other.__class__.__name__
401 or type(other))
402 raise TypeError("Can't compare %s and %s" %
403 (self.__class__.__name__, otype))
404 return s, o
405
406 def __lt__(self, other):
407 s, o = self.make_comparable(other)
408 return s < o
409
410 def __le__(self, other):
411 s, o = self.make_comparable(other)
412 return s <= o
413
414 def __gt__(self, other):
415 s, o = self.make_comparable(other)
416 return s > o
417
418 def __ge__(self, other):
419 s, o = self.make_comparable(other)
420 return s >= o
421
422 def __eq__(self, other):
423 s, o = self.make_comparable(other)
424 return s == o
425
426 def __ne__(self, other):
427 s, o = self.make_comparable(other)
428 return s != o
429
430 def timetuple(self):
431 return time.strptime(self.value, "%Y%m%dT%H:%M:%S")
432
433 def __cmp__(self, other):
434 s, o = self.make_comparable(other)
435 return cmp(s, o)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000436
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000437 ##
438 # Get date/time value.
439 #
440 # @return Date/time value, as an ISO 8601 string.
441
442 def __str__(self):
443 return self.value
444
Fredrik Lundhb9056332001-07-11 17:42:21 +0000445 def __repr__(self):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000446 return "<DateTime %s at %x>" % (repr(self.value), id(self))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000447
448 def decode(self, data):
Andrew M. Kuchlingbdb39012005-12-04 19:11:17 +0000449 data = str(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000450 self.value = string.strip(data)
451
452 def encode(self, out):
453 out.write("<value><dateTime.iso8601>")
454 out.write(self.value)
455 out.write("</dateTime.iso8601></value>\n")
456
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000457def _datetime(data):
458 # decode xml element contents into a DateTime structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000459 value = DateTime()
460 value.decode(data)
461 return value
462
Skip Montanaro174dd222005-05-14 20:54:16 +0000463def _datetime_type(data):
464 t = time.strptime(data, "%Y%m%dT%H:%M:%S")
465 return datetime.datetime(*tuple(t)[:6])
466
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000467##
468# Wrapper for binary data. This can be used to transport any kind
469# of binary data over XML-RPC, using BASE64 encoding.
470#
471# @param data An 8-bit string containing arbitrary data.
472
Skip Montanarobfcbfa72003-04-24 19:51:31 +0000473import base64
474try:
475 import cStringIO as StringIO
476except ImportError:
477 import StringIO
478
Fredrik Lundhb9056332001-07-11 17:42:21 +0000479class Binary:
Fred Drake1b410792001-09-04 18:55:03 +0000480 """Wrapper for binary data."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000481
482 def __init__(self, data=None):
483 self.data = data
484
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000485 ##
486 # Get buffer contents.
487 #
488 # @return Buffer contents, as an 8-bit string.
489
490 def __str__(self):
491 return self.data or ""
492
Fredrik Lundhb9056332001-07-11 17:42:21 +0000493 def __cmp__(self, other):
494 if isinstance(other, Binary):
495 other = other.data
496 return cmp(self.data, other)
497
498 def decode(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000499 self.data = base64.decodestring(data)
500
501 def encode(self, out):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000502 out.write("<value><base64>\n")
503 base64.encode(StringIO.StringIO(self.data), out)
504 out.write("</base64></value>\n")
505
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000506def _binary(data):
507 # decode xml element contents into a Binary structure
Fredrik Lundhb9056332001-07-11 17:42:21 +0000508 value = Binary()
509 value.decode(data)
510 return value
511
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000512WRAPPERS = (DateTime, Binary)
513if not _bool_is_builtin:
514 WRAPPERS = WRAPPERS + (Boolean,)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000515
516# --------------------------------------------------------------------
517# XML parsers
518
519try:
Fredrik Lundh7069c312004-10-13 06:48:37 +0000520 # optional xmlrpclib accelerator
Fredrik Lundhb9056332001-07-11 17:42:21 +0000521 import _xmlrpclib
522 FastParser = _xmlrpclib.Parser
523 FastUnmarshaller = _xmlrpclib.Unmarshaller
524except (AttributeError, ImportError):
525 FastParser = FastUnmarshaller = None
526
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000527try:
528 import _xmlrpclib
529 FastMarshaller = _xmlrpclib.Marshaller
530except (AttributeError, ImportError):
531 FastMarshaller = None
532
Fredrik Lundhb9056332001-07-11 17:42:21 +0000533try:
534 from xml.parsers import expat
Guido van Rossumb8551342001-10-02 18:33:11 +0000535 if not hasattr(expat, "ParserCreate"):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000536 raise ImportError
Fredrik Lundhb9056332001-07-11 17:42:21 +0000537except ImportError:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000538 ExpatParser = None # expat not available
Fredrik Lundhb9056332001-07-11 17:42:21 +0000539else:
540 class ExpatParser:
Georg Brandle6632b42009-06-04 08:58:32 +0000541 # fast expat parser for Python 2.0 and later.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000542 def __init__(self, target):
543 self._parser = parser = expat.ParserCreate(None, None)
544 self._target = target
545 parser.StartElementHandler = target.start
546 parser.EndElementHandler = target.end
547 parser.CharacterDataHandler = target.data
548 encoding = None
549 if not parser.returns_unicode:
550 encoding = "utf-8"
551 target.xml(encoding, None)
552
553 def feed(self, data):
554 self._parser.Parse(data, 0)
555
556 def close(self):
557 self._parser.Parse("", 1) # end of data
558 del self._target, self._parser # get rid of circular references
559
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000560class SlowParser:
561 """Default XML parser (based on xmllib.XMLParser)."""
Georg Brandle6632b42009-06-04 08:58:32 +0000562 # this is the slowest parser.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000563 def __init__(self, target):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000564 import xmllib # lazy subclassing (!)
565 if xmllib.XMLParser not in SlowParser.__bases__:
566 SlowParser.__bases__ = (xmllib.XMLParser,)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000567 self.handle_xml = target.xml
568 self.unknown_starttag = target.start
569 self.handle_data = target.data
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000570 self.handle_cdata = target.data
Fredrik Lundhb9056332001-07-11 17:42:21 +0000571 self.unknown_endtag = target.end
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000572 try:
573 xmllib.XMLParser.__init__(self, accept_utf8=1)
574 except TypeError:
575 xmllib.XMLParser.__init__(self) # pre-2.0
Fredrik Lundhb9056332001-07-11 17:42:21 +0000576
577# --------------------------------------------------------------------
578# XML-RPC marshalling and unmarshalling code
579
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000580##
581# XML-RPC marshaller.
582#
583# @param encoding Default encoding for 8-bit strings. The default
584# value is None (interpreted as UTF-8).
585# @see dumps
586
Fredrik Lundhb9056332001-07-11 17:42:21 +0000587class Marshaller:
Fred Drake1b410792001-09-04 18:55:03 +0000588 """Generate an XML-RPC params chunk from a Python data structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000589
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000590 Create a Marshaller instance for each set of parameters, and use
591 the "dumps" method to convert your data (represented as a tuple)
592 to an XML-RPC params chunk. To write a fault response, pass a
593 Fault instance instead. You may prefer to use the "dumps" module
594 function for this purpose.
Fred Drake1b410792001-09-04 18:55:03 +0000595 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000596
597 # by the way, if you don't understand what's going on in here,
598 # that's perfectly ok.
599
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000600 def __init__(self, encoding=None, allow_none=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000601 self.memo = {}
602 self.data = None
603 self.encoding = encoding
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000604 self.allow_none = allow_none
Tim Petersc2659cf2003-05-12 20:19:37 +0000605
Fredrik Lundhb9056332001-07-11 17:42:21 +0000606 dispatch = {}
607
608 def dumps(self, values):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000609 out = []
610 write = out.append
611 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000612 if isinstance(values, Fault):
613 # fault instance
614 write("<fault>\n")
Martin v. Löwis541342f2003-07-12 07:53:04 +0000615 dump({'faultCode': values.faultCode,
616 'faultString': values.faultString},
617 write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000618 write("</fault>\n")
619 else:
620 # parameter block
Fredrik Lundhc266bb02001-08-23 20:13:08 +0000621 # FIXME: the xml-rpc specification allows us to leave out
622 # the entire <params> block if there are no parameters.
623 # however, changing this may break older code (including
624 # old versions of xmlrpclib.py), so this is better left as
625 # is for now. See @XMLRPC3 for more information. /F
Fredrik Lundhb9056332001-07-11 17:42:21 +0000626 write("<params>\n")
627 for v in values:
628 write("<param>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000629 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000630 write("</param>\n")
631 write("</params>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000632 result = string.join(out, "")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000633 return result
634
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000635 def __dump(self, value, write):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000636 try:
637 f = self.dispatch[type(value)]
638 except KeyError:
Martin v. Löwis07529352006-11-19 18:51:54 +0000639 # check if this object can be marshalled as a structure
640 try:
641 value.__dict__
642 except:
643 raise TypeError, "cannot marshal %s objects" % type(value)
644 # check if this class is a sub-class of a basic type,
645 # because we don't know how to marshal these types
646 # (e.g. a string sub-class)
647 for type_ in type(value).__mro__:
648 if type_ in self.dispatch.keys():
649 raise TypeError, "cannot marshal %s objects" % type(value)
650 f = self.dispatch[InstanceType]
651 f(self, value, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000652
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000653 def dump_nil (self, value, write):
654 if not self.allow_none:
655 raise TypeError, "cannot marshal None unless allow_none is enabled"
656 write("<value><nil/></value>")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000657 dispatch[NoneType] = dump_nil
Tim Petersc2659cf2003-05-12 20:19:37 +0000658
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000659 def dump_int(self, value, write):
Skip Montanaro5449e082001-10-17 22:53:33 +0000660 # in case ints are > 32 bits
661 if value > MAXINT or value < MININT:
662 raise OverflowError, "int exceeds XML-RPC limits"
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000663 write("<value><int>")
664 write(str(value))
665 write("</int></value>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000666 dispatch[IntType] = dump_int
Fredrik Lundhb9056332001-07-11 17:42:21 +0000667
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000668 if _bool_is_builtin:
669 def dump_bool(self, value, write):
670 write("<value><boolean>")
671 write(value and "1" or "0")
672 write("</boolean></value>\n")
673 dispatch[bool] = dump_bool
674
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000675 def dump_long(self, value, write):
Skip Montanaro5449e082001-10-17 22:53:33 +0000676 if value > MAXINT or value < MININT:
677 raise OverflowError, "long int exceeds XML-RPC limits"
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000678 write("<value><int>")
679 write(str(int(value)))
680 write("</int></value>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000681 dispatch[LongType] = dump_long
Skip Montanaro5e9c71b2001-10-10 15:56:34 +0000682
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000683 def dump_double(self, value, write):
684 write("<value><double>")
685 write(repr(value))
686 write("</double></value>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000687 dispatch[FloatType] = dump_double
Fredrik Lundhb9056332001-07-11 17:42:21 +0000688
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000689 def dump_string(self, value, write, escape=escape):
690 write("<value><string>")
691 write(escape(value))
692 write("</string></value>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000693 dispatch[StringType] = dump_string
Fredrik Lundhb9056332001-07-11 17:42:21 +0000694
695 if unicode:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000696 def dump_unicode(self, value, write, escape=escape):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000697 value = value.encode(self.encoding)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000698 write("<value><string>")
699 write(escape(value))
700 write("</string></value>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000701 dispatch[UnicodeType] = dump_unicode
Fredrik Lundhb9056332001-07-11 17:42:21 +0000702
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000703 def dump_array(self, value, write):
704 i = id(value)
Brett Cannon814820b2008-08-04 00:50:11 +0000705 if i in self.memo:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000706 raise TypeError, "cannot marshal recursive sequences"
707 self.memo[i] = None
Fredrik Lundh1538c232001-10-01 19:42:03 +0000708 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000709 write("<value><array><data>\n")
710 for v in value:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000711 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000712 write("</data></array></value>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000713 del self.memo[i]
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000714 dispatch[TupleType] = dump_array
715 dispatch[ListType] = dump_array
Fredrik Lundhb9056332001-07-11 17:42:21 +0000716
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000717 def dump_struct(self, value, write, escape=escape):
718 i = id(value)
Brett Cannon814820b2008-08-04 00:50:11 +0000719 if i in self.memo:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000720 raise TypeError, "cannot marshal recursive dictionaries"
721 self.memo[i] = None
Fredrik Lundh1538c232001-10-01 19:42:03 +0000722 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000723 write("<value><struct>\n")
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000724 for k, v in value.items():
Fredrik Lundhb9056332001-07-11 17:42:21 +0000725 write("<member>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000726 if type(k) is not StringType:
727 if unicode and type(k) is UnicodeType:
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000728 k = k.encode(self.encoding)
729 else:
730 raise TypeError, "dictionary key must be string"
Fredrik Lundh1538c232001-10-01 19:42:03 +0000731 write("<name>%s</name>\n" % escape(k))
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000732 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000733 write("</member>\n")
734 write("</struct></value>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000735 del self.memo[i]
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000736 dispatch[DictType] = dump_struct
Fredrik Lundhb9056332001-07-11 17:42:21 +0000737
Fred Drakeba613c32005-02-10 18:33:30 +0000738 if datetime:
739 def dump_datetime(self, value, write):
740 write("<value><dateTime.iso8601>")
Skip Montanarob131f042008-04-18 20:35:46 +0000741 write(_strftime(value))
Fred Drakeba613c32005-02-10 18:33:30 +0000742 write("</dateTime.iso8601></value>\n")
743 dispatch[datetime.datetime] = dump_datetime
744
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000745 def dump_instance(self, value, write):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000746 # check for special wrappers
747 if value.__class__ in WRAPPERS:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000748 self.write = write
Fredrik Lundhb9056332001-07-11 17:42:21 +0000749 value.encode(self)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000750 del self.write
Fredrik Lundhb9056332001-07-11 17:42:21 +0000751 else:
752 # store instance attributes as a struct (really?)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000753 self.dump_struct(value.__dict__, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000754 dispatch[InstanceType] = dump_instance
755
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000756##
757# XML-RPC unmarshaller.
758#
759# @see loads
760
Fredrik Lundhb9056332001-07-11 17:42:21 +0000761class Unmarshaller:
Fred Drake1b410792001-09-04 18:55:03 +0000762 """Unmarshal an XML-RPC response, based on incoming XML event
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000763 messages (start, data, end). Call close() to get the resulting
Fred Drake1b410792001-09-04 18:55:03 +0000764 data structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000765
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000766 Note that this reader is fairly tolerant, and gladly accepts bogus
767 XML-RPC data without complaining (but not bogus XML).
Fred Drake1b410792001-09-04 18:55:03 +0000768 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000769
770 # and again, if you don't understand what's going on in here,
771 # that's perfectly ok.
772
Skip Montanaro174dd222005-05-14 20:54:16 +0000773 def __init__(self, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000774 self._type = None
775 self._stack = []
776 self._marks = []
777 self._data = []
778 self._methodname = None
779 self._encoding = "utf-8"
780 self.append = self._stack.append
Skip Montanaro174dd222005-05-14 20:54:16 +0000781 self._use_datetime = use_datetime
782 if use_datetime and not datetime:
783 raise ValueError, "the datetime module is not available"
Fredrik Lundhb9056332001-07-11 17:42:21 +0000784
785 def close(self):
786 # return response tuple and target method
787 if self._type is None or self._marks:
788 raise ResponseError()
789 if self._type == "fault":
Guido van Rossum68468eb2003-02-27 20:14:51 +0000790 raise Fault(**self._stack[0])
Fredrik Lundhb9056332001-07-11 17:42:21 +0000791 return tuple(self._stack)
792
793 def getmethodname(self):
794 return self._methodname
795
796 #
797 # event handlers
798
799 def xml(self, encoding, standalone):
800 self._encoding = encoding
801 # FIXME: assert standalone == 1 ???
802
803 def start(self, tag, attrs):
804 # prepare to handle this element
805 if tag == "array" or tag == "struct":
806 self._marks.append(len(self._stack))
807 self._data = []
808 self._value = (tag == "value")
809
810 def data(self, text):
811 self._data.append(text)
812
Fredrik Lundh1538c232001-10-01 19:42:03 +0000813 def end(self, tag, join=string.join):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000814 # call the appropriate end tag handler
815 try:
816 f = self.dispatch[tag]
817 except KeyError:
818 pass # unknown tag ?
819 else:
Fredrik Lundh1538c232001-10-01 19:42:03 +0000820 return f(self, join(self._data, ""))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000821
822 #
823 # accelerator support
824
825 def end_dispatch(self, tag, data):
826 # dispatch data
827 try:
828 f = self.dispatch[tag]
829 except KeyError:
830 pass # unknown tag ?
831 else:
832 return f(self, data)
833
834 #
835 # element decoders
836
837 dispatch = {}
838
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000839 def end_nil (self, data):
840 self.append(None)
841 self._value = 0
842 dispatch["nil"] = end_nil
Tim Petersc2659cf2003-05-12 20:19:37 +0000843
Fredrik Lundh1538c232001-10-01 19:42:03 +0000844 def end_boolean(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000845 if data == "0":
846 self.append(False)
847 elif data == "1":
848 self.append(True)
849 else:
850 raise TypeError, "bad boolean value"
851 self._value = 0
852 dispatch["boolean"] = end_boolean
853
Fredrik Lundh1538c232001-10-01 19:42:03 +0000854 def end_int(self, data):
855 self.append(int(data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000856 self._value = 0
857 dispatch["i4"] = end_int
Georg Brandld0b592f2008-05-29 07:45:26 +0000858 dispatch["i8"] = end_int
Fredrik Lundhb9056332001-07-11 17:42:21 +0000859 dispatch["int"] = end_int
860
Fredrik Lundh1538c232001-10-01 19:42:03 +0000861 def end_double(self, data):
862 self.append(float(data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000863 self._value = 0
864 dispatch["double"] = end_double
865
Fredrik Lundh1538c232001-10-01 19:42:03 +0000866 def end_string(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000867 if self._encoding:
868 data = _decode(data, self._encoding)
869 self.append(_stringify(data))
870 self._value = 0
871 dispatch["string"] = end_string
872 dispatch["name"] = end_string # struct keys are always strings
873
874 def end_array(self, data):
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000875 mark = self._marks.pop()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000876 # map arrays to Python lists
877 self._stack[mark:] = [self._stack[mark:]]
878 self._value = 0
879 dispatch["array"] = end_array
880
881 def end_struct(self, data):
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000882 mark = self._marks.pop()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000883 # map structs to Python dictionaries
884 dict = {}
885 items = self._stack[mark:]
886 for i in range(0, len(items), 2):
887 dict[_stringify(items[i])] = items[i+1]
888 self._stack[mark:] = [dict]
889 self._value = 0
890 dispatch["struct"] = end_struct
891
Fredrik Lundh1538c232001-10-01 19:42:03 +0000892 def end_base64(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000893 value = Binary()
Fredrik Lundh1538c232001-10-01 19:42:03 +0000894 value.decode(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000895 self.append(value)
896 self._value = 0
897 dispatch["base64"] = end_base64
898
Fredrik Lundh1538c232001-10-01 19:42:03 +0000899 def end_dateTime(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000900 value = DateTime()
Fredrik Lundh1538c232001-10-01 19:42:03 +0000901 value.decode(data)
Skip Montanaro174dd222005-05-14 20:54:16 +0000902 if self._use_datetime:
903 value = _datetime_type(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000904 self.append(value)
905 dispatch["dateTime.iso8601"] = end_dateTime
906
907 def end_value(self, data):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000908 # if we stumble upon a value element with no internal
Fredrik Lundhb9056332001-07-11 17:42:21 +0000909 # elements, treat it as a string element
910 if self._value:
911 self.end_string(data)
912 dispatch["value"] = end_value
913
914 def end_params(self, data):
915 self._type = "params"
916 dispatch["params"] = end_params
917
918 def end_fault(self, data):
919 self._type = "fault"
920 dispatch["fault"] = end_fault
921
Fredrik Lundh1538c232001-10-01 19:42:03 +0000922 def end_methodName(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000923 if self._encoding:
924 data = _decode(data, self._encoding)
925 self._methodname = data
926 self._type = "methodName" # no params
927 dispatch["methodName"] = end_methodName
928
Martin v. Löwis45394c22003-10-31 13:49:36 +0000929## Multicall support
930#
Fredrik Lundhb9056332001-07-11 17:42:21 +0000931
Martin v. Löwis45394c22003-10-31 13:49:36 +0000932class _MultiCallMethod:
933 # some lesser magic to store calls made to a MultiCall object
934 # for batch execution
935 def __init__(self, call_list, name):
936 self.__call_list = call_list
937 self.__name = name
938 def __getattr__(self, name):
939 return _MultiCallMethod(self.__call_list, "%s.%s" % (self.__name, name))
940 def __call__(self, *args):
941 self.__call_list.append((self.__name, args))
942
Martin v. Löwis12237b32004-08-22 16:04:50 +0000943class MultiCallIterator:
Martin v. Löwis45394c22003-10-31 13:49:36 +0000944 """Iterates over the results of a multicall. Exceptions are
945 thrown in response to xmlrpc faults."""
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000946
Martin v. Löwis12237b32004-08-22 16:04:50 +0000947 def __init__(self, results):
948 self.results = results
949
950 def __getitem__(self, i):
951 item = self.results[i]
952 if type(item) == type({}):
953 raise Fault(item['faultCode'], item['faultString'])
954 elif type(item) == type([]):
955 return item[0]
Martin v. Löwis45394c22003-10-31 13:49:36 +0000956 else:
957 raise ValueError,\
958 "unexpected type in multicall result"
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000959
Martin v. Löwis45394c22003-10-31 13:49:36 +0000960class MultiCall:
961 """server -> a object used to boxcar method calls
962
963 server should be a ServerProxy object.
964
965 Methods can be added to the MultiCall using normal
966 method call syntax e.g.:
967
968 multicall = MultiCall(server_proxy)
969 multicall.add(2,3)
970 multicall.get_address("Guido")
971
972 To execute the multicall, call the MultiCall object e.g.:
973
974 add_result, address = multicall()
975 """
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000976
Martin v. Löwis45394c22003-10-31 13:49:36 +0000977 def __init__(self, server):
978 self.__server = server
979 self.__call_list = []
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000980
Martin v. Löwis45394c22003-10-31 13:49:36 +0000981 def __repr__(self):
982 return "<MultiCall at %x>" % id(self)
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000983
Martin v. Löwis45394c22003-10-31 13:49:36 +0000984 __str__ = __repr__
985
986 def __getattr__(self, name):
987 return _MultiCallMethod(self.__call_list, name)
988
989 def __call__(self):
990 marshalled_list = []
991 for name, args in self.__call_list:
992 marshalled_list.append({'methodName' : name, 'params' : args})
993
994 return MultiCallIterator(self.__server.system.multicall(marshalled_list))
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000995
Fredrik Lundhb9056332001-07-11 17:42:21 +0000996# --------------------------------------------------------------------
997# convenience functions
998
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000999##
1000# Create a parser object, and connect it to an unmarshalling instance.
1001# This function picks the fastest available XML parser.
1002#
1003# return A (parser, unmarshaller) tuple.
1004
Skip Montanaro174dd222005-05-14 20:54:16 +00001005def getparser(use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001006 """getparser() -> parser, unmarshaller
1007
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +00001008 Create an instance of the fastest available parser, and attach it
1009 to an unmarshalling object. Return both objects.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001010 """
Skip Montanaro174dd222005-05-14 20:54:16 +00001011 if use_datetime and not datetime:
1012 raise ValueError, "the datetime module is not available"
Fredrik Lundhb9056332001-07-11 17:42:21 +00001013 if FastParser and FastUnmarshaller:
Skip Montanaro174dd222005-05-14 20:54:16 +00001014 if use_datetime:
1015 mkdatetime = _datetime_type
1016 else:
1017 mkdatetime = _datetime
1018 target = FastUnmarshaller(True, False, _binary, mkdatetime, Fault)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001019 parser = FastParser(target)
1020 else:
Skip Montanaro174dd222005-05-14 20:54:16 +00001021 target = Unmarshaller(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001022 if FastParser:
1023 parser = FastParser(target)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001024 elif ExpatParser:
1025 parser = ExpatParser(target)
1026 else:
1027 parser = SlowParser(target)
1028 return parser, target
1029
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001030##
1031# Convert a Python tuple or a Fault instance to an XML-RPC packet.
1032#
1033# @def dumps(params, **options)
1034# @param params A tuple or Fault instance.
1035# @keyparam methodname If given, create a methodCall request for
1036# this method name.
1037# @keyparam methodresponse If given, create a methodResponse packet.
1038# If used with a tuple, the tuple must be a singleton (that is,
1039# it must contain exactly one element).
1040# @keyparam encoding The packet encoding.
1041# @return A string containing marshalled data.
1042
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001043def dumps(params, methodname=None, methodresponse=None, encoding=None,
1044 allow_none=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001045 """data [,options] -> marshalled data
1046
1047 Convert an argument tuple or a Fault instance to an XML-RPC
1048 request (or response, if the methodresponse option is used).
1049
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +00001050 In addition to the data object, the following options can be given
1051 as keyword arguments:
Fredrik Lundhb9056332001-07-11 17:42:21 +00001052
1053 methodname: the method name for a methodCall packet
1054
1055 methodresponse: true to create a methodResponse packet.
1056 If this option is used with a tuple, the tuple must be
1057 a singleton (i.e. it can contain only one element).
1058
1059 encoding: the packet encoding (default is UTF-8)
1060
1061 All 8-bit strings in the data structure are assumed to use the
1062 packet encoding. Unicode strings are automatically converted,
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +00001063 where necessary.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001064 """
1065
Raymond Hettingerfe59dc12005-02-07 15:28:45 +00001066 assert isinstance(params, TupleType) or isinstance(params, Fault),\
Fredrik Lundhb9056332001-07-11 17:42:21 +00001067 "argument must be tuple or Fault instance"
1068
1069 if isinstance(params, Fault):
1070 methodresponse = 1
Raymond Hettingerfe59dc12005-02-07 15:28:45 +00001071 elif methodresponse and isinstance(params, TupleType):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001072 assert len(params) == 1, "response tuple must be a singleton"
1073
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001074 if not encoding:
Fredrik Lundhb9056332001-07-11 17:42:21 +00001075 encoding = "utf-8"
1076
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001077 if FastMarshaller:
1078 m = FastMarshaller(encoding)
1079 else:
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001080 m = Marshaller(encoding, allow_none)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001081
Fredrik Lundhb9056332001-07-11 17:42:21 +00001082 data = m.dumps(params)
1083
1084 if encoding != "utf-8":
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001085 xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001086 else:
1087 xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
1088
1089 # standard XML-RPC wrappings
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001090 if methodname:
Fredrik Lundhb9056332001-07-11 17:42:21 +00001091 # a method call
Raymond Hettingerfe59dc12005-02-07 15:28:45 +00001092 if not isinstance(methodname, StringType):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001093 methodname = methodname.encode(encoding)
1094 data = (
1095 xmlheader,
1096 "<methodCall>\n"
1097 "<methodName>", methodname, "</methodName>\n",
1098 data,
1099 "</methodCall>\n"
1100 )
1101 elif methodresponse:
1102 # a method response, or a fault structure
1103 data = (
1104 xmlheader,
1105 "<methodResponse>\n",
1106 data,
1107 "</methodResponse>\n"
1108 )
1109 else:
1110 return data # return as is
1111 return string.join(data, "")
1112
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001113##
1114# Convert an XML-RPC packet to a Python object. If the XML-RPC packet
1115# represents a fault condition, this function raises a Fault exception.
1116#
1117# @param data An XML-RPC packet, given as an 8-bit string.
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +00001118# @return A tuple containing the unpacked data, and the method name
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001119# (None if not present).
1120# @see Fault
1121
Skip Montanaro174dd222005-05-14 20:54:16 +00001122def loads(data, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001123 """data -> unmarshalled data, method name
1124
1125 Convert an XML-RPC packet to unmarshalled data plus a method
1126 name (None if not present).
1127
1128 If the XML-RPC packet represents a fault condition, this function
1129 raises a Fault exception.
1130 """
Skip Montanaro174dd222005-05-14 20:54:16 +00001131 p, u = getparser(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001132 p.feed(data)
1133 p.close()
1134 return u.close(), u.getmethodname()
1135
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001136##
1137# Encode a string using the gzip content encoding such as specified by the
1138# Content-Encoding: gzip
1139# in the HTTP header, as described in RFC 1952
1140#
1141# @param data the unencoded data
1142# @return the encoded data
1143
1144def gzip_encode(data):
1145 """data -> gzip encoded data
1146
1147 Encode data using the gzip content encoding as described in RFC 1952
1148 """
1149 f = StringIO.StringIO()
1150 gzf = gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1)
1151 gzf.write(data)
1152 gzf.close()
1153 encoded = f.getvalue()
1154 f.close()
1155 return encoded
1156
1157##
1158# Decode a string using the gzip content encoding such as specified by the
1159# Content-Encoding: gzip
1160# in the HTTP header, as described in RFC 1952
1161#
1162# @param data The encoded data
1163# @return the unencoded data
1164# @raises ValueError if data is not correctly coded.
1165
1166def gzip_decode(data):
1167 """gzip encoded data -> unencoded data
1168
1169 Decode data using the gzip content encoding as described in RFC 1952
1170 """
1171 f = StringIO.StringIO(data)
1172 gzf = gzip.GzipFile(mode="rb", fileobj=f)
1173 try:
1174 decoded = gzf.read()
1175 except IOError:
1176 raise ValueError("invalid data")
1177 f.close()
1178 gzf.close()
1179 return decoded
1180
1181##
1182# Return a decoded file-like object for the gzip encoding
1183# as described in RFC 1952.
1184#
1185# @param response A stream supporting a read() method
1186# @return a file-like object that the decoded data can be read() from
1187
1188class GzipDecodedResponse(gzip.GzipFile):
1189 """a file-like object to decode a response encoded with the gzip
1190 method, as described in RFC 1952.
1191 """
1192 def __init__(self, response):
1193 #response doesn't support tell() and read(), required by
1194 #GzipFile
1195 self.stringio = StringIO.StringIO(response.read())
1196 gzip.GzipFile.__init__(self, mode="rb", fileobj=self.stringio)
1197
1198 def close(self):
1199 gzip.GzipFile.close(self)
1200 self.stringio.close()
1201
Fredrik Lundhb9056332001-07-11 17:42:21 +00001202
1203# --------------------------------------------------------------------
1204# request dispatcher
1205
1206class _Method:
1207 # some magic to bind an XML-RPC method to an RPC server.
1208 # supports "nested" methods (e.g. examples.getStateName)
1209 def __init__(self, send, name):
1210 self.__send = send
1211 self.__name = name
1212 def __getattr__(self, name):
1213 return _Method(self.__send, "%s.%s" % (self.__name, name))
1214 def __call__(self, *args):
1215 return self.__send(self.__name, args)
1216
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001217##
1218# Standard transport class for XML-RPC over HTTP.
1219# <p>
1220# You can create custom transports by subclassing this method, and
1221# overriding selected methods.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001222
1223class Transport:
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001224 """Handles an HTTP transaction to an XML-RPC server."""
Fredrik Lundhb9056332001-07-11 17:42:21 +00001225
1226 # client identifier (may be overridden)
1227 user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__
1228
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001229 #if true, we'll request gzip encoding
1230 accept_gzip_encoding = True
1231
1232 # if positive, encode request using gzip if it exceeds this threshold
1233 # note that many server will get confused, so only use it if you know
1234 # that they can decode such a request
1235 encode_threshold = None #None = don't encode
1236
Skip Montanaro174dd222005-05-14 20:54:16 +00001237 def __init__(self, use_datetime=0):
1238 self._use_datetime = use_datetime
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001239 self._connection = (None, None)
1240 self._extra_headers = []
1241 ##
1242 # Send a complete request, and parse the response.
1243 # Retry request if a cached connection has disconnected.
1244 #
1245 # @param host Target host.
1246 # @param handler Target PRC handler.
1247 # @param request_body XML-RPC request body.
1248 # @param verbose Debugging flag.
1249 # @return Parsed response.
1250
1251 def request(self, host, handler, request_body, verbose=0):
1252 #retry request once if cached connection has gone cold
1253 for i in (0, 1):
1254 try:
1255 return self.single_request(host, handler, request_body, verbose)
1256 except (socket.error, httplib.HTTPException), e:
1257 retry = (errno.ECONNRESET,
1258 errno.ECONNABORTED,
1259 httplib.BadStatusLine) #close after we sent request
1260 if i or e[0] not in retry:
1261 raise
Skip Montanaro174dd222005-05-14 20:54:16 +00001262
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001263 ##
1264 # Send a complete request, and parse the response.
1265 #
1266 # @param host Target host.
1267 # @param handler Target PRC handler.
1268 # @param request_body XML-RPC request body.
1269 # @param verbose Debugging flag.
1270 # @return Parsed response.
1271
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001272 def single_request(self, host, handler, request_body, verbose=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001273 # issue XML-RPC request
1274
1275 h = self.make_connection(host)
1276 if verbose:
1277 h.set_debuglevel(1)
1278
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001279 try:
1280 self.send_request(h, handler, request_body)
1281 self.send_host(h, host)
1282 self.send_user_agent(h)
1283 self.send_content(h, request_body)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001284
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001285 response = h.getresponse(buffering=True)
1286 if response.status == 200:
1287 self.verbose = verbose
1288 return self.parse_response(response)
1289 except Fault:
1290 raise
1291 except Exception:
1292 # All unexpected errors leave connection in
1293 # a strange state, so we clear it.
1294 self.close()
1295 raise
Fredrik Lundhb9056332001-07-11 17:42:21 +00001296
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001297 #discard any response data and raise exception
1298 if (response.getheader("content-length", 0)):
1299 response.read()
1300 raise ProtocolError(
1301 host + handler,
1302 response.status, response.reason,
1303 response.msg,
1304 )
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001305
1306 ##
1307 # Create parser.
1308 #
1309 # @return A 2-tuple containing a parser and a unmarshaller.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001310
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001311 def getparser(self):
1312 # get parser and unmarshaller
Skip Montanaro174dd222005-05-14 20:54:16 +00001313 return getparser(use_datetime=self._use_datetime)
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001314
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001315 ##
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001316 # Get authorization info from host parameter
1317 # Host may be a string, or a (host, x509-dict) tuple; if a string,
1318 # it is checked for a "user:pw@host" format, and a "Basic
1319 # Authentication" header is added if appropriate.
1320 #
1321 # @param host Host descriptor (URL or (URL, x509 info) tuple).
1322 # @return A 3-tuple containing (actual host, extra headers,
1323 # x509 info). The header and x509 fields may be None.
1324
1325 def get_host_info(self, host):
1326
1327 x509 = {}
Raymond Hettingerfe59dc12005-02-07 15:28:45 +00001328 if isinstance(host, TupleType):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001329 host, x509 = host
1330
1331 import urllib
1332 auth, host = urllib.splituser(host)
1333
1334 if auth:
1335 import base64
Fredrik Lundh768c98b2002-11-01 17:14:16 +00001336 auth = base64.encodestring(urllib.unquote(auth))
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001337 auth = string.join(string.split(auth), "") # get rid of whitespace
1338 extra_headers = [
1339 ("Authorization", "Basic " + auth)
1340 ]
1341 else:
1342 extra_headers = None
1343
1344 return host, extra_headers, x509
1345
1346 ##
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001347 # Connect to server.
1348 #
1349 # @param host Target host.
1350 # @return A connection handle.
1351
Fredrik Lundhb9056332001-07-11 17:42:21 +00001352 def make_connection(self, host):
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001353 #return an existing connection if possible. This allows
1354 #HTTP/1.1 keep-alive.
1355 if self._connection and host == self._connection[0]:
1356 return self._connection[1]
1357
Fredrik Lundhb9056332001-07-11 17:42:21 +00001358 # create a HTTP connection object from a host descriptor
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001359 chost, self._extra_headers, x509 = self.get_host_info(host)
1360 #store the host argument along with the connection object
1361 self._connection = host, httplib.HTTPConnection(chost)
1362 return self._connection[1]
1363
1364 ##
1365 # Clear any cached connection object.
1366 # Used in the event of socket errors.
1367 #
1368 def close(self):
1369 if self._connection[1]:
1370 self._connection[1].close()
1371 self._connection = (None, None)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001372
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001373 ##
1374 # Send request header.
1375 #
1376 # @param connection Connection handle.
1377 # @param handler Target RPC handler.
1378 # @param request_body XML-RPC body.
1379
Fredrik Lundhb9056332001-07-11 17:42:21 +00001380 def send_request(self, connection, handler, request_body):
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001381 if (self.accept_gzip_encoding):
1382 connection.putrequest("POST", handler, skip_accept_encoding=True)
1383 connection.putheader("Accept-Encoding", "gzip")
1384 else:
1385 connection.putrequest("POST", handler)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001386
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001387 ##
1388 # Send host name.
1389 #
1390 # @param connection Connection handle.
1391 # @param host Host name.
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001392 #
1393 # Note: This function doesn't actually add the "Host"
1394 # header anymore, it is done as part of the connection.putrequest() in
1395 # send_request() above.
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001396
Fredrik Lundhb9056332001-07-11 17:42:21 +00001397 def send_host(self, connection, host):
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001398 extra_headers = self._extra_headers
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001399 if extra_headers:
Raymond Hettingerfe59dc12005-02-07 15:28:45 +00001400 if isinstance(extra_headers, DictType):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001401 extra_headers = extra_headers.items()
1402 for key, value in extra_headers:
1403 connection.putheader(key, value)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001404
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001405 ##
1406 # Send user-agent identifier.
1407 #
1408 # @param connection Connection handle.
1409
Fredrik Lundhb9056332001-07-11 17:42:21 +00001410 def send_user_agent(self, connection):
1411 connection.putheader("User-Agent", self.user_agent)
1412
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001413 ##
1414 # Send request body.
1415 #
1416 # @param connection Connection handle.
1417 # @param request_body XML-RPC request body.
1418
Fredrik Lundhb9056332001-07-11 17:42:21 +00001419 def send_content(self, connection, request_body):
1420 connection.putheader("Content-Type", "text/xml")
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001421
1422 #optionally encode the request
1423 if (self.encode_threshold is not None and
1424 self.encode_threshold < len(request_body)):
1425 connection.putheader("Content-Encoding", "gzip")
1426 request_body = gzip_encode(request_body)
1427
Fredrik Lundhb9056332001-07-11 17:42:21 +00001428 connection.putheader("Content-Length", str(len(request_body)))
Jeremy Hylton0381f482008-11-29 01:09:35 +00001429 connection.endheaders(request_body)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001430
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001431 ##
1432 # Parse response.
1433 #
1434 # @param file Stream.
1435 # @return Response tuple and target method.
1436
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001437 def parse_response(self, response):
1438 # read response data from httpresponse, and parse it
1439 if response.getheader("Content-Encoding", "") == "gzip":
1440 stream = GzipDecodedResponse(response)
1441 else:
1442 stream = response
Fredrik Lundhb9056332001-07-11 17:42:21 +00001443
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001444 p, u = self.getparser()
Fredrik Lundhb9056332001-07-11 17:42:21 +00001445
1446 while 1:
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001447 data = stream.read(1024)
1448 if not data:
Fredrik Lundhb9056332001-07-11 17:42:21 +00001449 break
1450 if self.verbose:
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001451 print "body:", repr(data)
1452 p.feed(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001453
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001454 if stream is not response:
1455 stream.close()
Fredrik Lundhb9056332001-07-11 17:42:21 +00001456 p.close()
1457
1458 return u.close()
1459
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001460##
1461# Standard transport class for XML-RPC over HTTPS.
1462
Fredrik Lundhb9056332001-07-11 17:42:21 +00001463class SafeTransport(Transport):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001464 """Handles an HTTPS transaction to an XML-RPC server."""
Fredrik Lundhb9056332001-07-11 17:42:21 +00001465
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001466 # FIXME: mostly untested
1467
Fredrik Lundhb9056332001-07-11 17:42:21 +00001468 def make_connection(self, host):
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001469 if self._connection and host == self._connection[0]:
1470 return self._connection[1]
Fredrik Lundhb9056332001-07-11 17:42:21 +00001471 # create a HTTPS connection object from a host descriptor
1472 # host may be a string, or a (host, x509-dict) tuple
Fredrik Lundhb9056332001-07-11 17:42:21 +00001473 try:
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001474 HTTPS = httplib.HTTPSConnection
Fredrik Lundhb9056332001-07-11 17:42:21 +00001475 except AttributeError:
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001476 raise NotImplementedError(
1477 "your version of httplib doesn't support HTTPS"
1478 )
Fredrik Lundhb9056332001-07-11 17:42:21 +00001479 else:
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001480 chost, self._extra_headers, x509 = self.get_host_info(host)
1481 self._connection = host, HTTPSConnection(chost, None, **(x509 or {}))
1482 return self._connection[1]
Fredrik Lundhb9056332001-07-11 17:42:21 +00001483
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001484##
1485# Standard server proxy. This class establishes a virtual connection
1486# to an XML-RPC server.
1487# <p>
1488# This class is available as ServerProxy and Server. New code should
1489# use ServerProxy, to avoid confusion.
1490#
1491# @def ServerProxy(uri, **options)
1492# @param uri The connection point on the server.
1493# @keyparam transport A transport factory, compatible with the
1494# standard transport class.
1495# @keyparam encoding The default encoding used for 8-bit strings
1496# (default is UTF-8).
1497# @keyparam verbose Use a true value to enable debugging output.
1498# (printed to standard output).
1499# @see Transport
1500
Fredrik Lundhb9056332001-07-11 17:42:21 +00001501class ServerProxy:
1502 """uri [,options] -> a logical connection to an XML-RPC server
1503
1504 uri is the connection point on the server, given as
1505 scheme://host/target.
1506
1507 The standard implementation always supports the "http" scheme. If
1508 SSL socket support is available (Python 2.0), it also supports
1509 "https".
1510
1511 If the target part and the slash preceding it are both omitted,
1512 "/RPC2" is assumed.
1513
1514 The following options can be given as keyword arguments:
1515
1516 transport: a transport factory
1517 encoding: the request encoding (default is UTF-8)
1518
1519 All 8-bit strings passed to the server proxy are assumed to use
1520 the given encoding.
1521 """
1522
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001523 def __init__(self, uri, transport=None, encoding=None, verbose=0,
Skip Montanaro174dd222005-05-14 20:54:16 +00001524 allow_none=0, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001525 # establish a "logical" server connection
1526
1527 # get the url
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001528 import urllib
Fredrik Lundhb9056332001-07-11 17:42:21 +00001529 type, uri = urllib.splittype(uri)
1530 if type not in ("http", "https"):
1531 raise IOError, "unsupported XML-RPC protocol"
1532 self.__host, self.__handler = urllib.splithost(uri)
1533 if not self.__handler:
1534 self.__handler = "/RPC2"
1535
1536 if transport is None:
1537 if type == "https":
Skip Montanaro174dd222005-05-14 20:54:16 +00001538 transport = SafeTransport(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001539 else:
Skip Montanaro174dd222005-05-14 20:54:16 +00001540 transport = Transport(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001541 self.__transport = transport
1542
1543 self.__encoding = encoding
1544 self.__verbose = verbose
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001545 self.__allow_none = allow_none
Tim Petersc2659cf2003-05-12 20:19:37 +00001546
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001547 def __close(self):
1548 self.__transport.close()
1549
Fredrik Lundhb9056332001-07-11 17:42:21 +00001550 def __request(self, methodname, params):
1551 # call a method on the remote server
1552
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001553 request = dumps(params, methodname, encoding=self.__encoding,
1554 allow_none=self.__allow_none)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001555
1556 response = self.__transport.request(
1557 self.__host,
1558 self.__handler,
1559 request,
1560 verbose=self.__verbose
1561 )
1562
1563 if len(response) == 1:
1564 response = response[0]
1565
1566 return response
1567
1568 def __repr__(self):
1569 return (
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001570 "<ServerProxy for %s%s>" %
Fredrik Lundhb9056332001-07-11 17:42:21 +00001571 (self.__host, self.__handler)
1572 )
1573
1574 __str__ = __repr__
Raymond Hettingercc523fc2003-11-02 09:47:05 +00001575
Fredrik Lundhb9056332001-07-11 17:42:21 +00001576 def __getattr__(self, name):
1577 # magic method dispatcher
1578 return _Method(self.__request, name)
1579
1580 # note: to call a remote object with an non-standard name, use
1581 # result getattr(server, "strange-python-name")(args)
1582
Kristján Valur Jónssone0078602009-06-28 21:04:17 +00001583 def __call__(self, attr):
1584 """A workaround to get special attributes on the ServerProxy
1585 without interfering with the magic __getattr__
1586 """
1587 if attr == "close":
1588 return self.__close
1589 elif attr == "transport":
1590 return self.__transport
1591 raise AttributeError("Attribute %r not found" % (attr,))
1592
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001593# compatibility
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001594
Fredrik Lundhb9056332001-07-11 17:42:21 +00001595Server = ServerProxy
1596
1597# --------------------------------------------------------------------
1598# test code
1599
1600if __name__ == "__main__":
1601
1602 # simple test program (from the XML-RPC specification)
1603
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001604 # server = ServerProxy("http://localhost:8000") # local server
Martin v. Löwis12237b32004-08-22 16:04:50 +00001605 server = ServerProxy("http://time.xmlrpc.com/RPC2")
Fredrik Lundhb9056332001-07-11 17:42:21 +00001606
1607 print server
1608
1609 try:
Martin v. Löwis12237b32004-08-22 16:04:50 +00001610 print server.currentTime.getCurrentTime()
1611 except Error, v:
1612 print "ERROR", v
1613
1614 multi = MultiCall(server)
1615 multi.currentTime.getCurrentTime()
1616 multi.currentTime.getCurrentTime()
1617 try:
1618 for response in multi():
1619 print response
Fredrik Lundhb9056332001-07-11 17:42:21 +00001620 except Error, v:
1621 print "ERROR", v