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

File web-in-60.xhtml.patch, 47.5 KB (added by jdb, 6 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 to provide a uniform interface to many asynchronous events, and shows you an 
    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
    from twisted.web.server import NOT_DONE_YET 
    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):
    class 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)
    example.</p> 
    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 class, <code class="API" base="twisted.web.resource">Resource</code>, is used 
    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
    class DelayedResource(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
    class DelayedResource(Resource): 
    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 class PaymentRequired(Resource): 
    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 from twisted.web.server import Site 
    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
    time module:</p> 
    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):
    class 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
    resource = ClockPage() 
    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 from twisted.web.resource import Resource 
    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 class Calendar(Resource): 
    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 def render_POST(self, request): 
    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 Twisted Web's basic or digest HTTP authentication to control access to these 
    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"
    Cred in much depth here. To make use of it with Twisted Web, the only thing you 
    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
    def requestAvatar(self, avatarId, mind, *interfaces): 
    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
    work after <code>HTTPAuthSessionWrapper</code> extracts the credentials from the 
    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">
    from twisted.web.guard import DigestCredentialFactory 
    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>
    resource = HTTPAuthSessionWrapper(portal, [credentialFactory]) 
    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 a resource class with the same <code>_delayedRender</code> used previously:</p> 
    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):
    def 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 dealt with response errors by aborting response generation, potentially avoiding 
    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>
    plus 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 write code to create the site or set up a listening port with the reactor. That 
    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,
    resource = ClockPage() 
    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 different aspects. This first example demonstrates the very basics of the 
    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
    class ExpireSession(Resource): 
    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 class ShortSession(Session): 
    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">
    factory.sessionFactory = ShortSession 
    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 True 
    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
    pieces interacting here:</p> 
    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>
    class CounterResource(Resource): 
    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 hierarchy: all URLs are children of this resource.</p> 
    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"))
    reactor.listenTCP(8880, factory) 
    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
    another <a href="rpy-scripts.xhtml">rpy script</a> example:</p> 
    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"