183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# XML-RPC CLIENT LIBRARY 383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# $Id$ 483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# an XML-RPC client interface for Python. 683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# the marshalling and response parser code can also be used to 883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# implement XML-RPC servers. 983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Notes: 1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# this version is designed to work with Python 2.1 or newer. 1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# History: 1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 1999-01-14 fl Created 1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 1999-01-15 fl Changed dateTime to use localtime 1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 1999-01-16 fl Added Binary/base64 element, default to RPC2 service 1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 1999-01-19 fl Fixed array data element (from Skip Montanaro) 1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 1999-01-21 fl Fixed dateTime constructor, etc. 1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 1999-02-02 fl Added fault handling, handle empty sequences, etc. 2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 1999-02-10 fl Fixed problem with empty responses (from Skip Montanaro) 2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 1999-06-20 fl Speed improvements, pluggable parsers/transports (0.9.8) 2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2000-11-28 fl Changed boolean to check the truth value of its argument 2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-02-24 fl Added encoding/Unicode/SafeTransport patches 2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-02-26 fl Added compare support to wrappers (0.9.9/1.0b1) 2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-03-28 fl Make sure response tuple is a singleton 2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-03-29 fl Don't require empty params element (from Nicholas Riley) 2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-06-10 fl Folded in _xmlrpclib accelerator support (1.0b2) 2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-08-20 fl Base xmlrpclib.Error on built-in Exception (from Paul Prescod) 2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-09-03 fl Allow Transport subclass to override getparser 3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-09-10 fl Lazy import of urllib, cgi, xmllib (20x import speedup) 3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-10-01 fl Remove containers from memo cache when done with them 3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-10-01 fl Use faster escape method (80% dumps speedup) 3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-10-02 fl More dumps microtuning 3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-10-04 fl Make sure import expat gets a parser (from Guido van Rossum) 3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-10-10 sm Allow long ints to be passed as ints if they don't overflow 3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-10-17 sm Test for int and long overflow (allows use on 64-bit systems) 3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2001-11-12 fl Use repr() to marshal doubles (from Paul Felix) 3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2002-03-17 fl Avoid buffered read when possible (from James Rucker) 3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2002-04-07 fl Added pythondoc comments 4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2002-04-16 fl Added __str__ methods to datetime/binary wrappers 4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2002-05-15 fl Added error constants (from Andrew Kuchling) 4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2002-06-27 fl Merged with Python CVS version 4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2002-10-22 fl Added basic authentication (based on code from Phillip Eby) 4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2003-01-22 sm Add support for the bool type 4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2003-02-27 gvr Remove apply calls 4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2003-04-24 sm Use cStringIO if available 4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2003-04-25 ak Add support for nil 4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2003-06-15 gn Add support for time.struct_time 4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2003-07-12 gp Correct marshalling of Faults 5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2003-10-31 mvl Add multicall support 5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2004-08-20 mvl Bump minimum supported Python version to 2.1 5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Copyright (c) 1999-2002 by Secret Labs AB. 5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Copyright (c) 1999-2002 by Fredrik Lundh. 5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# info@pythonware.com 5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# http://www.pythonware.com 5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# The XML-RPC client interface is 6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Copyright (c) 1999-2002 by Secret Labs AB 6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Copyright (c) 1999-2002 by Fredrik Lundh 6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# By obtaining, using, and/or copying this software and/or its 6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# associated documentation, you agree that you have read, understood, 6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# and will comply with the following terms and conditions: 6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Permission to use, copy, modify, and distribute this software and 7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# its associated documentation for any purpose and without fee is 7183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# hereby granted, provided that the above copyright notice appears in 7283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# all copies, and that both that copyright notice and this permission 7383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# notice appear in supporting documentation, and that the name of 7483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Secret Labs AB or the author not be used in advertising or publicity 7583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# pertaining to distribution of the software without specific, written 7683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# prior permission. 7783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 7883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD 7983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- 8083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR 8183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 8283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 8383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 8483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 8583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# OF THIS SOFTWARE. 8683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 8783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 8883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 8983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# things to look into some day: 9083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 9183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# TODO: sort out True/False/boolean issues for Python 2.3 9283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 9383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh""" 9483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehAn XML-RPC client interface for Python. 9583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 9683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehThe marshalling and response parser code can also be used to 9783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimplement XML-RPC servers. 9883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 9983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehExported exceptions: 10083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Error Base class for client errors 10283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ProtocolError Indicates an HTTP protocol error 10383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ResponseError Indicates a broken response package 10483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Fault Indicates an XML-RPC fault package 10583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehExported classes: 10783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 10883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ServerProxy Represents a logical connection to an XML-RPC server 10983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh MultiCall Executor of boxcared xmlrpc requests 11183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Boolean boolean wrapper to generate a "boolean" XML-RPC value 11283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh DateTime dateTime wrapper for an ISO 8601 string or time tuple or 11383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh localtime integer value to generate a "dateTime.iso8601" 11483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh XML-RPC value 11583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Binary binary data wrapper 11683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 11783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh SlowParser Slow but safe standard parser (based on xmllib) 11883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Marshaller Generate an XML-RPC params chunk from a Python data structure 11983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Unmarshaller Unmarshal an XML-RPC response from incoming XML event message 12083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Transport Handles an HTTP transaction to an XML-RPC server 12183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh SafeTransport Handles an HTTPS transaction to an XML-RPC server 12283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehExported constants: 12483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh True 12683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh False 12783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 12883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehExported functions: 12983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 13083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh boolean Convert any Python value to an XML-RPC boolean 13183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh getparser Create instance of the fastest available parser & attach 13283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh to an unmarshalling object 13383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dumps Convert an argument tuple or a Fault instance to an XML-RPC 13483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh request (or response, if the methodresponse option is used). 13583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh loads Convert an XML-RPC packet to unmarshalled data plus a method 13683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh name (None if not present). 13783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh""" 13883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 13983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport re, string, time, operator 14083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 14183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom types import * 14283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport socket 14383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport errno 14483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport httplib 14583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehtry: 14683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import gzip 14783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehexcept ImportError: 14883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh gzip = None #python can be built without zlib/gzip support 14983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 15083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 15183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Internal stuff 15283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 15383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehtry: 15483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh unicode 15583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehexcept NameError: 15683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh unicode = None # unicode support not available 15783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 15883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehtry: 15983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import datetime 16083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehexcept ImportError: 16183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh datetime = None 16283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 16383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehtry: 16483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh _bool_is_builtin = False.__class__.__name__ == "bool" 16583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehexcept NameError: 16683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh _bool_is_builtin = 0 16783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 16883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search): 16983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # decode non-ascii string (if possible) 17083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if unicode and encoding and is8bit(data): 17183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data = unicode(data, encoding) 17283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return data 17383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 17483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef escape(s, replace=string.replace): 17583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s = replace(s, "&", "&") 17683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s = replace(s, "<", "<") 17783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return replace(s, ">", ">",) 17883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 17983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehif unicode: 18083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _stringify(string): 18183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # convert to 7-bit ascii if possible 18283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 18383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return string.encode("ascii") 18483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except UnicodeError: 18583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return string 18683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehelse: 18783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def _stringify(string): 18883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return string 18983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh__version__ = "1.0.1" 19183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# xmlrpc integer limits 19383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehMAXINT = 2L**31-1 19483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehMININT = -2L**31 19583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 19683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 19783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Error constants (from Dan Libby's specification at 19883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php) 19983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 20083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Ranges of errors 20183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehPARSE_ERROR = -32700 20283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehSERVER_ERROR = -32600 20383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehAPPLICATION_ERROR = -32500 20483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehSYSTEM_ERROR = -32400 20583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehTRANSPORT_ERROR = -32300 20683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 20783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Specific errors 20883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehNOT_WELLFORMED_ERROR = -32700 20983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehUNSUPPORTED_ENCODING = -32701 21083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehINVALID_ENCODING_CHAR = -32702 21183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehINVALID_XMLRPC = -32600 21283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehMETHOD_NOT_FOUND = -32601 21383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehINVALID_METHOD_PARAMS = -32602 21483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehINTERNAL_ERROR = -32603 21583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 21783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Exceptions 21883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 21983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 22083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Base class for all kinds of client-side errors. 22183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass Error(Exception): 22383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Base class for client errors.""" 22483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __str__(self): 22583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return repr(self) 22683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 22783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 22883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Indicates an HTTP-level protocol error. This is raised by the HTTP 22983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# transport layer, if the server returns an error code other than 200 23083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# (OK). 23183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 23283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param url The target URL. 23383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param errcode The HTTP error code. 23483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param errmsg The HTTP error message. 23583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param headers The HTTP header dictionary. 23683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 23783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass ProtocolError(Error): 23883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Indicates an HTTP protocol error.""" 23983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, url, errcode, errmsg, headers): 24083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Error.__init__(self) 24183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.url = url 24283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.errcode = errcode 24383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.errmsg = errmsg 24483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.headers = headers 24583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 24683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return ( 24783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "<ProtocolError for %s: %s %s>" % 24883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (self.url, self.errcode, self.errmsg) 24983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ) 25083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 25183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 25283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Indicates a broken XML-RPC response package. This exception is 25383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# raised by the unmarshalling layer, if the XML-RPC response is 25483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# malformed. 25583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 25683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass ResponseError(Error): 25783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Indicates a broken response package.""" 25883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pass 25983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 26083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 26183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Indicates an XML-RPC fault response package. This exception is 26283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# raised by the unmarshalling layer, if the XML-RPC response contains 26383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# a fault string. This exception can also used as a class, to 26483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# generate a fault XML-RPC message. 26583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 26683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param faultCode The XML-RPC fault code. 26783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param faultString The XML-RPC fault string. 26883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 26983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass Fault(Error): 27083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Indicates an XML-RPC fault package.""" 27183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, faultCode, faultString, **extra): 27283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Error.__init__(self) 27383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.faultCode = faultCode 27483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.faultString = faultString 27583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 27683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return ( 27783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "<Fault %s: %s>" % 27883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (self.faultCode, repr(self.faultString)) 27983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ) 28083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 28183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 28283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Special values 28383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 28483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 28583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Wrapper for XML-RPC boolean values. Use the xmlrpclib.True and 28683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# xmlrpclib.False constants, or the xmlrpclib.boolean() function, to 28783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# generate boolean XML-RPC values. 28883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 28983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param value A boolean value. Any true value is interpreted as True, 29083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# all other values are interpreted as False. 29183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 29283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom sys import modules 29383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehmod_dict = modules[__name__].__dict__ 29483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehif _bool_is_builtin: 29583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh boolean = Boolean = bool 29683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # to avoid breaking code which references xmlrpclib.{True,False} 29783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh mod_dict['True'] = True 29883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh mod_dict['False'] = False 29983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehelse: 30083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh class Boolean: 30183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Boolean-value wrapper. 30283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 30383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Use True or False to generate a "boolean" XML-RPC value. 30483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 30583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 30683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, value = 0): 30783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.value = operator.truth(value) 30883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 30983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def encode(self, out): 31083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh out.write("<value><boolean>%d</boolean></value>\n" % self.value) 31183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 31283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __cmp__(self, other): 31383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(other, Boolean): 31483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh other = other.value 31583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return cmp(self.value, other) 31683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 31783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 31883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.value: 31983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "<Boolean True at %x>" % id(self) 32083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 32183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "<Boolean False at %x>" % id(self) 32283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 32383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __int__(self): 32483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.value 32583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 32683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __nonzero__(self): 32783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.value 32883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 32983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh mod_dict['True'] = Boolean(1) 33083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh mod_dict['False'] = Boolean(0) 33183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 33283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 33383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Map true or false value to XML-RPC boolean values. 33483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 33583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @def boolean(value) 33683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param value A boolean value. Any true value is mapped to True, 33783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # all other values are mapped to False. 33883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @return xmlrpclib.True or xmlrpclib.False. 33983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @see Boolean 34083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @see True 34183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @see False 34283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 34383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def boolean(value, _truefalse=(False, True)): 34483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Convert any Python value to XML-RPC 'boolean'.""" 34583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return _truefalse[operator.truth(value)] 34683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 34783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdel modules, mod_dict 34883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 34983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 35083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Wrapper for XML-RPC DateTime values. This converts a time value to 35183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# the format used by XML-RPC. 35283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# <p> 35383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# The value can be given as a string in the format 35483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by 35583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# time.localtime()), or an integer value (as returned by time.time()). 35683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# The wrapper uses time.localtime() to convert an integer to a time 35783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# tuple. 35883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 35983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param value The time, given as an ISO 8601 string, a time 36083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# tuple, or a integer time value. 36183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 36283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef _strftime(value): 36383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if datetime: 36483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(value, datetime.datetime): 36583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "%04d%02d%02dT%02d:%02d:%02d" % ( 36683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value.year, value.month, value.day, 36783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value.hour, value.minute, value.second) 36883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 36983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not isinstance(value, (TupleType, time.struct_time)): 37083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if value == 0: 37183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = time.time() 37283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = time.localtime(value) 37383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 37483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "%04d%02d%02dT%02d:%02d:%02d" % value[:6] 37583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 37683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass DateTime: 37783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """DateTime wrapper for an ISO 8601 string or time tuple or 37883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh localtime integer value to generate 'dateTime.iso8601' XML-RPC 37983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value. 38083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 38183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 38283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, value=0): 38383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(value, StringType): 38483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.value = value 38583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 38683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.value = _strftime(value) 38783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 38883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def make_comparable(self, other): 38983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(other, DateTime): 39083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s = self.value 39183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = other.value 39283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh elif datetime and isinstance(other, datetime.datetime): 39383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s = self.value 39483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = other.strftime("%Y%m%dT%H:%M:%S") 39583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh elif isinstance(other, (str, unicode)): 39683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s = self.value 39783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = other 39883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh elif hasattr(other, "timetuple"): 39983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s = self.timetuple() 40083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh o = other.timetuple() 40183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 40283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh otype = (hasattr(other, "__class__") 40383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh and other.__class__.__name__ 40483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh or type(other)) 40583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise TypeError("Can't compare %s and %s" % 40683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (self.__class__.__name__, otype)) 40783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s, o 40883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 40983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __lt__(self, other): 41083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s, o = self.make_comparable(other) 41183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s < o 41283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 41383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __le__(self, other): 41483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s, o = self.make_comparable(other) 41583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s <= o 41683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 41783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __gt__(self, other): 41883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s, o = self.make_comparable(other) 41983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s > o 42083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 42183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __ge__(self, other): 42283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s, o = self.make_comparable(other) 42383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s >= o 42483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 42583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __eq__(self, other): 42683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s, o = self.make_comparable(other) 42783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s == o 42883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 42983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __ne__(self, other): 43083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s, o = self.make_comparable(other) 43183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return s != o 43283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 43383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def timetuple(self): 43483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return time.strptime(self.value, "%Y%m%dT%H:%M:%S") 43583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 43683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __cmp__(self, other): 43783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh s, o = self.make_comparable(other) 43883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return cmp(s, o) 43983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 44083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 44183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Get date/time value. 44283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 44383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @return Date/time value, as an ISO 8601 string. 44483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 44583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __str__(self): 44683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.value 44783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 44883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 44983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "<DateTime %s at %x>" % (repr(self.value), id(self)) 45083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 45183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def decode(self, data): 45283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data = str(data) 45383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.value = string.strip(data) 45483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 45583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def encode(self, out): 45683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh out.write("<value><dateTime.iso8601>") 45783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh out.write(self.value) 45883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh out.write("</dateTime.iso8601></value>\n") 45983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 46083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef _datetime(data): 46183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # decode xml element contents into a DateTime structure. 46283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = DateTime() 46383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value.decode(data) 46483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return value 46583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 46683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef _datetime_type(data): 46783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh t = time.strptime(data, "%Y%m%dT%H:%M:%S") 46883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return datetime.datetime(*tuple(t)[:6]) 46983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 47083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 47183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Wrapper for binary data. This can be used to transport any kind 47283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# of binary data over XML-RPC, using BASE64 encoding. 47383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 47483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param data An 8-bit string containing arbitrary data. 47583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 47683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport base64 47783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehtry: 47883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import cStringIO as StringIO 47983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehexcept ImportError: 48083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import StringIO 48183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 48283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass Binary: 48383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Wrapper for binary data.""" 48483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 48583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, data=None): 48683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.data = data 48783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 48883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 48983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Get buffer contents. 49083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 49183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @return Buffer contents, as an 8-bit string. 49283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 49383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __str__(self): 49483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.data or "" 49583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 49683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __cmp__(self, other): 49783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(other, Binary): 49883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh other = other.data 49983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return cmp(self.data, other) 50083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 50183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def decode(self, data): 50283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.data = base64.decodestring(data) 50383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 50483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def encode(self, out): 50583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh out.write("<value><base64>\n") 50683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh base64.encode(StringIO.StringIO(self.data), out) 50783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh out.write("</base64></value>\n") 50883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 50983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef _binary(data): 51083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # decode xml element contents into a Binary structure 51183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = Binary() 51283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value.decode(data) 51383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return value 51483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 51583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehWRAPPERS = (DateTime, Binary) 51683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehif not _bool_is_builtin: 51783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh WRAPPERS = WRAPPERS + (Boolean,) 51883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 51983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 52083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# XML parsers 52183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 52283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehtry: 52383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # optional xmlrpclib accelerator 52483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import _xmlrpclib 52583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh FastParser = _xmlrpclib.Parser 52683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh FastUnmarshaller = _xmlrpclib.Unmarshaller 52783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehexcept (AttributeError, ImportError): 52883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh FastParser = FastUnmarshaller = None 52983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 53083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehtry: 53183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import _xmlrpclib 53283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh FastMarshaller = _xmlrpclib.Marshaller 53383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehexcept (AttributeError, ImportError): 53483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh FastMarshaller = None 53583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 53683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehtry: 53783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh from xml.parsers import expat 53883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not hasattr(expat, "ParserCreate"): 53983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise ImportError 54083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehexcept ImportError: 54183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ExpatParser = None # expat not available 54283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehelse: 54383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh class ExpatParser: 54483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # fast expat parser for Python 2.0 and later. 54583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, target): 54683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._parser = parser = expat.ParserCreate(None, None) 54783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._target = target 54883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh parser.StartElementHandler = target.start 54983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh parser.EndElementHandler = target.end 55083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh parser.CharacterDataHandler = target.data 55183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh encoding = None 55283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not parser.returns_unicode: 55383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh encoding = "utf-8" 55483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh target.xml(encoding, None) 55583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 55683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def feed(self, data): 55783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._parser.Parse(data, 0) 55883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 55983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def close(self): 56083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._parser.Parse("", 1) # end of data 56183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh del self._target, self._parser # get rid of circular references 56283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 56383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass SlowParser: 56483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Default XML parser (based on xmllib.XMLParser).""" 56583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # this is the slowest parser. 56683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, target): 56783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import xmllib # lazy subclassing (!) 56883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if xmllib.XMLParser not in SlowParser.__bases__: 56983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh SlowParser.__bases__ = (xmllib.XMLParser,) 57083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.handle_xml = target.xml 57183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.unknown_starttag = target.start 57283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.handle_data = target.data 57383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.handle_cdata = target.data 57483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.unknown_endtag = target.end 57583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 57683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh xmllib.XMLParser.__init__(self, accept_utf8=1) 57783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except TypeError: 57883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh xmllib.XMLParser.__init__(self) # pre-2.0 57983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 58083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 58183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# XML-RPC marshalling and unmarshalling code 58283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 58383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 58483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# XML-RPC marshaller. 58583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 58683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param encoding Default encoding for 8-bit strings. The default 58783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# value is None (interpreted as UTF-8). 58883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @see dumps 58983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 59083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass Marshaller: 59183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Generate an XML-RPC params chunk from a Python data structure. 59283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 59383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Create a Marshaller instance for each set of parameters, and use 59483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh the "dumps" method to convert your data (represented as a tuple) 59583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh to an XML-RPC params chunk. To write a fault response, pass a 59683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Fault instance instead. You may prefer to use the "dumps" module 59783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh function for this purpose. 59883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 59983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 60083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # by the way, if you don't understand what's going on in here, 60183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # that's perfectly ok. 60283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 60383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, encoding=None, allow_none=0): 60483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.memo = {} 60583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.data = None 60683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.encoding = encoding 60783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.allow_none = allow_none 60883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 60983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch = {} 61083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 61183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dumps(self, values): 61283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh out = [] 61383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write = out.append 61483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dump = self.__dump 61583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(values, Fault): 61683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # fault instance 61783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<fault>\n") 61883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dump({'faultCode': values.faultCode, 61983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 'faultString': values.faultString}, 62083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write) 62183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</fault>\n") 62283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 62383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # parameter block 62483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # FIXME: the xml-rpc specification allows us to leave out 62583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # the entire <params> block if there are no parameters. 62683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # however, changing this may break older code (including 62783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # old versions of xmlrpclib.py), so this is better left as 62883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # is for now. See @XMLRPC3 for more information. /F 62983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<params>\n") 63083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for v in values: 63183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<param>\n") 63283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dump(v, write) 63383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</param>\n") 63483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</params>\n") 63583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh result = string.join(out, "") 63683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return result 63783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 63883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __dump(self, value, write): 63983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 64083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = self.dispatch[type(value)] 64183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except KeyError: 64283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # check if this object can be marshalled as a structure 64383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 64483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value.__dict__ 64583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except: 64683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise TypeError, "cannot marshal %s objects" % type(value) 64783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # check if this class is a sub-class of a basic type, 64883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # because we don't know how to marshal these types 64983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # (e.g. a string sub-class) 65083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for type_ in type(value).__mro__: 65183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if type_ in self.dispatch.keys(): 65283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise TypeError, "cannot marshal %s objects" % type(value) 65383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = self.dispatch[InstanceType] 65483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f(self, value, write) 65583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 65683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_nil (self, value, write): 65783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not self.allow_none: 65883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise TypeError, "cannot marshal None unless allow_none is enabled" 65983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<value><nil/></value>") 66083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[NoneType] = dump_nil 66183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 66283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_int(self, value, write): 66383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # in case ints are > 32 bits 66483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if value > MAXINT or value < MININT: 66583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise OverflowError, "int exceeds XML-RPC limits" 66683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<value><int>") 66783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write(str(value)) 66883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</int></value>\n") 66983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[IntType] = dump_int 67083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 67183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if _bool_is_builtin: 67283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_bool(self, value, write): 67383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<value><boolean>") 67483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write(value and "1" or "0") 67583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</boolean></value>\n") 67683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[bool] = dump_bool 67783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 67883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_long(self, value, write): 67983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if value > MAXINT or value < MININT: 68083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise OverflowError, "long int exceeds XML-RPC limits" 68183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<value><int>") 68283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write(str(int(value))) 68383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</int></value>\n") 68483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[LongType] = dump_long 68583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 68683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_double(self, value, write): 68783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<value><double>") 68883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write(repr(value)) 68983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</double></value>\n") 69083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[FloatType] = dump_double 69183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 69283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_string(self, value, write, escape=escape): 69383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<value><string>") 69483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write(escape(value)) 69583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</string></value>\n") 69683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[StringType] = dump_string 69783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 69883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if unicode: 69983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_unicode(self, value, write, escape=escape): 70083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = value.encode(self.encoding) 70183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<value><string>") 70283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write(escape(value)) 70383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</string></value>\n") 70483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[UnicodeType] = dump_unicode 70583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 70683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_array(self, value, write): 70783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh i = id(value) 70883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if i in self.memo: 70983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise TypeError, "cannot marshal recursive sequences" 71083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.memo[i] = None 71183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dump = self.__dump 71283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<value><array><data>\n") 71383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for v in value: 71483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dump(v, write) 71583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</data></array></value>\n") 71683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh del self.memo[i] 71783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[TupleType] = dump_array 71883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[ListType] = dump_array 71983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 72083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_struct(self, value, write, escape=escape): 72183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh i = id(value) 72283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if i in self.memo: 72383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise TypeError, "cannot marshal recursive dictionaries" 72483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.memo[i] = None 72583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dump = self.__dump 72683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<value><struct>\n") 72783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for k, v in value.items(): 72883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<member>\n") 72983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if type(k) is not StringType: 73083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if unicode and type(k) is UnicodeType: 73183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh k = k.encode(self.encoding) 73283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 73383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise TypeError, "dictionary key must be string" 73483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<name>%s</name>\n" % escape(k)) 73583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dump(v, write) 73683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</member>\n") 73783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</struct></value>\n") 73883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh del self.memo[i] 73983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[DictType] = dump_struct 74083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 74183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if datetime: 74283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_datetime(self, value, write): 74383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("<value><dateTime.iso8601>") 74483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write(_strftime(value)) 74583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh write("</dateTime.iso8601></value>\n") 74683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[datetime.datetime] = dump_datetime 74783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 74883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def dump_instance(self, value, write): 74983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # check for special wrappers 75083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if value.__class__ in WRAPPERS: 75183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.write = write 75283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value.encode(self) 75383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh del self.write 75483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 75583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # store instance attributes as a struct (really?) 75683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.dump_struct(value.__dict__, write) 75783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch[InstanceType] = dump_instance 75883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 75983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 76083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# XML-RPC unmarshaller. 76183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 76283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @see loads 76383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 76483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass Unmarshaller: 76583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Unmarshal an XML-RPC response, based on incoming XML event 76683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh messages (start, data, end). Call close() to get the resulting 76783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data structure. 76883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 76983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Note that this reader is fairly tolerant, and gladly accepts bogus 77083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh XML-RPC data without complaining (but not bogus XML). 77183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 77283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 77383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # and again, if you don't understand what's going on in here, 77483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # that's perfectly ok. 77583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 77683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, use_datetime=0): 77783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._type = None 77883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._stack = [] 77983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._marks = [] 78083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._data = [] 78183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._methodname = None 78283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._encoding = "utf-8" 78383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.append = self._stack.append 78483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._use_datetime = use_datetime 78583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if use_datetime and not datetime: 78683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise ValueError, "the datetime module is not available" 78783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 78883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def close(self): 78983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # return response tuple and target method 79083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self._type is None or self._marks: 79183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise ResponseError() 79283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self._type == "fault": 79383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise Fault(**self._stack[0]) 79483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return tuple(self._stack) 79583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 79683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def getmethodname(self): 79783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self._methodname 79883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 79983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 80083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # event handlers 80183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 80283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def xml(self, encoding, standalone): 80383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._encoding = encoding 80483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # FIXME: assert standalone == 1 ??? 80583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 80683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def start(self, tag, attrs): 80783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # prepare to handle this element 80883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if tag == "array" or tag == "struct": 80983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._marks.append(len(self._stack)) 81083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._data = [] 81183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._value = (tag == "value") 81283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 81383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def data(self, text): 81483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._data.append(text) 81583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 81683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end(self, tag, join=string.join): 81783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # call the appropriate end tag handler 81883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 81983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = self.dispatch[tag] 82083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except KeyError: 82183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pass # unknown tag ? 82283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 82383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return f(self, join(self._data, "")) 82483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 82583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 82683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # accelerator support 82783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 82883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_dispatch(self, tag, data): 82983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # dispatch data 83083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 83183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = self.dispatch[tag] 83283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except KeyError: 83383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh pass # unknown tag ? 83483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 83583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return f(self, data) 83683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 83783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 83883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # element decoders 83983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 84083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch = {} 84183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 84283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_nil (self, data): 84383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.append(None) 84483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._value = 0 84583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["nil"] = end_nil 84683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 84783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_boolean(self, data): 84883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if data == "0": 84983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.append(False) 85083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh elif data == "1": 85183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.append(True) 85283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 85383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise TypeError, "bad boolean value" 85483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._value = 0 85583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["boolean"] = end_boolean 85683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 85783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_int(self, data): 85883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.append(int(data)) 85983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._value = 0 86083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["i4"] = end_int 86183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["i8"] = end_int 86283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["int"] = end_int 86383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 86483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_double(self, data): 86583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.append(float(data)) 86683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._value = 0 86783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["double"] = end_double 86883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 86983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_string(self, data): 87083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self._encoding: 87183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data = _decode(data, self._encoding) 87283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.append(_stringify(data)) 87383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._value = 0 87483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["string"] = end_string 87583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["name"] = end_string # struct keys are always strings 87683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 87783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_array(self, data): 87883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh mark = self._marks.pop() 87983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # map arrays to Python lists 88083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._stack[mark:] = [self._stack[mark:]] 88183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._value = 0 88283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["array"] = end_array 88383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 88483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_struct(self, data): 88583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh mark = self._marks.pop() 88683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # map structs to Python dictionaries 88783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dict = {} 88883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh items = self._stack[mark:] 88983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for i in range(0, len(items), 2): 89083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dict[_stringify(items[i])] = items[i+1] 89183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._stack[mark:] = [dict] 89283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._value = 0 89383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["struct"] = end_struct 89483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 89583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_base64(self, data): 89683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = Binary() 89783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value.decode(data) 89883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.append(value) 89983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._value = 0 90083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["base64"] = end_base64 90183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 90283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_dateTime(self, data): 90383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = DateTime() 90483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value.decode(data) 90583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self._use_datetime: 90683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh value = _datetime_type(data) 90783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.append(value) 90883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["dateTime.iso8601"] = end_dateTime 90983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 91083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_value(self, data): 91183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # if we stumble upon a value element with no internal 91283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # elements, treat it as a string element 91383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self._value: 91483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.end_string(data) 91583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["value"] = end_value 91683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 91783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_params(self, data): 91883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._type = "params" 91983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["params"] = end_params 92083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 92183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_fault(self, data): 92283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._type = "fault" 92383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["fault"] = end_fault 92483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 92583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def end_methodName(self, data): 92683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self._encoding: 92783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data = _decode(data, self._encoding) 92883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._methodname = data 92983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._type = "methodName" # no params 93083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh dispatch["methodName"] = end_methodName 93183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 93283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## Multicall support 93383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 93483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 93583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass _MultiCallMethod: 93683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # some lesser magic to store calls made to a MultiCall object 93783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # for batch execution 93883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, call_list, name): 93983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__call_list = call_list 94083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__name = name 94183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __getattr__(self, name): 94283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return _MultiCallMethod(self.__call_list, "%s.%s" % (self.__name, name)) 94383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __call__(self, *args): 94483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__call_list.append((self.__name, args)) 94583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 94683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass MultiCallIterator: 94783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Iterates over the results of a multicall. Exceptions are 94883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raised in response to xmlrpc faults.""" 94983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 95083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, results): 95183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.results = results 95283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 95383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __getitem__(self, i): 95483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh item = self.results[i] 95583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if type(item) == type({}): 95683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise Fault(item['faultCode'], item['faultString']) 95783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh elif type(item) == type([]): 95883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return item[0] 95983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 96083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise ValueError,\ 96183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "unexpected type in multicall result" 96283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 96383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass MultiCall: 96483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """server -> a object used to boxcar method calls 96583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 96683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh server should be a ServerProxy object. 96783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 96883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Methods can be added to the MultiCall using normal 96983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh method call syntax e.g.: 97083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 97183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh multicall = MultiCall(server_proxy) 97283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh multicall.add(2,3) 97383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh multicall.get_address("Guido") 97483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 97583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh To execute the multicall, call the MultiCall object e.g.: 97683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 97783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh add_result, address = multicall() 97883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 97983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 98083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, server): 98183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__server = server 98283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__call_list = [] 98383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 98483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 98583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return "<MultiCall at %x>" % id(self) 98683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 98783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh __str__ = __repr__ 98883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 98983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __getattr__(self, name): 99083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return _MultiCallMethod(self.__call_list, name) 99183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 99283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __call__(self): 99383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh marshalled_list = [] 99483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for name, args in self.__call_list: 99583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh marshalled_list.append({'methodName' : name, 'params' : args}) 99683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 99783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return MultiCallIterator(self.__server.system.multicall(marshalled_list)) 99883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 99983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 100083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# convenience functions 100183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 100283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 100383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Create a parser object, and connect it to an unmarshalling instance. 100483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# This function picks the fastest available XML parser. 100583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 100683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# return A (parser, unmarshaller) tuple. 100783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 100883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef getparser(use_datetime=0): 100983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """getparser() -> parser, unmarshaller 101083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 101183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Create an instance of the fastest available parser, and attach it 101283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh to an unmarshalling object. Return both objects. 101383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 101483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if use_datetime and not datetime: 101583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise ValueError, "the datetime module is not available" 101683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if FastParser and FastUnmarshaller: 101783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if use_datetime: 101883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh mkdatetime = _datetime_type 101983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 102083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh mkdatetime = _datetime 102183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh target = FastUnmarshaller(True, False, _binary, mkdatetime, Fault) 102283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh parser = FastParser(target) 102383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 102483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh target = Unmarshaller(use_datetime=use_datetime) 102583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if FastParser: 102683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh parser = FastParser(target) 102783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh elif ExpatParser: 102883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh parser = ExpatParser(target) 102983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 103083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh parser = SlowParser(target) 103183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return parser, target 103283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 103383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 103483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Convert a Python tuple or a Fault instance to an XML-RPC packet. 103583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 103683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @def dumps(params, **options) 103783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param params A tuple or Fault instance. 103883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @keyparam methodname If given, create a methodCall request for 103983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# this method name. 104083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @keyparam methodresponse If given, create a methodResponse packet. 104183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# If used with a tuple, the tuple must be a singleton (that is, 104283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# it must contain exactly one element). 104383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @keyparam encoding The packet encoding. 104483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @return A string containing marshalled data. 104583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 104683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef dumps(params, methodname=None, methodresponse=None, encoding=None, 104783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh allow_none=0): 104883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """data [,options] -> marshalled data 104983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 105083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Convert an argument tuple or a Fault instance to an XML-RPC 105183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh request (or response, if the methodresponse option is used). 105283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 105383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh In addition to the data object, the following options can be given 105483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh as keyword arguments: 105583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 105683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh methodname: the method name for a methodCall packet 105783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 105883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh methodresponse: true to create a methodResponse packet. 105983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If this option is used with a tuple, the tuple must be 106083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh a singleton (i.e. it can contain only one element). 106183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 106283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh encoding: the packet encoding (default is UTF-8) 106383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 106483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh All 8-bit strings in the data structure are assumed to use the 106583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh packet encoding. Unicode strings are automatically converted, 106683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh where necessary. 106783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 106883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 106983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert isinstance(params, TupleType) or isinstance(params, Fault),\ 107083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "argument must be tuple or Fault instance" 107183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 107283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(params, Fault): 107383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh methodresponse = 1 107483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh elif methodresponse and isinstance(params, TupleType): 107583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh assert len(params) == 1, "response tuple must be a singleton" 107683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 107783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not encoding: 107883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh encoding = "utf-8" 107983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 108083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if FastMarshaller: 108183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh m = FastMarshaller(encoding) 108283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 108383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh m = Marshaller(encoding, allow_none) 108483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 108583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data = m.dumps(params) 108683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 108783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if encoding != "utf-8": 108883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding) 108983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 109083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default 109183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 109283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # standard XML-RPC wrappings 109383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if methodname: 109483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # a method call 109583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not isinstance(methodname, StringType): 109683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh methodname = methodname.encode(encoding) 109783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data = ( 109883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh xmlheader, 109983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "<methodCall>\n" 110083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "<methodName>", methodname, "</methodName>\n", 110183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data, 110283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "</methodCall>\n" 110383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ) 110483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh elif methodresponse: 110583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # a method response, or a fault structure 110683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data = ( 110783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh xmlheader, 110883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "<methodResponse>\n", 110983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data, 111083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "</methodResponse>\n" 111183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ) 111283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 111383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return data # return as is 111483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return string.join(data, "") 111583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 111683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 111783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Convert an XML-RPC packet to a Python object. If the XML-RPC packet 111883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# represents a fault condition, this function raises a Fault exception. 111983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 112083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param data An XML-RPC packet, given as an 8-bit string. 112183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @return A tuple containing the unpacked data, and the method name 112283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# (None if not present). 112383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @see Fault 112483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 112583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef loads(data, use_datetime=0): 112683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """data -> unmarshalled data, method name 112783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 112883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Convert an XML-RPC packet to unmarshalled data plus a method 112983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh name (None if not present). 113083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 113183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If the XML-RPC packet represents a fault condition, this function 113283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raises a Fault exception. 113383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 113483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh p, u = getparser(use_datetime=use_datetime) 113583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh p.feed(data) 113683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh p.close() 113783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return u.close(), u.getmethodname() 113883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 113983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 114083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Encode a string using the gzip content encoding such as specified by the 114183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Content-Encoding: gzip 114283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# in the HTTP header, as described in RFC 1952 114383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 114483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param data the unencoded data 114583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @return the encoded data 114683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 114783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef gzip_encode(data): 114883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """data -> gzip encoded data 114983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 115083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Encode data using the gzip content encoding as described in RFC 1952 115183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 115283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not gzip: 115383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise NotImplementedError 115483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = StringIO.StringIO() 115583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh gzf = gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1) 115683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh gzf.write(data) 115783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh gzf.close() 115883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh encoded = f.getvalue() 115983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.close() 116083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return encoded 116183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 116283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 116383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Decode a string using the gzip content encoding such as specified by the 116483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Content-Encoding: gzip 116583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# in the HTTP header, as described in RFC 1952 116683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 116783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param data The encoded data 116883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @return the unencoded data 116983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @raises ValueError if data is not correctly coded. 117083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 117183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef gzip_decode(data): 117283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """gzip encoded data -> unencoded data 117383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 117483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh Decode data using the gzip content encoding as described in RFC 1952 117583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 117683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not gzip: 117783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise NotImplementedError 117883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f = StringIO.StringIO(data) 117983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh gzf = gzip.GzipFile(mode="rb", fileobj=f) 118083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 118183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh decoded = gzf.read() 118283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except IOError: 118383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise ValueError("invalid data") 118483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh f.close() 118583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh gzf.close() 118683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return decoded 118783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 118883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 118983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Return a decoded file-like object for the gzip encoding 119083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# as described in RFC 1952. 119183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 119283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param response A stream supporting a read() method 119383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @return a file-like object that the decoded data can be read() from 119483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 119583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass GzipDecodedResponse(gzip.GzipFile if gzip else object): 119683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """a file-like object to decode a response encoded with the gzip 119783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh method, as described in RFC 1952. 119883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 119983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, response): 120083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh #response doesn't support tell() and read(), required by 120183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh #GzipFile 120283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not gzip: 120383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise NotImplementedError 120483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.stringio = StringIO.StringIO(response.read()) 120583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh gzip.GzipFile.__init__(self, mode="rb", fileobj=self.stringio) 120683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 120783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def close(self): 120883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh gzip.GzipFile.close(self) 120983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.stringio.close() 121083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 121183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 121283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 121383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# request dispatcher 121483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 121583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass _Method: 121683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # some magic to bind an XML-RPC method to an RPC server. 121783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # supports "nested" methods (e.g. examples.getStateName) 121883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, send, name): 121983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__send = send 122083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__name = name 122183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __getattr__(self, name): 122283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return _Method(self.__send, "%s.%s" % (self.__name, name)) 122383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __call__(self, *args): 122483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.__send(self.__name, args) 122583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 122683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 122783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Standard transport class for XML-RPC over HTTP. 122883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# <p> 122983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# You can create custom transports by subclassing this method, and 123083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# overriding selected methods. 123183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 123283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass Transport: 123383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Handles an HTTP transaction to an XML-RPC server.""" 123483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 123583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # client identifier (may be overridden) 123683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__ 123783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 123883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh #if true, we'll request gzip encoding 123983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh accept_gzip_encoding = True 124083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 124183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # if positive, encode request using gzip if it exceeds this threshold 124283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # note that many server will get confused, so only use it if you know 124383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # that they can decode such a request 124483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh encode_threshold = None #None = don't encode 124583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 124683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, use_datetime=0): 124783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._use_datetime = use_datetime 124883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._connection = (None, None) 124983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._extra_headers = [] 125083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 125183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Send a complete request, and parse the response. 125283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Retry request if a cached connection has disconnected. 125383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 125483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param host Target host. 125583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param handler Target PRC handler. 125683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param request_body XML-RPC request body. 125783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param verbose Debugging flag. 125883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @return Parsed response. 125983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 126083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def request(self, host, handler, request_body, verbose=0): 126183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh #retry request once if cached connection has gone cold 126283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for i in (0, 1): 126383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 126483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.single_request(host, handler, request_body, verbose) 126583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except socket.error, e: 126683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE): 126783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise 126883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except httplib.BadStatusLine: #close after we sent request 126983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if i: 127083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise 127183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 127283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 127383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Send a complete request, and parse the response. 127483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 127583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param host Target host. 127683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param handler Target PRC handler. 127783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param request_body XML-RPC request body. 127883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param verbose Debugging flag. 127983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @return Parsed response. 128083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 128183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def single_request(self, host, handler, request_body, verbose=0): 128283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # issue XML-RPC request 128383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 128483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh h = self.make_connection(host) 128583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if verbose: 128683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh h.set_debuglevel(1) 128783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 128883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 128983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.send_request(h, handler, request_body) 129083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.send_host(h, host) 129183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.send_user_agent(h) 129283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.send_content(h, request_body) 129383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 129483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh response = h.getresponse(buffering=True) 129583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if response.status == 200: 129683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.verbose = verbose 129783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.parse_response(response) 129883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except Fault: 129983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise 130083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except Exception: 130183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # All unexpected errors leave connection in 130283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # a strange state, so we clear it. 130383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.close() 130483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise 130583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 130683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh #discard any response data and raise exception 130783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if (response.getheader("content-length", 0)): 130883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh response.read() 130983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise ProtocolError( 131083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh host + handler, 131183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh response.status, response.reason, 131283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh response.msg, 131383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ) 131483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 131583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 131683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Create parser. 131783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 131883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @return A 2-tuple containing a parser and a unmarshaller. 131983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 132083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def getparser(self): 132183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # get parser and unmarshaller 132283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return getparser(use_datetime=self._use_datetime) 132383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 132483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 132583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Get authorization info from host parameter 132683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Host may be a string, or a (host, x509-dict) tuple; if a string, 132783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # it is checked for a "user:pw@host" format, and a "Basic 132883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Authentication" header is added if appropriate. 132983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 133083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param host Host descriptor (URL or (URL, x509 info) tuple). 133183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @return A 3-tuple containing (actual host, extra headers, 133283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # x509 info). The header and x509 fields may be None. 133383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 133483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def get_host_info(self, host): 133583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 133683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh x509 = {} 133783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(host, TupleType): 133883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh host, x509 = host 133983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 134083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import urllib 134183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh auth, host = urllib.splituser(host) 134283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 134383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if auth: 134483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import base64 134583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh auth = base64.encodestring(urllib.unquote(auth)) 134683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh auth = string.join(string.split(auth), "") # get rid of whitespace 134783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh extra_headers = [ 134883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ("Authorization", "Basic " + auth) 134983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ] 135083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 135183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh extra_headers = None 135283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 135383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return host, extra_headers, x509 135483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 135583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 135683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Connect to server. 135783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 135883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param host Target host. 135983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @return A connection handle. 136083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 136183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def make_connection(self, host): 136283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh #return an existing connection if possible. This allows 136383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh #HTTP/1.1 keep-alive. 136483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self._connection and host == self._connection[0]: 136583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self._connection[1] 136683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 136783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # create a HTTP connection object from a host descriptor 136883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh chost, self._extra_headers, x509 = self.get_host_info(host) 136983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh #store the host argument along with the connection object 137083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._connection = host, httplib.HTTPConnection(chost) 137183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self._connection[1] 137283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 137383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 137483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Clear any cached connection object. 137583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Used in the event of socket errors. 137683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 137783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def close(self): 137883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self._connection[1]: 137983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._connection[1].close() 138083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._connection = (None, None) 138183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 138283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 138383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Send request header. 138483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 138583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param connection Connection handle. 138683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param handler Target RPC handler. 138783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param request_body XML-RPC body. 138883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 138983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def send_request(self, connection, handler, request_body): 139083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if (self.accept_gzip_encoding and gzip): 139183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh connection.putrequest("POST", handler, skip_accept_encoding=True) 139283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh connection.putheader("Accept-Encoding", "gzip") 139383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 139483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh connection.putrequest("POST", handler) 139583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 139683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 139783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Send host name. 139883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 139983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param connection Connection handle. 140083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param host Host name. 140183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 140283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Note: This function doesn't actually add the "Host" 140383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # header anymore, it is done as part of the connection.putrequest() in 140483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # send_request() above. 140583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 140683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def send_host(self, connection, host): 140783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh extra_headers = self._extra_headers 140883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if extra_headers: 140983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(extra_headers, DictType): 141083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh extra_headers = extra_headers.items() 141183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for key, value in extra_headers: 141283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh connection.putheader(key, value) 141383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 141483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 141583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Send user-agent identifier. 141683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 141783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param connection Connection handle. 141883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 141983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def send_user_agent(self, connection): 142083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh connection.putheader("User-Agent", self.user_agent) 142183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 142283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 142383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Send request body. 142483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 142583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param connection Connection handle. 142683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param request_body XML-RPC request body. 142783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 142883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def send_content(self, connection, request_body): 142983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh connection.putheader("Content-Type", "text/xml") 143083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 143183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh #optionally encode the request 143283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if (self.encode_threshold is not None and 143383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.encode_threshold < len(request_body) and 143483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh gzip): 143583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh connection.putheader("Content-Encoding", "gzip") 143683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh request_body = gzip_encode(request_body) 143783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 143883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh connection.putheader("Content-Length", str(len(request_body))) 143983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh connection.endheaders(request_body) 144083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 144183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ## 144283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Parse response. 144383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # 144483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @param file Stream. 144583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # @return Response tuple and target method. 144683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 144783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def parse_response(self, response): 144883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # read response data from httpresponse, and parse it 144983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 145083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # Check for new http response object, else it is a file object 145183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if hasattr(response,'getheader'): 145283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if response.getheader("Content-Encoding", "") == "gzip": 145383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh stream = GzipDecodedResponse(response) 145483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 145583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh stream = response 145683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 145783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh stream = response 145883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 145983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh p, u = self.getparser() 146083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 146183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh while 1: 146283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh data = stream.read(1024) 146383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not data: 146483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh break 146583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self.verbose: 146683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh print "body:", repr(data) 146783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh p.feed(data) 146883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 146983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if stream is not response: 147083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh stream.close() 147183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh p.close() 147283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 147383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return u.close() 147483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 147583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 147683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Standard transport class for XML-RPC over HTTPS. 147783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 147883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass SafeTransport(Transport): 147983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """Handles an HTTPS transaction to an XML-RPC server.""" 148083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 148183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # FIXME: mostly untested 148283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 148383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def make_connection(self, host): 148483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if self._connection and host == self._connection[0]: 148583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self._connection[1] 148683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # create a HTTPS connection object from a host descriptor 148783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # host may be a string, or a (host, x509-dict) tuple 148883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 148983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh HTTPS = httplib.HTTPSConnection 149083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except AttributeError: 149183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise NotImplementedError( 149283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "your version of httplib doesn't support HTTPS" 149383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ) 149483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 149583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh chost, self._extra_headers, x509 = self.get_host_info(host) 149683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self._connection = host, HTTPS(chost, None, **(x509 or {})) 149783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self._connection[1] 149883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 149983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh## 150083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Standard server proxy. This class establishes a virtual connection 150183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# to an XML-RPC server. 150283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# <p> 150383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# This class is available as ServerProxy and Server. New code should 150483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# use ServerProxy, to avoid confusion. 150583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 150683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @def ServerProxy(uri, **options) 150783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param uri The connection point on the server. 150883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @keyparam transport A transport factory, compatible with the 150983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# standard transport class. 151083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @keyparam encoding The default encoding used for 8-bit strings 151183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# (default is UTF-8). 151283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @keyparam verbose Use a true value to enable debugging output. 151383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# (printed to standard output). 151483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @see Transport 151583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 151683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass ServerProxy: 151783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """uri [,options] -> a logical connection to an XML-RPC server 151883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 151983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh uri is the connection point on the server, given as 152083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh scheme://host/target. 152183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 152283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The standard implementation always supports the "http" scheme. If 152383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh SSL socket support is available (Python 2.0), it also supports 152483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "https". 152583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 152683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh If the target part and the slash preceding it are both omitted, 152783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "/RPC2" is assumed. 152883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 152983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh The following options can be given as keyword arguments: 153083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 153183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh transport: a transport factory 153283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh encoding: the request encoding (default is UTF-8) 153383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 153483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh All 8-bit strings passed to the server proxy are assumed to use 153583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh the given encoding. 153683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 153783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 153883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __init__(self, uri, transport=None, encoding=None, verbose=0, 153983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh allow_none=0, use_datetime=0): 154083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # establish a "logical" server connection 154183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 154283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if isinstance(uri, unicode): 154383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh uri = uri.encode('ISO-8859-1') 154483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 154583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # get the url 154683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh import urllib 154783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh type, uri = urllib.splittype(uri) 154883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if type not in ("http", "https"): 154983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise IOError, "unsupported XML-RPC protocol" 155083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__host, self.__handler = urllib.splithost(uri) 155183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if not self.__handler: 155283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__handler = "/RPC2" 155383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 155483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if transport is None: 155583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if type == "https": 155683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh transport = SafeTransport(use_datetime=use_datetime) 155783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh else: 155883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh transport = Transport(use_datetime=use_datetime) 155983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__transport = transport 156083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 156183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__encoding = encoding 156283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__verbose = verbose 156383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__allow_none = allow_none 156483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 156583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __close(self): 156683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__transport.close() 156783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 156883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __request(self, methodname, params): 156983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # call a method on the remote server 157083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 157183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh request = dumps(params, methodname, encoding=self.__encoding, 157283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh allow_none=self.__allow_none) 157383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 157483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh response = self.__transport.request( 157583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__host, 157683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh self.__handler, 157783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh request, 157883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh verbose=self.__verbose 157983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ) 158083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 158183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if len(response) == 1: 158283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh response = response[0] 158383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 158483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return response 158583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 158683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __repr__(self): 158783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return ( 158883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh "<ServerProxy for %s%s>" % 158983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh (self.__host, self.__handler) 159083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh ) 159183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 159283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh __str__ = __repr__ 159383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 159483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __getattr__(self, name): 159583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # magic method dispatcher 159683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return _Method(self.__request, name) 159783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 159883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # note: to call a remote object with an non-standard name, use 159983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # result getattr(server, "strange-python-name")(args) 160083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 160183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh def __call__(self, attr): 160283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """A workaround to get special attributes on the ServerProxy 160383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh without interfering with the magic __getattr__ 160483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh """ 160583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh if attr == "close": 160683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.__close 160783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh elif attr == "transport": 160883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh return self.__transport 160983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh raise AttributeError("Attribute %r not found" % (attr,)) 161083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 161183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# compatibility 161283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 161383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehServer = ServerProxy 161483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 161583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# -------------------------------------------------------------------- 161683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# test code 161783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 161883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehif __name__ == "__main__": 161983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 162083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # simple test program (from the XML-RPC specification) 162183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 162283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh # server = ServerProxy("http://localhost:8000") # local server 162383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh server = ServerProxy("http://time.xmlrpc.com/RPC2") 162483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 162583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh print server 162683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 162783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 162883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh print server.currentTime.getCurrentTime() 162983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except Error, v: 163083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh print "ERROR", v 163183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh 163283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh multi = MultiCall(server) 163383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh multi.currentTime.getCurrentTime() 163483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh multi.currentTime.getCurrentTime() 163583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh try: 163683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh for response in multi(): 163783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh print response 163883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh except Error, v: 163983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh print "ERROR", v 1640