diff options
Diffstat (limited to 'vendor/Twisted-10.0.0/doc/web/howto')
35 files changed, 4835 insertions, 0 deletions
diff --git a/vendor/Twisted-10.0.0/doc/web/howto/client.html b/vendor/Twisted-10.0.0/doc/web/howto/client.html new file mode 100644 index 0000000000..22be61027f --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/client.html @@ -0,0 +1,469 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: + Using the Twisted Web Client + </title> +<link href="stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title"> + Using the Twisted Web Client + </h1> + <div class="toc"><ol><li><a href="#auto0"> + Overview + </a></li><ul><li><a href="#auto1"> + Prerequisites + </a></li></ul><li><a href="#auto2"> + The Agent + </a></li><ul><li><a href="#auto3">Issuing Requests</a></li><li><a href="#auto4"> + Receiving Responses + </a></li></ul><li><a href="#auto5"> + Conclusion + </a></li></ol></div> + <div class="content"> + <span/> + + <h2> + Overview + <a name="auto0"/></h2> + + <p> + This document describes how to use the HTTP client included in Twisted + Web. After reading it, you should be able to make HTTP requests using + Twisted Web. You will be able to specify the request method, headers, + and body and you will be able to retrieve the response code, headers, and + body. + </p> + + <h3> + Prerequisites + <a name="auto1"/></h3> + + <p> + This document assumes that you are familiar with <a href="../../core/howto/defer.html" shape="rect">Deferreds and Failures</a>, and <a href="../../core/howto/producers.html" shape="rect">producers and consumers</a>. + It also assumes you are familiar with the basic concepts of HTTP, such + as requests and responses, methods, headers, and message bodies. + </p> + + <h2> + The Agent + <a name="auto2"/></h2> + + <h3>Issuing Requests<a name="auto3"/></h3> + + <p> + The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.client.Agent.html" title="twisted.web.client.Agent">twisted.web.client.Agent</a></code> class is the entry + point into the client API. Requests are issued using the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.client.Agent.request.html" title="twisted.web.client.Agent.request">request</a></code> method, which + takes as parameters a request method, a request URI, the request headers, + and an object which can produce the request body (if there is to be one). + The agent is responsible for connection setup. Because of this, it + requires a reactor as an argument to its initializer. An example of + creating an agent and issuing a request using it might look like this: + </p> + + <div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +</p><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> +<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">client</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Agent</span> +<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">http_headers</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Headers</span> + +<span class="py-src-variable">agent</span> = <span class="py-src-variable">Agent</span>(<span class="py-src-variable">reactor</span>) + +<span class="py-src-variable">d</span> = <span class="py-src-variable">agent</span>.<span class="py-src-variable">request</span>( + <span class="py-src-string">'GET'</span>, + <span class="py-src-string">'http://example.com/'</span>, + <span class="py-src-variable">Headers</span>({<span class="py-src-string">'User-Agent'</span>: [<span class="py-src-string">'Twisted Web Client Example'</span>]}), + <span class="py-src-variable">None</span>) + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbResponse</span>(<span class="py-src-parameter">ignored</span>): + <span class="py-src-keyword">print</span> <span class="py-src-string">'Response received'</span> +<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">cbResponse</span>) + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbShutdown</span>(<span class="py-src-parameter">ignored</span>): + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>() +<span class="py-src-variable">d</span>.<span class="py-src-variable">addBoth</span>(<span class="py-src-variable">cbShutdown</span>) + +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre><div class="caption"> + Issue a request with an Agent + - <a href="listings/client/request.py"><span class="filename">listings/client/request.py</span></a></div></div> + + <p> + As may be obvious, this issues a new <em>GET</em> request for <em>/</em> + to the web server on <code>example.com</code>. <code>Agent</code> is + responsible for resolving the hostname into an IP address and connecting + to it on port 80. It is also responsible for cleaning up the connection + afterwards. This code sends a request which includes one custom header, + <em>User-Agent</em>. The last argument passed to <code>Agent.request</code> is + <code>None</code>, though, so the request has no body. + </p> + + <p> + Sending a request which does include a body requires passing an object + providing <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.iweb.IBodyProducer.html" title="twisted.web.iweb.IBodyProducer">twisted.web.iweb.IBodyProducer</a></code> + to <code>Agent.request</code>. This interface extends the more general + <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IPushProducer.html" title="twisted.internet.interfaces.IPushProducer">IPushProducer</a></code> + by adding a new <code>length</code> attribute and adding several + constraints to the way the producer and consumer interact. + </p> + + <ul> + <li> + The length attribute must be a non-negative integer or the constant + <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.iweb.UNKNOWN_LENGTH.html" title="twisted.web.iweb.UNKNOWN_LENGTH">twisted.web.iweb.UNKNOWN_LENGTH</a></code>. If the + length is known, it will be used to specify the value for the + <em>Content-Length</em> header in the request. If the length is + unknown the attribute should be set to <code>UNKNOWN_LENGTH</code>. + Since more servers support <em>Content-Length</em>, if a length can be + provided it should be. + </li> + + <li> + An additional method is required on <code>IEntityBodyProvider</code> + implementations: <code>startProducing</code>. This method is used to + associate a consumer with the producer. It should return a + <code>Deferred</code> which fires when all data has been produced. + </li> + + <li> + <code>IEntityBodyProvider</code> implementations should never call the + consumer's <code>unregisterProducer</code> method. Instead, when it + has produced all of the data it is going to produce, it should only + fire the <code>Deferred</code> returned by <code>startProducing</code>. + </li> + </ul> + + <p> + For additional details about the requirements of <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.iweb.IBodyProducer.html" title="twisted.web.iweb.IBodyProducer">IBodyProducer</a></code> implementations, see + the API documentation. + </p> + + <p> + Here's a simple <code>IEntityBodyProvider</code> implementation which + writes an in-memory string to the consumer: + </p> + + <div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +</p><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">implements</span> + +<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-variable">defer</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">succeed</span> +<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">iweb</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IBodyProducer</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">StringProducer</span>(<span class="py-src-parameter">object</span>): + <span class="py-src-variable">implements</span>(<span class="py-src-variable">IBodyProducer</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">body</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">body</span> = <span class="py-src-variable">body</span> + <span class="py-src-variable">self</span>.<span class="py-src-variable">length</span> = <span class="py-src-variable">len</span>(<span class="py-src-variable">body</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">startProducing</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">consumer</span>): + <span class="py-src-variable">consumer</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">body</span>) + <span class="py-src-keyword">return</span> <span class="py-src-variable">succeed</span>(<span class="py-src-variable">None</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">pauseProducing</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">pass</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">stopProducing</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">pass</span> +</pre><div class="caption"> + A string-based body producer. + - <a href="listings/client/stringprod.py"><span class="filename">listings/client/stringprod.py</span></a></div></div> + + <p> + This producer can be used to issue a request with a body: + </p> + + <div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +</p><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> +<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">client</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Agent</span> +<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">http_headers</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Headers</span> + +<span class="py-src-keyword">from</span> <span class="py-src-variable">stringprod</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">StringProducer</span> + +<span class="py-src-variable">agent</span> = <span class="py-src-variable">Agent</span>(<span class="py-src-variable">reactor</span>) +<span class="py-src-variable">body</span> = <span class="py-src-variable">StringProducer</span>(<span class="py-src-string">"hello, world"</span>) +<span class="py-src-variable">d</span> = <span class="py-src-variable">agent</span>.<span class="py-src-variable">request</span>( + <span class="py-src-string">'GET'</span>, + <span class="py-src-string">'http://example.com/'</span>, + <span class="py-src-variable">Headers</span>({<span class="py-src-string">'User-Agent'</span>: [<span class="py-src-string">'Twisted Web Client Example'</span>], + <span class="py-src-string">'Content-Type'</span>: [<span class="py-src-string">'text/x-greeting'</span>]}), + <span class="py-src-variable">body</span>) + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbResponse</span>(<span class="py-src-parameter">ignored</span>): + <span class="py-src-keyword">print</span> <span class="py-src-string">'Response received'</span> +<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">cbResponse</span>) + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbShutdown</span>(<span class="py-src-parameter">ignored</span>): + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>() +<span class="py-src-variable">d</span>.<span class="py-src-variable">addBoth</span>(<span class="py-src-variable">cbShutdown</span>) + +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre><div class="caption"> + Issue a request with a body. + - <a href="listings/client/sendbody.py"><span class="filename">listings/client/sendbody.py</span></a></div></div> + + <h3> + Receiving Responses + <a name="auto4"/></h3> + + <p> + So far, the examples have demonstrated how to issue a request. However, + they have ignored the response, except for showing that it is a + <code>Deferred</code> which seems to fire when the response has been + received. Next we'll cover what that response is and how to interpret + it. + </p> + + <p> + <code>Agent.request</code>, as with most <code>Deferred</code>-returning + APIs, can return a <code>Deferred</code> which fires with a + <code>Failure</code>. If the request fails somehow, this will be + reflected with a failure. This may be due to a problem looking up the + host IP address, or it may be because the HTTP server is not accepting + connections, or it may be because of a problem parsing the response, or + any other problem which arises which prevents the response from being + received. It does <em>not</em> include responses with an error status. + </p> + + <p> + If the request succeeds, though, the <code>Deferred</code> will fire with + a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.client.Response.html" title="twisted.web.client.Response">Response</a></code>. This + happens as soon as all the response headers have been received. It + happens before any of the response body, if there is one, is processed. + The <code>Response</code> object has several attributes giving the + response information: its code, version, phrase, and headers, as well as + the length of the body to expect. The <code>Response</code> object also + has a method which makes the response body available: <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web._newclient.Response.deliverBody.deliverBody.html" title="twisted.web._newclient.Response.deliverBody.deliverBody">deliverBody</a></code>. + Using the attributes of the response object and this method, here's an + example which displays part of the response to a request: + </p> + + <div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">pprint</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pformat</span> + +<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> +<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-variable">defer</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Deferred</span> +<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-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Protocol</span> +<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">client</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Agent</span> +<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">http_headers</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Headers</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">BeginningPrinter</span>(<span class="py-src-parameter">Protocol</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">finished</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">finished</span> = <span class="py-src-variable">finished</span> + <span class="py-src-variable">self</span>.<span class="py-src-variable">remaining</span> = <span class="py-src-number">1024</span> * <span class="py-src-number">10</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">dataReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">bytes</span>): + <span class="py-src-keyword">if</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">remaining</span>: + <span class="py-src-variable">display</span> = <span class="py-src-variable">bytes</span>[:<span class="py-src-variable">self</span>.<span class="py-src-variable">remaining</span>] + <span class="py-src-keyword">print</span> <span class="py-src-string">'Some data received:'</span> + <span class="py-src-keyword">print</span> <span class="py-src-variable">display</span> + <span class="py-src-variable">self</span>.<span class="py-src-variable">remaining</span> -= <span class="py-src-variable">len</span>(<span class="py-src-variable">display</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionLost</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">reason</span>): + <span class="py-src-keyword">print</span> <span class="py-src-string">'Finished receiving body:'</span>, <span class="py-src-variable">reason</span>.<span class="py-src-variable">getErrorMessage</span>() + <span class="py-src-variable">self</span>.<span class="py-src-variable">finished</span>.<span class="py-src-variable">callback</span>(<span class="py-src-variable">None</span>) + +<span class="py-src-variable">agent</span> = <span class="py-src-variable">Agent</span>(<span class="py-src-variable">reactor</span>) +<span class="py-src-variable">d</span> = <span class="py-src-variable">agent</span>.<span class="py-src-variable">request</span>( + <span class="py-src-string">'GET'</span>, + <span class="py-src-string">'http://example.com/'</span>, + <span class="py-src-variable">Headers</span>({<span class="py-src-string">'User-Agent'</span>: [<span class="py-src-string">'Twisted Web Client Example'</span>]}), + <span class="py-src-variable">None</span>) + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbRequest</span>(<span class="py-src-parameter">response</span>): + <span class="py-src-keyword">print</span> <span class="py-src-string">'Response version:'</span>, <span class="py-src-variable">response</span>.<span class="py-src-variable">version</span> + <span class="py-src-keyword">print</span> <span class="py-src-string">'Response code:'</span>, <span class="py-src-variable">response</span>.<span class="py-src-variable">code</span> + <span class="py-src-keyword">print</span> <span class="py-src-string">'Response phrase:'</span>, <span class="py-src-variable">response</span>.<span class="py-src-variable">phrase</span> + <span class="py-src-keyword">print</span> <span class="py-src-string">'Response headers:'</span> + <span class="py-src-keyword">print</span> <span class="py-src-variable">pformat</span>(<span class="py-src-variable">list</span>(<span class="py-src-variable">response</span>.<span class="py-src-variable">headers</span>.<span class="py-src-variable">getAllRawHeaders</span>())) + <span class="py-src-variable">finished</span> = <span class="py-src-variable">Deferred</span>() + <span class="py-src-variable">response</span>.<span class="py-src-variable">deliverBody</span>(<span class="py-src-variable">BeginningPrinter</span>(<span class="py-src-variable">finished</span>)) + <span class="py-src-keyword">return</span> <span class="py-src-variable">finished</span> +<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">cbRequest</span>) + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbShutdown</span>(<span class="py-src-parameter">ignored</span>): + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>() +<span class="py-src-variable">d</span>.<span class="py-src-variable">addBoth</span>(<span class="py-src-variable">cbShutdown</span>) + +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre><div class="caption"> + Inspect the response. + - <a href="listings/client/response.py"><span class="filename">listings/client/response.py</span></a></div></div> + + <p> + The <code>BeginningPrinter</code> protocol in this example is passed to + <code>Response.deliverBody</code> and the response body is then delivered + to its <code>dataReceived</code> method as it arrives. When the body has + been completely delivered, the protocol's <code>connectionLost</code> + method is called. It is important to inspect the <code>Failure</code> + passed to <code>connectionLost</code>. If the response body has been + completely received, the failure will wrap a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.client.ResponseDone.html" title="twisted.web.client.ResponseDone">twisted.web.client.ResponseDone</a></code> exception. This + indicates that it is <em>known</em> that all data has been received. It + is also possible for the failure to wrap a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.http.PotentialDataLoss.html" title="twisted.web.http.PotentialDataLoss">twisted.web.http.PotentialDataLoss</a></code> exception: this + indicates that the server framed the response such that there is no way + to know when the entire response body has been received. Only + HTTP/1.0 servers should behave this way. Finally, it is possible for + the exception to be of another type, indicating guaranteed data loss for + some reason (a lost connection, a memory error, etc). + </p> + + <p> + Just as protocols associated with a TCP connection are given a transport, + so will be a protocol passed to <code>deliverBody</code>. Since it makes + no sense to write more data to the connection at this stage of the + request, though, the transport <em>only</em> provides <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IPushProducer.html" title="twisted.internet.interfaces.IPushProducer">IPushProducer</a></code>. This allows the + protocol to control the flow of the response data: a call to the + transport's <code>pauseProducing</code> method will pause delivery; a + later call to <code>resumeProducing</code> will resume it. If it is + decided that the rest of the response body is not desired, + <code>stopProducing</code> can be used to stop delivery permanently; + after this, the protocol's <code>connectionLost</code> method will be + called. + </p> + + <p> + An important thing to keep in mind is that the body will only be read + from the connection after <code>Response.deliverBody</code> is called. + This also means that the connection will remain open until this is done + (and the body read). So, in general, any response with a body + <em>must</em> have that body read using <code>deliverBody</code>. If the + application is not interested in the body, it should issue a + <em>HEAD</em> request or use a protocol which immediately calls + <code>stopProducing</code> on its transport. + </p> + + <h2> + Conclusion + <a name="auto5"/></h2> + + <p> + You should now understand the basics of the Twisted Web HTTP client. In + particular, you should understand: + </p> + + <ul> + <li> + How to issue requests with arbitrary methods, headers, and bodies. + </li> + <li> + How to access the response version, code, phrase, headers, and body. + </li> + <li> + How to control the streaming of the response body. + </li> + </ul> + </div> + + <p><a href="index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/formindepth.html b/vendor/Twisted-10.0.0/doc/web/howto/formindepth.html new file mode 100644 index 0000000000..bbd7455c43 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/formindepth.html @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Form In Depth</title> +<link href="stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Form In Depth</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>XXX: To be written</p> + +</div> + + <p><a href="index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/glossary.html b/vendor/Twisted-10.0.0/doc/web/howto/glossary.html new file mode 100644 index 0000000000..780f4acf75 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/glossary.html @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Glossary</title> +<link href="stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Glossary</h1> + <div class="toc"><ol/></div> + <div class="content"> + <span/> + + <p class="note"><strong>Note: </strong>This glossary is very incomplete. Contributions are + welcome.</p> + + <dl> + <dt><a name="resource" shape="rect">resource</a></dt> + <dd> + An object accessible via HTTP at one or more URIs. In Twisted Web, + a resource is represented by an object which provides <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.IResource.html" title="twisted.web.resource.IResource">twisted.web.resource.IResource</a></code> and most often is + a subclass of <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">twisted.web.resource.Resource</a></code>. For example, here + is a resource which represents a simple HTML greeting. + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Greeting</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"Hello, world."</span> +</pre> + </dd> + </dl> + </div> + + <p><a href="index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/index.html b/vendor/Twisted-10.0.0/doc/web/howto/index.html new file mode 100644 index 0000000000..9850b37744 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/index.html @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Twisted.Web Documentation</title> +<link href="stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Twisted.Web Documentation</h1> + <div class="toc"><ol/></div> + <div class="content"> + +<span/> + +<ul class="toc"> + +<li>Introduction + <ul> + <li><a href="web-overview.html" shape="rect">Overview of Twisted Web</a></li> + </ul> +</li> + +<li>Web Applications + <ul> + <li><a href="using-twistedweb.html" shape="rect">Using twisted.web</a></li> + <li><a href="web-development.html" shape="rect">Web application development</a></li> + <li><a href="resource-templates.html" shape="rect">Quixote resource templates</a></li> + <li><a href="xmlrpc.html" shape="rect">XML-RPC and SOAP</a></li> + <li><a href="web-in-60/index.html" shape="rect">Twisted Web in 60 Seconds: A + series of short, complete examples using twisted.web</a></li> + </ul> +</li> + +<li>Other + <ul> + <li><a href="client.html" shape="rect">Using the Twisted Web Client</a></li> + </ul> +</li> + +<li>Appendix + <ul> + <li><a href="glossary.html" shape="rect">Glossary</a></li> + </ul> +</li> +</ul> +</div> + + <p><a href="index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/listings/client/request.py b/vendor/Twisted-10.0.0/doc/web/howto/listings/client/request.py new file mode 100644 index 0000000000..493186390d --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/listings/client/request.py @@ -0,0 +1,21 @@ +from twisted.internet import reactor +from twisted.web.client import Agent +from twisted.web.http_headers import Headers + +agent = Agent(reactor) + +d = agent.request( + 'GET', + 'http://example.com/', + Headers({'User-Agent': ['Twisted Web Client Example']}), + None) + +def cbResponse(ignored): + print 'Response received' +d.addCallback(cbResponse) + +def cbShutdown(ignored): + reactor.stop() +d.addBoth(cbShutdown) + +reactor.run() diff --git a/vendor/Twisted-10.0.0/doc/web/howto/listings/client/response.py b/vendor/Twisted-10.0.0/doc/web/howto/listings/client/response.py new file mode 100644 index 0000000000..6b3547c8dc --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/listings/client/response.py @@ -0,0 +1,47 @@ +from pprint import pformat + +from twisted.internet import reactor +from twisted.internet.defer import Deferred +from twisted.internet.protocol import Protocol +from twisted.web.client import Agent +from twisted.web.http_headers import Headers + +class BeginningPrinter(Protocol): + def __init__(self, finished): + self.finished = finished + self.remaining = 1024 * 10 + + def dataReceived(self, bytes): + if self.remaining: + display = bytes[:self.remaining] + print 'Some data received:' + print display + self.remaining -= len(display) + + def connectionLost(self, reason): + print 'Finished receiving body:', reason.getErrorMessage() + self.finished.callback(None) + +agent = Agent(reactor) +d = agent.request( + 'GET', + 'http://example.com/', + Headers({'User-Agent': ['Twisted Web Client Example']}), + None) + +def cbRequest(response): + print 'Response version:', response.version + print 'Response code:', response.code + print 'Response phrase:', response.phrase + print 'Response headers:' + print pformat(list(response.headers.getAllRawHeaders())) + finished = Deferred() + response.deliverBody(BeginningPrinter(finished)) + return finished +d.addCallback(cbRequest) + +def cbShutdown(ignored): + reactor.stop() +d.addBoth(cbShutdown) + +reactor.run() diff --git a/vendor/Twisted-10.0.0/doc/web/howto/listings/client/sendbody.py b/vendor/Twisted-10.0.0/doc/web/howto/listings/client/sendbody.py new file mode 100644 index 0000000000..31cac8fcfe --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/listings/client/sendbody.py @@ -0,0 +1,24 @@ +from twisted.internet import reactor +from twisted.web.client import Agent +from twisted.web.http_headers import Headers + +from stringprod import StringProducer + +agent = Agent(reactor) +body = StringProducer("hello, world") +d = agent.request( + 'GET', + 'http://example.com/', + Headers({'User-Agent': ['Twisted Web Client Example'], + 'Content-Type': ['text/x-greeting']}), + body) + +def cbResponse(ignored): + print 'Response received' +d.addCallback(cbResponse) + +def cbShutdown(ignored): + reactor.stop() +d.addBoth(cbShutdown) + +reactor.run() diff --git a/vendor/Twisted-10.0.0/doc/web/howto/listings/client/stringprod.py b/vendor/Twisted-10.0.0/doc/web/howto/listings/client/stringprod.py new file mode 100644 index 0000000000..da2b5cdffa --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/listings/client/stringprod.py @@ -0,0 +1,21 @@ +from zope.interface import implements + +from twisted.internet.defer import succeed +from twisted.web.iweb import IBodyProducer + +class StringProducer(object): + implements(IBodyProducer) + + def __init__(self, body): + self.body = body + self.length = len(body) + + def startProducing(self, consumer): + consumer.write(self.body) + return succeed(None) + + def pauseProducing(self): + pass + + def stopProducing(self): + pass diff --git a/vendor/Twisted-10.0.0/doc/web/howto/listings/soap.rpy b/vendor/Twisted-10.0.0/doc/web/howto/listings/soap.rpy new file mode 100644 index 0000000000..957380d2d8 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/listings/soap.rpy @@ -0,0 +1,13 @@ +from twisted.web import soap +import os + +def getQuote(): + return "That beverage, sir, is off the hizzy." + +class Quoter(soap.SOAPPublisher): + """Publish one method, 'quote'.""" + + def soap_quote(self): + return getQuote() + +resource = Quoter() diff --git a/vendor/Twisted-10.0.0/doc/web/howto/listings/webquote.rtl b/vendor/Twisted-10.0.0/doc/web/howto/listings/webquote.rtl new file mode 100644 index 0000000000..8807ac4320 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/listings/webquote.rtl @@ -0,0 +1,20 @@ +from twisted.web.resource import Resource + +def getQuote(): + return "An apple a day keeps the doctor away." + + +class QuoteResource(Resource): + + template render(self, request): + """\ + <html> + <head><title>Quotes Galore</title></head> + + <body><h1>Quotes</h1>""" + getQuote() + "</body></html>" + + +resource = QuoteResource() + diff --git a/vendor/Twisted-10.0.0/doc/web/howto/listings/xmlAndSoapQuote.py b/vendor/Twisted-10.0.0/doc/web/howto/listings/xmlAndSoapQuote.py new file mode 100644 index 0000000000..f17eb28317 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/listings/xmlAndSoapQuote.py @@ -0,0 +1,25 @@ +from twisted.web import soap, xmlrpc, resource, server +import os + +def getQuote(): + return "Victory to the burgeois, you capitalist swine!" + +class XMLRPCQuoter(xmlrpc.XMLRPC): + def xmlrpc_quote(self): + return getQuote() + +class SOAPQuoter(soap.SOAPPublisher): + def soap_quote(self): + return getQuote() + +def main(): + from twisted.internet import reactor + root = resource.Resource() + root.putChild('RPC2', XMLRPCQuoter()) + root.putChild('SOAP', SOAPQuoter()) + reactor.listenTCP(7080, server.Site(root)) + reactor.run() + +if __name__ == '__main__': + main() + diff --git a/vendor/Twisted-10.0.0/doc/web/howto/listings/xmlquote.rpy b/vendor/Twisted-10.0.0/doc/web/howto/listings/xmlquote.rpy new file mode 100644 index 0000000000..26b76f0a25 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/listings/xmlquote.rpy @@ -0,0 +1,12 @@ +from twisted.web import xmlrpc +import os + +def getQuote(): + return "What are you talking about, William?" + +class Quoter(xmlrpc.XMLRPC): + + def xmlrpc_quote(self): + return getQuote() + +resource = Quoter() diff --git a/vendor/Twisted-10.0.0/doc/web/howto/resource-templates.html b/vendor/Twisted-10.0.0/doc/web/howto/resource-templates.html new file mode 100644 index 0000000000..8e2bf6a8ee --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/resource-templates.html @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Light Weight Templating With Resource Templates</title> +<link href="stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Light Weight Templating With Resource Templates</h1> + <div class="toc"><ol><li><a href="#auto0">Overview</a></li><li><a href="#auto1">Configuring Twisted.Web</a></li><li><a href="#auto2">Using ResourceTemplate</a></li></ol></div> + <div class="content"> + <span/> + +<h2>Overview<a name="auto0"/></h2> + +<p>While high-level templating systems can be used with Twisted (for example, +<a href="http://divmod.org/trac/wiki/DivmodNevow" shape="rect">Divmod Nevow</a>, sometimes +one needs a less file-heavy system which lets one directly write HTML. While +ResourceScripts are available, they have a high overhead of coding, needing +some boring string arithmetic. ResourceTemplates fill the space between Nevow +and ResourceScript using Quixote's PTL (Python Templating Language).</p> + +<p>ResourceTemplates need Quixote installed. In +<a href="http://www.debian.org" shape="rect">Debian</a>, that means using Python 2.2 +and installing the <code>quixote</code> package +(<code>apt-get install quixote</code>). Other operating systems require +other ways to install quixote, or it can be done manually.</p> + +<h2>Configuring Twisted.Web<a name="auto1"/></h2> + +<p>The easiest way to get Twisted.Web to support ResourceTemplates is to +bind them to some extension using the web tap's <code>--processor</code> +flag. Here is an example:</p> + +<pre xml:space="preserve"> +% twistd web --path=/var/www \ + --processor=.rtl=twisted.web.script.ResourceTemplate +</pre> + +<p>The above command line binds the <code>rtl</code> extension to use the +ResourceTemplate processor. Other ways are possible, but would require +more Python coding and are outside the scope of this HOWTO.</p> + +<h2>Using ResourceTemplate<a name="auto2"/></h2> + +<p>ResourceTemplates are coded in an extension of Python called the +<q>Python Templating Language</q>. Complete documentation of the PTL +is available at <a href="http://www.mems-exchange.org/software/quixote/doc/PTL.html" shape="rect">the quixote web site</a>. The web server +will expect the PTL source file to define a variable named +<code>resource</code>. +This should be a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Resource.html" title="twisted.web.server.Resource">twisted.web.server.Resource</a></code>, +whose <code>.render</code> method be called. Usually, you would want +to define <code>render</code> using the keyword <code>template</code> +rather than <code>def</code>.</p> + +<p>Here is a simple example for a resource template.</p> + +<div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">getQuote</span>(): + <span class="py-src-keyword">return</span> <span class="py-src-string">"An apple a day keeps the doctor away."</span> + + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">QuoteResource</span>(<span class="py-src-parameter">Resource</span>): + + <span class="py-src-variable">template</span> <span class="py-src-variable">render</span>(<span class="py-src-variable">self</span>, <span class="py-src-variable">request</span>): + <span class="py-src-string">"""\ + <html> + <head><title>Quotes Galore</title></head> + + <body><h1>Quotes</h1>"""</span> + <span class="py-src-variable">getQuote</span>() + <span class="py-src-string">"</body></html>"</span> + + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">QuoteResource</span>() +</pre><div class="caption">Resource Template for Quotes - <a href="listings/webquote.rtl"><span class="filename">listings/webquote.rtl</span></a></div></div> + +</div> + + <p><a href="index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/using-twistedweb.html b/vendor/Twisted-10.0.0/doc/web/howto/using-twistedweb.html new file mode 100644 index 0000000000..c0577be0d1 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/using-twistedweb.html @@ -0,0 +1,972 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Configuring and Using the Twisted.Web Server</title> +<link href="stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Configuring and Using the Twisted.Web Server</h1> + <div class="toc"><ol><li><a href="#auto0">Twisted Web Development</a></li><ul><li><a href="#auto1">Main Concepts</a></li><li><a href="#auto2">Site Objects</a></li><li><a href="#auto3">Resource objects</a></li><li><a href="#auto4">Resource Trees</a></li><li><a href="#auto5">.rpy scripts</a></li><li><a href="#auto6">Resource rendering</a></li><li><a href="#auto7">Session</a></li></ul><li><a href="#auto8">Advanced Configuration</a></li><ul><li><a href="#auto9">Adding Children</a></li><li><a href="#auto10">Modifying File Resources</a></li><li><a href="#auto11">Virtual Hosts</a></li><li><a href="#auto12">Advanced Techniques</a></li></ul><li><a href="#auto13">Running a Twisted Web Server</a></li><ul><li><a href="#auto14">Serving Flat HTML</a></li><li><a href="#auto15">Resource Scripts</a></li><li><a href="#auto16">Web UIs</a></li><li><a href="#auto17">Spreadable Web Servers</a></li><li><a href="#auto18">Serving PHP/Perl/CGI</a></li><li><a href="#auto19">Serving WSGI Applications</a></li><li><a href="#auto20">Using VHostMonster</a></li></ul><li><a href="#auto21">Rewriting URLs</a></li><li><a href="#auto22">Knowing When We're Not Wanted</a></li><li><a href="#auto23">As-Is Serving</a></li></ol></div> + <div class="content"> +<span/> + +<h2>Twisted Web Development<a name="auto0"/></h2><a name="development" shape="rect"/> + +<p>Twisted Web serves Python objects that implement the interface +IResource.</p> + +<br clear="none"/><img alt="Twisted Web process" src="../img/web-process.png"/> + +<h3>Main Concepts<a name="auto1"/></h3> + +<ul> + +<li><a href="#sites" shape="rect">Site Objects</a> are responsible for creating +<code>HTTPChannel</code> instances to parse the HTTP request, and begin the object lookup process. They contain the root Resource, the resource which represents the URL <code>/</code> on the site.</li> + +<li><a href="#resources" shape="rect">Resource</a> objects represent a single URL segment. The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.IResource.html" title="twisted.web.resource.IResource">IResource</a></code> interface describes the methods a Resource object must implement in order to participate in the object publishing process.</li> + +<li><a href="#trees" shape="rect">Resource trees</a> are arrangements of Resource objects into a Resource tree. Starting at the root Resource object, the tree of Resource objects defines the URLs which will be valid.</li> + +<li><a href="#rpys" shape="rect">.rpy scripts</a> are python scripts which the twisted.web static file server will execute, much like a CGI. However, unlike CGI they must create a Resource object which will be rendered when the URL is visited.</li> + +<li><a href="#rendering" shape="rect">Resource rendering</a> occurs when Twisted Web locates a leaf Resource object. A Resource can either return an html string or write to the request object.</li> + +<li><a href="#sessions" shape="rect">Session</a> objects allow you to store information across multiple requests. Each individual browser using the system has a unique Session instance.</li> + +</ul> + +<p>The Twisted.Web server is started through the Twisted Daemonizer, as in:</p> + +<pre class="shell" xml:space="preserve"> +% twistd web +</pre> + +<h3>Site Objects<a name="auto2"/></h3> +<a name="sites" shape="rect"/> + +<p>Site objects serve as the glue between a port to listen for HTTP requests on, and a root Resource object.</p> + +<p>When using <code>twistd -n web --path /foo/bar/baz</code>, a Site object is created with a root Resource that serves files out of the given path.</p> + +<p>You can also create a <code>Site</code> instance by hand, passing it a +<code>Resource</code> object which will serve as the root of the site:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +</p><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-keyword">import</span> <span class="py-src-variable">server</span>, <span class="py-src-variable">resource</span> +<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> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Simple</span>(<span class="py-src-parameter">resource</span>.<span class="py-src-parameter">Resource</span>): + <span class="py-src-variable">isLeaf</span> = <span class="py-src-variable">True</span> + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"<html>Hello, world!</html>"</span> + +<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">Simple</span>()) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8080</span>, <span class="py-src-variable">site</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<h3>Resource objects<a name="auto3"/></h3> +<a name="resources" shape="rect"/> + +<p><code>Resource</code> objects represent a single URL segment of a site. During URL parsing, <code>getChild</code> is called on the current <code>Resource</code> to produce the next <code>Resource</code> object.</p> + +<p>When the leaf Resource is reached, either because there were no more URL segments or a Resource had isLeaf set to True, the leaf Resource is rendered by calling <code>render(request)</code>. See <q>Resource Rendering</q> below for more about this.</p> + +<p>During the Resource location process, the URL segments which have already been processed and those which have not yet been processed are available in <code>request.prepath</code> and <code>request.postpath</code>.</p> + +<p>A Resource can know where it is in the URL tree by looking at <code>request.prepath</code>, a list of URL segment strings.</p> + +<p>A Resource can know which path segments will be processed after it by looking at <code>request.postpath</code>.</p> + +<p>If the URL ends in a slash, for example <code>http://example.com/foo/bar/</code>, the final URL segment will be an empty string. Resources can thus know if they were requested with or without a final slash.</p> + +<p>Here is a simple Resource object:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Hello</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-variable">isLeaf</span> = <span class="py-src-variable">True</span> + <span class="py-src-keyword">def</span> <span class="py-src-identifier">getChild</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">name</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">''</span>: + <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span> + <span class="py-src-keyword">return</span> <span class="py-src-variable">Resource</span>.<span class="py-src-variable">getChild</span>(<span class="py-src-variable">self</span>, <span class="py-src-variable">name</span>, <span class="py-src-variable">request</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"Hello, world! I am located at %r."</span> % (<span class="py-src-variable">request</span>.<span class="py-src-variable">prepath</span>,) + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">Hello</span>() +</pre> + +<h3>Resource Trees<a name="auto4"/></h3> +<a name="trees" shape="rect"/> + +<p>Resources can be arranged in trees using <code>putChild</code>. <code>putChild</code> puts a Resource instance into another Resource instance, making it available at the given path segment name:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><span class="py-src-variable">root</span> = <span class="py-src-variable">Hello</span>() +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">'fred'</span>, <span class="py-src-variable">Hello</span>()) +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">'bob'</span>, <span class="py-src-variable">Hello</span>()) +</pre> + +<p>If this root resource is served as the root of a Site instance, the following URLs will all be valid:</p> + +<ul> +<li><code>http://example.com/</code></li> +<li><code>http://example.com/fred</code></li> +<li><code>http://example.com/bob</code></li> +<li><code>http://example.com/fred/</code></li> +<li><code>http://example.com/bob/</code></li> + +</ul> + +<h3>.rpy scripts<a name="auto5"/></h3> +<a name="rpys" shape="rect"/> + +<p>Files with the extension <code>.rpy</code> are python scripts which, when placed in a directory served by Twisted Web, will be executed when visited through the web.</p> + +<p>An <code>.rpy</code> script must define a variable, <code>resource</code>, which is the Resource object that will render the request.</p> + +<p><code>.rpy</code> files are very convenient for rapid development and prototyping. Since they are executed on every web request, defining a Resource subclass in an <code>.rpy</code> will make viewing the results of changes to your class visible simply by refreshing the page:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyResource</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"<html>Hello, world!</html>"</span> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">MyResource</span>() +</pre> + +<p>However, it is often a better idea to define Resource subclasses in Python modules. In order for changes in modules to be visible, you must either restart the Python process, or reload the module:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +</p><span class="py-src-keyword">import</span> <span class="py-src-variable">myresource</span> + +<span class="py-src-comment">## Comment out this line when finished debugging</span> +<span class="py-src-variable">reload</span>(<span class="py-src-variable">myresource</span>) + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">myresource</span>.<span class="py-src-variable">MyResource</span>() +</pre> + +<p>Creating a Twisted Web server which serves a directory is easy:</p> + +<pre class="shell" xml:space="preserve"> +% twistd -n web --path /Users/dsp/Sites +</pre> + +<h3>Resource rendering<a name="auto6"/></h3> +<a name="rendering" shape="rect"/> + +<p>Resource rendering occurs when Twisted Web locates a leaf Resource object to handle a web request. A Resource's <code>render</code> method may do various things to produce output which will be sent back to the browser:</p> + +<ul> +<li>Return a string</li> +<li>Call <code>request.write("stuff")</code> as many times as desired, then call <code>request.finish()</code> and return <code>server.NOT_DONE_YET</code> (This is deceptive, since you are in fact done with the request, but is the correct way to do this)</li> + +<li>Request a <code>Deferred</code>, return <code>server.NOT_DONE_YET</code>, and call <code>request.write("stuff")</code> and <code>request.finish()</code> later, in a callback on the <code>Deferred</code>.</li> +</ul> + +<p> + +The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code> +class, which is usually what one's Resource classes subclass, has a +convenient default implementation of <code class="python">render</code>. It will call a method named <code class="python">self.render_METHOD</code> where <q>METHOD</q> is +whatever HTTP method was used to request this resource. Examples: +request_GET, request_POST, request_HEAD, and so on. It is recommended +that you have your resource classes subclass <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code> and implement <code class="python">render_METHOD</code> methods as opposed to <code class="python">render</code> itself. Note that for certain resources, +<code class="python">request_POST = request_GET</code> may be +desirable in case one wants to process arguments passed to the +resource regardless of whether they used GET +(<code>?foo=bar&baz=quux</code>, and so forth) or POST. + +</p> + +<h3>Session<a name="auto7"/></h3> +<a name="sessions" shape="rect"/> + +<p>HTTP is a stateless protocol; every request-response is treated as an individual unit, distinguishable from any other request only by the URL requested. With the advent of Cookies in the mid nineties, dynamic web servers gained the ability to distinguish between requests coming from different <em>browser sessions</em> by sending a Cookie to a browser. The browser then sends this cookie whenever it makes a request to a web server, allowing the server to track which requests come from which browser session.</p> + +<p>Twisted Web provides an abstraction of this browser-tracking behavior called the <em>Session object</em>. Calling <code>request.getSession()</code> checks to see if a session cookie has been set; if not, it creates a unique session id, creates a Session object, stores it in the Site, and returns it. If a session object already exists, the same session object is returned. In this way, you can store data specific to the session in the session object.</p> + +<img src="../img/web-session.png"/> + +<h2>Advanced Configuration<a name="auto8"/></h2> + +<p>Non-trivial configurations of Twisted Web are achieved with Python +configuration files. This is a Python snippet which builds up a variable +called application. Usually, a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.application.internet.TCPServer.html" title="twisted.application.internet.TCPServer">twisted.application.internet.TCPServer</a></code> instance will +be used to make the application listen on a TCP port (80, in case direct +web serving is desired), with the listener being a +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Site.html" title="twisted.web.server.Site">twisted.web.server.Site</a></code>. The resulting file can then +be run with <code class="shell">twistd -y</code>. Alternatively a reactor +object can be used directly to make a runnable script.</p> + +<p>The <code>Site</code> will wrap a <code>Resource</code> object -- the +root.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +9 +</p><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">internet</span>, <span class="py-src-variable">service</span> +<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-keyword">import</span> <span class="py-src-variable">static</span>, <span class="py-src-variable">server</span> + +<span class="py-src-variable">root</span> = <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/htdocs"</span>) +<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">'web'</span>) +<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>) +<span class="py-src-variable">sc</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>) +<span class="py-src-variable">i</span> = <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">80</span>, <span class="py-src-variable">site</span>) +<span class="py-src-variable">i</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">sc</span>) +</pre> + +<p>Most advanced configurations will be in the form of tweaking the +root resource object.</p> + +<h3>Adding Children<a name="auto9"/></h3> + +<p>Usually, the root's children will be based on the filesystem's contents. +It is possible to override the filesystem by explicit <code>putChild</code> +methods.</p> + +<p>Here are two examples. The first one adds a <code>/doc</code> child +to serve the documentation of the installed packages, while the second +one adds a <code>cgi-bin</code> directory for CGI scripts.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +</p><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> +<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-keyword">import</span> <span class="py-src-variable">static</span>, <span class="py-src-variable">server</span> + +<span class="py-src-variable">root</span> = <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/htdocs"</span>) +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"doc"</span>, <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/usr/share/doc"</span>)) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">80</span>, <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>)) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +</p><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> +<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-keyword">import</span> <span class="py-src-variable">static</span>, <span class="py-src-variable">server</span>, <span class="py-src-variable">twcgi</span> + +<span class="py-src-variable">root</span> = <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/htdocs"</span>) +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"cgi-bin"</span>, <span class="py-src-variable">twcgi</span>.<span class="py-src-variable">CGIDirectory</span>(<span class="py-src-string">"/var/www/cgi-bin"</span>)) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">80</span>, <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>)) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<h3>Modifying File Resources<a name="auto10"/></h3> + +<p><code>File</code> resources, be they root object or children thereof, +have two important attributes that often need to be modified: +<code>indexNames</code> and <code>processors</code>. <code>indexNames</code> +determines which files are treated as <q>index files</q> -- served +up when a directory is rendered. <code>processors</code> determine how +certain file extensions are treated.</p> + +<p>Here is an example for both, creating a site where all <code>.rpy</code> +extensions are Resource Scripts, and which renders directories by +searching for a <code>index.rpy</code> file.</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +</p><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">internet</span>, <span class="py-src-variable">service</span> +<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-keyword">import</span> <span class="py-src-variable">static</span>, <span class="py-src-variable">server</span>, <span class="py-src-variable">script</span> + +<span class="py-src-variable">root</span> = <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/htdocs"</span>) +<span class="py-src-variable">root</span>.<span class="py-src-variable">indexNames</span>=[<span class="py-src-string">'index.rpy'</span>] +<span class="py-src-variable">root</span>.<span class="py-src-variable">processors</span> = {<span class="py-src-string">'.rpy'</span>: <span class="py-src-variable">script</span>.<span class="py-src-variable">ResourceScript</span>} +<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">'web'</span>) +<span class="py-src-variable">sc</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>) +<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>) +<span class="py-src-variable">i</span> = <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">80</span>, <span class="py-src-variable">site</span>) +<span class="py-src-variable">i</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">sc</span>) +</pre> + +<p><code>File</code> objects also have a method called <code>ignoreExt</code>. +This method can be used to give extension-less URLs to users, so that +implementation is hidden. Here is an example:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +</p><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">internet</span>, <span class="py-src-variable">service</span> +<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-keyword">import</span> <span class="py-src-variable">static</span>, <span class="py-src-variable">server</span>, <span class="py-src-variable">script</span> + +<span class="py-src-variable">root</span> = <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/htdocs"</span>) +<span class="py-src-variable">root</span>.<span class="py-src-variable">ignoreExt</span>(<span class="py-src-string">".rpy"</span>) +<span class="py-src-variable">root</span>.<span class="py-src-variable">processors</span> = {<span class="py-src-string">'.rpy'</span>: <span class="py-src-variable">script</span>.<span class="py-src-variable">ResourceScript</span>} +<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">'web'</span>) +<span class="py-src-variable">sc</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>) +<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>) +<span class="py-src-variable">i</span> = <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">80</span>, <span class="py-src-variable">site</span>) +<span class="py-src-variable">i</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">sc</span>) +</pre> + +<p>Now, a URL such as <code>/foo</code> might be served from a Resource +Script called <code>foo.rpy</code>, if no file by the name of <code>foo</code> +exists.</p> + +<h3>Virtual Hosts<a name="auto11"/></h3> + +<p>Virtual hosting is done via a special resource, that should be +used as the root resource -- <code>NameVirtualHost</code>. +<code>NameVirtualHost</code> has an attribute named <code>default</code>, +which holds the default website. If a different root for some other +name is desired, the <code>addHost</code> method should be called.</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +</p><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">internet</span>, <span class="py-src-variable">service</span> +<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-keyword">import</span> <span class="py-src-variable">static</span>, <span class="py-src-variable">server</span>, <span class="py-src-variable">vhost</span>, <span class="py-src-variable">script</span> + +<span class="py-src-variable">root</span> = <span class="py-src-variable">vhost</span>.<span class="py-src-variable">NameVirtualHost</span>() + +<span class="py-src-comment"># Add a default -- htdocs</span> +<span class="py-src-variable">root</span>.<span class="py-src-variable">default</span>=<span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/htdocs"</span>) + +<span class="py-src-comment"># Add a simple virtual host -- foo.com</span> +<span class="py-src-variable">root</span>.<span class="py-src-variable">addHost</span>(<span class="py-src-string">"foo.com"</span>, <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/foo"</span>)) + +<span class="py-src-comment"># Add a simple virtual host -- bar.com</span> +<span class="py-src-variable">root</span>.<span class="py-src-variable">addHost</span>(<span class="py-src-string">"bar.com"</span>, <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/bar"</span>)) + +<span class="py-src-comment"># The "baz" people want to use Resource Scripts in their web site</span> +<span class="py-src-variable">baz</span> = <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/baz"</span>) +<span class="py-src-variable">baz</span>.<span class="py-src-variable">processors</span> = {<span class="py-src-string">'.rpy'</span>: <span class="py-src-variable">script</span>.<span class="py-src-variable">ResourceScript</span>} +<span class="py-src-variable">baz</span>.<span class="py-src-variable">ignoreExt</span>(<span class="py-src-string">'.rpy'</span>) +<span class="py-src-variable">root</span>.<span class="py-src-variable">addHost</span>(<span class="py-src-string">'baz'</span>, <span class="py-src-variable">baz</span>) + +<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">'web'</span>) +<span class="py-src-variable">sc</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>) +<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>) +<span class="py-src-variable">i</span> = <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">80</span>, <span class="py-src-variable">site</span>) +<span class="py-src-variable">i</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">sc</span>) +</pre> + +<h3>Advanced Techniques<a name="auto12"/></h3> + +<p>Since the configuration is a Python snippet, it is possible to +use the full power of Python. Here are some simple examples:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +</p><span class="py-src-comment"># No need for configuration of virtual hosts -- just make sure</span> +<span class="py-src-comment"># a directory /var/vhosts/<vhost name> exists:</span> +<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-keyword">import</span> <span class="py-src-variable">vhost</span>, <span class="py-src-variable">static</span>, <span class="py-src-variable">server</span> +<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">internet</span>, <span class="py-src-variable">service</span> + +<span class="py-src-variable">root</span> = <span class="py-src-variable">vhost</span>.<span class="py-src-variable">NameVirtualHost</span>() +<span class="py-src-variable">root</span>.<span class="py-src-variable">default</span> = <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/htdocs"</span>) +<span class="py-src-keyword">for</span> <span class="py-src-variable">dir</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">os</span>.<span class="py-src-variable">listdir</span>(<span class="py-src-string">"/var/vhosts"</span>): + <span class="py-src-variable">root</span>.<span class="py-src-variable">addHost</span>(<span class="py-src-variable">dir</span>, <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-variable">os</span>.<span class="py-src-variable">path</span>.<span class="py-src-variable">join</span>(<span class="py-src-string">"/var/vhosts"</span>, <span class="py-src-variable">dir</span>))) + +<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">'web'</span>) +<span class="py-src-variable">sc</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>) +<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>) +<span class="py-src-variable">i</span> = <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">80</span>, <span class="py-src-variable">site</span>) +<span class="py-src-variable">i</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">sc</span>) +</pre> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +</p><span class="py-src-comment"># Determine ports we listen on based on a file with numbers:</span> +<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-keyword">import</span> <span class="py-src-variable">vhost</span>, <span class="py-src-variable">static</span>, <span class="py-src-variable">server</span> +<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">internet</span>, <span class="py-src-variable">service</span> + +<span class="py-src-variable">root</span> = <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/var/www/htdocs"</span>) + +<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>) +<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">'web'</span>) +<span class="py-src-variable">serviceCollection</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>) + +<span class="py-src-keyword">for</span> <span class="py-src-variable">num</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">map</span>(<span class="py-src-variable">int</span>, <span class="py-src-variable">open</span>(<span class="py-src-string">"/etc/web/ports"</span>).<span class="py-src-variable">read</span>().<span class="py-src-variable">split</span>()): + <span class="py-src-variable">serviceCollection</span>.<span class="py-src-variable">addCollection</span>(<span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-variable">num</span>, <span class="py-src-variable">site</span>)) +</pre> + + +<h2>Running a Twisted Web Server<a name="auto13"/></h2> + +<p>In many cases, you'll end up repeating common usage patterns of +twisted.web. In those cases you'll probably want to use Twisted's +pre-configured web server setup.</p> + +<p>The easiest way to run a Twisted Web server is with the Twisted Daemonizer. +For example, this command will run a web server which serves static files from +a particular directory:</p> + +<pre class="shell" xml:space="preserve"> +% twistd web --path /path/to/web/content +</pre> + +<p>If you just want to serve content from your own home directory, the +following will do:</p> + +<pre class="shell" xml:space="preserve"> +% twistd web --path ~/public_html/ +</pre> + +<p>You can stop the server at any time by going back to the directory you +started it in and running the command:</p> + +<pre class="shell" xml:space="preserve"> +% kill `cat twistd.pid` +</pre> + +<p> Some other configuration options are available as well: </p> + +<ul> + <li> <code>--port</code>: Specify the port for the web + server to listen on. This defaults to 8080. </li> + <li> <code>--logfile</code>: Specify the path to the + log file. </li> +</ul> + +<p> The full set of options that are available can be seen with: </p> + +<pre class="shell" xml:space="preserve"> +% twistd web --help +</pre> + +<h3>Serving Flat HTML<a name="auto14"/></h3> + +<p> Twisted.Web serves flat HTML files just as it does any other flat file. </p> + +<a name="ResourceScripts" shape="rect"/> +<h3>Resource Scripts<a name="auto15"/></h3> + +<p> A Resource script is a Python file ending with the extension <code>.rpy</code>, which is required to create an instance of a (subclass of a) <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">twisted.web.resource.Resource</a></code>. </p> + +<p> Resource scripts have 3 special variables: </p> + +<ul> + <li> <code class="py-src-identifier">__file__</code>: The name of the .rpy file, including the full path. This variable is automatically defined and present within the namespace. </li> + <li> <code class="py-src-identifier">registry</code>: An object of class <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.static.Registry.html" title="twisted.web.static.Registry">static.Registry</a></code>. It can be used to access and set persistent data keyed by a class.</li> + <li> <code class="py-src-identifier">resource</code>: The variable which must be defined by the script and set to the resource instance that will be used to render the page. </li> +</ul> + +<p> A very simple Resource Script might look like: </p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +</p><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-keyword">import</span> <span class="py-src-variable">resource</span> +<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyGreatResource</span>(<span class="py-src-parameter">resource</span>.<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"<html>foo</html>"</span> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">MyGreatResource</span>() +</pre> + +<p> A slightly more complicated resource script, which accesses some +persistent data, might look like:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +</p><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-keyword">import</span> <span class="py-src-variable">resource</span> +<span class="py-src-keyword">from</span> <span class="py-src-variable">SillyWeb</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Counter</span> + +<span class="py-src-variable">counter</span> = <span class="py-src-variable">registry</span>.<span class="py-src-variable">getComponent</span>(<span class="py-src-variable">Counter</span>) +<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">counter</span>: + <span class="py-src-variable">registry</span>.<span class="py-src-variable">setComponent</span>(<span class="py-src-variable">Counter</span>, <span class="py-src-variable">Counter</span>()) +<span class="py-src-variable">counter</span> = <span class="py-src-variable">registry</span>.<span class="py-src-variable">getComponent</span>(<span class="py-src-variable">Counter</span>) + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyResource</span>(<span class="py-src-parameter">resource</span>.<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">counter</span>.<span class="py-src-variable">increment</span>() + <span class="py-src-keyword">return</span> <span class="py-src-string">"you are visitor %d"</span> % <span class="py-src-variable">counter</span>.<span class="py-src-variable">getValue</span>() + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">MyResource</span>() +</pre> + +<p> This is assuming you have the <code>SillyWeb.Counter</code> module, +implemented something like the following:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>: + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">value</span> = <span class="py-src-number">0</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">increment</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">value</span> += <span class="py-src-number">1</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">getValue</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">value</span> +</pre> + +<h3>Web UIs<a name="auto16"/></h3> + +<p> +The +<a href="http://www.divmod.org/projects/nevow" shape="rect">Nevow</a> framework, available as +part of the <a href="http://www.divmod.org/projects/quotient" shape="rect">Quotient</a> project, +is an advanced system for giving Web UIs to your application. Nevow uses Twisted Web but is +not itself part of Twisted. +</p> + +<a name="SpreadableWebServers" shape="rect"/> +<h3>Spreadable Web Servers<a name="auto17"/></h3> + +<p> One of the most interesting applications of Twisted.Web is the distributed webserver; multiple servers can all answer requests on the same port, using the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.html" title="twisted.spread">twisted.spread</a></code> package for <q>spreadable</q> computing. In two different directories, run the commands: </p> + +<pre class="shell" xml:space="preserve"> +% twistd web --user +% twistd web --personal [other options, if you desire] +</pre> + +<p> Once you're running both of these instances, go to <code>http://localhost:8080/your_username.twistd/</code> -- you will see the front page from the server you created with the <code>--personal</code> option. What's happening here is that the request you've sent is being relayed from the central (User) server to your own (Personal) server, over a PB connection. This technique can be highly useful for small <q>community</q> sites; using the code that makes this demo work, you can connect one HTTP port to multiple resources running with different permissions on the same machine, on different local machines, or even over the internet to a remote site. </p> + +<p> +By default, a personal server listens on a UNIX socket in the owner's home +directory. The <code class="shell">--port</code> option can be used to make +it listen on a different address, such as a TCP or SSL server or on a UNIX +server in a different location. If you use this option to make a personal +server listen on a different address, the central (User) server won't be +able to find it, but a custom server which uses the same APIs as the central +server might. Another use of the <code class="shell">--port</code> option +is to make the UNIX server robust against system crashes. If the server +crashes and the UNIX socket is left on the filesystem, the personal server +will not be able to restart until it is removed. However, if <code class="shell">--port unix:/home/username/.twistd-web-pb:wantPID=1</code> is +supplied when creating the personal server, then a lockfile will be used to +keep track of whether the server socket is in use and automatically delete +it when it is not. +</p> + +<h3>Serving PHP/Perl/CGI<a name="auto18"/></h3> + +<p>Everything related to CGI is located in the +<code>twisted.web.twcgi</code>, and it's here you'll find the classes that you +need to subclass in order to support the language of your (or somebody elses) +taste. You'll also need to create your own kind of resource if you are using a +non-unix operatingsystem (such as Windows), or if the default resources has +wrong pathnames to the parsers.</p> + +<p>The following snippet is a .rpy that serves perl-files. Look at <code>twisted.web.twcgi</code> +for more examples regarding twisted.web and CGI.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +9 +</p><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-keyword">import</span> <span class="py-src-variable">static</span>, <span class="py-src-variable">twcgi</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">PerlScript</span>(<span class="py-src-parameter">twcgi</span>.<span class="py-src-parameter">FilteredScript</span>): + <span class="py-src-variable">filter</span> = <span class="py-src-string">'/usr/bin/perl'</span> <span class="py-src-comment"># Points to the perl parser</span> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">static</span>.<span class="py-src-variable">File</span>(<span class="py-src-string">"/perlsite"</span>) <span class="py-src-comment"># Points to the perl website</span> +<span class="py-src-variable">resource</span>.<span class="py-src-variable">processors</span> = {<span class="py-src-string">".pl"</span>: <span class="py-src-variable">PerlScript</span>} <span class="py-src-comment"># Files that end with .pl will be</span> + <span class="py-src-comment"># processed by PerlScript</span> +<span class="py-src-variable">resource</span>.<span class="py-src-variable">indexNames</span> = [<span class="py-src-string">'index.pl'</span>] +</pre> + +<h3>Serving WSGI Applications<a name="auto19"/></h3> + +<p><a href="http://wsgi.org/wsgi/" shape="rect">WSGI</a> is the Web Server Gateway +Interface. It is a specification for web servers and application servers to +communicate with Python web applications. All modern Python web frameworks +support the WSGI interface.</p> + +<p>The easiest way to get started with WSGI application is to use the twistd +command:</p> + +<pre class="shell" xml:space="preserve"> +% twistd -n web --wsgi=helloworld.application +</pre> + +<p>This assumes that you have a WSGI application called application in +your helloworld module/package, which might look like this:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><span class="py-src-keyword">def</span> <span class="py-src-identifier">application</span>(<span class="py-src-parameter">environ</span>, <span class="py-src-parameter">start_response</span>): + <span class="py-src-string">"""Basic WSGI Application"""</span> + <span class="py-src-variable">start_response</span>(<span class="py-src-string">'200 OK'</span>, [(<span class="py-src-string">'Content-type'</span>,<span class="py-src-string">'text/plain'</span>)]) + <span class="py-src-keyword">return</span> [<span class="py-src-string">'Hello World!'</span>] +</pre> + +<p>The above setup will be suitable for many applications where all that is +needed is to server the WSGI application at the site's root. However, for +greater control, Twisted provides support for using WSGI applications as +resources <code class="api">twisted.web.wsgi.WSGIResource</code>.</p> + +<p>Here is an example of a WSGI application being served as the root resource +for a site, in the following tac file:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +</p><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-keyword">import</span> <span class="py-src-variable">server</span> +<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">wsgi</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">WSGIResource</span> +<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">threadpool</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ThreadPool</span> +<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> +<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> + +<span class="py-src-comment"># Create and start a thread pool,</span> +<span class="py-src-variable">wsgiThreadPool</span> = <span class="py-src-variable">ThreadPool</span>() +<span class="py-src-variable">wsgiThreadPool</span>.<span class="py-src-variable">start</span>() + +<span class="py-src-comment"># ensuring that it will be stopped when the reactor shuts down</span> +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">addSystemEventTrigger</span>(<span class="py-src-string">'after'</span>, <span class="py-src-string">'shutdown'</span>, <span class="py-src-variable">wsgiThreadPool</span>.<span class="py-src-variable">stop</span>) + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">application</span>(<span class="py-src-parameter">environ</span>, <span class="py-src-parameter">start_response</span>): + <span class="py-src-string">"""A basic WSGI application"""</span> + <span class="py-src-variable">start_response</span>(<span class="py-src-string">'200 OK'</span>, [(<span class="py-src-string">'Content-type'</span>,<span class="py-src-string">'text/plain'</span>)]) + <span class="py-src-keyword">return</span> [<span class="py-src-string">'Hello World!'</span>] + +<span class="py-src-comment"># Create the WSGI resource</span> +<span class="py-src-variable">wsgiAppAsResource</span> = <span class="py-src-variable">WSGIResource</span>(<span class="py-src-variable">reactor</span>, <span class="py-src-variable">wsgiThreadPool</span>, <span class="py-src-variable">application</span>) + +<span class="py-src-comment"># Hooks for twistd</span> +<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">'Twisted.web.wsgi Hello World Example'</span>) +<span class="py-src-variable">server</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">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">wsgiAppAsResource</span>)) +<span class="py-src-variable">server</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">application</span>) +</pre> + +<p>This can then be run like any other .tac file:</p> + +<pre class="shell" xml:space="preserve"> +% twistd -ny myapp.tac +</pre> + +<p>Because of the synchronous nature of WSGI, each application call (for +each request) is called within a thread, and the result is written back to the +web server. For this, a <code class="api">twisted.python.threadpool.ThreadPool</code> +instance is used.</p> + +<h3>Using VHostMonster<a name="auto20"/></h3> + +<p>It is common to use one server (for example, Apache) on a site with multiple +names which then uses reverse proxy (in Apache, via <code>mod_proxy</code>) to different +internal web servers, possibly on different machines. However, naive +configuration causes miscommunication: the internal server firmly believes it +is running on <q>internal-name:port</q>, and will generate URLs to that effect, +which will be completely wrong when received by the client.</p> + +<p>While Apache has the ProxyPassReverse directive, it is really a hack +and is nowhere near comprehensive enough. Instead, the recommended practice +in case the internal web server is Twisted.Web is to use VHostMonster.</p> + +<p>From the Twisted side, using VHostMonster is easy: just drop a file named +(for example) <code>vhost.rpy</code> containing the following:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +</p><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-keyword">import</span> <span class="py-src-variable">vhost</span> +<span class="py-src-variable">resource</span> = <span class="py-src-variable">vhost</span>.<span class="py-src-variable">VHostMonsterResource</span>() +</pre> + +<p>Of course, an equivalent <code>.trp</code> can also be used. Make sure +the web server is configured with the correct processors for the +<code>rpy</code> or <code>trp</code> extensions (the web server +<code>twistd web --path</code> generates by default is so configured).</p> + +<p>From the Apache side, instead of using the following ProxyPass directive:</p> + +<pre xml:space="preserve"> +<VirtualHost ip-addr> +ProxyPass / http://localhost:8538/ +ServerName example.com +</VirtualHost> +</pre> + +<p>Use the following directive:</p> + +<pre xml:space="preserve"> +<VirtualHost ip-addr> +ProxyPass / http://localhost:8538/vhost.rpy/http/example.com:80/ +ServerName example.com +</VirtualHost> +</pre> + +<p>Here is an example for Twisted.Web's reverse proxy:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +</p><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">internet</span>, <span class="py-src-variable">service</span> +<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-keyword">import</span> <span class="py-src-variable">proxy</span>, <span class="py-src-variable">server</span>, <span class="py-src-variable">vhost</span> +<span class="py-src-variable">vhostName</span> = <span class="py-src-string">'example.com'</span> +<span class="py-src-variable">reverseProxy</span> = <span class="py-src-variable">proxy</span>.<span class="py-src-variable">ReverseProxyResource</span>(<span class="py-src-string">'internal'</span>, <span class="py-src-number">8538</span>, + <span class="py-src-string">'/vhost.rpy/http/'</span>+<span class="py-src-variable">vhostName</span>+<span class="py-src-string">'/'</span>) +<span class="py-src-variable">root</span> = <span class="py-src-variable">vhost</span>.<span class="py-src-variable">NameVirtualHost</span>() +<span class="py-src-variable">root</span>.<span class="py-src-variable">addHost</span>(<span class="py-src-variable">vhostName</span>, <span class="py-src-variable">reverseProxy</span>) +<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>) +<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">'web-proxy'</span>) +<span class="py-src-variable">sc</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>) +<span class="py-src-variable">i</span> = <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">80</span>, <span class="py-src-variable">site</span>) +<span class="py-src-variable">i</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">sc</span>) +</pre> + +<h2>Rewriting URLs<a name="auto21"/></h2> + +<p>Sometimes it is convenient to modify the content of the +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Request.html" title="twisted.web.server.Request">Request</a></code> object +before passing it on. Because this is most often used to rewrite +either the URL, the similarity to Apache's <code>mod_rewrite</code> has +inspired the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.rewrite.html" title="twisted.web.rewrite">twisted.web.rewrite</a></code> module. Using +this module is done via wrapping a resource with a +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.rewrite.RewriterResource.html" title="twisted.web.rewrite.RewriterResource">twisted.web.rewrite.RewriterResource</a></code> which +then has rewrite rules. Rewrite rules are functions which accept a request +object, and possible modify it. After all rewrite rules run, the child +resolution chain continues as if the wrapped resource, rather than +the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.rewrite.RewriterResource.html" title="twisted.web.rewrite.RewriterResource">RewriterResource</a></code>, +was the child.</p> + +<p>Here is an example, using the only rule currently supplied by Twisted +itself:</p> + +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-variable">default_root</span> = <span class="py-src-variable">rewrite</span>.<span class="py-src-variable">RewriterResource</span>(<span class="py-src-variable">default</span>, <span class="py-src-variable">rewrite</span>.<span class="py-src-variable">tildeToUsers</span>) +</pre> + +<p>This causes the URL <code>/~foo/bar.html</code> to be treated like +<code>/users/foo/bar.html</code>. If done after setting default's +<code>users</code> child to a +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.distrib.UserDirectory.html" title="twisted.web.distrib.UserDirectory">distrib.UserDirectory</a></code>, +it gives a configuration similar to the classical configuration of +web server, common since the first NCSA servers.</p> + +<h2>Knowing When We're Not Wanted<a name="auto22"/></h2> + +<p>Sometimes it is useful to know when the other side has broken the connection. +Here is an example which does that:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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-keyword">import</span> <span class="py-src-variable">server</span> +<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> +<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">util</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">println</span> + + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">ExampleResource</span>(<span class="py-src-parameter">Resource</span>): + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"hello world"</span>) + <span class="py-src-variable">d</span> = <span class="py-src-variable">request</span>.<span class="py-src-variable">notifyFinish</span>() + <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-variable">println</span>(<span class="py-src-string">"finished normally"</span>)) + <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">println</span>, <span class="py-src-string">"error"</span>) + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">10</span>, <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>) + <span class="py-src-keyword">return</span> <span class="py-src-variable">server</span>.<span class="py-src-variable">NOT_DONE_YET</span> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">ExampleResource</span>() +</pre> + +<p>This will allow us to run statistics on the log-file to see how many users +are frustrated after merely 10 seconds.</p> + +<h2>As-Is Serving<a name="auto23"/></h2> + +<p>Sometimes, you want to be able to send headers and status directly. While +you can do this with a +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.script.ResourceScript.html" title="twisted.web.script.ResourceScript">ResourceScript</a></code>, an easier +way is to use <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.static.AsIsProcessor.html" title="twisted.web.static.AsIsProcessor">AsIsProcessor</a></code>. +Use it by, for example, addding it as a processor for the <code>.asis</code> +extension. Here is a sample file:</p> + +<pre xml:space="preserve"> +HTTP/1.0 200 OK +Content-Type: text/html + +Hello world +</pre> + +</div> + + <p><a href="index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-development.html b/vendor/Twisted-10.0.0/doc/web/howto/web-development.html new file mode 100644 index 0000000000..481a8b3184 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-development.html @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Web Application Development</title> +<link href="stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Web Application Development</h1> + <div class="toc"><ol><li><a href="#auto0">Code layout</a></li><li><a href="#auto1">Web application deployment</a></li><li><a href="#auto2">Understanding resource scripts (.rpy files)</a></li></ol></div> + <div class="content"> +<span/> + +<h2>Code layout<a name="auto0"/></h2> + +<p>The development of a Twisted Web application should be orthogonal to its +deployment. This means is that if you are developing a web application, it +should be a resource with children, and internal links. Some of the children +might use <a href="http://www.divmod.org/projects/nevow" shape="rect">Nevow</a>, some +might be resources manually using <code>.write</code>, and so on. Regardless, +the code should be in a Python module, or package, <em>outside</em> the web +tree.</p> + +<p>You will probably want to test your application as you develop it. There are +many ways to test, including dropping an <code>.rpy</code> which looks +like:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">mypackage</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">toplevel</span> +<span class="py-src-variable">resource</span> = <span class="py-src-variable">toplevel</span>.<span class="py-src-variable">Resource</span>(<span class="py-src-variable">file</span>=<span class="py-src-string">"foo/bar"</span>, <span class="py-src-variable">color</span>=<span class="py-src-string">"blue"</span>) +</pre> + +<p>into a directory, and then running:</p> + +<pre class="shell" xml:space="preserve"> +% twistd web --path=/directory +</pre> + +<p>You can also write a Python script like:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +9 +</p><span class="py-src-comment">#!/usr/bin/env python</span> + +<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-keyword">import</span> <span class="py-src-variable">server</span> +<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> +<span class="py-src-keyword">from</span> <span class="py-src-variable">mypackage</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">toplevel</span> + +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8080</span>, + <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">toplevel</span>.<span class="py-src-variable">Resource</span>(<span class="py-src-variable">file</span>=<span class="py-src-string">"foo/bar"</span>, <span class="py-src-variable">color</span>=<span class="py-src-string">"blue"</span>))) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<h2>Web application deployment<a name="auto1"/></h2> + +<p>Which one of these development strategies you use is not terribly important, +since (and this is the important part) deployment is <em>orthogonal</em>. +Later, when you want users to actually <em>use</em> your code, you should worry +about what to do -- or rather, don't. Users may have widely different needs. +Some may want to run your code in a different process, so they'll use +distributed web (<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.distrib.html" title="twisted.web.distrib">twisted.web.distrib</a></code>). Some may be +using the <code>twisted-web</code> Debian package, and will drop in:</p> + +<pre class="shell" xml:space="preserve"> +% cat > /etc/local.d/99addmypackage.py +from mypackage import toplevel +default.putChild("mypackage", toplevel.Resource(file="foo/bar", color="blue")) +^D +</pre> + +<p>If you want to be friendly to your users, you can supply many examples in +your package, like the above <code>.rpy</code> and the Debian-package drop-in. +But the <em>ultimate</em> friendliness is to write a useful resource which does +not have deployment assumptions built in.</p> + +<h2>Understanding resource scripts (<code>.rpy</code> files)<a name="auto2"/></h2> + +<p>Twisted Web is not PHP -- it has better tools for organizing code Python +modules and packages, so use them. In PHP, the only tool for organizing code is +a web page, which leads to silly things like PHP pages full of functions that +other pages import, and so on. If you were to write your code this way with +Twisted Web, you would do web development using many <code>.rpy</code> files, +all importing some Python module. This is a <em>bad idea</em> -- it mashes +deployment with development, and makes sure your users will be <em>tied</em> to +the file-system.</p> + +<p>We have <code>.rpy</code>s because they are useful and necessary. But using +them incorrectly leads to horribly unmaintainable applications. The best way to +ensure you are using them correctly is to not use them at all, until you are on +your <em>final</em> deployment stages. You should then find your +<code>.rpy</code> files will be less than 10 lines, because you will not +<em>have</em> more than 10 lines to write.</p> + +</div> + + <p><a href="index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/asynchronous-deferred.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/asynchronous-deferred.html new file mode 100644 index 0000000000..6d63b9531c --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/asynchronous-deferred.html @@ -0,0 +1,161 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Asynchronous Responses (via Deferred)</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Asynchronous Responses (via Deferred)</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>The previous example had a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code> that generates its response +asynchronously rather than immediately upon the call to its render +method. Though it was a useful demonstration of the <code>NOT_DONE_YET</code> +feature of Twisted Web, the example didn't reflect what a realistic application +might want to do. This example introduces <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>, the Twisted class which is used +to provide a uniform interface to many asynchronous events, and shows you an +example of using a <code>Deferred</code>-returning API to generate an +asynchronous response to a request in Twisted Web.</p> + +<p><code>Deferred</code> is the result of two consequences of the asynchronous +programming approach. First, asynchronous code is frequently (if not always) +concerned with some data (in Python, an object) which is not yet available but +which probably will be soon. Asynchronous code needs a way to define what will +be done to the object once it does exist. It also needs a way to define how to +handle errors in the creation or acquisition of that object. These two needs are +satisfied by the <i>callbacks</i> and <i>errbacks</i> of a +<code>Deferred</code>. Callbacks are added to a <code>Deferred</code> with <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.addCallback.html" title="twisted.internet.defer.Deferred.addCallback">Deferred.addCallback</a></code>; errbacks +are added with <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.addErrback.html" title="twisted.internet.defer.Deferred.addErrback">Deferred.addErrback</a></code>. When the object +finally does exist, it is passed to <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.callback.html" title="twisted.internet.defer.Deferred.callback">Deferred.callback</a></code> which passes it on to the +callback added with <code>addCallback</code>. Similarly, if an error occurs, +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.errback.html" title="twisted.internet.defer.Deferred.errback">Deferred.errback</a></code> is +called and the error is passed along to the errback added with +<code>addErrback</code>. Second, the events that make asynchronous code actually +work often take many different, incompatible forms. <code>Deferred</code> acts +as the uniform interface which lets different parts of an asynchronous +application interact and isolates them from implementation details they +shouldn't be concerned with.</p> + +<p>That's almost all there is to Deferred. To solidify your new understanding, +now consider this rewritten version of DelayedResource which uses a +Deferred-based delay API. It does exactly the same thing as the <a href="asynchronous.html" shape="rect">previous example</a>. Only the implementation is +different.</p> + +<p>First, the example must import that new API that was just mentioned, <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.task.deferLater.html" title="twisted.internet.task.deferLater">deferLater</a></code>:</p> + +<pre class="python"><p class="py-linenumber">1 +</p><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-variable">task</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">deferLater</span> +</pre> + +<p>Next, all the other imports (these are the same as last time):</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NOT_DONE_YET</span> +<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> +</pre> + +<p>With the imports done, here's the first part of the +<code>DelayedResource</code> implementation. Again, this part of the code is +identical to the previous version:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_delayedRender</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"Sorry to keep you waiting."</span>) + <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>() +</pre> + +<p>Next we need to define the render method. Here's where things change a +bit. Instead of using <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IReactorTime.callLater.html" title="twisted.internet.interfaces.IReactorTime.callLater">callLater</a></code>, We're going to +use <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.task.deferLater.html" title="twisted.internet.task.deferLater">deferLater</a></code> this +time. <code>deferLater</code> accepts a reactor, delay (in seconds, as with +<code>callLater</code>), and a function to call after the delay to produce that +elusive object discussed in the description of Deferreds. We're also going to +use <code>_delayedRender</code> as the callback to add to the +<code>Deferred</code> returned by <code>deferLater</code>. Since it expects the +request object as an argument, we're going to set up the <code>deferLater</code> +call to return a <code>Deferred</code> which has the request object as its +result.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +</p><span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">d</span> = <span class="py-src-variable">deferLater</span>(<span class="py-src-variable">reactor</span>, <span class="py-src-number">5</span>, <span class="py-src-keyword">lambda</span>: <span class="py-src-variable">request</span>) +</pre> + +<p>The <code>Deferred</code> referenced by <code>d</code> now needs to have the +<code>_delayedRender</code> callback added to it. Once this is done, +<code>_delayedRender</code> will be called with the result of <code>d</code> +(which will be <code>request</code>, of course — the result of <code>(lambda: +request)()</code>).</p> + +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">_delayedRender</span>) +</pre> + +<p>Finally, the render method still needs to return <code>NOT_DONE_YET</code>, +for exactly the same reasons as it did in the previous version of the +example.</p> + +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span> +</pre> + +<p>And with that, <code>DelayedResource</code> is now implemented based on a +<code>Deferred</code>. The example still isn't very realistic, but remember that +since Deferreds offer a uniform interface to many different asynchronous event +sources, this code now resembles a real application even more closely; you could +easily replace <code>deferLater</code> with another +<code>Deferred</code>-returning API and suddenly you might have a resource that +does something useful.</p> + +<p>Finally, here's the complete, uninterrupted example source, as an rpy script:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +</p><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-variable">task</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">deferLater</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NOT_DONE_YET</span> +<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> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_delayedRender</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"Sorry to keep you waiting."</span>) + <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>() + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">d</span> = <span class="py-src-variable">deferLater</span>(<span class="py-src-variable">reactor</span>, <span class="py-src-number">5</span>, <span class="py-src-keyword">lambda</span>: <span class="py-src-variable">request</span>) + <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">_delayedRender</span>) + <span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">DelayedResource</span>() +</pre> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/asynchronous.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/asynchronous.html new file mode 100644 index 0000000000..11584d5ddf --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/asynchronous.html @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Asynchronous Responses</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Asynchronous Responses</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>In all of the previous examples, the resource examples presented generated +responses immediately. One of the features of prime interest of Twisted Web, +though, is the ability to generate a response over a longer period of time while +leaving the server free to respond to other requests. In other words, +asynchronously. In this installment, we'll write a resource like this.</p> + +<p>A resource that generates a response asynchronously looks like one that +generates a response synchronously in many ways. The same base class, <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code>, is used either way; the +same render methods are used. There are three basic differences, though.</p> + +<p>First, instead of returning the string which will be used as the body of the +response, the resource uses <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.http.Request.write.html" title="twisted.web.http.Request.write">Request.write</a></code>. This method can be called +repeatedly. Each call appends another string to the response body. Second, when +the entire response body has been passed to <code>Request.write</code>, the +application must call <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.http.Request.finish.html" title="twisted.web.http.Request.finish">Request.finish</a></code>. As you might expect from the +name, this ends the response. Finally, in order to make Twisted Web not end the +response as soon as the render method returns, the render method must return +<code>NOT_DONE_YET</code>. Consider this example:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NOT_DONE_YET</span> +<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> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_delayedRender</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"Sorry to keep you waiting."</span>) + <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>() + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">5</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">_delayedRender</span>, <span class="py-src-variable">request</span>) + <span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span> +</pre> + +<p>If you're not familiar with reactor.<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IReactorTime.callLater.html" title="twisted.internet.interfaces.IReactorTime.callLater">callLater</a></code>, all you really +need to know about it to understand this example is that the above usage of it +arranges to have <code>self._delayedRender(request)</code> run about 5 seconds +after <code>callLater</code> is invoked from this render method and that it +returns immediately.</p> + +<p>All three of the elements mentioned earlier can be seen in this example. The +resource uses <code>Request.write</code> to set the response body. It uses +<code>Request.finish</code> after the entire body has been specified (all with +just one call to write in this case). Lastly, it returns +<code>NOT_DONE_YET</code> from its render method. So there you have it, +asynchronous rendering with Twisted Web.</p> + +<p>Here's a complete rpy script based on this resource class (see the <a href="rpy-scripts.html" shape="rect">previous example</a> if you need a reminder about rpy +scripts):</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NOT_DONE_YET</span> +<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> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_delayedRender</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"Sorry to keep you waiting."</span>) + <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>() + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">5</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">_delayedRender</span>, <span class="py-src-variable">request</span>) + <span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">DelayedResource</span>() +</pre> + +<p>Drop this source into a <code>.rpy</code> file and fire up a server using +<code>twistd -n web --path /directory/containing/script/.</code> You'll see that +loading the page takes 5 seconds. If you try to load a second before the first +completes, it will also take 5 seconds from the time you request it (but it +won't be delayed by any other outstanding requests).</p> + +<p>Something else to consider when generating responses asynchronously is that +the client may not wait around to get the response to its +request. A <a href="interrupted.html" shape="rect">subsequent example</a> demonstrates how +to detect that the client has abandoned the request and that the server +shouldn't bother to finish generating its response.</p> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/custom-codes.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/custom-codes.html new file mode 100644 index 0000000000..2b68465436 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/custom-codes.html @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Custom Response Codes</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Custom Response Codes</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>The previous example introduced <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.error.NoResource.html" title="twisted.web.error.NoResource">NoResource</a></code>, a Twisted Web error +resource which responds with a 404 (not found) code. This example will +cover the APIs that <code>NoResource</code> uses to do this so that +you can generate your own custom response codes as desired.</p> + +<p>First, the now-standard import preamble:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> +</pre> + +<p>Now we'll define a new resource class that always returns a 402 +(payment required) response. This is really not very different from +the resources that was defined in previous examples. The fact that it +has a response code other than 200 doesn't change anything else about +its role. This will require using the request object, though, which +none of the previous examples have done.</p> + +<p>The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Request.html" title="twisted.web.server.Request">Request</a></code> +object has shown up in a couple of places, but so far we've ignored +it. It is a parameter to the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.getChild.html" title="twisted.web.resource.Resource.getChild">getChild</a></code> API as well as to +render methods such as <code>render_GET</code>. As you might have +suspected, it represents the request for which a response is to be +generated. Additionally, it also represents the response being +generated. In this example we're going to use its <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.http.Request.setResponseCode.html" title="twisted.web.http.Request.setResponseCode">setResponseCode</a></code> method to - you +guessed it - set the response's status code.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">PaymentRequired</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">setResponseCode</span>(<span class="py-src-number">402</span>) + <span class="py-src-keyword">return</span> <span class="py-src-string">"Please swipe your credit card."</span> +</pre> + +<p>Just like the other resources I've demonstrated, this one returns a +string from its <code>render_GET</code> method to define the body of +the response. All that's different is the call to +<code>setResponseCode</code> to override the default response code, +200, with a different one.</p> + +<p>Finally, the code to set up the site and reactor. We'll put an +instance of the above defined resource at <code>/buy</code>:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +</p><span class="py-src-variable">root</span> = <span class="py-src-variable">Resource</span>() +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"buy"</span>, <span class="py-src-variable">PaymentRequired</span>()) +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8880</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>Here's the complete example:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">PaymentRequired</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">setResponseCode</span>(<span class="py-src-number">402</span>) + <span class="py-src-keyword">return</span> <span class="py-src-string">"Please swipe your credit card."</span> + +<span class="py-src-variable">root</span> = <span class="py-src-variable">Resource</span>() +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"buy"</span>, <span class="py-src-variable">PaymentRequired</span>()) +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8880</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>Run the server and visit <code>http://localhost:8880/buy</code> in +your browser. It'll look pretty boring, but if you use Firefox's View +Page Info right-click menu item (or your browser's equivalent), you'll +be able to see that the server indeed sent back a 402 response +code.</p> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/dynamic-content.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/dynamic-content.html new file mode 100644 index 0000000000..04524af396 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/dynamic-content.html @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Generating a Page Dynamically</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Generating a Page Dynamically</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>The goal of this example is to show you how to dynamically generate the +contents of a page.</p> + +<p>Taking care of some of the necessary imports first, we'll import <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Site.html" title="twisted.web.server.Site">Site</a></code> and the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.reactor.html" title="twisted.internet.reactor">reactor</a></code>:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +</p><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> +<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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +</pre> + +<p>The Site is a factory which associates a listening port with the HTTP +protocol implementation. The reactor is the main loop that drives any Twisted +application; we'll use it to actually create the listening port in a moment.</p> + +<p>Next, we'll import one more thing from Twisted Web: <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code>. An instance of +<code>Resource</code> (or a subclass) represents a page (technically, the entity +addressed by a URI).</p> + +<pre class="python"><p class="py-linenumber">1 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +</pre> + +<p>Since we're going to make the demo resource a clock, we'll also import the +time module:</p> + +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-keyword">import</span> <span class="py-src-variable">time</span> +</pre> + +<p>With imports taken care of, the next step is to define a +<code>Resource</code> subclass which has the dynamic rendering behavior we +want. Here's a resource which generates a page giving the time:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">ClockPage</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-variable">isLeaf</span> = <span class="py-src-variable">True</span> + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"%s"</span> % (<span class="py-src-variable">time</span>.<span class="py-src-variable">ctime</span>(),) +</pre> + +<p>Setting <code>isLeaf</code> to <code>True</code> indicates that +<code>ClockPage</code> resources will never have any children.</p> + +<p>The <code>render_GET</code> method here will be called whenever the URI we +hook this resource up to is requested with the <code>GET</code> method. The byte +string it returns is what will be sent to the browser.</p> + +<p>With the resource defined, we can create a <code>Site</code> from it:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +</p><span class="py-src-variable">resource</span> = <span class="py-src-variable">ClockPage</span>() +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">resource</span>) +</pre> + +<p>Just as with the previous static content example, this configuration puts our +resource at the very top of the URI hierarchy, ie at <code>/</code>. With that +<code>Site</code> instance, we can tell the reactor to <a href="../../../core/howto/servers.html" shape="rect">create a TCP server</a> and start +servicing requests:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +</p><span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8880</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>Here's the code with no interruptions:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +</p><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> +<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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<span class="py-src-keyword">import</span> <span class="py-src-variable">time</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">ClockPage</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-variable">isLeaf</span> = <span class="py-src-variable">True</span> + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"%s"</span> % (<span class="py-src-variable">time</span>.<span class="py-src-variable">ctime</span>(),) + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">ClockPage</span>() +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">resource</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8880</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/dynamic-dispatch.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/dynamic-dispatch.html new file mode 100644 index 0000000000..1bb127a050 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/dynamic-dispatch.html @@ -0,0 +1,142 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Dynamic URL Dispatch</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Dynamic URL Dispatch</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>In the <a href="static-dispatch.html" shape="rect">previous example</a> we covered how to +statically configure Twisted Web to serve different content at different +URLs. The goal of this example is to show you how to do this dynamically +instead. Reading the previous installment if you haven't already is suggested in +order to get an overview of how URLs are treated when using Twisted Web's <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.html" title="twisted.web.resource">resource</a></code> APIs.</p> + +<p><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Site.html" title="twisted.web.server.Site">Site</a></code> (the object which +associates a listening server port with the HTTP implementation), <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code> (a convenient base class +to use when defining custom pages), and <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.reactor.html" title="twisted.internet.reactor">reactor</a></code> (the object which implements the Twisted +main loop) return once again:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> +</pre> + +<p>With that out of the way, here's the interesting part of this example. We're +going to define a resource which renders a whole-year calendar. The year it will +render the calendar for will be the year in the request URL. So, for example, +<code>/2009</code> will render a calendar for 2009. First, here's a resource +that renders a calendar for the year passed to its initializer:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +9 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">calendar</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">calendar</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">YearPage</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">year</span>): + <span class="py-src-variable">Resource</span>.<span class="py-src-variable">__init__</span>(<span class="py-src-variable">self</span>) + <span class="py-src-variable">self</span>.<span class="py-src-variable">year</span> = <span class="py-src-variable">year</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"%s"</span> % (<span class="py-src-variable">calendar</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">year</span>),) +</pre> + +<p>Pretty simple - not all that different from the first dynamic resource +demonstrated in <a href="dynamic-content.html" shape="rect">Generating a Page +Dynamically</a>. Now here's the resource that handles URLs with a year in them +by creating a suitable instance of this <code>YearPage</code> class:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">Calendar</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">getChild</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">name</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">YearPage</span>(<span class="py-src-variable">int</span>(<span class="py-src-variable">name</span>)) +</pre> + +<p>By implementing <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.getChild.html" title="twisted.web.resource.Resource.getChild">getChild</a></code> here, we've just defined +how Twisted Web should find children of <code>Calendar</code> instances when +it's resolving an URL into a resource. This implementation defines all integers +as the children of <code>Calendar</code> (and punts on error handling, more on +that later).</p> + +<p>All that's left is to create a <code>Site</code> using this resource as its +root and then start the reactor:</p> + +<pre xml:space="preserve"> +root = Calendar() +factory = Site(root) +reactor.listenTCP(8880, factory) +reactor.run() +</pre> + +<p>And that's all. Any resource-based dynamic URL handling is going to look +basically like <code>Calendar.getPage</code>. Here's the full example code:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> + +<span class="py-src-keyword">from</span> <span class="py-src-variable">calendar</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">calendar</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">YearPage</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">year</span>): + <span class="py-src-variable">Resource</span>.<span class="py-src-variable">__init__</span>(<span class="py-src-variable">self</span>) + <span class="py-src-variable">self</span>.<span class="py-src-variable">year</span> = <span class="py-src-variable">year</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"%s"</span> % (<span class="py-src-variable">calendar</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">year</span>),) + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Calendar</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">getChild</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">name</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">YearPage</span>(<span class="py-src-variable">int</span>(<span class="py-src-variable">name</span>)) + +<span class="py-src-variable">root</span> = <span class="py-src-variable">Calendar</span>() +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8880</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/error-handling.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/error-handling.html new file mode 100644 index 0000000000..f481bab31a --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/error-handling.html @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Error Handling</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Error Handling</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>In this example we'll extend dynamic dispatch to return a 404 (not found) +response when a client requests a non-existent URL.</p> + +<p>As in the previous examples, we'll start with <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Site.html" title="twisted.web.server.Site">Site</a></code>, <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code>, and <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.reactor.html" title="twisted.internet.reactor">reactor</a></code> imports:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> +</pre> + +<p>Next, we'll add one more import. <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.error.NoResource.html" title="twisted.web.error.NoResource">NoResource</a></code> is one of the pre-defined error +resources provided by Twisted Web. It generates the necessary 404 response code +and renders a simple html page telling the client there is no such resource.</p> + +<pre class="python"><p class="py-linenumber">1 +</p><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">error</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NoResource</span> +</pre> + +<p>Next, we'll define a custom resource which does some dynamic URL +dispatch. This example is going to be just like the <a href="dynamic-dispatch.html" shape="rect">previous one</a>, where the path segment is +interpreted as a year; the difference is that this time we'll handle requests +which don't conform to that pattern by returning the not found response:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">Calendar</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">getChild</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">name</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">try</span>: + <span class="py-src-variable">year</span> = <span class="py-src-variable">int</span>(<span class="py-src-variable">name</span>) + <span class="py-src-keyword">except</span> <span class="py-src-variable">ValueError</span>: + <span class="py-src-keyword">return</span> <span class="py-src-variable">NoResource</span>() + <span class="py-src-keyword">else</span>: + <span class="py-src-keyword">return</span> <span class="py-src-variable">YearPage</span>(<span class="py-src-variable">year</span>) +</pre> + +<p>Aside from including the definition of <code>YearPage</code> from the +previous example, the only other thing left to do is the normal +<code>Site</code> and <code>reactor</code> setup. Here's the complete code for +this example:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> +<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">error</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NoResource</span> + +<span class="py-src-keyword">from</span> <span class="py-src-variable">calendar</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">calendar</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">YearPage</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">year</span>): + <span class="py-src-variable">Resource</span>.<span class="py-src-variable">__init__</span>(<span class="py-src-variable">self</span>) + <span class="py-src-variable">self</span>.<span class="py-src-variable">year</span> = <span class="py-src-variable">year</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"%s"</span> % (<span class="py-src-variable">calendar</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">year</span>),) + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Calendar</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">getChild</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">name</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">try</span>: + <span class="py-src-variable">year</span> = <span class="py-src-variable">int</span>(<span class="py-src-variable">name</span>) + <span class="py-src-keyword">except</span> <span class="py-src-variable">ValueError</span>: + <span class="py-src-keyword">return</span> <span class="py-src-variable">NoResource</span>() + <span class="py-src-keyword">else</span>: + <span class="py-src-keyword">return</span> <span class="py-src-variable">YearPage</span>(<span class="py-src-variable">year</span>) + +<span class="py-src-variable">root</span> = <span class="py-src-variable">Calendar</span>() +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8880</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>This server hands out the same calendar views as the one from the previous +installment, but it will also hand out a nice error page with a 404 response +when a request is made for a URL which cannot be interpreted as a year.</p> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/handling-posts.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/handling-posts.html new file mode 100644 index 0000000000..5a3d98ca04 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/handling-posts.html @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Handling POSTs</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Handling POSTs</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>All of the previous examples have focused on <code>GET</code> +requests. Unlike <code>GET</code> requests, <code>POST</code> requests can have +a request body - extra data after the request headers; for example, data +representing the contents of an HTML form. Twisted Web makes this data available +to applications via the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Request.html" title="twisted.web.server.Request">Request</a></code> object.</p> + +<p>Here's an example web server which renders a static HTML form and then +generates a dynamic page when that form is posted back to it. Disclaimer: While +it's convenient for this example, it's often not a good idea to make a resource +that <code>POST</code>s to itself; this isn't about Twisted Web, but the nature +of HTTP in general; if you do this in a real application, make sure you +understand the possible negative consequences.</p> + +<p>As usual, we start with some imports. In addition to the Twisted imports, +this example uses the <code>cgi</code> module to <a href="http://en.wikipedia.org/wiki/Cross-site_scripting" shape="rect">escape user-entered +content</a> for inclusion in the output.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> + +<span class="py-src-keyword">import</span> <span class="py-src-variable">cgi</span> +</pre> + +<p>Next, we'll define a resource which is going to do two things. First, it will +respond to <code>GET</code> requests with a static HTML form:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">FormPage</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">''</span> +</pre> + +<p>This is similar to the resource used in a <a href="dynamic-content.html" shape="rect">previous installment</a>. However, we'll now add +one more method to give it a second behavior; this <code>render_POST</code> +method will allow it to accept <code>POST</code> requests:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +</p><span class="py-src-keyword">def</span> <span class="py-src-identifier">render_POST</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'You submitted: %s'</span> % (<span class="py-src-variable">cgi</span>.<span class="py-src-variable">escape</span>(<span class="py-src-variable">request</span>.<span class="py-src-variable">args</span>[<span class="py-src-string">"the-field"</span>][<span class="py-src-number">0</span>]),) +</pre> + +<p>The main thing to note here is the use of <code>request.args</code>. This is +a dictionary-like object that provides access to the contents of the form. The +keys in this dictionary are the names of inputs in the form. Each value is a +list containing strings (since there can be multiple inputs with the same name), +which is why we had to extract the first element to pass to +<code>cgi.escape</code>. <code>request.args</code> will be populated from form +contents whenever a <code>POST</code> request is made with a content type of +<code>application/x-www-form-urlencoded</code> or +<code>multipart/form-data</code> (it's also populated by query arguments for any +type of request).</p> + +<p>Finally, the example just needs the usual site creation and port setup:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +</p><span class="py-src-variable">root</span> = <span class="py-src-variable">Resource</span>() +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"form"</span>, <span class="py-src-variable">FormPage</span>()) +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8880</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>Run the server and visit <a href="http://localhost:8880/form" shape="rect">http://localhost:8880/form</a>, submit the +form, and watch it generate a page including the value you entered into the +single field.</p> + +<p>Here's the complete source for the example:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> + +<span class="py-src-keyword">import</span> <span class="py-src-variable">cgi</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">FormPage</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">''</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_POST</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'You submitted: %s'</span> % (<span class="py-src-variable">cgi</span>.<span class="py-src-variable">escape</span>(<span class="py-src-variable">request</span>.<span class="py-src-variable">args</span>[<span class="py-src-string">"the-field"</span>][<span class="py-src-number">0</span>]),) + +<span class="py-src-variable">root</span> = <span class="py-src-variable">Resource</span>() +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"form"</span>, <span class="py-src-variable">FormPage</span>()) +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8880</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/http-auth.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/http-auth.html new file mode 100644 index 0000000000..fd4036f321 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/http-auth.html @@ -0,0 +1,250 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: HTTP Authentication</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">HTTP Authentication</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>Many of the previous examples have looked at how to serve content by using +existing resource classes or implementing new ones. In this example we'll use +Twisted Web's basic or digest HTTP authentication to control access to these +resources.</p> + +<p><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.guard.html" title="twisted.web.guard">guard</a></code>, the Twisted Web +module which provides most of the APIs that will be used in this example, helps +you to +add <a href="http://en.wikipedia.org/wiki/Authentication" shape="rect">authentication</a> +and <a href="http://en.wikipedia.org/wiki/Authorization" shape="rect">authorization</a> to a +resource hierarchy. It does this by providing a resource which implements +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.getChild.html" title="twisted.web.resource.Resource.getChild">getChild</a></code> to return +a <a href="dynamic-dispatch.html" shape="rect">dynamically selected resource</a>. The +selection is based on the authentication headers in the request. If those +headers indicate that the request is made on behalf of Alice, then Alice's +resource will be returned. If they indicate that it was made on behalf of Bob, +his will be returned. If the headers contain invalid credentials, an error +resource is returned. Whatever happens, once this resource is returned, URL +traversal continues as normal from that resource.</p> + +<p>The resource that implements this is <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.guard.HTTPAuthSessionWrapper.html" title="twisted.web.guard.HTTPAuthSessionWrapper">HTTPAuthSessionWrapper</a></code>, though it is directly +responsible for very little of the process. It will extract headers from the +request and hand them off to a credentials factory to parse them according to +the appropriate standards (eg <a href="http://tools.ietf.org/html/rfc2617" shape="rect">HTTP +Authentication: Basic and Digest Access Authentication</a>) and then hand the +resulting credentials object off to a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.portal.Portal.html" title="twisted.cred.portal.Portal">Portal</a></code>, the core +of <a href="../../../core/howto/cred.html" shape="rect">Twisted Cred</a>, a system for +uniform handling of authentication and authorization. We won't discuss Twisted +Cred in much depth here. To make use of it with Twisted Web, the only thing you +really need to know is how to implement an <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.portal.IRealm.html" title="twisted.cred.portal.IRealm">IRealm</a></code>.</p> + +<p>You need to implement a realm because the realm is the object that actually +decides which resources are used for which users. This can be as complex or as +simple as it suitable for your application. For this example we'll keep it very +simple: each user will have a resource which is a static file listing of the +<code>public_html</code> directory in their UNIX home directory. First, we need +to import <code>implements</code> from <code>zope.interface</code> and <code>IRealm</code> from +<code>twisted.cred.portal</code>. Together these will let me mark this class as +a realm (this is mostly - but not entirely - a documentation thing). We'll also +need <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.static.File.html" title="twisted.web.static.File">File</a></code> for the actual +implementation later.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +</p><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">implements</span> + +<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-variable">portal</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IRealm</span> +<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">static</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">File</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">PublicHTMLRealm</span>(<span class="py-src-parameter">object</span>): + <span class="py-src-variable">implements</span>(<span class="py-src-variable">IRealm</span>) +</pre> + +<p>A realm only needs to implement one method: <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.portal.IRealm.requestAvatar.html" title="twisted.cred.portal.IRealm.requestAvatar">requestAvatar</a></code>. This method is called +after any successful authentication attempt (ie, Alice supplied the right +password). Its job is to return the <i>avatar</i> for the user who succeeded in +authenticating. An <i>avatar</i> is just an object that represents a user. In +this case, it will be a <code>File</code>. In general, with <code>Guard</code>, +the avatar must be a resource of some sort.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><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>): + <span class="py-src-keyword">if</span> <span class="py-src-variable">IResource</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">interfaces</span>: + <span class="py-src-keyword">return</span> (<span class="py-src-variable">IResource</span>, <span class="py-src-variable">File</span>(<span class="py-src-string">"/home/%s/public_html"</span> % (<span class="py-src-variable">avatarId</span>,)), <span class="py-src-keyword">lambda</span>: <span class="py-src-variable">None</span>) + <span class="py-src-keyword">raise</span> <span class="py-src-variable">NotImplementedError</span>() +</pre> + +<p>A few notes on this method:</p> +<ul> + <li>The <code>avatarId</code> parameter is essentially the username. It's the + job of some other code to extract the username from the request headers and + make sure it gets passed here.</li> + <li>The <code>mind</code> is always <code>None</code> when writing a realm to + be used with <code>Guard</code>. You can ignore it until you want to write a + realm for something else.</li> + <li><code>Guard</code> is always + passed <code class="twisted.web.resource">IResource</code> as + the <code>interfaces</code> parameter. If <code>interfaces</code> only + contains interfaces your code doesn't understand, + raising <code>NotImplementedError</code> is the thing to do, as + above. You'll only need to worry about getting a different interface when + you write a realm for something other than <code>Guard</code>.</li> + <li>If you want to track when a user logs out, that's what the last element of + the returned tuple is for. It will be called when this avatar logs + out. <code>lambda: None</code> is the idiomatic no-op logout function.</li> + <li>Notice that the path handling code in this example is written very + poorly. This example may be vulnerable to certain unintentional information + disclosure attacks. This sort of problem is exactly the + reason <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.filepath.FilePath.html" title="twisted.python.filepath.FilePath">FilePath</a></code> + exists. However, that's an example for another day...</li> +</ul> + +<p>We're almost ready to set up the resource for this example. To create an +<code>HTTPAuthSessionWrapper</code>, though, we need two things. First, a +portal, which requires the realm above, plus at least one credentials +checker:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><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-variable">portal</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Portal</span> +<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-variable">checkers</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">FilePasswordDB</span> + +<span class="py-src-variable">portal</span> = <span class="py-src-variable">Portal</span>(<span class="py-src-variable">PublicHTMLRealm</span>(), [<span class="py-src-variable">FilePasswordDB</span>(<span class="py-src-string">'httpd.password'</span>)]) +</pre> + +<p><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.checkers.FilePasswordDB.html" title="twisted.cred.checkers.FilePasswordDB">FilePasswordDB</a></code> is the +credentials checker. It knows how to read <code>passwd(5)</code>-style (loosely) +files to check credentials against. It is responsible for the authentication +work after <code>HTTPAuthSessionWrapper</code> extracts the credentials from the +request.</p> + +<p>Next we need either <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.guard.BasicCredentialFactory.html" title="twisted.web.guard.BasicCredentialFactory">BasicCredentialFactory</a></code> or +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.guard.DigestCredentialFactory.html" title="twisted.web.guard.DigestCredentialFactory">DigestCredentialFactory</a></code>. The +former knows how to challenge HTTP clients to do basic authentication; the +latter, digest authentication. We'll use digest here:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><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">guard</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">DigestCredentialFactory</span> + +<span class="py-src-variable">credentialFactory</span> = <span class="py-src-variable">DigestCredentialFactory</span>(<span class="py-src-string">"md5"</span>, <span class="py-src-string">"example.org"</span>) +</pre> + +<p>The two parameters to this constructor are the hash algorithm and the HTTP +authentication realm which will be used. The only other valid hash algorithm is +"sha" (but be careful, MD5 is more widely supported than SHA). The HTTP +authentication realm is mostly just a string that is presented to the user to +let them know why they're authenticating (you can read more about this in the +<a href="http://tools.ietf.org/html/rfc2617" shape="rect">RFC</a>).</p> + +<p>With those things created, we can finally +instantiate <code>HTTPAuthSessionWrapper</code>:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><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">guard</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">HTTPAuthSessionWrapper</span> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">HTTPAuthSessionWrapper</span>(<span class="py-src-variable">portal</span>, [<span class="py-src-variable">credentialFactory</span>]) +</pre> + +<p>There's just one last thing that needs to be done +here. When <a href="rpy-scripts.html" shape="rect">rpy scripts</a> were introduced, it was +mentioned that they are evaluated in an unusual context. This is the first +example that actually needs to take this into account. It so happens that +<code>DigestCredentialFactory</code> instances are stateful. Authentication will +only succeed if the same instance is used to both generate challenges and +examine the responses to those challenges. However, the normal mode of operation +for an rpy script is for it to be re-executed for every request. This leads to a +new +<code>DigestCredentialFactory</code> being created for every request, preventing +any authentication attempt from ever succeeding.</p> + +<p>There are two ways to deal with this. First, and the better of the two ways, +we could move almost all of the code into a real Python module, including the +code that instantiates the <code>DigestCredentialFactory</code>. This would +ensure that the same instance was used for every request. Second, and the easier +of the two ways, we could add a call to <code>cache()</code> to the beginning of +the rpy script:</p> + +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-variable">cache</span>() +</pre> + +<p><code>cache</code> is part of the globals of any rpy script, so you don't +need to import it (it's okay to be cringing at this +point). Calling <code>cache</code> makes Twisted re-use the result of the first +evaluation of the rpy script for subsequent requests too - just what we want in +this case.</p> + +<p>Here's the complete example (with imports re-arranged to the more +conventional style):</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +</p><span class="py-src-variable">cache</span>() + +<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">implements</span> + +<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-variable">portal</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IRealm</span>, <span class="py-src-variable">Portal</span> +<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-variable">checkers</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">FilePasswordDB</span> +<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">static</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">File</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IResource</span> +<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">guard</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">HTTPAuthSessionWrapper</span>, <span class="py-src-variable">DigestCredentialFactory</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">PublicHTMLRealm</span>(<span class="py-src-parameter">object</span>): + <span class="py-src-variable">implements</span>(<span class="py-src-variable">IRealm</span>) + + <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>): + <span class="py-src-keyword">if</span> <span class="py-src-variable">IResource</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">interfaces</span>: + <span class="py-src-keyword">return</span> (<span class="py-src-variable">IResource</span>, <span class="py-src-variable">File</span>(<span class="py-src-string">"/home/%s/public_html"</span> % (<span class="py-src-variable">avatarId</span>,)), <span class="py-src-keyword">lambda</span>: <span class="py-src-variable">None</span>) + <span class="py-src-keyword">raise</span> <span class="py-src-variable">NotImplementedError</span>() + +<span class="py-src-variable">portal</span> = <span class="py-src-variable">Portal</span>(<span class="py-src-variable">PublicHTMLRealm</span>(), [<span class="py-src-variable">FilePasswordDB</span>(<span class="py-src-string">'httpd.password'</span>)]) + +<span class="py-src-variable">credentialFactory</span> = <span class="py-src-variable">DigestCredentialFactory</span>(<span class="py-src-string">"md5"</span>, <span class="py-src-string">"localhost:8080"</span>) +<span class="py-src-variable">resource</span> = <span class="py-src-variable">HTTPAuthSessionWrapper</span>(<span class="py-src-variable">portal</span>, [<span class="py-src-variable">credentialFactory</span>]) +</pre> + +<p>And voila, a password-protected per-user Twisted Web server.</p> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/index.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/index.html new file mode 100644 index 0000000000..7bca942560 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/index.html @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Twisted.Web In 60 Seconds</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Twisted.Web In 60 Seconds</h1> + <div class="toc"><ol/></div> + <div class="content"> + +<span/> + +<p>This set of examples contains short, complete applications of +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.html" title="twisted.web">twisted.web</a></code>. For subjects not covered here, see +the <a href="../using-twistedweb.html" shape="rect">Twisted Web tutorial</a> and the API +documentation.</p> + +<ol> +<li><a href="static-content.html" shape="rect">Serving static content from a directory</a></li> +<li><a href="dynamic-content.html" shape="rect">Generating a page dynamically</a></li> +<li><a href="static-dispatch.html" shape="rect">Static URL dispatch</a></li> +<li><a href="dynamic-dispatch.html" shape="rect">Dynamic URL dispatch</a></li> +<li><a href="error-handling.html" shape="rect">Error handling</a></li> +<li><a href="custom-codes.html" shape="rect">Custom response codes</a></li> +<li><a href="handling-posts.html" shape="rect">Handling POSTs</a></li> +<li><a href="rpy-scripts.html" shape="rect">rpy scripts (or, how to save yourself some typing)</a></li> +<li><a href="asynchronous.html" shape="rect">Asynchronous responses</a></li> +<li><a href="asynchronous-deferred.html" shape="rect">Asynchronous responses (via Deferred)</a></li> +<li><a href="interrupted.html" shape="rect">Interrupted responses</a></li> +<li><a href="logging-errors.html" shape="rect">Logging errors</a></li> +<li><a href="wsgi.html" shape="rect">WSGIs</a></li> +<li><a href="http-auth.html" shape="rect">HTTP authentication</a></li> +<li><a href="session-basics.html" shape="rect">Session basics</a></li> +<li><a href="session-store.html" shape="rect">Storing objects in the session</a></li> +<li><a href="session-endings.html" shape="rect">Session endings</a></li> +</ol> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/interrupted.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/interrupted.html new file mode 100644 index 0000000000..ecd8320bc9 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/interrupted.html @@ -0,0 +1,141 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Interrupted Responses</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Interrupted Responses</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>The previous example had a Resource that generates its response +asynchronously rather than immediately upon the call to its render method. When +generating responses asynchronously, the possibility is introduced that the +connection to the client may be lost before the response is generated. In such a +case, it is often desirable to abandon the response generation entirely, since +there is nothing to do with the data once it is produced. This example shows how +to be notified that the connection has been lost.</p> + +<p>This example will build upon the <a href="asynchronous.html" shape="rect">asynchronous +responses example</a> which simply (if not very realistically) generated its +response after a fixed delay. We will expand that resource so that as soon as +the client connection is lost, the delayed event is cancelled and the response +is never generated.</p> + +<p>The feature this example relies on is provided by another <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Request.html" title="twisted.web.server.Request">Request</a></code> method: <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.http.Request.notifyFinish.html" title="twisted.web.http.Request.notifyFinish">notifyFinish</a></code>. This method returns a new +Deferred which will fire with <code>None</code> if the request is successfully +responded to or with an error otherwise - for example if the connection is lost +before the response is sent.</p> + +<p>The example starts in a familiar way, with the requisite Twisted imports and +a resource class with the same <code>_delayedRender</code> used previously:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> + <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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NOT_DONE_YET</span> + <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> + + <span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_delayedRender</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"Sorry to keep you waiting."</span>) + <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>() +</pre> + +<p>Before defining the render method, we're going to define an errback (an +errback being a callback that gets called when there's an error), though. This +will be the errback attached to the <code>Deferred</code> returned by +<code>Request.notifyFinish</code>. It will cancel the delayed call to +<code>_delayedRender</code>.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +</p><span class="py-src-keyword">def</span> <span class="py-src-identifier">_responseFailed</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">err</span>, <span class="py-src-parameter">call</span>): + <span class="py-src-variable">call</span>.<span class="py-src-variable">cancel</span>() +</pre> + +<p>Finally, the render method will set up the delayed call just as it did +before, and return <code>NOT_DONE_YET</code> likewise. However, it will also use +<code>Request.notifyFinish</code> to make sure <code>_responseFailed</code> is +called if appropriate.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">call</span> = <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">5</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">_delayedRender</span>, <span class="py-src-variable">request</span>) + <span class="py-src-variable">request</span>.<span class="py-src-variable">notifyFinish</span>().<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">_responseFailed</span>, <span class="py-src-variable">call</span>) + <span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span> +</pre> + +<p>Notice that since <code>_responseFailed</code> needs a reference to the +delayed call object in order to cancel it, we passed that object to +<code>addErrback</code>. Any additional arguments passed to +<code>addErrback</code> (or <code>addCallback</code>) will be passed along to +the errback after the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.failure.Failure.html" title="twisted.python.failure.Failure">Failure</a></code> instance which is always passed as +the first argument. Passing <code>call</code> here means it will be passed to +<code>_responseFailed</code>, where it is expected and required.</p> + +<p>That covers almost all the code for this example. Here's the entire example +without interruptions, as an <a href="rpy-scripts.html" shape="rect">rpy script</a>:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NOT_DONE_YET</span> +<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> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_delayedRender</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"Sorry to keep you waiting."</span>) + <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>() + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_responseFailed</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">err</span>, <span class="py-src-parameter">call</span>): + <span class="py-src-variable">call</span>.<span class="py-src-variable">cancel</span>() + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">call</span> = <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">5</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">_delayedRender</span>, <span class="py-src-variable">request</span>) + <span class="py-src-variable">request</span>.<span class="py-src-variable">notifyFinish</span>().<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">_responseFailed</span>, <span class="py-src-variable">call</span>) + <span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">DelayedResource</span>() +</pre> + +<p>Toss this into example.rpy, fire it up with <code>twistd -n web --path +.</code>, and hit <a href="http://localhost:8080/example.rpy" shape="rect">http://localhost:8080/example.rpy</a>. If +you wait five seconds, you'll get the page content. If you interrupt the request +before then, say by hitting escape (in Firefox, at least), then you'll see +perhaps the most boring demonstration ever - no page content, and nothing in the +server logs. Success!</p> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/logging-errors.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/logging-errors.html new file mode 100644 index 0000000000..b14506943f --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/logging-errors.html @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Logging Errors</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Logging Errors</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>The <a href="interrupted.html" shape="rect">previous example</a> created a server that +dealt with response errors by aborting response generation, potentially avoiding +pointless work. However, it did this silently for any error. In this example, +we'll modify the previous example so that it logs each failed response.</p> + +<p>This example will use the Twisted API for logging errors. As was mentioned in +the <a href="asynchronous-deferred.html" shape="rect">first example covering Deferreds</a>, +errbacks are passed an error. In the previous example, the +<code>_responseFailed</code> errback accepted this error as a parameter but +ignored it. The only way this example will differ is that this +<code>_responseFailed</code> will use that error parameter to log a message.</p> + +<p>This example will require all of the imports required by the previous example +plus one new import:</p> + +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">log</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">err</span> +</pre> + +<p>The only other part of the previous example which changes is the +<code>_responseFailed</code> callback, which will now log the error passed to +it:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><span class="py-src-keyword">def</span> <span class="py-src-identifier">_responseFailed</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">failure</span>, <span class="py-src-parameter">call</span>): + <span class="py-src-variable">call</span>.<span class="py-src-variable">cancel</span>() + <span class="py-src-variable">err</span>(<span class="py-src-variable">failure</span>, <span class="py-src-string">"Async response demo interrupted response"</span>) +</pre> + +<p>We're passing two arguments to <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.log.err.html" title="twisted.python.log.err">err</a></code> here. The first is the error which is being +passed in to the callback. This is always an object of type <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.failure.Failure.html" title="twisted.python.failure.Failure">Failure</a></code>, a class which represents an +exception and (sometimes, but not always) a traceback. <code>err</code> will +format this nicely for the log. The second argument is a descriptive string that +tells someone reading the log what the source of the error was.</p> + +<p>Here's the full example with the two above modifications:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NOT_DONE_YET</span> +<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> +<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">log</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">err</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_delayedRender</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"Sorry to keep you waiting."</span>) + <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>() + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_responseFailed</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">failure</span>, <span class="py-src-parameter">call</span>): + <span class="py-src-variable">call</span>.<span class="py-src-variable">cancel</span>() + <span class="py-src-variable">err</span>(<span class="py-src-variable">failure</span>, <span class="py-src-string">"Async response demo interrupted response"</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">call</span> = <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">5</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">_delayedRender</span>, <span class="py-src-variable">request</span>) + <span class="py-src-variable">request</span>.<span class="py-src-variable">notifyFinish</span>().<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">_responseFailed</span>, <span class="py-src-variable">call</span>) + <span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">DelayedResource</span>() +</pre> + +<p>Run this server as in the <a href="interrupted.html" shape="rect">previous example</a> +and interrupt a request. Unlike the previous example, where the server gave no +indication that this had happened, you'll see a message in the log output with +this version.</p> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/rpy-scripts.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/rpy-scripts.html new file mode 100644 index 0000000000..19be767388 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/rpy-scripts.html @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: rpy scripts (or, how to save yourself some typing)</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">rpy scripts (or, how to save yourself some typing)</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>The goal of this installment is to show you another way to run a Twisted Web +server with a custom resource which doesn't require as much code as the previous +examples.</p> + +<p>The feature in question is called an <code>rpy script</code>. An rpy script +is a Python source file which defines a resource and can be loaded into a +Twisted Web server. The advantages of this approach are that you don't have to +write code to create the site or set up a listening port with the reactor. That +means fewer lines of code that aren't dedicated to the task you're trying to +accomplish.</p> + +<p>There are some disadvantages, though. An rpy script must have the extension +<code>.rpy</code>. This means you can't import it using the usual Python import +statement. This means it's hard to re-use code in an rpy script. This also means +you can't easily unit test it. The code in an rpy script is evaluated in an +unusual context. So, while rpy scripts may be useful for testing out ideas, +they're not recommend for much more than that.</p> + +<p>Okay, with that warning out of the way, let's dive in. First, as mentioned, +rpy scripts are Python source files with the <code>.rpy</code> extension. So, +open up an appropriately named file (for example, <code>example.rpy</code>) and +put this code in it:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +</p><span class="py-src-keyword">import</span> <span class="py-src-variable">time</span> + +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">ClockPage</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-variable">isLeaf</span> = <span class="py-src-variable">True</span> + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">"%s"</span> % (<span class="py-src-variable">time</span>.<span class="py-src-variable">ctime</span>(),) + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">ClockPage</span>() +</pre> + +<p>You may recognize this as the resource from the <a href="dynamic-content.html" shape="rect">first dynamic rendering example</a>. What's +different is what you don't see: we didn't import <code>reactor</code> or +<code>Site</code>. There are no calls to <code>listenTCP</code> or +<code>run</code>. Instead, and this is the core idea for rpy scripts, we just +bound the name <code>resource</code> to the resource we want the script to +serve. Every rpy script must bind this name, and this name is the only thing +Twisted Web will pay attention to in an rpy script.</p> + +<p>All that's left is to drop this rpy script into a Twisted Web server. There +are a few ways to do this. The simplest way is with <code>twistd</code>:</p> + +<pre class="shell" xml:space="preserve"> +$ twistd -n web --path . +</pre> + +<p>Hit <a href="http://localhost:8080/example.rpy" shape="rect">http://localhost:8080/example.rpy</a> +to see it run. You can pass other arguments here too. <code>twistd web</code> +has options for specifying which port number to bind, whether to set up an HTTPS +server, and plenty more. Other options you can pass to <code>twistd</code> allow +you to configure logging to work differently, to select a different reactor, +etc. For a full list of options, see <code>twistd --help</code> and <code>twistd +web --help</code>.</p> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/session-basics.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/session-basics.html new file mode 100644 index 0000000000..75918ecb59 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/session-basics.html @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Session Basics</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Session Basics</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>Sessions are the most complicated topic covered in this series of examples, +and because of that it is going to take a few examples to cover all of the +different aspects. This first example demonstrates the very basics of the +Twisted Web session API: how to get the session object for the current request +and how to prematurely expire a session.</p> + +<p>Before diving into the APIs, let's look at the big picture of sessions in +Twisted Web. Sessions are represented by instances of <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Session.html" title="twisted.web.server.Session">Session</a></code>. The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Site.html" title="twisted.web.server.Site">Site</a></code> creates a new instance of +<code>Session</code> the first time an application asks for it for a particular +session. <code>Session</code> instances are kept on the <code>Site</code> +instance until they expire (due to inactivity or because they are explicitly +expired). Each time after the first that a particular session's +<code>Session</code> object is requested, it is retrieved from +the <code>Site</code>.</p> + +<p>With the conceptual underpinnings of the upcoming API in place, here comes +the example. This will be a very simple <a href="rpy-scripts.html" shape="rect">rpy +script</a> which tells a user what its unique session identifier is and lets it +prematurely expire the session.</p> + +<p>First, we'll import <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code> so we can define a couple of +subclasses of it:</p> + +<pre class="python"><p class="py-linenumber">1 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +</pre> + +<p>Next we'll define the resource which tells the client what its session +identifier is. This is done easily by first getting the session object +using <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Request.getSession.html" title="twisted.web.server.Request.getSession">Request.getSession</a></code> and +then getting the session object's uid attribute:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">ShowSession</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'Your session id is: '</span> + <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>().<span class="py-src-variable">uid</span> +</pre> + +<p>To let the client expire its own session before it times out, we'll define +another resource which expires whatever session it is requested with. This is +done using the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Session.expire.html" title="twisted.web.server.Session.expire">Session.expire</a></code> +method:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">ExpireSession</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>().<span class="py-src-variable">expire</span>() + <span class="py-src-keyword">return</span> <span class="py-src-string">'Your session has been expired.'</span> +</pre> + +<p>Finally, to make the example an rpy script, we'll make an instance of +<code>ShowSession</code> and give it an instance of <code>ExpireSession</code> +as a child using <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.putChild.html" title="twisted.web.resource.Resource.putChild">Resource.putChild</a></code>:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +</p><span class="py-src-variable">resource</span> = <span class="py-src-variable">ShowSession</span>() +<span class="py-src-variable">resource</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"expire"</span>, <span class="py-src-variable">ExpireSession</span>()) +</pre> + +<p>And that is the complete example. You can fire this up and load the top +page. You'll see a (rather opaque) session identifier that remains the same +across reloads (at least until you flush the <code>TWISTED_SESSION</code> cookie +from your browser or enough time passes). You can then visit +the <code>expire</code> child and go back to the top page and see that you have +a new session.</p> + +<p>Here's the complete source for the example:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">ShowSession</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'Your session id is: '</span> + <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>().<span class="py-src-variable">uid</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">ExpireSession</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>().<span class="py-src-variable">expire</span>() + <span class="py-src-keyword">return</span> <span class="py-src-string">'Your session has been expired.'</span> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">ShowSession</span>() +<span class="py-src-variable">resource</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"expire"</span>, <span class="py-src-variable">ExpireSession</span>()) +</pre> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/session-endings.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/session-endings.html new file mode 100644 index 0000000000..46793a7b85 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/session-endings.html @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Session Endings</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Session Endings</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>The previous two examples introduced Twisted Web's session APIs. This +included accessing the session object, storing state on it, and retrieving it +later, as well as the idea that the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Session.html" title="twisted.web.server.Session">Session</a></code> object has a lifetime which is tied to +the notional session it represents. This example demonstrates how to exert some +control over that lifetime and react when it expires.</p> + +<p>The lifetime of a session is controlled by the <code>sessionTimeout</code> +attribute of the <code>Session</code> class. This attribute gives the number of +seconds a session may go without being accessed before it expires. The default +is 15 minutes. In this example we'll change that to a different value.</p> + +<p>One way to override the value is with a subclass:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Session</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">ShortSession</span>(<span class="py-src-parameter">Session</span>): + <span class="py-src-variable">sessionTimeout</span> = <span class="py-src-number">60</span> +</pre> + +<p>To have Twisted Web actually make use of this session class, rather than the +default, it is also necessary to override the <code>sessionFactory</code> attribute of +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Site.html" title="twisted.web.server.Site">Site</a></code>. We could do this with +another subclass, but we could also do it to just one instance +of <code>Site</code>:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> + +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">rootResource</span>) +<span class="py-src-variable">factory</span>.<span class="py-src-variable">sessionFactory</span> = <span class="py-src-variable">ShortSession</span> +</pre> + +<p>Sessions given out for requests served by this <code>Site</code> will +use <code>ShortSession</code> and only last one minute without activity.</p> + +<p>You can have arbitrary functions run when sessions expire, too. This can be +useful for cleaning up external resources associated with the session, tracking +usage statistics, and more. This functionality is provided via +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Session.notifyOnExpire.html" title="twisted.web.server.Session.notifyOnExpire">Session.notifyOnExpire</a></code>. It +accepts a single argument: a function to call when the session expires. Here's a +trivial example which prints a message whenever a session expires:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">ExpirationLogger</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-variable">sessions</span> = <span class="py-src-variable">set</span>() + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">session</span> = <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>() + <span class="py-src-keyword">if</span> <span class="py-src-variable">session</span>.<span class="py-src-variable">uid</span> <span class="py-src-keyword">not</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">sessions</span>: + <span class="py-src-variable">self</span>.<span class="py-src-variable">sessions</span>.<span class="py-src-variable">add</span>(<span class="py-src-variable">session</span>.<span class="py-src-variable">uid</span>) + <span class="py-src-variable">session</span>.<span class="py-src-variable">notifyOnExpire</span>(<span class="py-src-keyword">lambda</span>: <span class="py-src-variable">self</span>.<span class="py-src-variable">_expired</span>(<span class="py-src-variable">session</span>.<span class="py-src-variable">uid</span>)) + <span class="py-src-keyword">return</span> <span class="py-src-string">""</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_expired</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">uid</span>): + <span class="py-src-keyword">print</span> <span class="py-src-string">"Session"</span>, <span class="py-src-variable">uid</span>, <span class="py-src-string">"has expired."</span> + <span class="py-src-variable">self</span>.<span class="py-src-variable">sessions</span>.<span class="py-src-variable">remove</span>(<span class="py-src-variable">uid</span>) +</pre> + +<p>Keep in mind that using a method as the callback will keep the instance (in +this case, the <code>ExpirationLogger</code> resource) in memory until the +session expires.</p> + +<p>With those pieces in hand, here's an example that prints a message whenever a +session expires, and uses sessions which last for 5 seconds:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span>, <span class="py-src-variable">Session</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">ShortSession</span>(<span class="py-src-parameter">Session</span>): + <span class="py-src-variable">sessionTimeout</span> = <span class="py-src-number">5</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">ExpirationLogger</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-variable">sessions</span> = <span class="py-src-variable">set</span>() + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">session</span> = <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>() + <span class="py-src-keyword">if</span> <span class="py-src-variable">session</span>.<span class="py-src-variable">uid</span> <span class="py-src-keyword">not</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">sessions</span>: + <span class="py-src-variable">self</span>.<span class="py-src-variable">sessions</span>.<span class="py-src-variable">add</span>(<span class="py-src-variable">session</span>.<span class="py-src-variable">uid</span>) + <span class="py-src-variable">session</span>.<span class="py-src-variable">notifyOnExpire</span>(<span class="py-src-keyword">lambda</span>: <span class="py-src-variable">self</span>.<span class="py-src-variable">_expired</span>(<span class="py-src-variable">session</span>.<span class="py-src-variable">uid</span>)) + <span class="py-src-keyword">return</span> <span class="py-src-string">""</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">_expired</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">uid</span>): + <span class="py-src-keyword">print</span> <span class="py-src-string">"Session"</span>, <span class="py-src-variable">uid</span>, <span class="py-src-string">"has expired."</span> + <span class="py-src-variable">self</span>.<span class="py-src-variable">sessions</span>.<span class="py-src-variable">remove</span>(<span class="py-src-variable">uid</span>) + +<span class="py-src-variable">rootResource</span> = <span class="py-src-variable">Resource</span>() +<span class="py-src-variable">rootResource</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"logme"</span>, <span class="py-src-variable">ExpirationLogger</span>()) +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">rootResource</span>) +<span class="py-src-variable">factory</span>.<span class="py-src-variable">sessionFactory</span> = <span class="py-src-variable">ShortSession</span> + +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8080</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>Since <code>Site</code> customization is required, this example can't be +rpy-based, so it brings back the manual <code>reactor.listenTCP</code> +and <code>reactor.run</code> calls. Run it and visit <code>/logme</code> to see +it in action. Keep visiting it to keep your session active. Stop visiting it for +five seconds to see your session expiration message.</p> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/session-store.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/session-store.html new file mode 100644 index 0000000000..4887be0b05 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/session-store.html @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Storing Objects in the Session</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Storing Objects in the Session</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>This example shows you how you can persist objects across requests in the +session object.</p> + +<p>As was discussed <a href="session-basics.html" shape="rect">previously</a>, instances +of <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Session.html" title="twisted.web.server.Session">Session</a></code> last as long as +the notional session itself does. Each time <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Request.getSession.html" title="twisted.web.server.Request.getSession">Request.getSession</a></code> is called, if the session +for the request is still active, then the same <code>Session</code> instance is +returned as was returned previously. Because of this, <code>Session</code> +instances can be used to keep other objects around for as long as the session +exists.</p> + +<p>It's easier to demonstrate how this works than explain it, so here's an +example:</p> + +<pre class="shell" xml:space="preserve"> +>>> from zope.interface import Interface, Attribute, implements +>>> from twisted.python.components import registerAdapter +>>> from twisted.web.server import Session +>>> class ICounter(Interface): +... value = Attribute("An int value which counts up once per page view.") +... +>>> class Counter(object): +... implements(ICounter) +... def __init__(self, session): +... self.value = 0 +... +>>> registerAdapter(Counter, Session, ICounter) +>>> ses = Session(None, None) +>>> data = ICounter(ses) +>>> print data +<__main__.Counter object at 0x8d535ec> +>>> print data is ICounter(ses) +True +>>> +</pre> + +<p><i>What?</i>, I hear you say.</p> + +<p>What's shown in this example is the interface and adaption-based API which +<code>Session</code> exposes for persisting state. There are several critical +pieces interacting here:</p> + +<ul> + <li><code>ICounter</code> is an interface which serves several purposes. Like + all interfaces, it documents the API of some class of objects (in this case, + just the <code>value</code> attribute). It also serves as a key into what is + basically a dictionary within the session object: the interface is used to + store or retrieve a value on the session (the <code>Counter</code> instance, + in this case).</li> + <li><code>Counter</code> is the class which actually holds the session data in + this example. It implements <code>ICounter</code> (again, mostly for + documentation purposes). It also has a <code>value</code> attribute, as the + interface declared.</li> + <li>The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.components.registerAdapter.html" title="twisted.python.components.registerAdapter">registerAdapter</a></code> call sets up the + relationship between its three arguments so that adaption will do what we + want in this case.</li> + <li>Adaption is performed by the expression <code>ICounter(ses)</code>. This + is read as <i>adapt <code>ses</code> to <code>ICounter</code></i>. Because + of the <code>registerAdapter</code> call, it is roughly equivalent + to <code>Counter(ses)</code>. However (because of certain + things <code>Session</code> does), it also saves the <code>Counter</code> + instance created so that it will be returned the next time this adaption is + done. This is why the last statement produces <code>True</code>.</li> +</ul> + +<p>If you're still not clear on some of the details there, don't worry about it +and just remember this: <code>ICounter(ses)</code> gives you an object you can +persist state on. It can be as much or as little state as you want, and you can +use as few or as many different <code>Interface</code> classes as you want on a +single <code>Session</code> instance.</p> + +<p>With those conceptual dependencies out of the way, it's a very short step to +actually getting persistent state into a Twisted Web application. Here's an +example which implements a simple counter, re-using the definitions from the +example above:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +</p><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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">CounterResource</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">session</span> = <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>() + <span class="py-src-variable">counter</span> = <span class="py-src-variable">ICounter</span>(<span class="py-src-variable">session</span>) + <span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span> += <span class="py-src-number">1</span> + <span class="py-src-keyword">return</span> <span class="py-src-string">"Visit #%d for you!"</span> % (<span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span>,) +</pre> + +<p>Pretty simple from this side, eh? All this does is +use <code>Request.getSession</code> and the adaption from above, plus some +integer math to give you a session-based visit counter.</p> + +<p>Here's the complete source for an <a href="rpy-scripts.html" shape="rect">rpy script</a> +based on this example:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +</p><span class="py-src-variable">cache</span>() + +<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">Attribute</span>, <span class="py-src-variable">implements</span> +<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">components</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">registerAdapter</span> +<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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Session</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">ICounter</span>(<span class="py-src-parameter">Interface</span>): + <span class="py-src-variable">value</span> = <span class="py-src-variable">Attribute</span>(<span class="py-src-string">"An int value which counts up once per page view."</span>) + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>): + <span class="py-src-variable">implements</span>(<span class="py-src-variable">ICounter</span>) + <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">session</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">value</span> = <span class="py-src-number">0</span> + +<span class="py-src-variable">registerAdapter</span>(<span class="py-src-variable">Counter</span>, <span class="py-src-variable">Session</span>, <span class="py-src-variable">ICounter</span>) + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">CounterResource</span>(<span class="py-src-parameter">Resource</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>): + <span class="py-src-variable">session</span> = <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>() + <span class="py-src-variable">counter</span> = <span class="py-src-variable">ICounter</span>(<span class="py-src-variable">session</span>) + <span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span> += <span class="py-src-number">1</span> + <span class="py-src-keyword">return</span> <span class="py-src-string">"Visit #%d for you!"</span> % (<span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span>,) + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">CounterResource</span>() +</pre> + +<p>One more thing to note is the <code>cache()</code> call at the top of this +example. As with the <a href="http-auth.html" shape="rect">previous example</a> where this +came up, this rpy script is stateful. This time, it's the <code>ICounter</code> +definition and the +<code>registerAdapter</code> call that need to be executed only once. If we +didn't use <code>cache</code>, every request would define a new, different +interface named <code>ICounter</code>. Each of these would be a different key in +the session, so the counter would never get past one.</p> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/static-content.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/static-content.html new file mode 100644 index 0000000000..3499f9849a --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/static-content.html @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Serving Static Content From a Directory</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Serving Static Content From a Directory</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>The goal of this example is to show you how to serve static content +from a filesystem. First, we need to import some objects:</p> + +<ul> + +<li> +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Site.html" title="twisted.web.server.Site">Site</a></code>, an <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IProtocolFactory.html" title="twisted.internet.interfaces.IProtocolFactory">IProtocolFactory</a></code> which +glues a listening server port (<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IListeningPort.html" title="twisted.internet.interfaces.IListeningPort">IListeningPort</a></code>) to the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.http.HTTPChannel.html" title="twisted.web.http.HTTPChannel">HTTPChannel</a></code> +implementation: +<pre class="python"><p class="py-linenumber">1 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +</pre> +</li> + +<li> +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.static.File.html" title="twisted.web.static.File">File</a></code>, an <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.IResource.html" title="twisted.web.resource.IResource">IResource</a></code> which glues +the HTTP protocol implementation to the filesystem: +<pre class="python"><p class="py-linenumber">1 +</p><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">static</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">File</span> +</pre> +</li> + +<li> +The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.reactor.html" title="twisted.internet.reactor">reactor</a></code>, which +drives the whole process, actually accepting TCP connections and +moving bytes into and out of them: +<pre class="python"><p class="py-linenumber">1 +</p><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> +</pre> +</li> + +</ul> + +Next, we create an instance of the File resource pointed at the +directory to serve: +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-variable">resource</span> = <span class="py-src-variable">File</span>(<span class="py-src-string">"/tmp"</span>) +</pre> + +Then we create an instance of the Site factory with that resource: +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">resource</span>) +</pre> + +Now we glue that factory to a TCP port: +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8888</span>, <span class="py-src-variable">factory</span>) +</pre> + +Finally, we start the reactor so it can make the program work: +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> +And that's it. Here's the complete program: + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">static</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">File</span> +<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> + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">File</span>(<span class="py-src-string">'/tmp'</span>) +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">resource</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8888</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>Bonus example! For those times when you don't actually want to +write a new program, the above implemented functionality is one of the +things the command line <code>twistd</code> tool can do. In this case, +the command +<pre xml:space="preserve"> +twistd -n web --path /tmp +</pre> +will accomplish the same thing as the above server. See <a href="../../../core/howto/basics.html" shape="rect">helper programs</a> in the +Twisted Core documentation for more information on using +<code>twistd</code>.</p> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/static-dispatch.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/static-dispatch.html new file mode 100644 index 0000000000..3e5c47000b --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/static-dispatch.html @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Static URL Dispatch</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Static URL Dispatch</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>The goal of this example is to show you how to serve different content at +different URLs.</p> + +<p>The key to understanding how different URLs are handled with the resource +APIs in Twisted Web is understanding that any URL can be used to address a node +in a tree. Resources in Twisted Web exist in such a tree, and a request for a +URL will be responded to by the resource which that URL addresses. The +addressing scheme considers only the path segments of the URL. Starting with the +root resource (the one used to construct the <code>Site</code>) and the first +path segment, a child resource is looked up. As long as there are more path +segments, this process is repeated using the result of the previous lookup and +the next path segment. For example, to handle a request for +<code>/foo/bar</code>, first the root's "<code>foo</code>" child is retrieved, +then that resource's "<code>bar</code>" child is retrieved, then that resource +is used to create the response.</p> + +<p>With that out of the way, let's consider an example that can serve a few +different resources at a few different URLs.</p> + +<p>First things first: we need to import <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Site.html" title="twisted.web.server.Site">Site</a></code>, the factory for HTTP servers, <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code>, a convenient base class +for custom pages, and <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.reactor.html" title="twisted.internet.reactor">reactor</a></code>, +the object which implements the Twisted main loop. We'll also import <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.static.File.html" title="twisted.web.static.File">File</a></code> to use as the resource at one +of the example URLs.</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> +<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">static</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">File</span> +</pre> + +<p>Now we create a resource which will correspond to the root of the URL +hierarchy: all URLs are children of this resource.</p> + +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-variable">root</span> = <span class="py-src-variable">Resource</span>() +</pre> + +<p>Here comes the interesting part of this example. We're now going to create +three more resources and attach them to the three URLs <code>/foo</code>, +<code>/bar</code>, and <code>/baz</code>:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"foo"</span>, <span class="py-src-variable">File</span>(<span class="py-src-string">"/tmp"</span>)) +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"bar"</span>, <span class="py-src-variable">File</span>(<span class="py-src-string">"/lost+found"</span>)) +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"baz"</span>, <span class="py-src-variable">File</span>(<span class="py-src-string">"/opt"</span>)) +</pre> + +<p>Last, all that's required is to create a <code>Site</code> with the root +resource, associate it with a listening server port, and start the reactor:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8880</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>With this server running, <code>http://localhost:8880/foo</code> will serve a +listing of files from <code>/tmp</code>, <code>http://localhost:8880/bar</code> +will serve a listing of files from <code>/lost+found</code>, and +<code>http://localhost:8880/baz</code> will serve a listing of files from +<code>/opt</code>.</p> + +<p>Here's the whole example uninterrupted:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +</p><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">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Site</span> +<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">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span> +<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> +<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">static</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">File</span> + +<span class="py-src-variable">root</span> = <span class="py-src-variable">Resource</span>() +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"foo"</span>, <span class="py-src-variable">File</span>(<span class="py-src-string">"/tmp"</span>)) +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"bar"</span>, <span class="py-src-variable">File</span>(<span class="py-src-string">"/lost+found"</span>)) +<span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">"baz"</span>, <span class="py-src-variable">File</span>(<span class="py-src-string">"/opt"</span>)) + +<span class="py-src-variable">factory</span> = <span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8880</span>, <span class="py-src-variable">factory</span>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/wsgi.html b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/wsgi.html new file mode 100644 index 0000000000..c42f748f3b --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-in-60/wsgi.html @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: WSGI</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">WSGI</h1> + <div class="toc"><ol/></div> + <div class="content"> +<span/> + +<p>The goal of this example is to show you how to use <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.wsgi.WSGIResource.html" title="twisted.web.wsgi.WSGIResource">WSGIResource</a></code>, another existing +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code> subclass, to serve +<a href="http://www.python.org/dev/peps/pep-0333/" shape="rect">WSGI applications</a> in a +Twisted Web server.</p> + +<p>Note thate <code>WSGIResource</code> is a multithreaded WSGI container. Like +any other WSGI container, you can't do anything asynchronous in your WSGI +applications, even though this is a Twisted WSGI container.</p> + +<p>The first new thing in this example is the import +of <code>WSGIResource</code>:</p> + +<pre class="python"><p class="py-linenumber">1 +</p><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">wsgi</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">WSGIResource</span> +</pre> + +<p>Nothing too surprising there. We still need one of the other usual suspects, +too:</p> + +<pre class="python"><p class="py-linenumber">1 +</p><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> +</pre> + +<p>You'll see why in a minute. Next, we need a WSGI application. Here's a really +simple one just to get things going:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +</p><span class="py-src-keyword">def</span> <span class="py-src-identifier">application</span>(<span class="py-src-parameter">environ</span>, <span class="py-src-parameter">start_response</span>): + <span class="py-src-variable">start_response</span>(<span class="py-src-string">'200 OK'</span>, [(<span class="py-src-string">'Content-type'</span>, <span class="py-src-string">'text/plain'</span>)]) + <span class="py-src-keyword">return</span> [<span class="py-src-string">'Hello, world!'</span>] +</pre> + +<p>If this doesn't make sense to you, take a look at one of +these <a href="http://wsgi.org/wsgi/Learn_WSGI" shape="rect">fine tutorials</a>. Otherwise, +or once you're done with that, the next step is to create +a <code>WSGIResource</code> instance, as this is going to be +another <a href="rpy-scripts.html" shape="rect">rpy script</a> example:</p> + +<pre class="python"><p class="py-linenumber">1 +</p><span class="py-src-variable">resource</span> = <span class="py-src-variable">WSGIResource</span>(<span class="py-src-variable">reactor</span>, <span class="py-src-variable">reactor</span>.<span class="py-src-variable">getThreadPool</span>(), <span class="py-src-variable">application</span>) +</pre> + +<p>Let's dwell on this line for a minute. The first parameter passed to +<code>WSGIResource</code> is the reactor. Despite the fact that the reactor is +global and any code that wants it can always just import it (as, in fact, this +rpy script simply does itself), passing it around as a parameter leaves the door +open for certain future possibilities - for example, having more than one +reactor. There are also testing implications. Consider how much easier it is to +unit test a function that accepts a reactor - perhaps a mock reactor specially +constructed to make your tests easy to write - rather than importing the real +global reactor. That's why <code>WSGIResource</code> requires you to pass the +reactor to it.</p> + +<p>The second parameter passed to <code>WSGIResource</code> is +a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.threadpool.ThreadPool.html" title="twisted.python.threadpool.ThreadPool">ThreadPool</a></code>. <code>WSGIResource</code> +uses this to actually call the application object passed in to it. To keep this +example short, we're passing in the reactor's internal threadpool here, letting +us skip its creation and shutdown-time destruction. For finer control over how +many WSGI requests are served in parallel, you may want to create your own +thread pool to use with your <code>WSGIResource</code>, but for simple testing, +using the reactor's is fine.</p> + +<p>The final argument is the application object. This is pretty typical of how +WSGI containers work.</p> + +<p>The example, sans interruption:</p> + +<pre class="python"><p class="py-linenumber">1 +2 +3 +4 +5 +6 +7 +8 +</p><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">wsgi</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">WSGIResource</span> +<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> + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">application</span>(<span class="py-src-parameter">environ</span>, <span class="py-src-parameter">start_response</span>): + <span class="py-src-variable">start_response</span>(<span class="py-src-string">'200 OK'</span>, [(<span class="py-src-string">'Content-type'</span>, <span class="py-src-string">'text/plain'</span>)]) + <span class="py-src-keyword">return</span> [<span class="py-src-string">'Hello, world!'</span>] + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">WSGIResource</span>(<span class="py-src-variable">reactor</span>, <span class="py-src-variable">reactor</span>.<span class="py-src-variable">getThreadPool</span>(), <span class="py-src-variable">application</span>) +</pre> + +<p>Up to the point where the <code>WSGIResource</code> instance defined here +exists in the resource hierarchy, the normal resource traversal rules +apply: <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.getChild.html" title="twisted.web.resource.Resource.getChild">getChild</a></code> +will be called to handle each segment. Once the <code>WSGIResource</code> is +encountered, though, that process stops and all further URL handling is the +responsibility of the WSGI application. This application does nothing with the +URL, though, so you won't be able to tell that.</p> + +<p>Oh, and as was the case with the first static file example, there's also a +command line option you can use to avoid a lot of this. If you just put the +above application function, without all of the <code>WSGIResource</code> stuff, +into a file, say, <code>foo.py</code>, then you can launch a roughly equivalent +server like this:</p> + +<pre class="shell" xml:space="preserve"> +$ twistd -n web --wsgi foo.application +</pre> + +</div> + + <p><a href="../index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/web-overview.html b/vendor/Twisted-10.0.0/doc/web/howto/web-overview.html new file mode 100644 index 0000000000..d6780c1e36 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/web-overview.html @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Overview of Twisted Web</title> +<link href="stylesheet.css" rel="stylesheet" type="text/css"/> + </head> + + <body bgcolor="white"> + <h1 class="title">Overview of Twisted Web</h1> + <div class="toc"><ol><li><a href="#auto0">Introduction</a></li><li><a href="#auto1">Twisted Web's Structure</a></li><li><a href="#auto2">Resources</a></li><li><a href="#auto3"> + Web programming with Twisted Web + </a></li></ol></div> + <div class="content"> + <span/> + + <h2>Introduction<a name="auto0"/></h2> + + <p>Twisted Web is a web application server written in pure + Python, with APIs at multiple levels of abstraction to + facilitate different kinds of web programming. + </p> + + <h2>Twisted Web's Structure<a name="auto1"/></h2> + + <p><img src="../img/web-overview.png"/></p> + + <p>When + the Web Server receives a request from a Client, it creates + a Request object and passes it on to the Resource system. + The Resource system dispatches to the appropriate Resource + object based on what path was requested by the client. The + Resource is asked to render itself, and the result is + returned to the client.</p> + + <h2>Resources<a name="auto2"/></h2> + + <p>Resources are the lowest-level abstraction for applications + in the Twisted web server. Each Resource is a 1:1 mapping with + a path that is requested: you can think of a Resource as a + single <q>page</q> to be rendered. The interface for making + Resources is very simple; they must have a method named + <code>render</code> which takes a single argument, which is the + Request object (an instance of <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Request.html" title="twisted.web.server.Request">twisted.web.server.Request</a></code>). This render + method must return a string, which will be returned to the web + browser making the request. Alternatively, they can return a + special constant, <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.NOT_DONE_YET.html" title="twisted.web.server.NOT_DONE_YET">twisted.web.server.NOT_DONE_YET</a></code>, which tells + the web server not to close the connection; you must then use + <code class="python">request.write(data)</code> to render the + page, and call <code class="python">request.finish()</code> + whenever you're done. + </p> + + <h2> + Web programming with Twisted Web + <a name="auto3"/></h2> + + <p> + Web programmers seeking a higher level abstraction than the Resource system + should look at <a href="http://divmod.org/trac/wiki/DivmodNevow" shape="rect">Nevow</a>. + Nevow is based on ideas previously developed in Twisted, but is now maintained + outside of Twisted to easy development and release cycle pressures. + </p> + </div> + + <p><a href="index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file diff --git a/vendor/Twisted-10.0.0/doc/web/howto/xmlrpc.html b/vendor/Twisted-10.0.0/doc/web/howto/xmlrpc.html new file mode 100644 index 0000000000..b9a0634c90 --- /dev/null +++ b/vendor/Twisted-10.0.0/doc/web/howto/xmlrpc.html @@ -0,0 +1,457 @@ +<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> +<title>Twisted Documentation: Creating XML-RPC Servers and Clients with Twisted</title> +<link href="stylesheet.css" rel="stylesheet" type="text/css"/> + </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">Serving SOAP and XML-RPC simultaneously</a></li></ol></div> + <div class="content"> +<span/> + +<h2>Introduction<a name="auto0"/></h2> + +<p><a href="http://www.xmlrpc.com" shape="rect">XML-RPC</a> is a simple request/reply protocol that runs over HTTP. It is simple, +easy to implement and supported by most programming languages. Twisted's XML-RPC +support is implemented using the xmlrpclib library that is included with Python 2.2 and later.</p> + +<h2>Creating a XML-RPC server<a name="auto1"/></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/10.0.0/api/twisted.web.xmlrpc.XMLRPC.html" title="twisted.web.xmlrpc.XMLRPC">twisted.web.xmlrpc.XMLRPC</a></code>. +You then create methods beginning with <code>xmlrpc_</code>. The methods' +arguments determine what arguments it will accept from XML-RPC clients. +The result is what will be returned to the clients.</p> + +<p>Methods published via XML-RPC can return all the basic XML-RPC +types, such as strings, lists and so on (just return a regular python +integer, etc). They can also raise exceptions or return Failure instances to indicate an +error has occurred, or <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.xmlrpc.Binary.html" title="twisted.web.xmlrpc.Binary">Binary</a></code>, <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.xmlrpc.Boolean.html" title="twisted.web.xmlrpc.Boolean">Boolean</a></code> or <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.xmlrpc.DateTime.html" title="twisted.web.xmlrpc.DateTime">DateTime</a></code> instances (all of these are the same as +the respective classes in xmlrpclib. In addition, XML-RPC published +methods can return <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code> instances whose results are one of the +above. This allows you to return results that can't be calculated +immediately, such as database queries. See the <a href="../../core/howto/defer.html" shape="rect">Deferred documentation</a> for more details.</p> + +<p><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.xmlrpc.XMLRPC.html" title="twisted.web.xmlrpc.XMLRPC">XMLRPC</a></code> instances +are Resource objects, and they can thus be published using a Site. The +following example has two methods published via XML-RPC, <code>add(a, +b)</code> and <code>echo(x)</code>.</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +</p><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-keyword">import</span> <span class="py-src-variable">xmlrpc</span>, <span class="py-src-variable">server</span> + +<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>): + <span class="py-src-string">"""An example object to be published."""</span> + + <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">x</span>): + <span class="py-src-string">""" + Return all passed args. + """</span> + <span class="py-src-keyword">return</span> <span class="py-src-variable">x</span> + + <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">a</span>, <span class="py-src-parameter">b</span>): + <span class="py-src-string">""" + Return sum of arguments. + """</span> + <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> + <span class="py-src-variable">b</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_fault</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-string">""" + Raise a Fault indicating that the procedure should not be used. + """</span> + <span class="py-src-keyword">raise</span> <span class="py-src-variable">xmlrpc</span>.<span class="py-src-variable">Fault</span>(<span class="py-src-number">123</span>, <span class="py-src-string">"The fault procedure is faulty."</span>) + +<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>: + <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> + <span class="py-src-variable">r</span> = <span class="py-src-variable">Example</span>() + <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">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">r</span>)) + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>After we run this command, we can connect with a client and send commands +to the server:</p> + +<pre class="python-interpreter" xml:space="preserve"> +>>> import xmlrpclib +>>> s = xmlrpclib.Server('http://localhost:7080/') +>>> s.echo("lala") +'lala' +>>> s.add(1, 2) +3 +>>> s.fault() +Traceback (most recent call last): +... +xmlrpclib.Fault: <Fault 123: 'The fault procedure is faulty.'> +>>> + +</pre> + +<p>XML-RPC resources can also be part of a normal Twisted web server, using +resource scripts. The following is an example of such a resource script:</p> + +<div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +</p><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-keyword">import</span> <span class="py-src-variable">xmlrpc</span> +<span class="py-src-keyword">import</span> <span class="py-src-variable">os</span> + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">getQuote</span>(): + <span class="py-src-keyword">return</span> <span class="py-src-string">"What are you talking about, William?"</span> + +<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>): + + <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-keyword">return</span> <span class="py-src-variable">getQuote</span>() + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">Quoter</span>() +</pre><div class="caption">Source listing - <a href="listings/xmlquote.rpy"><span class="filename">listings/xmlquote.rpy</span></a></div></div> + +<h3>Using XML-RPC sub-handlers<a name="auto2"/></h3> + +<p>XML-RPC resource can be nested so that one handler calls another if +a method with a given prefix is called. For example, to add support for +an XML-RPC method <code>date.time()</code> to the +<code class="python">Example</code> class, you could do the following:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +</p><span class="py-src-keyword">import</span> <span class="py-src-variable">time</span> +<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-keyword">import</span> <span class="py-src-variable">xmlrpc</span>, <span class="py-src-variable">server</span> + +<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>): + <span class="py-src-string">"""An example object to be published."""</span> + + <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">x</span>): + <span class="py-src-string">"""Return all passed args."""</span> + <span class="py-src-keyword">return</span> <span class="py-src-variable">x</span> + + <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">a</span>, <span class="py-src-parameter">b</span>): + <span class="py-src-string">"""Return sum of arguments."""</span> + <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> + <span class="py-src-variable">b</span> + +<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>): + <span class="py-src-string">"""Serve the XML-RPC 'time' method."""</span> + + <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-string">"""Return UNIX time."""</span> + <span class="py-src-keyword">return</span> <span class="py-src-variable">time</span>.<span class="py-src-variable">time</span>() + +<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>: + <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> + <span class="py-src-variable">r</span> = <span class="py-src-variable">Example</span>() + <span class="py-src-variable">date</span> = <span class="py-src-variable">Date</span>() + <span class="py-src-variable">r</span>.<span class="py-src-variable">putSubHandler</span>(<span class="py-src-string">'date'</span>, <span class="py-src-variable">date</span>) + <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">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">r</span>)) + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>By default, a period ('.') separates the prefix from the method +name, but you can use a different character by overriding the <code class="python">XMLRPC.separator</code> data member in your base +XML-RPC server. XML-RPC servers may be nested to arbitrary depths +using this method.</p> + +<h3>Adding XML-RPC Introspection support<a name="auto3"/></h3> + +<p>XML-RPC has an informal <a href="http://ldp.kernelnotes.de/HOWTO/XML-RPC-HOWTO/xmlrpc-howto-interfaces.html" shape="rect">Introspection API</a> that specifies three +methods in a <code>system</code> sub-handler which allow a client to query +a server about the server's API. Adding Introspection support to the +<code class="python">Example</code> class is easy using the +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.xmlrpc.XMLRPCIntrospection.html" title="twisted.web.xmlrpc.XMLRPCIntrospection">XMLRPCIntrospection</a></code> +class:</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +</p><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-keyword">import</span> <span class="py-src-variable">xmlrpc</span>, <span class="py-src-variable">server</span> + +<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>): + <span class="py-src-string">"""An example object to be published."""</span> + + <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">x</span>): + <span class="py-src-string">"""Return all passed args."""</span> + <span class="py-src-keyword">return</span> <span class="py-src-variable">x</span> + + <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>], + [<span class="py-src-string">'int'</span>, <span class="py-src-string">'int'</span>], + [<span class="py-src-string">'double'</span>, <span class="py-src-string">'double'</span>], + [<span class="py-src-string">'array'</span>, <span class="py-src-string">'array'</span>], + [<span class="py-src-string">'struct'</span>, <span class="py-src-string">'struct'</span>]] + + <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">a</span>, <span class="py-src-parameter">b</span>): + <span class="py-src-string">"""Return sum of arguments."""</span> + <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> + <span class="py-src-variable">b</span> + + <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>], + [<span class="py-src-string">'double'</span>, <span class="py-src-string">'double'</span>, <span class="py-src-string">'double'</span>]] + <span class="py-src-variable">xmlrpc_add</span>.<span class="py-src-variable">help</span> = <span class="py-src-string">"Add the arguments and return the sum."</span> + +<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>: + <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> + <span class="py-src-variable">r</span> = <span class="py-src-variable">Example</span>() + <span class="py-src-variable">xmlrpc</span>.<span class="py-src-variable">addIntrospection</span>(<span class="py-src-variable">r</span>) + <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">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">r</span>)) + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>Note the method attributes <code class="python">help</code> and +<code class="python">signature</code> which are used by the Introspection +API methods <code>system.methodHelp</code> and +<code>system.methodSignature</code> respectively. If no +<code class="python">help</code> attribute is specified, +the method's documentation string is used instead.</p> + +<h2>SOAP Support<a name="auto4"/></h2> + +<p>From the point of view of a Twisted developer, there is little difference +between XML-RPC support and SOAP support. Here is an example of SOAP usage:</p> + +<div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +</p><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-keyword">import</span> <span class="py-src-variable">soap</span> +<span class="py-src-keyword">import</span> <span class="py-src-variable">os</span> + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">getQuote</span>(): + <span class="py-src-keyword">return</span> <span class="py-src-string">"That beverage, sir, is off the hizzy."</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">Quoter</span>(<span class="py-src-parameter">soap</span>.<span class="py-src-parameter">SOAPPublisher</span>): + <span class="py-src-string">"""Publish one method, 'quote'."""</span> + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">soap_quote</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">getQuote</span>() + +<span class="py-src-variable">resource</span> = <span class="py-src-variable">Quoter</span>() +</pre><div class="caption">Source listing - <a href="listings/soap.rpy"><span class="filename">listings/soap.rpy</span></a></div></div> + + +<h2>Creating an XML-RPC Client<a name="auto5"/></h2> + +<p>XML-RPC clients in Twisted are meant to look as something which will be +familiar either to <code>xmlrpclib</code> or to Perspective Broker users, +taking features from both, as appropriate. There are two major deviations +from 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 + 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 + <code>callRemote</code>.</li> +</ol> + +<p>The interface Twisted presents to XML-RPC client is that of a proxy object: +<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.xmlrpc.Proxy.html" title="twisted.web.xmlrpc.Proxy">twisted.web.xmlrpc.Proxy</a></code>. The constructor for the +object receives a URL: it must be an HTTP or HTTPS URL. When an XML-RPC service +is 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, +which accepts a method name and a variable argument list (but no named +arguments, as these are not supported by XML-RPC). It returns a deferred, +which will be called back with the result. If there is any error, at any +level, the errback will be called. The exception will be the relevant Twisted +error in the case of a problem with the underlying connection (for example, +a timeout), <code>IOError</code> containing the status and message in the case +of a non-200 status or a <code>xmlrpclib.Fault</code> in the case of an +XML-RPC level problem.</p> + +<pre class="python"><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +</p><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> +<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> + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">printValue</span>(<span class="py-src-parameter">value</span>): + <span class="py-src-keyword">print</span> <span class="py-src-variable">repr</span>(<span class="py-src-variable">value</span>) + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>() + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">printError</span>(<span class="py-src-parameter">error</span>): + <span class="py-src-keyword">print</span> <span class="py-src-string">'error'</span>, <span class="py-src-variable">error</span> + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>() + +<span class="py-src-variable">proxy</span> = <span class="py-src-variable">Proxy</span>(<span class="py-src-string">'http://advogato.org/XMLRPC'</span>) +<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>) +<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() +</pre> + +<p>prints:</p> + +<pre xml:space="preserve"> +[8, 15] +</pre> + +<h2>Serving SOAP and XML-RPC simultaneously<a name="auto6"/></h2> + +<p><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.xmlrpc.XMLRPC.html" title="twisted.web.xmlrpc.XMLRPC">twisted.web.xmlrpc.XMLRPC</a></code> and <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.soap.SOAPPublisher.html" title="twisted.web.soap.SOAPPublisher">twisted.web.soap.SOAPPublisher</a></code> are both <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resources.html" title="twisted.web.resource.Resources">Resources</a></code>. So, to serve both XML-RPC and +SOAP in the one web server, you can use the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.IResource.putChild.html" title="twisted.web.resource.IResource.putChild">putChild</a></code> method of Resources.</p> + +<p>The following example uses an empty <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">resource.Resource</a></code> as the root resource for a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Site.html" title="twisted.web.server.Site">Site</a></code>, and then adds +<code>/RPC2</code> and <code>/SOAP</code> paths to it.</p> + +<div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +</p><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-keyword">import</span> <span class="py-src-variable">soap</span>, <span class="py-src-variable">xmlrpc</span>, <span class="py-src-variable">resource</span>, <span class="py-src-variable">server</span> +<span class="py-src-keyword">import</span> <span class="py-src-variable">os</span> + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">getQuote</span>(): + <span class="py-src-keyword">return</span> <span class="py-src-string">"Victory to the burgeois, you capitalist swine!"</span> + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">XMLRPCQuoter</span>(<span class="py-src-parameter">xmlrpc</span>.<span class="py-src-parameter">XMLRPC</span>): + <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-keyword">return</span> <span class="py-src-variable">getQuote</span>() + +<span class="py-src-keyword">class</span> <span class="py-src-identifier">SOAPQuoter</span>(<span class="py-src-parameter">soap</span>.<span class="py-src-parameter">SOAPPublisher</span>): + <span class="py-src-keyword">def</span> <span class="py-src-identifier">soap_quote</span>(<span class="py-src-parameter">self</span>): + <span class="py-src-keyword">return</span> <span class="py-src-variable">getQuote</span>() + +<span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>(): + <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> + <span class="py-src-variable">root</span> = <span class="py-src-variable">resource</span>.<span class="py-src-variable">Resource</span>() + <span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">'RPC2'</span>, <span class="py-src-variable">XMLRPCQuoter</span>()) + <span class="py-src-variable">root</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">'SOAP'</span>, <span class="py-src-variable">SOAPQuoter</span>()) + <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">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">root</span>)) + <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>() + +<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>: + <span class="py-src-variable">main</span>() +</pre><div class="caption">Source listing - <a href="listings/xmlAndSoapQuote.py"><span class="filename">listings/xmlAndSoapQuote.py</span></a></div></div> + +<p>Refer to <a href="using-twistedweb.html#development" shape="rect">Twisted Web +Development</a> for more details about Resources.</p> + + </div> + + <p><a href="index.html">Index</a></p> + <span class="version">Version: 10.0.0</span> + </body> +</html>
\ No newline at end of file |