Ticket #1549: xmlrpc.html

File xmlrpc.html, 44.4 KB (added by oubiwann, 13 years ago)

First draft of t.w2.xmlrpc howto

Line 
1<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>Twisted Documentation: Creating XML-RPC Servers and Clients with Twisted</title><link href="web2_oubiwann/howto/../core/documentation/howto/stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">Creating XML-RPC Servers and Clients with Twisted</h1><div class="toc"><ol><li><a href="#auto0">Introduction</a></li><li><a href="#auto1">Creating a XML-RPC server</a></li><ul><li><a href="#auto2">Using XML-RPC sub-handlers</a></li><li><a href="#auto3">Adding XML-RPC Introspection support</a></li></ul><li><a href="#auto4">SOAP Support</a></li><li><a href="#auto5">Creating an XML-RPC Client</a></li><li><a href="#auto6">XML-RPC and Authentication</a></li><li><a href="#auto7">Migrating twisted.web XML-RPC to twisted.web2</a></li><ul><li><a href="#auto8">Add addSlash</a></li><li><a href="#auto9">Add request to the Method Signatures</a></li><li><a href="#auto10">Wrap the Site Object</a></li></ul></ol></div><div class="content"><span></span><h2>Introduction<a name="auto0"></a></h2><p><a href="http://www.xmlrpc.com">XML-RPC</a> is a simple request/reply protocol that runs over HTTP. It is simple,
3easy to implement and supported by most programming languages. Twisted's XML-RPC
4support is implemented using the xmlrpclib library that is included with Python 2.2 and later.</p><p>This document assumes some familiarity with cred and suggests you read the
5<a href="http://twistedmatrix.com/projects/web2/documentation/howto">twisted.web2
6howtos</a> as well as
7<a href="http://twistedmatrix.com/projects/core/documentation/howto/application.html">Using
8the Twisted Application Framework</a></p><h2>Creating a XML-RPC server<a name="auto1"></a></h2><p>Making a server is very easy - all you need to do is inherit from <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web2.xmlrpc.XMLRPC.html" title="twisted.web2.xmlrpc.XMLRPC">twisted.web2.xmlrpc.XMLRPC</a></code>.
9You then create methods beginning with <code>xmlrpc_</code>. The methods'
10arguments determine what arguments it will accept from XML-RPC clients.
11The result is what will be returned to the clients.</p><p>Methods published via XML-RPC can return all the basic XML-RPC
12types, such as strings, lists and so on (just return a regular python
13integer, etc).  They can also return Failure instances to indicate an
14error has occurred, or <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web.xmlrpc.Binary.html" title="twisted.web.xmlrpc.Binary">Binary</a></code>, <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web.xmlrpc.Boolean.html" title="twisted.web.xmlrpc.Boolean">Boolean</a></code> or <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web.xmlrpc.DateTime.html" title="twisted.web.xmlrpc.DateTime">DateTime</a></code> instances (all of these are the same as
15the respective classes in xmlrpclib. In addition, XML-RPC published
16methods can return <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code> instances whose results are one of the
17above. This allows you to return results that can't be calculated
18immediately, such as database queries. See the <a href="defer.html">Deferred documentation</a> for more details.</p><p><code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web.xmlrpc.XMLRPC.html" title="twisted.web.xmlrpc.XMLRPC">XMLRPC</a></code> instances
19are Resource objects, and they can thus be published using a Site. The
20following example has two methods published via XML-RPC, <code>add(a,
21b)</code> and <code>echo(x)</code>.</p><div class="py-listing"><pre>
22<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">xmlrpc</span>
23<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">server</span>
24<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">channel</span>
25<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">service</span>, <span class="py-src-variable">strports</span>
26
27<span class="py-src-keyword">class</span> <span class="py-src-identifier">Example</span>(<span class="py-src-parameter">xmlrpc</span>.<span class="py-src-parameter">XMLRPC</span>):
28    <span class="py-src-string">&quot;&quot;&quot;An example object to be published.&quot;&quot;&quot;</span>
29
30    <span class="py-src-variable">addSlash</span> = <span class="py-src-variable">True</span>
31
32    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_echo</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">x</span>):
33        <span class="py-src-string">&quot;&quot;&quot;Return all passed args.&quot;&quot;&quot;</span>
34        <span class="py-src-keyword">return</span> <span class="py-src-variable">x</span>
35
36    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
37        <span class="py-src-string">&quot;&quot;&quot;Return sum of arguments.&quot;&quot;&quot;</span>
38        <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> + <span class="py-src-variable">b</span>
39
40<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
41    <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
42    <span class="py-src-variable">site</span> = <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">Example</span>())
43    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">7080</span>, <span class="py-src-variable">channel</span>.<span class="py-src-variable">HTTPFactory</span>(<span class="py-src-variable">site</span>))
44    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
45</pre><div class="caption">Source listing - <a href="../examples/xmlrpc/example1.py"><span class="filename">../examples/xmlrpc/example1.py</span></a></div></div><p>We could run example1.py in the background like so,
46<code>python example1.py &amp;</code> and then connect with client code in the
47following manner:</p><pre class="python-interpreter">
48&gt;&gt;&gt; import xmlrpclib
49&gt;&gt;&gt; s = xmlrpclib.Server('http://localhost:7080/')
50&gt;&gt;&gt; s.echo('A self-perpetuating autocracy in which the working class...')
51'A self-perpetuating autocracy in which the working class...'
52&gt;&gt;&gt; s.add(1, 2)
533
54</pre><p>If you are coming from <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web.xmlrpc.html" title="twisted.web.xmlrpc">twisted.web.xmlrpc</a></code>, then you probably noticed two differences: the use of <code>addSlash</code> and that <code>request</code> appears in the signature for methods.</p><p>To run this example as a twisted application, save the following as
55<code>example1.tac</code>:</p><div class="py-listing"><pre>
56<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">xmlrpc</span>
57<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">server</span>
58<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">channel</span>
59<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">service</span>, <span class="py-src-variable">strports</span>
60
61<span class="py-src-keyword">class</span> <span class="py-src-identifier">Example</span>(<span class="py-src-parameter">xmlrpc</span>.<span class="py-src-parameter">XMLRPC</span>):
62    <span class="py-src-string">&quot;&quot;&quot;An example object to be published.&quot;&quot;&quot;</span>
63
64    <span class="py-src-variable">addSlash</span> = <span class="py-src-variable">True</span>
65
66    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_echo</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">x</span>):
67        <span class="py-src-string">&quot;&quot;&quot;Return all passed args.&quot;&quot;&quot;</span>
68        <span class="py-src-keyword">return</span> <span class="py-src-variable">x</span>
69
70    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
71        <span class="py-src-string">&quot;&quot;&quot;Return sum of arguments.&quot;&quot;&quot;</span>
72        <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> + <span class="py-src-variable">b</span>
73
74<span class="py-src-variable">site</span> = <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">Example</span>())
75<span class="py-src-variable">application</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">Application</span>(<span class="py-src-string">&quot;Example XML-RPC Server&quot;</span>)
76<span class="py-src-variable">s</span> = <span class="py-src-variable">strports</span>.<span class="py-src-variable">service</span>(<span class="py-src-string">'tcp:7080'</span>, <span class="py-src-variable">channel</span>.<span class="py-src-variable">HTTPFactory</span>(<span class="py-src-variable">site</span>))
77<span class="py-src-variable">s</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">application</span>)
78</pre><div class="caption">Source listing - <a href="../examples/xmlrpc/example1.tac"><span class="filename">../examples/xmlrpc/example1.tac</span></a></div></div><p>Then execute with the command <code>twistd -noy example.tac</code>.</p><p>XML-RPC resources can be seamlessly integrated with other
79<code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web2.html" title="twisted.web2">twisted.web2</a></code> resources. Here is an example of a
80web2 server running a simple HTTP resource as well as an XML-RPC resource:</p><div class="py-listing"><pre>
81<span class="py-src-keyword">from</span> <span class="py-src-variable">random</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">choice</span>
82
83<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">http</span>
84<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">server</span>
85<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">channel</span>
86<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">resource</span>
87<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">xmlrpc</span>
88<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">service</span>, <span class="py-src-variable">strports</span>
89
90<span class="py-src-keyword">def</span> <span class="py-src-identifier">getQuote</span>():
91    <span class="py-src-variable">quotes</span> = [
92        <span class="py-src-string">'The concept of progress acts as a protective mechanism '</span> +
93            <span class="py-src-string">'to shield us from the terrors of the future.'</span>,
94        <span class="py-src-string">'Truth suffers from too much analysis'</span>,
95        <span class="py-src-string">'A process cannot be understood by stopping it.'</span>,
96    ]
97    <span class="py-src-keyword">return</span> <span class="py-src-variable">choice</span>(<span class="py-src-variable">quotes</span>)
98
99<span class="py-src-keyword">class</span> <span class="py-src-identifier">Quoter</span>(<span class="py-src-parameter">xmlrpc</span>.<span class="py-src-parameter">XMLRPC</span>):
100
101    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_quote</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>):
102        <span class="py-src-keyword">return</span> <span class="py-src-variable">getQuote</span>()
103
104<span class="py-src-keyword">class</span> <span class="py-src-identifier">Toplevel</span>(<span class="py-src-parameter">resource</span>.<span class="py-src-parameter">Resource</span>):
105  <span class="py-src-variable">addSlash</span> = <span class="py-src-variable">True</span>
106  <span class="py-src-variable">child_RPC2</span> = <span class="py-src-variable">Quoter</span>()
107  <span class="py-src-keyword">def</span> <span class="py-src-identifier">render</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">ctx</span>):
108        <span class="py-src-keyword">return</span> <span class="py-src-variable">http</span>.<span class="py-src-variable">Response</span>(<span class="py-src-variable">stream</span>=<span class="py-src-string">&quot;Hello monkey!&quot;</span>)
109
110<span class="py-src-variable">site</span> = <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">Toplevel</span>())
111<span class="py-src-variable">application</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">Application</span>(<span class="py-src-string">&quot;Quote Server+&quot;</span>)
112<span class="py-src-variable">s</span> = <span class="py-src-variable">strports</span>.<span class="py-src-variable">service</span>(<span class="py-src-string">'tcp:8080'</span>, <span class="py-src-variable">channel</span>.<span class="py-src-variable">HTTPFactory</span>(<span class="py-src-variable">site</span>))
113<span class="py-src-variable">s</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">application</span>)
114</pre><div class="caption">Source listing - <a href="../examples/xmlrpc/quote.tac"><span class="filename">../examples/xmlrpc/quote.tac</span></a></div></div><p>Not only can one browse to http://localhost:8080, but one can also access the
115XML-RPC service available at http://localhost:8080/RPC2.</p><h3>Using XML-RPC sub-handlers<a name="auto2"></a></h3><p>XML-RPC resource can be nested so that one handler calls another if
116a method with a given prefix is called. This can be a very convenient mechanism
117for organizing RPC APIs. For example, we can add support for
118an XML-RPC method <code>date.time()</code> to the
119<code class="python">Example</code> class, and move the <code>add()</code>
120method to <code>math.add()</code>:</p><div class="py-listing"><pre>
121<span class="py-src-keyword">import</span> <span class="py-src-variable">time</span>
122
123<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">server</span>
124<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">channel</span>
125<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">xmlrpc</span>
126<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">service</span>, <span class="py-src-variable">strports</span>
127
128<span class="py-src-keyword">class</span> <span class="py-src-identifier">Example</span>(<span class="py-src-parameter">xmlrpc</span>.<span class="py-src-parameter">XMLRPC</span>):
129
130    <span class="py-src-variable">addSlash</span> = <span class="py-src-variable">True</span>
131
132    <span class="py-src-string">&quot;&quot;&quot;An example object to be published.&quot;&quot;&quot;</span>
133    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_echo</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">x</span>):
134        <span class="py-src-string">&quot;&quot;&quot;Return all passed args.&quot;&quot;&quot;</span>
135        <span class="py-src-keyword">return</span> <span class="py-src-variable">x</span>
136
137<span class="py-src-keyword">class</span> <span class="py-src-identifier">Math</span>(<span class="py-src-parameter">xmlrpc</span>.<span class="py-src-parameter">XMLRPC</span>):
138    <span class="py-src-string">&quot;&quot;&quot;Put our math methods here.&quot;&quot;&quot;</span>
139
140    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
141        <span class="py-src-string">&quot;&quot;&quot;Return sum of arguments.&quot;&quot;&quot;</span>
142        <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> + <span class="py-src-variable">b</span>
143
144<span class="py-src-keyword">class</span> <span class="py-src-identifier">Date</span>(<span class="py-src-parameter">xmlrpc</span>.<span class="py-src-parameter">XMLRPC</span>):
145    <span class="py-src-string">&quot;&quot;&quot;Put our date methods here.&quot;&quot;&quot;</span>
146
147    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_time</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>):
148        <span class="py-src-string">&quot;&quot;&quot;Return UNIX time.&quot;&quot;&quot;</span>
149        <span class="py-src-keyword">return</span> <span class="py-src-variable">time</span>.<span class="py-src-variable">time</span>()
150
151<span class="py-src-variable">root</span> = <span class="py-src-variable">Example</span>()
152<span class="py-src-variable">root</span>.<span class="py-src-variable">putSubHandler</span>(<span class="py-src-string">'math'</span>, <span class="py-src-variable">Math</span>())
153<span class="py-src-variable">root</span>.<span class="py-src-variable">putSubHandler</span>(<span class="py-src-string">'date'</span>, <span class="py-src-variable">Date</span>())
154
155<span class="py-src-variable">site</span> = <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>)
156<span class="py-src-variable">application</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">Application</span>(<span class="py-src-string">&quot;XML-RPC Server With Sub-handlers&quot;</span>)
157<span class="py-src-variable">s</span> = <span class="py-src-variable">strports</span>.<span class="py-src-variable">service</span>(<span class="py-src-string">'tcp:8080'</span>, <span class="py-src-variable">channel</span>.<span class="py-src-variable">HTTPFactory</span>(<span class="py-src-variable">site</span>))
158<span class="py-src-variable">s</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">application</span>)
159</pre><div class="caption">Source listing - <a href="../examples/xmlrpc/example2.tac"><span class="filename">../examples/xmlrpc/example2.tac</span></a></div></div><p>By default, a period ('.') separates the prefix from the method
160name, but you can use a different character by overriding the <code class="python">XMLRPC.separator</code> data member in your base
161XML-RPC server. XML-RPC servers may be nested to arbitrary depths
162using this method.</p><p>Running client code from the python interpreter, we can see the subhandlers
163in action:</p><pre class="python-interpreter">
164&gt;&gt;&gt; import xmlrpclib
165&gt;&gt;&gt; s = xmlrpclib.ServerProxy('http://127.0.0.1:8080/')
166&gt;&gt;&gt; s.echo('Oh, there you go bringing class into it again.')
167'Oh, there you go bringing class into it again.'
168&gt;&gt;&gt; s.math.add(1,2)
1693
170&gt;&gt;&gt; s.date.time()
1711151921139.9897649
172</pre><h3>Adding XML-RPC Introspection support<a name="auto3"></a></h3><p>XML-RPC has an informal
173<a href="http://ldp.kernelnotes.de/HOWTO/XML-RPC-HOWTO/xmlrpc-howto-interfaces.html">Introspection API</a> 
174that specifies three methods in a <code>system</code> sub-handler which allow a
175client to query a server about the server's API. Adding Introspection support
176to the <code class="python">Example</code> class is easy using the
177<code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web.xmlrpc.XMLRPCIntrospection.html" title="twisted.web.xmlrpc.XMLRPCIntrospection">XMLRPCIntrospection</a></code>
178class:</p><div class="py-listing"><pre>
179<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">server</span>
180<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">channel</span>
181<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">xmlrpc</span>
182<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">service</span>, <span class="py-src-variable">strports</span>
183
184<span class="py-src-keyword">class</span> <span class="py-src-identifier">Example</span>(<span class="py-src-parameter">xmlrpc</span>.<span class="py-src-parameter">XMLRPC</span>):
185    <span class="py-src-string">&quot;&quot;&quot;An example object to be published.&quot;&quot;&quot;</span>
186
187    <span class="py-src-variable">addSlash</span> = <span class="py-src-variable">True</span>
188
189    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_echo</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">x</span>):
190        <span class="py-src-string">&quot;&quot;&quot;Return all passed args.&quot;&quot;&quot;</span>
191        <span class="py-src-keyword">return</span> <span class="py-src-variable">x</span>
192
193    <span class="py-src-variable">xmlrpc_echo</span>.<span class="py-src-variable">signature</span> = [[<span class="py-src-string">'string'</span>, <span class="py-src-string">'string'</span>],
194                             [<span class="py-src-string">'int'</span>, <span class="py-src-string">'int'</span>],
195                             [<span class="py-src-string">'double'</span>, <span class="py-src-string">'double'</span>],
196                             [<span class="py-src-string">'array'</span>, <span class="py-src-string">'array'</span>],
197                             [<span class="py-src-string">'struct'</span>, <span class="py-src-string">'struct'</span>]]
198
199    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
200        <span class="py-src-string">&quot;&quot;&quot;Return sum of arguments.&quot;&quot;&quot;</span>
201        <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> + <span class="py-src-variable">b</span>
202
203    <span class="py-src-variable">xmlrpc_add</span>.<span class="py-src-variable">signature</span> = [[<span class="py-src-string">'int'</span>, <span class="py-src-string">'int'</span>, <span class="py-src-string">'int'</span>],
204                            [<span class="py-src-string">'double'</span>, <span class="py-src-string">'double'</span>, <span class="py-src-string">'double'</span>]]
205    <span class="py-src-variable">xmlrpc_add</span>.<span class="py-src-variable">help</span> = <span class="py-src-string">&quot;Add the arguments and return the sum.&quot;</span>
206
207<span class="py-src-variable">root</span> = <span class="py-src-variable">Example</span>()
208<span class="py-src-variable">xmlrpc</span>.<span class="py-src-variable">addIntrospection</span>(<span class="py-src-variable">root</span>)
209
210<span class="py-src-variable">site</span> = <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>)
211<span class="py-src-variable">application</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">Application</span>(<span class="py-src-string">&quot;XML-RPC Server With Sub-handlers&quot;</span>)
212<span class="py-src-variable">s</span> = <span class="py-src-variable">strports</span>.<span class="py-src-variable">service</span>(<span class="py-src-string">'tcp:8080'</span>, <span class="py-src-variable">channel</span>.<span class="py-src-variable">HTTPFactory</span>(<span class="py-src-variable">site</span>))
213<span class="py-src-variable">s</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">application</span>)
214</pre><div class="caption">Source listing - <a href="../examples/xmlrpc/introspection.tac"><span class="filename">../examples/xmlrpc/introspection.tac</span></a></div></div><p>Note the method attributes <code class="python">help</code> and
215<code class="python">signature</code> which are used by the Introspection
216API methods <code>system.methodHelp</code> and
217<code>system.methodSignature</code> respectively. If no
218<code class="python">help</code> attribute is specified,
219the method's documentation string is used instead.</p><p>
220We can see how introspection can be used via this interactive python session:
221<pre class="python-interpreter">
222&gt;&gt;&gt; import xmlrpclib
223&gt;&gt;&gt; s = xmlrpclib.ServerProxy('http://127.0.0.1:8080/')
224&gt;&gt;&gt; s.system.listMethods()
225['add', 'echo', 'system.methodHelp', 'system.listMethods', 'system.methodSignature']
226&gt;&gt;&gt; s.system.methodHelp('echo')
227'Return all passed args.'
228&gt;&gt;&gt; s.system.methodSignature('echo')
229[['string', 'string'], ['int', 'int'], ['double', 'double'], ['array', 'array'], ['struct', 'struct']]
230&gt;&gt;&gt; s.system.methodHelp('add')
231'Add the arguments and return the sum.'
232&gt;&gt;&gt; s.system.methodSignature('add')
233[['int', 'int', 'int'], ['double', 'double', 'double']]
234</pre></p><h2>SOAP Support<a name="auto4"></a></h2><p>We are not currently supporting SOAP. However, there have been Twisted SOAP
235efforts made in the <a href="http://pywebsvcs.sourceforge.net/">Zolera
236SOAP Infrastructure (ZSI) project</a>.</p><h2>Creating an XML-RPC Client<a name="auto5"></a></h2><p>XML-RPC clients in Twisted are meant to look like something which will be
237familiar either to <code>xmlrpclib</code> or to Perspective Broker users,
238taking features from both, as appropriate. There are two major deviations
239from the <code>xmlrpclib</code> way which should be noted:</p><ol><li>No implicit <code>/RPC2</code>. If the services uses this path for the
240    XML-RPC calls, then it will have to be given explicitly.</li><li>No magic <code>__getattr__</code>: calls must be made by an explicit
241    <code>callRemote</code>.</li></ol><p>The interface Twisted presents to XML-RPC client is that of a proxy object:
242<code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web.xmlrpc.Proxy.html" title="twisted.web.xmlrpc.Proxy">twisted.web.xmlrpc.Proxy</a></code>. The constructor for the
243object receives a URL: it must be an HTTP or HTTPS URL. When an XML-RPC service
244is described, the URL to that service will be given there.</p><p>Having a proxy object, one can just call the <code>callRemote</code> method,
245which accepts a method name and a variable argument list (but no named
246arguments, as these are not supported by XML-RPC). It returns a deferred,
247which will be called back with the result. If there is any error, at any
248level, the errback will be called. The exception will be the relevant Twisted
249error in the case of a problem with the underlying connection (for example,
250a timeout), <code>IOError</code> containing the status and message in the case
251of a non-200 status or a <code>xmlrpclib.Fault</code> in the case of an
252XML-RPC level problem.</p><div class="py-listing"><pre>
253<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">xmlrpc</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Proxy</span>
254<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
255
256<span class="py-src-keyword">def</span> <span class="py-src-identifier">printValue</span>(<span class="py-src-parameter">value</span>):
257    <span class="py-src-keyword">print</span> <span class="py-src-variable">repr</span>(<span class="py-src-variable">value</span>)
258    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
259
260<span class="py-src-keyword">def</span> <span class="py-src-identifier">printError</span>(<span class="py-src-parameter">error</span>):
261    <span class="py-src-keyword">print</span> <span class="py-src-string">'error'</span>, <span class="py-src-variable">error</span>
262    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
263
264<span class="py-src-variable">proxy</span> = <span class="py-src-variable">Proxy</span>(<span class="py-src-string">'http://advogato.org/XMLRPC'</span>)
265<span class="py-src-variable">proxy</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">'test.sumprod'</span>, <span class="py-src-number">3</span>, <span class="py-src-number">5</span>).<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">printValue</span>, <span class="py-src-variable">printError</span>)
266<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
267</pre><div class="caption">Source listing - <a href="../examples/xmlrpc/client.py"><span class="filename">../examples/xmlrpc/client.py</span></a></div></div><p>prints:</p><pre>
268[8, 15]
269</pre><h2>XML-RPC and Authentication<a name="auto6"></a></h2><p>This section is based on the
270<a href="http://twistedmatrix.com/projects/web2/documentation/howto/authentication.html">twisted.web2
271Authentication Demo</a>. Please keep in mind the caveats at the end of that
272howto, as the same conditions apply here.</p><p>Listed below is a working example from the above-mentioned demo. The important
273change made here is the substitution of a <code>resource.Resouce</code>
274instance with an <code>xmlrpc.XMLRPC</code> instance:</p><div class="py-listing"><pre>
275<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Interface</span>, <span class="py-src-variable">implements</span>
276
277<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">cred</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">portal</span>
278<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">cred</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">checkers</span>
279
280<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">channel</span>
281<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">http</span>
282<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">responsecode</span>
283<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">server</span>
284<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">xmlrpc</span>
285
286<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span>.<span class="py-src-variable">auth</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">digest</span>
287<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span>.<span class="py-src-variable">auth</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">basic</span>
288<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web2</span>.<span class="py-src-variable">auth</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">wrapper</span>
289
290<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">service</span>, <span class="py-src-variable">strports</span>
291
292<span class="py-src-keyword">class</span> <span class="py-src-identifier">IHTTPUser</span>(<span class="py-src-parameter">Interface</span>):
293    <span class="py-src-keyword">pass</span>
294
295<span class="py-src-keyword">class</span> <span class="py-src-identifier">HTTPUser</span>(<span class="py-src-parameter">object</span>):
296    <span class="py-src-variable">implements</span>(<span class="py-src-variable">IHTTPUser</span>)
297
298<span class="py-src-keyword">class</span> <span class="py-src-identifier">HTTPAuthRealm</span>(<span class="py-src-parameter">object</span>):
299    <span class="py-src-variable">implements</span>(<span class="py-src-variable">portal</span>.<span class="py-src-variable">IRealm</span>)
300
301    <span class="py-src-keyword">def</span> <span class="py-src-identifier">requestAvatar</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">avatarId</span>, <span class="py-src-parameter">mind</span>, *<span class="py-src-parameter">interfaces</span>):
302        <span class="py-src-keyword">if</span> <span class="py-src-variable">IHTTPUser</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">interfaces</span>:
303            <span class="py-src-keyword">return</span> <span class="py-src-variable">IHTTPUser</span>, <span class="py-src-variable">HTTPUser</span>()
304
305        <span class="py-src-keyword">raise</span> <span class="py-src-variable">NotImplementedError</span>(<span class="py-src-string">&quot;Only IHTTPUser interface is supported&quot;</span>)
306
307<span class="py-src-keyword">class</span> <span class="py-src-identifier">Example</span>(<span class="py-src-parameter">xmlrpc</span>.<span class="py-src-parameter">XMLRPC</span>):
308    <span class="py-src-string">&quot;&quot;&quot;An example object to be published.&quot;&quot;&quot;</span>
309
310    <span class="py-src-variable">addSlash</span> = <span class="py-src-variable">True</span>
311
312    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_echo</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">x</span>):
313        <span class="py-src-string">&quot;&quot;&quot;Return all passed args.&quot;&quot;&quot;</span>
314        <span class="py-src-keyword">return</span> <span class="py-src-variable">x</span>
315
316    <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
317        <span class="py-src-string">&quot;&quot;&quot;Return sum of arguments.&quot;&quot;&quot;</span>
318        <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> + <span class="py-src-variable">b</span>
319
320<span class="py-src-variable">portal</span> = <span class="py-src-variable">portal</span>.<span class="py-src-variable">Portal</span>(<span class="py-src-variable">HTTPAuthRealm</span>())
321<span class="py-src-variable">checker</span> = <span class="py-src-variable">checkers</span>.<span class="py-src-variable">InMemoryUsernamePasswordDatabaseDontUse</span>(<span class="py-src-variable">guest</span>=<span class="py-src-string">'guest123'</span>)
322<span class="py-src-variable">portal</span>.<span class="py-src-variable">registerChecker</span>(<span class="py-src-variable">checker</span>)
323<span class="py-src-variable">rsrc</span> = <span class="py-src-variable">Example</span>()
324<span class="py-src-variable">credFactories</span> = (<span class="py-src-variable">basic</span>.<span class="py-src-variable">BasicCredentialFactory</span>(<span class="py-src-string">'My Realm'</span>),
325    <span class="py-src-variable">digest</span>.<span class="py-src-variable">DigestCredentialFactory</span>(<span class="py-src-string">'md5'</span>, <span class="py-src-string">'My Realm'</span>))
326<span class="py-src-variable">ifaces</span> = (<span class="py-src-variable">IHTTPUser</span>,)
327<span class="py-src-variable">root</span> = <span class="py-src-variable">wrapper</span>.<span class="py-src-variable">HTTPAuthResource</span>(<span class="py-src-variable">rsrc</span>, <span class="py-src-variable">credFactories</span>, <span class="py-src-variable">portal</span>, <span class="py-src-variable">ifaces</span>)
328
329<span class="py-src-variable">site</span> = <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>)
330<span class="py-src-variable">application</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">Application</span>(<span class="py-src-string">&quot;XML-RPC Auth Demo&quot;</span>)
331<span class="py-src-variable">s</span> = <span class="py-src-variable">strports</span>.<span class="py-src-variable">service</span>(<span class="py-src-string">'tcp:8080'</span>, <span class="py-src-variable">channel</span>.<span class="py-src-variable">HTTPFactory</span>(<span class="py-src-variable">site</span>))
332<span class="py-src-variable">s</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">application</span>)
333</pre><div class="caption">Source listing - <a href="../examples/xmlrpc/auth.tac"><span class="filename">../examples/xmlrpc/auth.tac</span></a></div></div><p>Accessing this from an interactive python session, we can see the inability
334to call the RPC methods unless we have supplied the correct name and password:
335
336<pre class="python-interpreter">
337&gt;&gt;&gt; from xmlrpclib import ServerProxy
338&gt;&gt;&gt; s = ServerProxy('http://localhost:8080/')
339&gt;&gt;&gt; s.echo('There are some who call me... Tim?')
340Traceback (most recent call last):
341  [snipped]
342&gt;&gt;&gt; s = ServerProxy('http://guest:guest123@localhost:8080/')
343&gt;&gt;&gt; s.echo('There are some who call me... Tim?')
344'There are some who call me... Tim?'
345</pre></p><h2>Migrating twisted.web XML-RPC to twisted.web2<a name="auto7"></a></h2><p>Migrating your XML-RPC servers written with
346<code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web.xmlrpc.html" title="twisted.web.xmlrpc">twisted.web.xmlrpc</a></code> to ones
347written with <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web2.xmlrpc.html" title="twisted.web2.xmlrpc">twisted.web2.xmlrpc</a></code> should be fairly
348trivial. There are three things you you need to do in order to migrate:
349
350<ul><li>add <code>addSlash</code></li><li>add <code>request</code> to the <code>xmlrpc_*</code> method
351signatures</li><li>wrap the <code>Site</code> instance in
352<code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web2.channel.http.HTTPFactory.html" title="twisted.web2.channel.http.HTTPFactory">HTTPFactory</a></code></li></ul>
353
354These are detailed below.
355</p><h3>Add <code>addSlash</code><a name="auto8"></a></h3><p>Each of your <code>xmlrpc.XMLRPC</code> classes needs to set the class
356attribute <code>addSlash = True</code>. All of the examples in this howto
357demonstrate this.</p><h3>Add <code>request</code> to the Method Signatures<a name="auto9"></a></h3><p>When defining <code>xmlrpc_*</code> methods in
358<code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web.xmlrpc.html" title="twisted.web.xmlrpc">twisted.web.xmlrpc</a></code>, you only needed to pass the
359<code>self</code> parameter. In <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web2.xmlrpc.html" title="twisted.web2.xmlrpc">twisted.web2.xmlrpc</a></code>,
360you need to pass two parameters, at the very minimum: <code>self</code> and
361<code>request</code>. This is also demonstrated clearly in the examples of this
362howto.</p><h3>Wrap the <code>Site</code> Object<a name="auto10"></a></h3><p>In <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web.xmlrpc.html" title="twisted.web.xmlrpc">twisted.web.xmlrpc</a></code>, a Site instance is passed to
363<code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.application.strports.service.html" title="twisted.application.strports.service">strports.service</a></code> or
364TCPServer (in <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.application.internet.html" title="twisted.application.internet">twisted.application.internet</a></code>). In
365<code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web2.xmlrpc.html" title="twisted.web2.xmlrpc">twisted.web2.xmlrpc</a></code>, the <code>Site</code> instance
366is passed to <code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.web2.channel.http.HTTPFactory.html" title="twisted.web2.channel.http.HTTPFactory">HTTPFactory</a></code>
367and then
368the factory is passed in
369<code class="API"><a href="http://twistedmatrix.com/documents/current/api/twisted.application.strports.service.html" title="twisted.application.strports.service">strports.service</a></code> or
370internet.TCPServer. As with the previous two, the examples in this howto show
371this clearly.
372</p></div><p><a href="web2_oubiwann/howto/../core/documentation/howto/index.html">Index</a></p><span class="version">Version: </span></body></html>