Twisted.Web2 Introduction

  1. What is twisted.web2
  2. What twisted.web2 is not
  3. Introduction
  4. Simple application

What is twisted.web2

Twisted.web2 is an asynchronous HTTP 1.1 server written for the Twisted internet framework. It provides a RFC 2616 compliant HTTP 1.1 protocol implementation, with pipelined and persistent request support, in a non-blocking threadless manner.

It also includes a simple web framework with request and response objects, static file support, error handling, form upload support, HTTP range support, pre-built parsers for all standard headers, and a bunch of other goodies.

It is deployable as a standalone HTTP or HTTPS server, as a HTTP[S] server proxied behind another server, or as a SCGI, FastCGI, or CGI script.

In addition to running native twisted.web2 applications, it can also run any WSGI or CGI application, or, via compatibility wrappers, most applications written for the older twisted.web API.

Currently, twisted.web2 does not include a HTTP client or proxy, but will at a future date.

What twisted.web2 is not

Twisted.web2 is not a templating framework. It provides mechanisms for locating and running code associated with a URL, but does not provide any means for separating code and data or to ease the task of generating HTML.

Twisted.web2 is in general fairly speedy. However, keep in mind that it is a python program, and, while it is empirically "fast enough", it cannot match Apache in static file serving speed. <insert actual measurements here>

Introduction

This tutorial should be readable by people who do not have much Twisted experience yet, but, you should know Python, and HTML, before starting. While it is hopefully redundant to say this, you also ought to have installed twisted, and twisted.web2.

When you have finished this tutorial, you should be able to write some simple resources and publish them with twisted.web2.

Simple application

from twisted.web2 import server, http, resource, channel

class Toplevel(resource.Resource):
  addSlash = True
  def render(self, ctx):
	return http.Response(stream="Hello monkey!")

site = server.Site(Toplevel())

# Standard twisted application Boilerplate
from twisted.application import service, strports
application = service.Application("demoserver")
s = strports.service('tcp:8080', channel.HTTPFactory(site))
s.setServiceParent(application)
Listing 1: A simple application - ../examples/intro/simple.py

You may run this program via twistd -ny simple.py. twistd is the Twisted runner; it knows how to execute applications by looking for the application variable declared at top-level. You can also run your server in the background (daemonized), via twistd -y simple.py. You can access your server via the url "http://localhost:8080/". For more deployment options, see the deployment chapter.

What this is doing

A resource is responsible for handling one segment of the URL. Here, we have created a resource to handle the top level of the url hierarchy. The addSlash = True setting tells twisted.web2 that this is a directory-like resource. This means that it will add a "/" to the end of the URL automatically, if needed, and respond under that name. Root resources should always have addSlash = True.

The defined class has just a single method: render. This method takes a single argument: request, which contains all the state related to the current rendering operation. This particular render method always returns the same data, so we won't use request. We'll get back to it later.

Here, the render method simply returns a http.Response object containing the output.

After defining this class, next we need to tell twisted.web2 to serve it up. This is accomplished by creating the server.Site object, with an instance of your top-level resource as its argument, and then some standard boilerplate to tell Twisted what services to start and what port to serve them on.

Child resources

Of course, what good is a webserver that can only serve up a single page? So, you can also add child resources to your top-level resource, via child_<name> attributes.

import os.path, time
from twisted.web2 import server, http, resource, channel
from twisted.web2 import static, http_headers, responsecode

class Child(resource.Resource):
  creation_time = time.time()
  text = 'Yo Ho Ho and a bottle of rum.'
  content_type = http_headers.MimeType('text', 'plain')

  def render(self, ctx):
    return http.Response(
      responsecode.OK,
      {'last-modified': self.creation_time,
      'etag': http_headers.ETag(str(hash(self.text))),
      'content-type': self.content_type},
      self.text)

class Toplevel(resource.Resource):
  addSlash = True
  child_monkey = static.File(os.path.dirname(static.__file__)+'/static.py')
  child_elephant = Child()

  def render(self, ctx):
    return http.Response(
      200,
      {'content-type': http_headers.MimeType('text', 'html')},
      """<html><body>
      <a href="monkey">The source code of twisted.web2.static</a><br>
      <a href="elephant">A defined child</a></body></html>""")

site = server.Site(Toplevel())

# Standard twisted application Boilerplate
from twisted.application import service, strports
application = service.Application("demoserver")
s = strports.service('tcp:8080', channel.HTTPFactory(site))
s.setServiceParent(application)
Listing 2: Child Resources - ../examples/intro/children.py

Here a few new concepts have been introduced:

As an aside for those who know a bit about HTTP, note that just by setting the Last-Modified and ETag response headers, you enable automatic precondition checks which support the If-Modified-Since, If-Unmodified-Since, If-Match, and If-None-Match input headers. This allows the client to request that the resource only be sent if it has changed since the last time the client downloaded it, saving bandwidth. Also, the Range and If-Range headers are supported on every resource, allowing partial downloads, and default values for the "Server" and "Date" headers are added to the output for you automatically.

Index

Version: 8.1.0