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