Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(195)

Side by Side Diff: third_party/twisted_8_1/twisted/web/xmlrpc.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: twisted.web.test.test_xmlrpc -*-
2 #
3 # Copyright (c) 2001-2007 Twisted Matrix Laboratories.
4 # See LICENSE for details.
5
6
7 """
8 A generic resource for publishing objects via XML-RPC.
9
10 Requires xmlrpclib (comes standard with Python 2.2 and later, otherwise can be
11 downloaded from http://www.pythonware.com/products/xmlrpc/).
12
13 Maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>}
14 """
15 from __future__ import nested_scopes
16
17 __version__ = "$Revision: 1.32 $"[11:-2]
18
19 # System Imports
20 import xmlrpclib
21 import urlparse
22
23 # Sibling Imports
24 from twisted.web import resource, server, http
25 from twisted.internet import defer, protocol, reactor
26 from twisted.python import log, reflect, failure
27
28 # These are deprecated, use the class level definitions
29 NOT_FOUND = 8001
30 FAILURE = 8002
31
32
33 # Useful so people don't need to import xmlrpclib directly
34 Fault = xmlrpclib.Fault
35 Binary = xmlrpclib.Binary
36 Boolean = xmlrpclib.Boolean
37 DateTime = xmlrpclib.DateTime
38
39 class NoSuchFunction(Fault):
40 """
41 There is no function by the given name.
42 """
43
44
45 class Handler:
46 """
47 Handle a XML-RPC request and store the state for a request in progress.
48
49 Override the run() method and return result using self.result,
50 a Deferred.
51
52 We require this class since we're not using threads, so we can't
53 encapsulate state in a running function if we're going to have
54 to wait for results.
55
56 For example, lets say we want to authenticate against twisted.cred,
57 run a LDAP query and then pass its result to a database query, all
58 as a result of a single XML-RPC command. We'd use a Handler instance
59 to store the state of the running command.
60 """
61
62 def __init__(self, resource, *args):
63 self.resource = resource # the XML-RPC resource we are connected to
64 self.result = defer.Deferred()
65 self.run(*args)
66
67 def run(self, *args):
68 # event driven equivalent of 'raise UnimplementedError'
69 self.result.errback(
70 NotImplementedError("Implement run() in subclasses"))
71
72
73 class XMLRPC(resource.Resource):
74 """
75 A resource that implements XML-RPC.
76
77 You probably want to connect this to '/RPC2'.
78
79 Methods published can return XML-RPC serializable results, Faults,
80 Binary, Boolean, DateTime, Deferreds, or Handler instances.
81
82 By default methods beginning with 'xmlrpc_' are published.
83
84 Sub-handlers for prefixed methods (e.g., system.listMethods)
85 can be added with putSubHandler. By default, prefixes are
86 separated with a '.'. Override self.separator to change this.
87 """
88
89 # Error codes for Twisted, if they conflict with yours then
90 # modify them at runtime.
91 NOT_FOUND = 8001
92 FAILURE = 8002
93
94 isLeaf = 1
95 separator = '.'
96 allowedMethods = ('POST',)
97
98 def __init__(self, allowNone=False):
99 resource.Resource.__init__(self)
100 self.subHandlers = {}
101 self.allowNone = allowNone
102
103 def putSubHandler(self, prefix, handler):
104 self.subHandlers[prefix] = handler
105
106 def getSubHandler(self, prefix):
107 return self.subHandlers.get(prefix, None)
108
109 def getSubHandlerPrefixes(self):
110 return self.subHandlers.keys()
111
112 def render_POST(self, request):
113 request.content.seek(0, 0)
114 request.setHeader("content-type", "text/xml")
115 try:
116 args, functionPath = xmlrpclib.loads(request.content.read())
117 except Exception, e:
118 f = Fault(self.FAILURE, "Can't deserialize input: %s" % (e,))
119 self._cbRender(f, request)
120 else:
121 try:
122 function = self._getFunction(functionPath)
123 except Fault, f:
124 self._cbRender(f, request)
125 else:
126 defer.maybeDeferred(function, *args).addErrback(
127 self._ebRender
128 ).addCallback(
129 self._cbRender, request
130 )
131 return server.NOT_DONE_YET
132
133 def _cbRender(self, result, request):
134 if isinstance(result, Handler):
135 result = result.result
136 if not isinstance(result, Fault):
137 result = (result,)
138 try:
139 s = xmlrpclib.dumps(result, methodresponse=True,
140 allow_none=self.allowNone)
141 except Exception, e:
142 f = Fault(self.FAILURE, "Can't serialize output: %s" % (e,))
143 s = xmlrpclib.dumps(f, methodresponse=True,
144 allow_none=self.allowNone)
145 request.setHeader("content-length", str(len(s)))
146 request.write(s)
147 request.finish()
148
149 def _ebRender(self, failure):
150 if isinstance(failure.value, Fault):
151 return failure.value
152 log.err(failure)
153 return Fault(self.FAILURE, "error")
154
155 def _getFunction(self, functionPath):
156 """
157 Given a string, return a function, or raise NoSuchFunction.
158
159 This returned function will be called, and should return the result
160 of the call, a Deferred, or a Fault instance.
161
162 Override in subclasses if you want your own policy. The default
163 policy is that given functionPath 'foo', return the method at
164 self.xmlrpc_foo, i.e. getattr(self, "xmlrpc_" + functionPath).
165 If functionPath contains self.separator, the sub-handler for
166 the initial prefix is used to search for the remaining path.
167 """
168 if functionPath.find(self.separator) != -1:
169 prefix, functionPath = functionPath.split(self.separator, 1)
170 handler = self.getSubHandler(prefix)
171 if handler is None:
172 raise NoSuchFunction(self.NOT_FOUND,
173 "no such subHandler %s" % prefix)
174 return handler._getFunction(functionPath)
175
176 f = getattr(self, "xmlrpc_%s" % functionPath, None)
177 if not f:
178 raise NoSuchFunction(self.NOT_FOUND,
179 "function %s not found" % functionPath)
180 elif not callable(f):
181 raise NoSuchFunction(self.NOT_FOUND,
182 "function %s not callable" % functionPath)
183 else:
184 return f
185
186 def _listFunctions(self):
187 """
188 Return a list of the names of all xmlrpc methods.
189 """
190 return reflect.prefixedMethodNames(self.__class__, 'xmlrpc_')
191
192
193 class XMLRPCIntrospection(XMLRPC):
194 """
195 Implement the XML-RPC Introspection API.
196
197 By default, the methodHelp method returns the 'help' method attribute,
198 if it exists, otherwise the __doc__ method attribute, if it exists,
199 otherwise the empty string.
200
201 To enable the methodSignature method, add a 'signature' method attribute
202 containing a list of lists. See methodSignature's documentation for the
203 format. Note the type strings should be XML-RPC types, not Python types.
204 """
205
206 def __init__(self, parent):
207 """
208 Implement Introspection support for an XMLRPC server.
209
210 @param parent: the XMLRPC server to add Introspection support to.
211 """
212
213 XMLRPC.__init__(self)
214 self._xmlrpc_parent = parent
215
216 def xmlrpc_listMethods(self):
217 """
218 Return a list of the method names implemented by this server.
219 """
220 functions = []
221 todo = [(self._xmlrpc_parent, '')]
222 while todo:
223 obj, prefix = todo.pop(0)
224 functions.extend([prefix + name for name in obj._listFunctions()])
225 todo.extend([ (obj.getSubHandler(name),
226 prefix + name + obj.separator)
227 for name in obj.getSubHandlerPrefixes() ])
228 return functions
229
230 xmlrpc_listMethods.signature = [['array']]
231
232 def xmlrpc_methodHelp(self, method):
233 """
234 Return a documentation string describing the use of the given method.
235 """
236 method = self._xmlrpc_parent._getFunction(method)
237 return (getattr(method, 'help', None)
238 or getattr(method, '__doc__', None) or '')
239
240 xmlrpc_methodHelp.signature = [['string', 'string']]
241
242 def xmlrpc_methodSignature(self, method):
243 """
244 Return a list of type signatures.
245
246 Each type signature is a list of the form [rtype, type1, type2, ...]
247 where rtype is the return type and typeN is the type of the Nth
248 argument. If no signature information is available, the empty
249 string is returned.
250 """
251 method = self._xmlrpc_parent._getFunction(method)
252 return getattr(method, 'signature', None) or ''
253
254 xmlrpc_methodSignature.signature = [['array', 'string'],
255 ['string', 'string']]
256
257
258 def addIntrospection(xmlrpc):
259 """
260 Add Introspection support to an XMLRPC server.
261
262 @param xmlrpc: The xmlrpc server to add Introspection support to.
263 """
264 xmlrpc.putSubHandler('system', XMLRPCIntrospection(xmlrpc))
265
266
267 class QueryProtocol(http.HTTPClient):
268
269 def connectionMade(self):
270 self.sendCommand('POST', self.factory.path)
271 self.sendHeader('User-Agent', 'Twisted/XMLRPClib')
272 self.sendHeader('Host', self.factory.host)
273 self.sendHeader('Content-type', 'text/xml')
274 self.sendHeader('Content-length', str(len(self.factory.payload)))
275 if self.factory.user:
276 auth = '%s:%s' % (self.factory.user, self.factory.password)
277 auth = auth.encode('base64').strip()
278 self.sendHeader('Authorization', 'Basic %s' % (auth,))
279 self.endHeaders()
280 self.transport.write(self.factory.payload)
281
282 def handleStatus(self, version, status, message):
283 if status != '200':
284 self.factory.badStatus(status, message)
285
286 def handleResponse(self, contents):
287 self.factory.parseResponse(contents)
288
289
290 payloadTemplate = """<?xml version="1.0"?>
291 <methodCall>
292 <methodName>%s</methodName>
293 %s
294 </methodCall>
295 """
296
297
298 class _QueryFactory(protocol.ClientFactory):
299
300 deferred = None
301 protocol = QueryProtocol
302
303 def __init__(self, path, host, method, user=None, password=None,
304 allowNone=False, args=()):
305 self.path, self.host = path, host
306 self.user, self.password = user, password
307 self.payload = payloadTemplate % (method,
308 xmlrpclib.dumps(args, allow_none=allowNone))
309 self.deferred = defer.Deferred()
310
311 def parseResponse(self, contents):
312 if not self.deferred:
313 return
314 try:
315 response = xmlrpclib.loads(contents)
316 except:
317 deferred, self.deferred = self.deferred, None
318 deferred.errback(failure.Failure())
319 else:
320 deferred, self.deferred = self.deferred, None
321 deferred.callback(response[0][0])
322
323 def clientConnectionLost(self, _, reason):
324 if self.deferred is not None:
325 deferred, self.deferred = self.deferred, None
326 deferred.errback(reason)
327
328 clientConnectionFailed = clientConnectionLost
329
330 def badStatus(self, status, message):
331 deferred, self.deferred = self.deferred, None
332 deferred.errback(ValueError(status, message))
333
334
335
336 class Proxy:
337 """
338 A Proxy for making remote XML-RPC calls.
339
340 Pass the URL of the remote XML-RPC server to the constructor.
341
342 Use proxy.callRemote('foobar', *args) to call remote method
343 'foobar' with *args.
344
345 @ivar queryFactory: object returning a factory for XML-RPC protocol. Mainly
346 useful for tests.
347 """
348 queryFactory = _QueryFactory
349
350 def __init__(self, url, user=None, password=None, allowNone=False):
351 """
352 @type url: C{str}
353 @param url: The URL to which to post method calls. Calls will be made
354 over SSL if the scheme is HTTPS. If netloc contains username or
355 password information, these will be used to authenticate, as long as
356 the C{user} and C{password} arguments are not specified.
357
358 @type user: C{str} or None
359 @param user: The username with which to authenticate with the server
360 when making calls. If specified, overrides any username information
361 embedded in C{url}. If not specified, a value may be taken from C{url}
362 if present.
363
364 @type password: C{str} or None
365 @param password: The password with which to authenticate with the
366 server when making calls. If specified, overrides any password
367 information embedded in C{url}. If not specified, a value may be taken
368 from C{url} if present.
369
370 @type allowNone: C{bool} or None
371 @param allowNone: allow the use of None values in parameters. It's
372 passed to the underlying xmlrpclib implementation. Default to False.
373 """
374 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
375 netlocParts = netloc.split('@')
376 if len(netlocParts) == 2:
377 userpass = netlocParts.pop(0).split(':')
378 self.user = userpass.pop(0)
379 try:
380 self.password = userpass.pop(0)
381 except:
382 self.password = None
383 else:
384 self.user = self.password = None
385 hostport = netlocParts[0].split(':')
386 self.host = hostport.pop(0)
387 try:
388 self.port = int(hostport.pop(0))
389 except:
390 self.port = None
391 self.path = path
392 if self.path in ['', None]:
393 self.path = '/'
394 self.secure = (scheme == 'https')
395 if user is not None:
396 self.user = user
397 if password is not None:
398 self.password = password
399 self.allowNone = allowNone
400
401 def callRemote(self, method, *args):
402 factory = self.queryFactory(
403 self.path, self.host, method, self.user,
404 self.password, self.allowNone, args)
405 if self.secure:
406 from twisted.internet import ssl
407 reactor.connectSSL(self.host, self.port or 443,
408 factory, ssl.ClientContextFactory())
409 else:
410 reactor.connectTCP(self.host, self.port or 80, factory)
411 return factory.deferred
412
413 __all__ = ["XMLRPC", "Handler", "NoSuchFunction", "Fault", "Proxy"]
414
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/web/woven/widgets.py ('k') | third_party/twisted_8_1/twisted/words/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698