Ch 7: Implementation as WSGI app

The WSGI specification

Overview

WSGI stands for Web Server Gateway Interface. It is a Python standard, but it is implemented by Apache and other web servers. A WSGI script is much like a CGI script, except that it is executed by Python rather than by the shell. A WSGI script usually has file suffix .wsgi and resides in the web server's cgi-bin directory. The script must set the variable application to an application that conforms to WSGI expectations.

A WSGI application may also be called from a CGI script using the CGIHandler class from wsgiref.handlers.

Definition

The WSGI standard defines a WSGI application to be a callable that behaves as follows: it takes two arguments, environ and callback, and it responds by passing status and header information to callback, and by returning the page contents as a list of byte-strings. The following provides a bare-bones example:

def app (environ, callback):
    value = [b'This is a test.\r\n'
             b'It is only a test.\r\n']
    nbytes = sum(len(s) for s in value)
    callback('200 OK', 
             [('Content-Type', 'text/plain'),
              ('Content-Length', str(nbytes))])
    return value

This little example ignores environ. The value for callback is a function that accepts two arguments, status_line and headers. The status_line is a string that conforms to the HTTP standard; here it is '200 OK'. The value for headers is a list of pairs of form (key, value). Keys and values are all strings. The keys must be valid HTTP header keys.

The server further expects the app's return value to be a list of byte-strings representing the contents of the HTTP response. 'Content-Length' must be included in the headers passed to callback, and its value must match the total number of bytes in the return value. Note that the arguments to callback consist of strings, whereas the return value consists of byte-strings.

Running a WSGI application

Python also provides an implementation of a WSGI server, which can be run as in the following example:

>>> from wsgiref.simple_server import make_server
>>> server = make_server('localhost', 8000, app)
>>> server.serve_forever()

Then visit the URL http://localhost:8000/. Alternatively, do the following in a separate terminal window:

$ curl http://localhost:8000/

One can alternatively run a WSGI application inside a CGI script. Here is a hypothetical example:

#!/home/clling/bin/python
import site
site.addsitedir('/home/my/python')
from mystuff import app
from wsgiref.handlers import CGIHandler
CGIHandler().run(app)

WsgiApp

The WsgiApp __call__ method

The class WsgiApp wraps a Seal application function and makes it behave like a WSGI app. To be precise, the WsgiApp constructor is called on a Resources instance, which contains a pointer to a Seal application in the member app. The WsgiApp accepts environ and callback arguments in accordance with the WSGI specification, and it instantiates Request from the environ and resources. It passes the request to the Seal application to obtain a Response, and it calls the Response methods http_status(), http_headers(), and body() to get the pieces of the WSGI output. In accordance with the WSGI specification, the status headers are passed to callback, and the body is returned.

If an error occurs in the call to the Seal application, the WsgiApp constructs the status, headers, and body from the error.

Response methods

The Response provides the following three methods for the use of WsgiApp:

http_status()
Returns a string consisting of the page's response_code and the corresponding message.
http_headers()
With the exception of redirects (status 303), there are two headers: Content-Type and Content-Length. The value of the Content-Type header is constructed from the mime type and character encoding, and the value of the Content-Length header comes from nbytes. A redirect substitutes Location for Content-Type; the value for Location comes from the page's uri member.
body()
Simply returns the contents.

The WsgiApp calls these three methods and returns the results to its caller in accordance with the WSGI specification.