Ticket #4577: web-in-60.xhtml.patch

File web-in-60.xhtml.patch, 47.5 KB (added by jdb, 4 years ago)

Adapted the lore input to fix typos in the html. Suppressed in the nested formatting.

  • doc/web/howto/web-in-60/asynchronous-deferred.xhtml

    diff --git a/doc/web/howto/web-in-60/asynchronous-deferred.xhtml b/doc/web/howto/web-in-60/asynchronous-deferred.xhtml
    index 78ce564..325164d 100644
    a b  
    2121example of using a <code>Deferred</code>-returning API to generate an 
    2222asynchronous response to a request in Twisted Web.</p> 
    2323 
    24 <p><code>Deferred</code> is the result of two consequences of the asynchronous 
    25 programming approach. First, asynchronous code is frequently (if not always) 
    26 concerned with some data (in Python, an object) which is not yet available but 
    27 which probably will be soon. Asynchronous code needs a way to define what will 
    28 be done to the object once it does exist. It also needs a way to define how to 
    29 handle errors in the creation or acquisition of that object. These two needs are 
    30 satisfied by the <i>callbacks</i> and <i>errbacks</i> of a 
    31 <code>Deferred</code>. Callbacks are added to a <code>Deferred</code> with <code 
    32 class="API" base="twisted.internet.defer">Deferred.addCallback</code>; errbacks 
     24<p><code>Deferred</code> is the result of two consequences of the 
     25asynchronous programming approach. First, asynchronous code is 
     26frequently (if not always) concerned with some data (in Python, an 
     27object) which is not yet available but which probably will be 
     28soon. Asynchronous code needs a way to define what will be done to the 
     29object once it does exist. It also needs a way to define how to handle 
     30errors in the creation or acquisition of that object. These two needs 
     31are satisfied by the <i>callbacks</i> and <i>errbacks</i> of 
     32a <code>Deferred</code>. Callbacks are added to 
     33a <code>Deferred</code> with <code class="API" 
     34base="twisted.internet.defer">Deferred.addCallback</code>; errbacks 
    3335are added with <code class="API" 
    34 base="twisted.internet.defer">Deferred.addErrback</code>. When the object 
    35 finally does exist, it is passed to <code class="API" 
    36 base="twisted.internet.defer">Deferred.callback</code> which passes it on to the 
    37 callback added with <code>addCallback</code>. Similarly, if an error occurs, 
    38 <code class="API" base="twisted.internet.defer">Deferred.errback</code> is 
    39 called and the error is passed along to the errback added with 
    40 <code>addErrback</code>. Second, the events that make asynchronous code actually 
    41 work often take many different, incompatible forms. <code>Deferred</code> acts 
    42 as the uniform interface which lets different parts of an asynchronous 
    43 application interact and isolates them from implementation details they 
    44 shouldn't be concerned with.</p> 
     36base="twisted.internet.defer">Deferred.addErrback</code>. When the 
     37object finally does exist, it is passed to <code class="API" 
     38base="twisted.internet.defer">Deferred.callback</code> which passes it 
     39on to the callback added with <code>addCallback</code>. Similarly, if 
     40an error occurs, <code class="API" 
     41base="twisted.internet.defer">Deferred.errback</code> is called and 
     42the error is passed along to the errback added 
     43with <code>addErrback</code>. Second, the events that make 
     44asynchronous code actually work often take many different, 
     45incompatible forms. <code>Deferred</code> acts as the uniform 
     46interface which lets different parts of an asynchronous application 
     47interact and isolates them from implementation details they shouldn't 
     48be concerned with.</p> 
    4549 
    4650<p>That's almost all there is to <code>Deferred</code>. To solidify your new 
    4751understanding, now consider this rewritten version 
     
    6468from twisted.internet import reactor 
    6569</pre> 
    6670 
    67 <p>With the imports done, here's the first part of the 
    68 <code>DelayedResource</code> implementation. Again, this part of the code is 
    69 identical to the previous version:</p> 
     71<p>With the imports done, here's the first part of 
     72the <code>DelayedResource</code> implementation. Again, this part of 
     73the code is identical to the previous version:</p> 
    7074 
    7175<pre class="python"> 
    7276class DelayedResource(Resource): 
     
    7579        request.finish() 
    7680</pre> 
    7781 
    78 <p>Next we need to define the render method. Here's where things change a 
    79 bit. Instead of using <code class="API" 
    80 base="twisted.internet.interfaces.IReactorTime">callLater</code>, We're going to 
    81 use <code class="API" base="twisted.internet.task">deferLater</code> this 
    82 time. <code>deferLater</code> accepts a reactor, delay (in seconds, as with 
    83 <code>callLater</code>), and a function to call after the delay to produce that 
    84 elusive object discussed in the description of <code>Deferred</code>s. We're 
    85 also going to use <code>_delayedRender</code> as the callback to add to the 
    86 <code>Deferred</code> returned by <code>deferLater</code>. Since it expects the 
    87 request object as an argument, we're going to set up the <code>deferLater</code> 
    88 call to return a <code>Deferred</code> which has the request object as its 
    89 result.</p> 
     82<p>Next we need to define the render method. Here's where things 
     83change a bit. Instead of using <code class="API" 
     84base="twisted.internet.interfaces.IReactorTime">callLater</code>, 
     85We're going to use <code class="API" 
     86base="twisted.internet.task">deferLater</code> this 
     87time. <code>deferLater</code> accepts a reactor, delay (in seconds, as 
     88with <code>callLater</code>), and a function to call after the delay 
     89to produce that elusive object discussed in the description 
     90of <code>Deferred</code>s. We're also going to 
     91use <code>_delayedRender</code> as the callback to add to 
     92the <code>Deferred</code> returned by <code>deferLater</code>. Since 
     93it expects the request object as an argument, we're going to set up 
     94the <code>deferLater</code> call to return a <code>Deferred</code> 
     95which has the request object as its result.</p> 
    9096 
    9197<pre class="python"> 
    9298def render_GET(self, request): 
    9399    d = deferLater(reactor, 5, lambda: request) 
    94100</pre> 
    95101 
    96 <p>The <code>Deferred</code> referenced by <code>d</code> now needs to have the 
    97 <code>_delayedRender</code> callback added to it. Once this is done, 
    98 <code>_delayedRender</code> will be called with the result of <code>d</code> 
    99 (which will be <code>request</code>, of course — the result of <code>(lambda: 
    100 request)()</code>).</p> 
     102<p>The <code>Deferred</code> referenced by <code>d</code> now needs to 
     103have the <code>_delayedRender</code> callback added to it. Once this 
     104is done, <code>_delayedRender</code> will be called with the result 
     105of <code>d</code> (which will be <code>request</code>, of course — the 
     106result of <code>(lambda: request)()</code>).</p> 
    101107 
    102108<pre class="python"> 
    103109d.addCallback(self._delayedRender) 
     
    111117return NOT_DONE_YET 
    112118</pre> 
    113119 
    114 <p>And with that, <code>DelayedResource</code> is now implemented based on a 
    115 <code>Deferred</code>. The example still isn't very realistic, but remember that 
    116 since <code>Deferred</code>s offer a uniform interface to many different 
    117 asynchronous event sources, this code now resembles a real application even more 
    118 closely; you could easily replace <code>deferLater</code> with another 
    119 <code>Deferred</code>-returning API and suddenly you might have a resource that 
    120 does something useful.</p> 
     120<p>And with that, <code>DelayedResource</code> is now implemented 
     121based on a <code>Deferred</code>. The example still isn't very 
     122realistic, but remember that since <code>Deferred</code>s offer a 
     123uniform interface to many different asynchronous event sources, this 
     124code now resembles a real application even more closely; you could 
     125easily replace <code>deferLater</code> with 
     126another <code>Deferred</code>-returning API and suddenly you might 
     127have a resource that does something useful.</p> 
    121128 
    122129<p>Finally, here's the complete, uninterrupted example source, as an rpy script:</p> 
    123130 
  • doc/web/howto/web-in-60/asynchronous.xhtml

    diff --git a/doc/web/howto/web-in-60/asynchronous.xhtml b/doc/web/howto/web-in-60/asynchronous.xhtml
    index 1b9b39f..d35e043 100644
    a b  
    2222either way; the same render methods are used. There are three basic differences, 
    2323though.</p> 
    2424 
    25 <p>First, instead of returning the string which will be used as the body of the 
    26 response, the resource uses <code class="API" 
    27 base="twisted.web.http">Request.write</code>. This method can be called 
    28 repeatedly. Each call appends another string to the response body. Second, when 
    29 the entire response body has been passed to <code>Request.write</code>, the 
    30 application must call <code class="API" 
    31 base="twisted.web.http">Request.finish</code>. As you might expect from the 
    32 name, this ends the response. Finally, in order to make Twisted Web not end the 
    33 response as soon as the render method returns, the render method must return 
    34 <code>NOT_DONE_YET</code>. Consider this example:</p> 
     25<p>First, instead of returning the string which will be used as the 
     26body of the response, the resource uses <code class="API" 
     27base="twisted.web.http">Request.write</code>. This method can be 
     28called repeatedly. Each call appends another string to the response 
     29body. Second, when the entire response body has been passed 
     30to <code>Request.write</code>, the application must 
     31call <code class="API" 
     32base="twisted.web.http">Request.finish</code>. As you might expect 
     33from the name, this ends the response. Finally, in order to make 
     34Twisted Web not end the response as soon as the render method returns, 
     35the render method must return <code>NOT_DONE_YET</code>. Consider this 
     36example:</p> 
    3537 
    3638<pre class="python"> 
    3739from twisted.web.resource import Resource 
     
    4850        return NOT_DONE_YET 
    4951</pre> 
    5052 
    51 <p>If you're not familiar with reactor.<code class="API" 
    52 base="twisted.internet.interfaces.IReactorTime">callLater</code>, all you really 
    53 need to know about it to understand this example is that the above usage of it 
    54 arranges to have <code>self._delayedRender(request)</code> run about 5 seconds 
    55 after <code>callLater</code> is invoked from this render method and that it 
    56 returns immediately.</p> 
    57  
    58 <p>All three of the elements mentioned earlier can be seen in this example. The 
    59 resource uses <code>Request.write</code> to set the response body. It uses 
    60 <code>Request.finish</code> after the entire body has been specified (all with 
    61 just one call to write in this case). Lastly, it returns 
    62 <code>NOT_DONE_YET</code> from its render method. So there you have it, 
    63 asynchronous rendering with Twisted Web.</p> 
     53<p>If you're not familiar with the reactor <code class="API" 
     54base="twisted.internet.interfaces.IReactorTime">callLater</code> 
     55method, all you really need to know about it to understand this 
     56example is that the above usage of it arranges to 
     57have <code>self._delayedRender(request)</code> run about 5 seconds 
     58after <code>callLater</code> is invoked from this render method and 
     59that it returns immediately.</p> 
     60 
     61<p>All three of the elements mentioned earlier can be seen in this 
     62example. The resource uses <code>Request.write</code> to set the 
     63response body. It uses <code>Request.finish</code> after the entire 
     64body has been specified (all with just one call to write in this 
     65case). Lastly, it returns <code>NOT_DONE_YET</code> from its render 
     66method. So there you have it, asynchronous rendering with Twisted 
     67Web.</p> 
    6468 
    6569<p>Here's a complete rpy script based on this resource class (see the <a 
    6670href="rpy-scripts.xhtml">previous example</a> if you need a reminder about rpy 
     
    8387resource = DelayedResource() 
    8488</pre> 
    8589 
    86 <p>Drop this source into a <code>.rpy</code> file and fire up a server using 
    87 <code>twistd -n web --path /directory/containing/script/.</code> You'll see that 
    88 loading the page takes 5 seconds. If you try to load a second before the first 
    89 completes, it will also take 5 seconds from the time you request it (but it 
    90 won't be delayed by any other outstanding requests).</p> 
     90<p>Drop this source into a <code>.rpy</code> file and fire up a server 
     91using <code>twistd -n web --path /directory/containing/script/.</code> 
     92You'll see that loading the page takes 5 seconds. If you try to load a 
     93second before the first completes, it will also take 5 seconds from 
     94the time you request it (but it won't be delayed by any other 
     95outstanding requests).</p> 
    9196 
    9297<p>Something else to consider when generating responses asynchronously is that 
    9398the client may not wait around to get the response to its 
  • doc/web/howto/web-in-60/custom-codes.xhtml

    diff --git a/doc/web/howto/web-in-60/custom-codes.xhtml b/doc/web/howto/web-in-60/custom-codes.xhtml
    index 8f5ddfd..ab61a42 100644
    a b  
    4747        return "&lt;html&gt;&lt;body&gt;Please swipe your credit card.&lt;/body&gt;&lt;/html&gt;" 
    4848</pre> 
    4949 
    50 <p>Just like the other resources I've demonstrated, this one returns a string 
    51 from its <code>render_GET</code> method to define the body of the response. All 
    52 that's different is the call to 
    53 <code>setResponseCode</code> to override the default response code, 
     50<p>Just like the other resources I've demonstrated, this one returns a 
     51string from its <code>render_GET</code> method to define the body of 
     52the response. All that's different is the call 
     53to <code>setResponseCode</code> to override the default response code, 
    5454200, with a different one.</p> 
    5555 
    5656<p>Finally, the code to set up the site and reactor. We'll put an instance of 
  • doc/web/howto/web-in-60/dynamic-content.xhtml

    diff --git a/doc/web/howto/web-in-60/dynamic-content.xhtml b/doc/web/howto/web-in-60/dynamic-content.xhtml
    index 888ddc2..e64d238 100644
    a b  
    2626protocol implementation. The reactor is the main loop that drives any Twisted 
    2727application; we'll use it to actually create the listening port in a moment.</p> 
    2828 
    29 <p>Next, we'll import one more thing from Twisted Web: <code class="API" 
    30 base="twisted.web.resource">Resource</code>. An instance of 
    31 <code>Resource</code> (or a subclass) represents a page (technically, the entity 
    32 addressed by a URI).</p> 
     29<p>Next, we'll import one more thing from Twisted 
     30Web: <code class="API" base="twisted.web.resource">Resource</code>. An 
     31instance of <code>Resource</code> (or a subclass) represents a page 
     32(technically, the entity addressed by a URI).</p> 
    3333 
    3434<pre class="python"> 
    3535from twisted.web.resource import Resource 
     
    4242import time 
    4343</pre> 
    4444 
    45 <p>With imports taken care of, the next step is to define a 
    46 <code>Resource</code> subclass which has the dynamic rendering behavior we 
    47 want. Here's a resource which generates a page giving the time:</p> 
     45<p>With imports taken care of, the next step is to define 
     46a <code>Resource</code> subclass which has the dynamic rendering 
     47behavior we want. Here's a resource which generates a page giving the 
     48time:</p> 
    4849 
    4950<pre class="python"> 
    5051class ClockPage(Resource): 
     
    5354        return "&lt;html&gt;&lt;body&gt;%s&lt;/body&gt;&lt;/html&gt;" % (time.ctime(),) 
    5455</pre> 
    5556 
    56 <p>Setting <code>isLeaf</code> to <code>True</code> indicates that 
    57 <code>ClockPage</code> resources will never have any children.</p> 
     57<p>Setting <code>isLeaf</code> to <code>True</code> indicates 
     58that <code>ClockPage</code> resources will never have any 
     59children.</p> 
    5860 
    5961<p>The <code>render_GET</code> method here will be called whenever the URI we 
    6062hook this resource up to is requested with the <code>GET</code> method. The byte 
     
    6769factory = Site(resource) 
    6870</pre> 
    6971 
    70 <p>Just as with the previous static content example, this configuration puts our 
    71 resource at the very top of the URI hierarchy, ie at <code>/</code>. With that 
    72 <code>Site</code> instance, we can tell the reactor to <a 
    73 href="../../../core/howto/servers.xhtml">create a TCP server</a> and start 
    74 servicing requests:</p> 
     72<p>Just as with the previous static content example, this 
     73configuration puts our resource at the very top of the URI hierarchy, 
     74ie at <code>/</code>. With that <code>Site</code> instance, we can 
     75tell the reactor to <a href="../../../core/howto/servers.xhtml">create 
     76a TCP server</a> and start servicing requests:</p> 
    7577 
    7678<pre class="python"> 
    7779reactor.listenTCP(8880, factory) 
  • doc/web/howto/web-in-60/dynamic-dispatch.xhtml

    diff --git a/doc/web/howto/web-in-60/dynamic-dispatch.xhtml b/doc/web/howto/web-in-60/dynamic-dispatch.xhtml
    index 8e4ab16..3faa3ac 100644
    a b  
    3030from twisted.internet import reactor 
    3131</pre> 
    3232 
    33 <p>With that out of the way, here's the interesting part of this example. We're 
    34 going to define a resource which renders a whole-year calendar. The year it will 
    35 render the calendar for will be the year in the request URL. So, for example, 
    36 <code>/2009</code> will render a calendar for 2009. First, here's a resource 
    37 that renders a calendar for the year passed to its initializer:</p> 
     33<p>With that out of the way, here's the interesting part of this 
     34example. We're going to define a resource which renders a whole-year 
     35calendar. The year it will render the calendar for will be the year in 
     36the request URL. So, for example, <code>/2009</code> will render a 
     37calendar for 2009. First, here's a resource that renders a calendar 
     38for the year passed to its initializer:</p> 
    3839 
    3940<pre class="python"> 
    4041from calendar import calendar 
  • doc/web/howto/web-in-60/error-handling.xhtml

    diff --git a/doc/web/howto/web-in-60/error-handling.xhtml b/doc/web/howto/web-in-60/error-handling.xhtml
    index 141396c..71d0ddc 100644
    a b  
    5050            return YearPage(year) 
    5151</pre> 
    5252 
    53 <p>Aside from including the definition of <code>YearPage</code> from the 
    54 previous example, the only other thing left to do is the normal 
    55 <code>Site</code> and <code>reactor</code> setup. Here's the complete code for 
    56 this example:</p> 
     53<p>Aside from including the definition of <code>YearPage</code> from 
     54the previous example, the only other thing left to do is the 
     55normal <code>Site</code> and <code>reactor</code> setup. Here's the 
     56complete code for this example:</p> 
    5757 
    5858<pre class="python"> 
    5959from twisted.web.server import Site 
  • doc/web/howto/web-in-60/handling-posts.xhtml

    diff --git a/doc/web/howto/web-in-60/handling-posts.xhtml b/doc/web/howto/web-in-60/handling-posts.xhtml
    index 70ac268..7d8efd8 100644
    a b  
    5656    return '&lt;html&gt;&lt;body&gt;You submitted: %s&lt;/body&gt;&lt;/html&gt;' % (cgi.escape(request.args["the-field"][0]),) 
    5757</pre> 
    5858 
    59 <p>The main thing to note here is the use of <code>request.args</code>. This is 
    60 a dictionary-like object that provides access to the contents of the form. The 
    61 keys in this dictionary are the names of inputs in the form. Each value is a 
    62 list containing strings (since there can be multiple inputs with the same name), 
    63 which is why we had to extract the first element to pass to 
    64 <code>cgi.escape</code>. <code>request.args</code> will be populated from form 
    65 contents whenever a <code>POST</code> request is made with a content type of 
    66 <code>application/x-www-form-urlencoded</code> or 
    67 <code>multipart/form-data</code> (it's also populated by query arguments for any 
    68 type of request).</p> 
     59<p>The main thing to note here is the use 
     60of <code>request.args</code>. This is a dictionary-like object that 
     61provides access to the contents of the form. The keys in this 
     62dictionary are the names of inputs in the form. Each value is a list 
     63containing strings (since there can be multiple inputs with the same 
     64name), which is why we had to extract the first element to pass 
     65to <code>cgi.escape</code>. <code>request.args</code> will be 
     66populated from form contents whenever a <code>POST</code> request is 
     67made with a content type 
     68of <code>application/x-www-form-urlencoded</code> 
     69or <code>multipart/form-data</code> (it's also populated by query 
     70arguments for any type of request).</p> 
    6971 
    7072<p>Finally, the example just needs the usual site creation and port setup:</p> 
    7173 
  • doc/web/howto/web-in-60/http-auth.xhtml

    diff --git a/doc/web/howto/web-in-60/http-auth.xhtml b/doc/web/howto/web-in-60/http-auth.xhtml
    index 36f3921..5302afe 100644
    a b  
    1616resources.</p> 
    1717 
    1818<p><code class="API" base="twisted.web">guard</code>, the Twisted Web 
    19 module which provides most of the APIs that will be used in this example, helps 
    20 you to 
     19module which provides most of the APIs that will be used in this 
     20example, helps you to 
    2121add <a href="http://en.wikipedia.org/wiki/Authentication">authentication</a> 
    22 and <a href="http://en.wikipedia.org/wiki/Authorization">authorization</a> to a 
    23 resource hierarchy. It does this by providing a resource which implements 
    24 <code class="API" base="twisted.web.resource.Resource">getChild</code> to return 
    25 a <a href="dynamic-dispatch.xhtml">dynamically selected resource</a>. The 
    26 selection is based on the authentication headers in the request. If those 
    27 headers indicate that the request is made on behalf of Alice, then Alice's 
    28 resource will be returned. If they indicate that it was made on behalf of Bob, 
    29 his will be returned. If the headers contain invalid credentials, an error 
    30 resource is returned. Whatever happens, once this resource is returned, URL 
     22and <a href="http://en.wikipedia.org/wiki/Authorization">authorization</a> 
     23to a resource hierarchy. It does this by providing a resource which 
     24implements <code class="API" 
     25base="twisted.web.resource.Resource">getChild</code> to return 
     26a <a href="dynamic-dispatch.xhtml">dynamically selected 
     27resource</a>. The selection is based on the authentication headers in 
     28the request. If those headers indicate that the request is made on 
     29behalf of Alice, then Alice's resource will be returned. If they 
     30indicate that it was made on behalf of Bob, his will be returned. If 
     31the headers contain invalid credentials, an error resource is 
     32returned. Whatever happens, once this resource is returned, URL 
    3133traversal continues as normal from that resource.</p> 
    3234 
    3335<p>The resource that implements this is <code class="API" 
     
    4446really need to know is how to implement an <code class="API" 
    4547base="twisted.cred.portal">IRealm</code>.</p> 
    4648 
    47 <p>You need to implement a realm because the realm is the object that actually 
    48 decides which resources are used for which users. This can be as complex or as 
    49 simple as it suitable for your application. For this example we'll keep it very 
    50 simple: each user will have a resource which is a static file listing of the 
    51 <code>public_html</code> directory in their UNIX home directory. First, we need 
    52 to import <code>implements</code> from <code>zope.interface</code> and 
    53 <code>IRealm</code> from <code>twisted.cred.portal</code>. Together these will 
    54 let me mark this class as a realm (this is mostly - but not entirely - a 
     49<p>You need to implement a realm because the realm is the object that 
     50actually decides which resources are used for which users. This can be 
     51as complex or as simple as it suitable for your application. For this 
     52example we'll keep it very simple: each user will have a resource 
     53which is a static file listing of the <code>public_html</code> 
     54directory in their UNIX home directory. First, we need to 
     55import <code>implements</code> from <code>zope.interface</code> 
     56and <code>IRealm</code> 
     57from <code>twisted.cred.portal</code>. Together these will let me mark 
     58this class as a realm (this is mostly - but not entirely - a 
    5559documentation thing). We'll also need <code class="API" 
    56 base="twisted.web.static">File</code> for the actual implementation later.</p> 
     60base="twisted.web.static">File</code> for the actual implementation 
     61later.</p> 
    5762 
    5863<pre class="python"> 
    5964from zope.interface import implements 
     
    105110    exists. However, that's an example for another day...</li> 
    106111</ul> 
    107112 
    108 <p>We're almost ready to set up the resource for this example. To create an 
    109 <code>HTTPAuthSessionWrapper</code>, though, we need two things. First, a 
    110 portal, which requires the realm above, plus at least one credentials 
    111 checker:</p> 
     113<p>We're almost ready to set up the resource for this example. To 
     114create an <code>HTTPAuthSessionWrapper</code>, though, we need two 
     115things. First, a portal, which requires the realm above, plus at least 
     116one credentials checker:</p> 
    112117 
    113118<pre class="python"> 
    114119from twisted.cred.portal import Portal 
     
    124129request.</p> 
    125130 
    126131<p>Next we need either <code class="API" 
    127 base="twisted.web.guard">BasicCredentialFactory</code> or 
    128 <code class="API" base="twisted.web.guard">DigestCredentialFactory</code>. The 
    129 former knows how to challenge HTTP clients to do basic authentication; the 
     132base="twisted.web.guard">BasicCredentialFactory</code> 
     133or <code class="API" 
     134base="twisted.web.guard">DigestCredentialFactory</code>. The former 
     135knows how to challenge HTTP clients to do basic authentication; the 
    130136latter, digest authentication. We'll use digest here:</p> 
    131137 
    132138<pre class="python"> 
     
    135141credentialFactory = DigestCredentialFactory("md5", "example.org") 
    136142</pre> 
    137143 
    138 <p>The two parameters to this constructor are the hash algorithm and the HTTP 
    139 authentication realm which will be used. The only other valid hash algorithm is 
    140 "sha" (but be careful, MD5 is more widely supported than SHA). The HTTP 
    141 authentication realm is mostly just a string that is presented to the user to 
    142 let them know why they're authenticating (you can read more about this in the 
    143 <a href="http://tools.ietf.org/html/rfc2617">RFC</a>).</p> 
     144<p>The two parameters to this constructor are the hash algorithm and 
     145the HTTP authentication realm which will be used. The only other valid 
     146hash algorithm is "sha" (but be careful, MD5 is more widely supported 
     147than SHA). The HTTP authentication realm is mostly just a string that 
     148is presented to the user to let them know why they're authenticating 
     149(you can read more about this in 
     150the <a href="http://tools.ietf.org/html/rfc2617">RFC</a>).</p> 
    144151 
    145152<p>With those things created, we can finally 
    146153instantiate <code>HTTPAuthSessionWrapper</code>:</p> 
     
    152159</pre> 
    153160 
    154161<p>There's just one last thing that needs to be done 
    155 here. When <a href="rpy-scripts.xhtml">rpy scripts</a> were introduced, it was 
    156 mentioned that they are evaluated in an unusual context. This is the first 
    157 example that actually needs to take this into account. It so happens that 
    158 <code>DigestCredentialFactory</code> instances are stateful. Authentication will 
    159 only succeed if the same instance is used to both generate challenges and 
    160 examine the responses to those challenges. However, the normal mode of operation 
    161 for an rpy script is for it to be re-executed for every request. This leads to a 
    162 new 
    163 <code>DigestCredentialFactory</code> being created for every request, preventing 
     162here. When <a href="rpy-scripts.xhtml">rpy scripts</a> were 
     163introduced, it was mentioned that they are evaluated in an unusual 
     164context. This is the first example that actually needs to take this 
     165into account. It so happens that <code>DigestCredentialFactory</code> 
     166instances are stateful. Authentication will only succeed if the same 
     167instance is used to both generate challenges and examine the responses 
     168to those challenges. However, the normal mode of operation for an rpy 
     169script is for it to be re-executed for every request. This leads to a 
     170new <code>DigestCredentialFactory</code> being created for every request, preventing 
    164171any authentication attempt from ever succeeding.</p> 
    165172 
    166173<p>There are two ways to deal with this. First, and the better of the two ways, 
  • doc/web/howto/web-in-60/index.xhtml

    diff --git a/doc/web/howto/web-in-60/index.xhtml b/doc/web/howto/web-in-60/index.xhtml
    index 93dc1ae..1874cf8 100644
    a b  
    99 
    1010<h1>Twisted.Web In 60 Seconds</h1> 
    1111 
    12 <p>This set of examples contains short, complete applications of 
    13 <code class="API">twisted.web</code>. For subjects not covered here, see 
    14 the <a href="../using-twistedweb.xhtml">Twisted Web tutorial</a> and the API 
    15 documentation.</p> 
     12<p>This set of examples contains short, complete applications 
     13of <code class="API">twisted.web</code>. For subjects not covered 
     14here, see the <a href="../using-twistedweb.xhtml">Twisted Web 
     15tutorial</a> and the API documentation.</p> 
    1616 
    1717<ol> 
    1818<li><a href="static-content.xhtml">Serving static content from a directory</a></li> 
  • doc/web/howto/web-in-60/interrupted.xhtml

    diff --git a/doc/web/howto/web-in-60/interrupted.xhtml b/doc/web/howto/web-in-60/interrupted.xhtml
    index 0babe80..3d36790 100644
    a b  
    4545         request.finish() 
    4646</pre> 
    4747 
    48 <p>Before defining the render method, we're going to define an errback (an 
    49 errback being a callback that gets called when there's an error), though. This 
    50 will be the errback attached to the <code>Deferred</code> returned by 
    51 <code>Request.notifyFinish</code>. It will cancel the delayed call to 
    52 <code>_delayedRender</code>.</p> 
     48<p>Before defining the render method, we're going to define an errback 
     49(an errback being a callback that gets called when there's an error), 
     50though. This will be the errback attached to the <code>Deferred</code> 
     51returned by <code>Request.notifyFinish</code>. It will cancel the 
     52delayed call to <code>_delayedRender</code>.</p> 
    5353 
    5454<pre class="python"> 
    5555def _responseFailed(self, err, call): 
    5656    call.cancel() 
    5757</pre> 
    5858 
    59 <p>Finally, the render method will set up the delayed call just as it did 
    60 before, and return <code>NOT_DONE_YET</code> likewise. However, it will also use 
    61 <code>Request.notifyFinish</code> to make sure <code>_responseFailed</code> is 
    62 called if appropriate.</p> 
     59<p>Finally, the render method will set up the delayed call just as it 
     60did before, and return <code>NOT_DONE_YET</code> likewise. However, it 
     61will also use <code>Request.notifyFinish</code> to make 
     62sure <code>_responseFailed</code> is called if appropriate.</p> 
    6363 
    6464<pre class="python"> 
    6565def render_GET(self, request): 
     
    6868    return NOT_DONE_YET 
    6969</pre> 
    7070 
    71 <p>Notice that since <code>_responseFailed</code> needs a reference to the 
    72 delayed call object in order to cancel it, we passed that object to 
    73 <code>addErrback</code>. Any additional arguments passed to 
    74 <code>addErrback</code> (or <code>addCallback</code>) will be passed along to 
    75 the errback after the <code class="API" 
    76 base="twisted.python.failure">Failure</code> instance which is always passed as 
    77 the first argument. Passing <code>call</code> here means it will be passed to 
    78 <code>_responseFailed</code>, where it is expected and required.</p> 
     71<p>Notice that since <code>_responseFailed</code> needs a reference to 
     72the delayed call object in order to cancel it, we passed that object 
     73to <code>addErrback</code>. Any additional arguments passed 
     74to <code>addErrback</code> (or <code>addCallback</code>) will be 
     75passed along to the errback after the <code class="API" 
     76base="twisted.python.failure">Failure</code> instance which is always 
     77passed as the first argument. Passing <code>call</code> here means it 
     78will be passed to <code>_responseFailed</code>, where it is expected 
     79and required.</p> 
    7980 
    8081<p>That covers almost all the code for this example. Here's the entire example 
    8182without interruptions, as an <a href="rpy-scripts.xhtml">rpy script</a>:</p> 
  • doc/web/howto/web-in-60/logging-errors.xhtml

    diff --git a/doc/web/howto/web-in-60/logging-errors.xhtml b/doc/web/howto/web-in-60/logging-errors.xhtml
    index cd36927..5897080 100644
    a b  
    1515pointless work. However, it did this silently for any error. In this example, 
    1616we'll modify the previous example so that it logs each failed response.</p> 
    1717 
    18 <p>This example will use the Twisted API for logging errors. As was mentioned in 
    19 the <a href="asynchronous-deferred.xhtml">first example covering Deferreds</a>, 
    20 errbacks are passed an error. In the previous example, the 
    21 <code>_responseFailed</code> errback accepted this error as a parameter but 
    22 ignored it. The only way this example will differ is that this 
    23 <code>_responseFailed</code> will use that error parameter to log a message.</p> 
     18<p>This example will use the Twisted API for logging errors. As was 
     19mentioned in the <a href="asynchronous-deferred.xhtml">first example 
     20covering Deferreds</a>, errbacks are passed an error. In the previous 
     21example, the <code>_responseFailed</code> errback accepted this error 
     22as a parameter but ignored it. The only way this example will differ 
     23is that this <code>_responseFailed</code> will use that error 
     24parameter to log a message.</p> 
    2425 
    2526<p>This example will require all of the imports required by the previous example 
    2627plus one new import:</p> 
     
    2930from twisted.python.log import err 
    3031</pre> 
    3132 
    32 <p>The only other part of the previous example which changes is the 
    33 <code>_responseFailed</code> callback, which will now log the error passed to 
    34 it:</p> 
     33<p>The only other part of the previous example which changes is 
     34the <code>_responseFailed</code> callback, which will now log the 
     35error passed to it:</p> 
    3536 
    3637<pre class="python"> 
    3738def _responseFailed(self, failure, call): 
  • doc/web/howto/web-in-60/rpy-scripts.xhtml

    diff --git a/doc/web/howto/web-in-60/rpy-scripts.xhtml b/doc/web/howto/web-in-60/rpy-scripts.xhtml
    index 4c1c2b6..cb8114c 100644
    a b  
    2121means fewer lines of code that aren't dedicated to the task you're trying to 
    2222accomplish.</p> 
    2323 
    24 <p>There are some disadvantages, though. An rpy script must have the extension 
    25 <code>.rpy</code>. This means you can't import it using the usual Python import 
    26 statement. This means it's hard to re-use code in an rpy script. This also means 
    27 you can't easily unit test it. The code in an rpy script is evaluated in an 
    28 unusual context. So, while rpy scripts may be useful for testing out ideas, 
    29 they're not recommend for much more than that.</p> 
     24<p>There are some disadvantages, though. An rpy script must have the 
     25extension <code>.rpy</code>. This means you can't import it using the 
     26usual Python import statement. This means it's hard to re-use code in 
     27an rpy script. This also means you can't easily unit test it. The code 
     28in an rpy script is evaluated in an unusual context. So, while rpy 
     29scripts may be useful for testing out ideas, they're not recommend for 
     30much more than that.</p> 
    3031 
    3132<p>Okay, with that warning out of the way, let's dive in. First, as mentioned, 
    3233rpy scripts are Python source files with the <code>.rpy</code> extension. So, 
     
    4748</pre> 
    4849 
    4950<p>You may recognize this as the resource from 
    50 the <a href="dynamic-content.xhtml">first dynamic rendering example</a>. What's 
    51 different is what you don't see: we didn't import <code>reactor</code> or 
    52 <code>Site</code>. There are no calls to <code>listenTCP</code> or 
    53 <code>run</code>. Instead, and this is the core idea for rpy scripts, we just 
    54 bound the name <code>resource</code> to the resource we want the script to 
    55 serve. Every rpy script must bind this name, and this name is the only thing 
    56 Twisted Web will pay attention to in an rpy script.</p> 
     51the <a href="dynamic-content.xhtml">first dynamic rendering 
     52example</a>. What's different is what you don't see: we didn't 
     53import <code>reactor</code> or <code>Site</code>. There are no calls 
     54to <code>listenTCP</code> or <code>run</code>. Instead, and this is 
     55the core idea for rpy scripts, we just bound the 
     56name <code>resource</code> to the resource we want the script to 
     57serve. Every rpy script must bind this name, and this name is the only 
     58thing Twisted Web will pay attention to in an rpy script.</p> 
    5759 
    5860<p>All that's left is to drop this rpy script into a Twisted Web server. There 
    5961are a few ways to do this. The simplest way is with <code>twistd</code>:</p> 
  • doc/web/howto/web-in-60/session-basics.xhtml

    diff --git a/doc/web/howto/web-in-60/session-basics.xhtml b/doc/web/howto/web-in-60/session-basics.xhtml
    index a6b8e84..8b72a58 100644
    a b  
    1616Twisted Web session API: how to get the session object for the current request 
    1717and how to prematurely expire a session.</p> 
    1818 
    19 <p>Before diving into the APIs, let's look at the big picture of sessions in 
    20 Twisted Web. Sessions are represented by instances of <code class="API" 
     19<p>Before diving into the APIs, let's look at the big picture of 
     20sessions in Twisted Web. Sessions are represented by instances 
     21of <code class="API" 
    2122base="twisted.web.server">Session</code>. The <code class="API" 
    22 base="twisted.web.server">Site</code> creates a new instance of 
    23 <code>Session</code> the first time an application asks for it for a particular 
    24 session. <code>Session</code> instances are kept on the <code>Site</code> 
    25 instance until they expire (due to inactivity or because they are explicitly 
    26 expired). Each time after the first that a particular session's 
    27 <code>Session</code> object is requested, it is retrieved from 
    28 the <code>Site</code>.</p> 
     23base="twisted.web.server">Site</code> creates a new instance 
     24of <code>Session</code> the first time an application asks for it for 
     25a particular session. <code>Session</code> instances are kept on 
     26the <code>Site</code> instance until they expire (due to inactivity or 
     27because they are explicitly expired). Each time after the first that a 
     28particular session's <code>Session</code> object is requested, it is 
     29retrieved from the <code>Site</code>.</p> 
    2930 
    3031<p>With the conceptual underpinnings of the upcoming API in place, here comes 
    3132the example. This will be a very simple <a href="rpy-scripts.xhtml">rpy 
     
    6364        return 'Your session has been expired.' 
    6465</pre> 
    6566 
    66 <p>Finally, to make the example an rpy script, we'll make an instance of 
    67 <code>ShowSession</code> and give it an instance of <code>ExpireSession</code> 
    68 as a child using <code class="API" 
     67<p>Finally, to make the example an rpy script, we'll make an instance 
     68of <code>ShowSession</code> and give it an instance 
     69of <code>ExpireSession</code> as a child using <code class="API" 
    6970base="twisted.web.resource">Resource.putChild</code>:</p> 
    7071 
    7172<pre class="python"> 
  • doc/web/howto/web-in-60/session-endings.xhtml

    diff --git a/doc/web/howto/web-in-60/session-endings.xhtml b/doc/web/howto/web-in-60/session-endings.xhtml
    index 33852c8..44b4d96 100644
    a b  
    3131    sessionTimeout = 60 
    3232</pre> 
    3333 
    34 <p>To have Twisted Web actually make use of this session class, rather than the 
    35 default, it is also necessary to override the <code>sessionFactory</code> attribute of 
    36 <code class="API" base="twisted.web.server">Site</code>. We could do this with 
    37 another subclass, but we could also do it to just one instance 
     34<p>To have Twisted Web actually make use of this session class, rather 
     35than the default, it is also necessary to override 
     36the <code>sessionFactory</code> attribute of <code class="API" 
     37base="twisted.web.server">Site</code>. We could do this with another 
     38subclass, but we could also do it to just one instance 
    3839of <code>Site</code>:</p> 
    3940 
    4041<pre class="python"> 
     
    4748<p>Sessions given out for requests served by this <code>Site</code> will 
    4849use <code>ShortSession</code> and only last one minute without activity.</p> 
    4950 
    50 <p>You can have arbitrary functions run when sessions expire, too. This can be 
    51 useful for cleaning up external resources associated with the session, tracking 
    52 usage statistics, and more. This functionality is provided via 
    53 <code class="API" base="twisted.web.server">Session.notifyOnExpire</code>. It 
    54 accepts a single argument: a function to call when the session expires. Here's a 
     51<p>You can have arbitrary functions run when sessions expire, 
     52too. This can be useful for cleaning up external resources associated 
     53with the session, tracking usage statistics, and more. This 
     54functionality is provided via <code class="API" 
     55base="twisted.web.server">Session.notifyOnExpire</code>. It accepts a 
     56single argument: a function to call when the session expires. Here's a 
    5557trivial example which prints a message whenever a session expires:</p> 
    5658 
    5759<pre class="python"> 
  • doc/web/howto/web-in-60/session-store.xhtml

    diff --git a/doc/web/howto/web-in-60/session-store.xhtml b/doc/web/howto/web-in-60/session-store.xhtml
    index a07c7ff..d961e4f 100644
    a b  
    4949 
    5050<p><i>What?</i>, I hear you say.</p> 
    5151 
    52 <p>What's shown in this example is the interface and adaption-based API which 
    53 <code>Session</code> exposes for persisting state. There are several critical 
    54 pieces interacting here:</p> 
     52<p>What's shown in this example is the interface and adaption-based 
     53API which <code>Session</code> exposes for persisting state. There are 
     54several critical pieces interacting here:</p> 
    5555 
    5656<ul> 
    5757  <li><code>ICounter</code> is an interface which serves several purposes. Like 
     
    6969    relationship between its three arguments so that adaption will do what we 
    7070    want in this case.</li> 
    7171  <li>Adaption is performed by the expression <code>ICounter(ses)</code>. This 
    72     is read as <i>adapt <code>ses</code> to <code>ICounter</code></i>. Because 
     72    is read as : adapt <code>ses</code> to <code>ICounter</code>. Because 
    7373    of the <code>registerAdapter</code> call, it is roughly equivalent 
    7474    to <code>Counter(ses)</code>. However (because of certain 
    7575    things <code>Session</code> does), it also saves the <code>Counter</code> 
     
    134134resource = CounterResource() 
    135135</pre> 
    136136 
    137 <p>One more thing to note is the <code>cache()</code> call at the top of this 
    138 example. As with the <a href="http-auth.xhtml">previous example</a> where this 
    139 came up, this rpy script is stateful. This time, it's the <code>ICounter</code> 
    140 definition and the 
    141 <code>registerAdapter</code> call that need to be executed only once. If we 
    142 didn't use <code>cache</code>, every request would define a new, different 
    143 interface named <code>ICounter</code>. Each of these would be a different key in 
    144 the session, so the counter would never get past one.</p> 
     137<p>One more thing to note is the <code>cache()</code> call at the top 
     138of this example. As with the <a href="http-auth.xhtml">previous 
     139example</a> where this came up, this rpy script is stateful. This 
     140time, it's the <code>ICounter</code> definition and 
     141the <code>registerAdapter</code> call that need to be executed only 
     142once. If we didn't use <code>cache</code>, every request would define 
     143a new, different interface named <code>ICounter</code>. Each of these 
     144would be a different key in the session, so the counter would never 
     145get past one.</p> 
    145146 
    146147</body> 
    147148</html> 
  • doc/web/howto/web-in-60/static-dispatch.xhtml

    diff --git a/doc/web/howto/web-in-60/static-dispatch.xhtml b/doc/web/howto/web-in-60/static-dispatch.xhtml
    index b1d8e3d..9cf3db5 100644
    a b  
    5151root = Resource() 
    5252</pre> 
    5353 
    54 <p>Here comes the interesting part of this example. We're now going to create 
    55 three more resources and attach them to the three URLs <code>/foo</code>, 
    56 <code>/bar</code>, and <code>/baz</code>:</p> 
     54<p>Here comes the interesting part of this example. We're now going to 
     55create three more resources and attach them to the three 
     56URLs <code>/foo</code>, <code>/bar</code>, and <code>/baz</code>:</p> 
    5757 
    5858<pre class="python"> 
    5959root.putChild("foo", File("/tmp")) 
     
    7070reactor.run() 
    7171</pre> 
    7272 
    73 <p>With this server running, <code>http://localhost:8880/foo</code> will serve a 
    74 listing of files from <code>/tmp</code>, <code>http://localhost:8880/bar</code> 
    75 will serve a listing of files from <code>/lost+found</code>, and 
    76 <code>http://localhost:8880/baz</code> will serve a listing of files from 
    77 <code>/opt</code>.</p> 
     73<p>With this server running, <code>http://localhost:8880/foo</code> 
     74will serve a listing of files 
     75from <code>/tmp</code>, <code>http://localhost:8880/bar</code> will 
     76serve a listing of files from <code>/lost+found</code>, 
     77and <code>http://localhost:8880/baz</code> will serve a listing of 
     78files from <code>/opt</code>.</p> 
    7879 
    7980<p>Here's the whole example uninterrupted:</p> 
    8081 
  • doc/web/howto/web-in-60/wsgi.xhtml

    diff --git a/doc/web/howto/web-in-60/wsgi.xhtml b/doc/web/howto/web-in-60/wsgi.xhtml
    index ddc0735..22ff8c1 100644
    a b  
    1010<body> 
    1111<h1>WSGI</h1> 
    1212 
    13 <p>The goal of this example is to show you how to use <code class="API" 
    14 base="twisted.web.wsgi">WSGIResource</code>, another existing 
    15 <code class="API" base="twisted.web.resource">Resource</code> subclass, to serve 
    16 <a href="http://www.python.org/dev/peps/pep-0333/">WSGI applications</a> in a 
    17 Twisted Web server.</p> 
     13<p>The goal of this example is to show you how to 
     14use <code class="API" base="twisted.web.wsgi">WSGIResource</code>, 
     15another existing <code class="API" 
     16base="twisted.web.resource">Resource</code> subclass, to 
     17serve <a href="http://www.python.org/dev/peps/pep-0333/">WSGI 
     18applications</a> in a Twisted Web server.</p> 
    1819 
    1920<p>Note thate <code>WSGIResource</code> is a multithreaded WSGI container. Like 
    2021any other WSGI container, you can't do anything asynchronous in your WSGI 
     
    5354resource = WSGIResource(reactor, reactor.getThreadPool(), application) 
    5455</pre> 
    5556 
    56 <p>Let's dwell on this line for a minute. The first parameter passed to 
    57 <code>WSGIResource</code> is the reactor. Despite the fact that the reactor is 
    58 global and any code that wants it can always just import it (as, in fact, this 
    59 rpy script simply does itself), passing it around as a parameter leaves the door 
    60 open for certain future possibilities - for example, having more than one 
    61 reactor. There are also testing implications. Consider how much easier it is to 
    62 unit test a function that accepts a reactor - perhaps a mock reactor specially 
    63 constructed to make your tests easy to write - rather than importing the real 
    64 global reactor. That's why <code>WSGIResource</code> requires you to pass the 
    65 reactor to it.</p> 
     57<p>Let's dwell on this line for a minute. The first parameter passed 
     58to <code>WSGIResource</code> is the reactor. Despite the fact that the 
     59reactor is global and any code that wants it can always just import it 
     60(as, in fact, this rpy script simply does itself), passing it around 
     61as a parameter leaves the door open for certain future possibilities - 
     62for example, having more than one reactor. There are also testing 
     63implications. Consider how much easier it is to unit test a function 
     64that accepts a reactor - perhaps a mock reactor specially constructed 
     65to make your tests easy to write - rather than importing the real 
     66global reactor. That's why <code>WSGIResource</code> requires you to 
     67pass the reactor to it.</p> 
    6668 
    6769<p>The second parameter passed to <code>WSGIResource</code> is 
    6870a <code class="API"