python-peps/pep-0333.txt

1020 lines
44 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

PEP: 333
Title: Python Web Server Gateway Interface v1.0
Version: $Revision$
Last-Modified: $Date$
Author: Phillip J. Eby <pje@telecommunity.com>
Discussions-To: Python Web-SIG <web-sig@python.org>
Status: Draft
Type: Informational
Content-Type: text/x-rst
Created: 07-Dec-2003
Post-History: 07-Dec-2003, 08-Aug-2004, 20-Aug-2004
Abstract
========
This document specifies a proposed standard interface between web
servers and Python web applications or frameworks, to promote web
application portability across a variety of web servers.
Rationale and Goals
===================
Python currently boasts a wide variety of web application frameworks,
such as Zope, Quixote, Webware, SkunkWeb, PSO, and Twisted Web -- to
name just a few [1]_. This wide variety of choices can be a problem
for new Python users, because generally speaking, their choice of web
framework will limit their choice of usable web servers, and vice
versa.
By contrast, although Java has just as many web application frameworks
available, Java's "servlet" API makes it possible for applications
written with any Java web application framework to run in any web
server that supports the servlet API.
The availability and widespread use of such an API in web servers for
Python -- whether those servers are written in Python (e.g. Medusa),
embed Python (e.g. mod_python), or invoke Python via a gateway
protocol (e.g. CGI, FastCGI, etc.) -- would separate choice of
framework from choice of web server, freeing users to choose a pairing
that suits them, while freeing framework and server developers to
focus on their preferred area of specialization.
This PEP, therefore, proposes a simple and universal interface between
web servers and web applications or frameworks: the Python Web Server
Gateway Interface (WSGI).
But the mere existence of a WSGI spec does nothing to address the
existing state of servers and frameworks for Python web applications.
Server and framework authors and maintainers must actually implement
WSGI for there to be any effect.
However, since no existing servers or frameworks support WSGI, there
is little immediate reward for an author who implements WSGI support.
Thus, WSGI *must* be easy to implement, so that an author's initial
investment in the interface can be reasonably low.
Thus, simplicity of implementation on *both* the server and framework
sides of the interface is absolutely critical to the utility of the
WSGI interface, and is therefore the principal criterion for any
design decisions.
Note, however, that simplicity of implementation for a framework
author is not the same thing as ease of use for a web application
author. WSGI presents an absolutely "no frills" interface to the
framework author, because bells and whistles like response objects and
cookie handling would just get in the way of existing frameworks'
handling of these issues. Again, the goal of WSGI is to facilitate
easy interconnection of existing servers and applications or
frameworks, not to create a new web framework.
Note also that this goal precludes WSGI from requiring anything that
is not already available in deployed versions of Python. Therefore,
new standard library modules are not proposed or required by this
specification, and nothing in WSGI requires a Python version greater
than 2.2.2. (It would be a good idea, however, for future versions
of Python to include support for this interface in web servers
provided by the standard library.)
In addition to ease of implementation for existing and future
frameworks and servers, it should also be easy to create request
preprocessors, response postprocessors, and other WSGI-based
"middleware" components that look like an application to their
containing server, while acting as a server for their contained
applications.
If middleware can be both simple and robust, and WSGI is widely
available in servers and frameworks, it allows for the possibility
of an entirely new kind of Python web application framework: one
consisting of loosely-coupled WSGI middleware components. Indeed,
existing framework authors may even choose to refactor their
frameworks' existing services to be provided in this way, becoming
more like libraries used with WSGI, and less like monolithic
frameworks. This would then allow application developers to choose
"best-of-breed" components for specific functionality, rather than
having to commit to all the pros and cons of a single framework.
Of course, as of this writing, that day is doubtless quite far off.
In the meantime, it is a sufficient short-term goal for WSGI to
enable the use of any framework with any server.
Finally, it should be mentioned that the current version of WSGI
does not prescribe any particular mechanism for "deploying" an
application for use with a web server or server gateway. At the
present time, this is necessarily implementation-defined by the
server or gateway. After a sufficient number of servers and
frameworks have implemented WSGI to provide field experience with
varying deployment requirements, it may make sense to create
another PEP, describing a deployment standard for WSGI servers and
application frameworks.
Specification Overview
======================
The WSGI interface has two sides: the "server" or "gateway" side, and
the "application" or "framework" side. The server side invokes a
callable object that is provided by the application side. The
specifics of how that object is provided are up to the server or
gateway. It is assumed that some servers or gateways will require an
application's deployer to write a short script to create an instance
of the server or gateway, and supply it with the application object.
Other servers and gateways may use configuration files or other
mechanisms to specify where an application object should be
imported from, or otherwise obtained.
The application object is simply a callable object that accepts
two arguments. The term "object" should not be misconstrued as
requiring an actual object instance: a function, method, class,
or instance with a ``__call__`` method are all acceptable for
use as an application object.
(Note: although we refer to it as an "application" object, this
should not be construed to mean that application developers will use
WSGI as a web programming API! It is assumed that application
developers will continue to use existing, high-level framework
services to develop their applications. WSGI is a tool for
framework and server developers, and is not intended to directly
support application developers.)
Here are two example application objects; one is a function, and the
other is a class::
def simple_app(environ, start_response):
"""Simplest possible application object"""
status = '200 OK'
headers = [('Content-type','text/plain')]
write = start_response(status, headers)
write('Hello world!\n')
class AppClass:
"""Much the same thing, but as a class
(Note: 'AppClass' is the "application", so calling it
returns an instance of 'AppClass', which is the iterable
return value of the "application callable", as required
by the spec.)
"""
def __init__(self, environ, start_response):
self.environ = environ
self.start = start_response
def __iter__(self):
status = '200 OK'
headers = [('Content-type','text/plain')]
self.start(status, headers)
yield "Hello world!\n"
for i in range(1,11):
yield "Extra line %s\n" % i
Throughout this specification, we will use the term "a callable" to
mean "a function, method, class, or an instance with a ``__call__``
method". It is up to the server, gateway, or application implementing
the callable to choose the appropriate implementation technique for
their needs. Conversely, a server, gateway, or application that is
invoking a callable must *not* have any dependency on what kind of
callable was provided to it. Callables are only to be called, not
introspected upon.
The server or gateway invokes the application callable once for each
request it receives from an HTTP client, that is directed at the
application. To illustrate, here is a simple CGI gateway, implemented
as a function taking an application object (all error handling
omitted)::
import os, sys
def run_with_cgi(application):
environ = {}
environ.update(os.environ)
environ['wsgi.input'] = sys.stdin
environ['wsgi.errors'] = sys.stderr
environ['wsgi.version'] = (1,0)
environ['wsgi.multithread'] = False
environ['wsgi.multiprocess'] = True
environ['wsgi.last_call'] = True
def start_response(status,headers):
write = sys.stdout.write
write("Status: %s\r\n" % status)
for key,val in headers:
write("%s: %s\r\n" % (key,val))
write("\r\n")
return write
result = application(environ, start_response)
if result is not None:
try:
for data in result:
sys.stdout.write(data)
finally:
if hasattr(result,'close'):
result.close()
In the next section, we will specify the precise semantics that
these illustrations are examples of.
Specification Details
=====================
The application object must accept two positional arguments. For
the sake of illustration, we have named them ``environ`` and
``start_response``, but they are not required to have these names.
A server or gateway *must* invoke the application object using
positional (not keyword) arguments. (E.g. by calling
``result = application(environ,start_response)`` as shown above.)
The ``environ`` parameter is a dictionary object, containing CGI-style
environment variables. This object *must* be a builtin Python
dictionary (*not* a subclass, ``UserDict`` or other dictionary
emulation), and the application is allowed to modify the dictionary
in any way it desires. The dictionary must also include certain
WSGI-required variables (described in a later section), and may
also include server-specific extension variables, named according
to a convention that will be described below.
The ``start_response`` parameter is a callable accepting two
positional arguments. For the sake of illustration, we have named
them ``status`` and ``headers``, but they are not required to have
these names, and the application *must* invoke the ``start_response``
callable using positional arguments
(e.g. ``start_response(status,headers)``).
The ``status`` parameter is a status string of the form
``"999 Message here"``, and a list of ``(header_name,header_value)``
tuples describing the HTTP response header. This ``start_response``
callable must return a ``write(body_data)`` callable that takes one
positional parameter: a string to be written as part of the HTTP
response body.
The application object may return either ``None`` (indicating that
there is no additional output), or it may return a non-empty
iterable yielding strings. (For example, it could be a
generator-iterator that yields strings, or it could be a
sequence such as a list of strings.) The server or gateway will
treat the strings yielded by the iterable as if they had been
passed to the ``write()`` method. If a call to ``len(iterable)``
succeeds, the server must be able to rely on the result being
accurate. That is, if the iterable returned by the application
provides a working ``__len__()`` method, it *must* return an
accurate result.
If the returned iterable has a ``fileno`` attribute, the server *may*
assume that this is a ``fileno()`` method returning an operating
system file descriptor, and that it is allowed to read directly from
that descriptor up to the end of the file, and/or use any appropriate
operating system facilities (e.g. the ``sendfile()`` system call) to
transmit the file's contents. If the server does this, it must begin
transmission with the file's current position, and end at the end of
the file.
Finally, if the application returned an iterable, and the iterable has
a ``close()`` method, the server or gateway *must* call that method
upon completion of the current request, whether the request was
completed normally, or terminated early due to an error. (This is to
support resource release by the application. This protocol is
intended to support PEP 325, and also the simple case of an
application returning an open text file.)
(Note: the application *must* invoke the ``start_response()`` callable
before the iterable yields its first body string, so that the server
can send headers before any body content. However, this invocation
*may* be performed by the iterable's first iteration, so servers *must
not* assume that ``start_response()`` has been called before they
begin iterating over the iterable.)
``environ`` Variables
---------------------
The ``environ`` dictionary is required to contain these CGI
environment variables, as defined by the Common Gateway Interface
specification [2]_. The following variables *must* be present, but
*may* be an empty string, if there is no more appropriate value for
them:
* ``REQUEST_METHOD``
* ``SCRIPT_NAME`` (The initial portion of the request URL's "path"
that corresponds to the application object, so that the application
knows its virtual "location".)
* ``PATH_INFO`` (The remainder of the request URL's "path",
designating the virtual "location" of the request's target within
the application)
* ``QUERY_STRING``
* ``CONTENT_TYPE``
* ``CONTENT_LENGTH``
* ``SERVER_NAME`` and ``SERVER_PORT`` (which, when combined with
``SCRIPT_NAME`` and ``PATH_INFO``, should complete the URL. Note,
however, that ``HTTP_HOST``, if present, should be used in
preference to ``SERVER_NAME`` for constructing the URL. See the
`URL Reconstruction`_ section below for more detail.)
* Variables corresponding to the client-supplied HTTP headers (i.e.,
variables whose names begin with ``"HTTP_"``).
In general, a server or gateway should attempt to provide as many
other CGI variables as are applicable, including e.g. the nonstandard
SSL variables such as ``HTTPS=on``, if an SSL connection is in effect.
However, an application that uses any variables other than the ones
listed above are necessarily non-portable to web servers that do not
support the relevant extensions.
A WSGI-compliant server or gateway *should* document what variables it
provides, along with their definitions as appropriate. Applications
*should* check for the presence of any nonstandard variables they
require, and have a fallback plan in the event such a variable is
absent.
Note: missing variables (such as ``REMOTE_USER`` when no
authentication has occurred) should be left out of the ``environ``
dictionary. Also note that CGI-defined variables must be strings,
if they are present at all. It is a violation of this specification
for a CGI variable's value to be of any type other than ``str``.
In addition to the CGI-defined variables, the ``environ`` dictionary
must also contain the following WSGI-defined variables:
===================== ===============================================
Variable Value
===================== ===============================================
``wsgi.version`` The tuple ``(1,0)``, representing WSGI
version 1.0.
``wsgi.input`` An input stream from which the HTTP request
body can be read. (The server or gateway may
perform reads on-demand as requested by the
application, or it may pre-read the client's
request body and buffer it in-memory or on
disk, or use any other technique for providing
such an input stream, according to its
preference.)
``wsgi.errors`` An output stream to which error output can be
written. For most servers, this will be the
server's error log.
``wsgi.multithread`` This value should be true if the application
object may be simultaneously invoked by another
thread in the same process, and false
otherwise.
``wsgi.multiprocess`` This value should be true if an equivalent
application object may be simultaneously
invoked by another process, and false
otherwise.
``wsgi.run_once`` This value should be true if the server/gateway
expects (but does not guarantee!) that the
application will only be invoked this one time
during the life of its containing process.
Normally, this will only be true for a gateway
based on CGI (or something similar).
===================== ===============================================
Finally, the ``environ`` dictionary may also contain server-defined
variables. These variables should be named using only lower-case
letters, numbers, dots, and underscores, and should be prefixed with
a name that is unique to the defining server or gateway. For
example, ``mod_python`` might define variables with names like
``mod_python.some_variable``.
Input and Error Streams
~~~~~~~~~~~~~~~~~~~~~~~
The input and error streams provided by the server must support
the following methods:
=================== ========== ========
Method Stream Notes
=================== ========== ========
``read(size)`` ``input`` 1
``readline()`` ``input`` 1,2
``readlines(hint)`` ``input`` 1,3
``__iter__()`` ``input``
``flush()`` ``errors`` 4
``write(str)`` ``errors``
``writelines(seq)`` ``errors``
=================== ========== ========
The semantics of each method are as documented in the Python Library
Reference, except for these notes as listed in the table above:
1. The server is not required to read past the client's specified
``Content-Length``, and is allowed to simulate an end-of-file
condition if the application attempts to read past that point.
The application *should not* attempt to read more data than is
specified by the ``CONTENT_LENGTH`` variable.
2. The optional "size" argument to ``readline()`` is not supported,
as it may be complex for server authors to implement, and is not
often used in practice.
3. Note that the ``hint`` argument to ``readlines()`` is optional for
both caller and implementer. The application is free not to
supply it, and the server or gateway is free to ignore it.
4. Since the ``errors`` stream may not be rewound, a container is
free to forward write operations immediately, without buffering.
In this case, the ``flush()`` method may be a no-op. Portable
applications, however, cannot assume that output is unbuffered
or that ``flush()`` is a no-op. They must call ``flush()`` if
they need to ensure that output has in fact been written. (For
example, to minimize intermingling of data from multiple processes
writing to the same error log.)
The methods listed in the table above *must* be supported by all
servers conforming to this specification. Applications conforming
to this specification *must not* use any other methods or attributes
of the ``input`` or ``errors`` objects. In particular, applications
*must not* attempt to close these streams, even if they possess
``close()`` methods.
The ``start_response()`` Callable
---------------------------------
The second parameter passed to the application object is itself a
two-argument callable, of the form ``start_response(status,headers)``.
(As with all WSGI callables, the arguments must be supplied
positionally, not by keyword.) The ``start_response`` callable is
used to begin the HTTP response, and it must return a
``write(body_data)`` callable.
The ``status`` argument is an HTTP "status" string like ``"200 OK"``
or ``"404 Not Found"``. The string *must* be pure 7-bit ASCII,
containing no control characters. It must not be terminated with
a carriage return or linefeed.
The ``headers`` argument is a sequence of
``(header_name,header_value)`` tuples. Each ``header_name`` must be a
valid HTTP header name, without a trailing colon or other punctuation.
Each ``header_value`` *must not* include *any* control characters,
including carriage returns or linefeeds, either embedded or at the
end. (These requirements are to minimize the complexity of any
parsing that must be performed by servers, gateways, and intermediate
response processors that need to inspect or modify response headers.)
In general, the server or gateway is responsible for ensuring that
correct headers are sent to the client: if the application omits
a needed header, the server or gateway *should* add it. For example,
the HTTP ``Date:`` and ``Server:`` headers would normally be supplied
by the server or gateway. If the application supplies a header that
the server would ordinarily supply, or that contradicts the server's
intended behavior (e.g. supplying a different ``Connection:`` header),
the server or gateway *may* discard the conflicting header, provided
that its action is recorded for the benefit of the application author.
(A reminder for server/gateway authors: HTTP header names are
case-insensitive, so be sure to take that into consideration when
examining application-supplied headers!)
Handling the ``Content-Length`` Header
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the application does not supply a ``Content-Length`` header, a
server or gateway may choose one of several approaches to handling
it. The simplest of these is to close the client connection when
the response is completed.
Under some circumstances, however, the server or gateway may be
able to either generate a ``Content-Length`` header, or at least
avoid the need to close the client connection. If the application
does *not* call the ``write()`` callable, and returns an iterable
whose ``len()`` is 1, then the server can automatically determine
``Content-Length`` by taking the length of the first string yielded
by the iterable.
And, if the server and client both support HTTP/1.1 "chunked
encoding" [3]_, then the server *may* use chunked encoding to send
a chunk for each ``write()`` call or string yielded by the iterable,
thus generating a ``Content-Length`` header for each chunk. This
allows the server to keep the client connection alive, if it wishes
to do so. Note that the server *must* comply fully with RFC 2616 when
doing this, or else fall back to one of the other strategies for
dealing with the absence of ``Content-Length``.
The ``write()`` Callable
------------------------
The return value of the ``start_response()`` callable is a
one-argument `write()`` callable, that accepts strings to write as
part of the HTTP response body.
Note that the purpose of the ``write()`` callable is primarily to
support existing application frameworks that support a streaming
"push" API. Therefore, strings passed to ``write()`` *must* be sent
to the client *as soon as possible*; they must *not* be buffered
unless the buffer will be emptied in parallel with the application's
continuing execution (e.g. by a separate I/O thread). If the server
or gateway does not have a separate I/O thread available, it *must*
finish writing the supplied string before it returns from each
``write()`` invocation.
If the application returns an iterable, each string produced by the
iterable must be treated as though it had been passed to ``write()``,
with the data sent in an "as soon as possible" manner. That is,
the iterable should not be asked for a new string until the previous
string has been sent to the client, or is buffered for such sending
by a parallel thread.
Notice that these rules discourage the generation of content before a
client is ready for it, in excess of the buffer sizes provided by the
server and operating system. For this reason, some applications may
wish to buffer data internally before passing any of it to ``write()``
or yielding it from an iterator, in order to avoid waiting for the
client to catch up with their output. This approach may yield better
throughput for dynamically generated pages of moderate size, since the
application is then freed for other tasks.
In addition to improved performance, buffering all of an application's
output has an advantage for error handling: the buffered output can
be thrown away and replaced by an error page, rather than dumping an
error message in the middle of some partially-completed output. For
this and other reasons, many existing Python frameworks already
accumulate their output for a single write, unless the application
explicitly requests streaming, or the expected output is larger than
practical for buffering (e.g. multi-megabyte PDFs). So, these
application frameworks are already a natural fit for the WSGI
streaming model: for most requests they will only call ``write()``
once anyway!
Implementation/Application Notes
================================
Unicode
-------
HTTP does not directly support Unicode, and neither does this
interface. All encoding/decoding must be handled by the application;
all strings and streams passed to or from the server must be standard
Python byte strings, not Unicode objects. The result of using a
Unicode object where a string object is required, is undefined.
Multiple Invocations
--------------------
Application objects must be able to be invoked more than once, since
virtually all servers/gateways will make such requests.
Error Handling
--------------
Servers *should* trap and log exceptions raised by
applications, and *may* continue to execute, or attempt to shut down
gracefully. Applications *should* avoid allowing exceptions to
escape their execution scope, since the result of uncaught exceptions
is server-defined.
Thread Support
--------------
Thread support, or lack thereof, is also server-dependent.
Servers that can run multiple requests in parallel, *should* also
provide the option of running an application in a single-threaded
fashion, so that applications or frameworks that are not thread-safe
may still be used with that server.
URL Reconstruction
------------------
If an application wishes to reconstruct a request's complete URL, it
may do so using the following algorithm, contributed by Ian Bicking::
if environ.get('HTTPS') == 'on':
url = 'https://'
else:
url = 'http://'
if environ.get('HTTP_HOST'):
url += environ['HTTP_HOST']
else:
url += environ['SERVER_NAME']
if environ.get('HTTPS') == 'on':
if environ['SERVER_PORT'] != '443'
url += ':' + environ['SERVER_PORT']
else:
if environ['SERVER_PORT'] != '80':
url += ':' + environ['SERVER_PORT']
url += environ['SCRIPT_NAME']
url += environ['PATH_INFO']
if environ.get('QUERY_STRING'):
url += '?' + environ['QUERY_STRING']
Note that such a reconstructed URL may not be precisely the same URI
as requested by the client. Server rewrite rules, for example, may
have modified the client's originally requested URL to place it in a
canonical form.
Application Configuration
-------------------------
This specification does not define how a server selects or obtains an
application to invoke. These and other configuration options are
highly server-specific matters. It is expected that server/gateway
authors will document how to configure the server to execute a
particular application object, and with what options (such as
threading options).
Framework authors, on the other hand, should document how to create an
application object that wraps their framework's functionality. The
user, who has chosen both the server and the application framework,
must connect the two together. However, since both the framework and
the server now have a common interface, this should be merely a
mechanical matter, rather than a significant engineering effort for
each new server/framework pair.
Middleware
----------
Note that a single object may play the role of a server with respect
to some application(s), while also acting as an application with
respect to some server(s). Such "middleware" components can perform
such functions as:
* Routing a request to different application objects based on the
target URL, after rewriting the ``environ`` accordingly.
* Allowing multiple applications or frameworks to run side-by-side
in the same process
* Load balancing and remote processing, by forwarding requests and
responses over a network
* Perform content postprocessing, such as applying XSL stylesheets
Given the existence of applications and servers conforming to this
specification, the appearance of such reusable middleware becomes
a possibility.
Server Extension APIs
---------------------
Some server authors may wish to expose more advanced APIs, that
application or framework authors can use for specialized purposes.
For example, a gateway based on ``mod_python`` might wish to expose
part of the Apache API as a WSGI extension.
In the simplest case, this requires nothing more than defining an
``environ`` variable, such as ``mod_python.some_api``. But, in many
cases, the possible presence of middleware can make this difficult.
For example, an API that offers access to the same HTTP headers that
are found in ``environ`` variables, might return different data if
``environ`` has been modified by middleware.
In general, any extension API that duplicates, supplants, or bypasses
some portion of WSGI functionality runs the risk of being incompatible
with middleware components. Server/gateway developers should *not*
assume that nobody will use middleware, because some framework
developers specifically intend to organize or reorganize their
frameworks to function almost entirely as middleware of various kinds.
So, to provide maximum compatibility, servers and gateways that
provide extension APIs that replace some WSGI functionality, *must*
design those APIs so that they are invoked using the portion of the
API that they replace. For example, an extension API to access HTTP
request headers must require the application to pass in its current
``environ``, so that the server/gateway may verify that HTTP headers
accessible via the API have not been altered by middleware. If the
extension API cannot guarantee that it will always agree with
``environ`` about the contents of HTTP headers, it must refuse service
to the application, e.g. by raising an error, returning ``None``
instead of a header collection, or whatever is appropriate to the API.
Similarly, if an extension API provides an alternate means of writing
response data or headers, it should require the ``start_response``
callable to be passed in, before the application can obtain the
extended service. If the object passed in is not the same one that
the server/gateway originally supplied to the application, it cannot
guarantee correct operation and must refuse to provide the extended
service to the application.
These guidelines also apply to middleware that adds information such
as parsed cookies, form variables, sessions, and the like to
``environ``. Specifically, such middleware should provide these
features as functions which operate on ``environ``, rather than simply
stuffing values into ``environ``. This helps ensure that information
is calculated from ``environ`` *after* any middleware has done any URL
rewrites or other ``environ`` modifications.
It is very important that these "safe extension" rules be followed by
both server/gateway and middleware developers, in order to avoid a
future in which middleware developers are forced to delete any and all
extension APIs from ``environ`` to ensure that their mediation isn't
being bypassed by applications using those extensions!
HTTP 1.1 Expect/Continue
------------------------
Servers and gateways *must* provide transparent support for HTTP 1.1's
"expect/continue" mechanism, if they implement HTTP 1.1. This may be
done in any of several ways:
1. Reject all client requests containing an ``Expect: 100-continue``
header with a "417 Expectation failed" error. Such requests will
not be forwarded to an application object.
2. Respond to requests containing an ``Expect: 100-continue`` request
with an immediate "100 Continue" response, and proceed normally.
3. Proceed with the request normally, but provide the application
with a ``wsgi.input`` stream that will send the "100 Continue"
response if/when the application first attempts to read from the
input stream. The read request must then remain blocked until the
client responds.
Note that this behavior restriction does not apply for HTTP 1.0
requests, or for requests that are not directed to an application
object. For more information on HTTP 1.1 Expect/Continue, see RFC
2616, sections 8.2.3 and 10.1.1.
Questions and Answers
=====================
1. Why must ``environ`` be a dictionary? What's wrong with using a
subclass?
The rationale for requiring a dictionary is to maximize portability
between servers. The alternative would be to define some subset of
a dictionary's methods as being the standard and portable
interface. In practice, however, most servers will probably find a
dictionary adequate to their needs, and thus framework authors will
come to expect the full set of dictionary features to be available,
since they will be there more often than not. But, if some server
chooses *not* to use a dictionary, then there will be
interoperability problems despite that server's "conformance" to
spec. Therefore, making a dictionary mandatory simplifies the
specification and guarantees interoperabilty.
Note that this does not prevent server or framework developers from
offering specialized services as custom variables *inside* the
``environ`` dictionary. This is the recommended approach for
offering any such value-added services.
2. Why can you call ``write()`` *and* yield strings/return an
iterator? Shouldn't we pick just one way?
If we supported only the iteration approach, then current
frameworks that assume the availability of "push" suffer. But, if
we only support pushing via ``write()``, then server performance
suffers for transmission of e.g. large files (if a worker thread
can't begin work on a new request until all of the output has been
sent). Thus, this compromise allows an application framework to
support both approaches, as appropriate, but with only a little
more burden to the server implementor than a push-only approach
would require.
3. What's the ``close()`` for?
When writes are done from during the execution of an application
object, the application can ensure that resources are released
using a try/finally block. But, if the application returns an
iterator, any resources used will not be released until the
iterator is garbage collected. The ``close()`` idiom allows an
application to release critical resources at the end of a request,
and it's forward-compatible with the support for try/finally in
generators that's proposed by PEP 325.
4. Why is this interface so low-level? I want feature X! (e.g.
cookies, sessions, persistence, ...)
This isn't Yet Another Python Web Framework. It's just a way for
frameworks to talk to web servers, and vice versa. If you want
these features, you need to pick a web framework that provides the
features you want. And if that framework lets you create a WSGI
application, you should be able to run it in most WSGI-supporting
servers. Also, some WSGI servers may offer additional services via
objects provided in their ``environ`` dictionary; see the
applicable server documentation for details. (Of course,
applications that use such extensions will not be portable to other
WSGI-based servers.)
5. Why use CGI variables instead of good old HTTP headers? And why
mix them in with WSGI-defined variables?
Many existing web frameworks are built heavily upon the CGI spec,
and existing web servers know how to generate CGI variables. In
contrast, alternative ways of representing inbound HTTP information
are fragmented and lack market share. Thus, using the CGI
"standard" seems like a good way to leverage existing
implementations. As for mixing them with WSGI variables,
separating them would just require two dictionary arguments to be
passed around, while providing no real benefits.
6. What about the status string? Can't we just use the number,
passing in ``200`` instead of ``"200 OK"``?
Doing this would complicate the server or gateway, by requiring
them to have a table of numeric statuses and corresponding
messages. By contrast, it is easy for an application or framework
author to type the extra text to go with the specific response code
they are using, and existing frameworks often already have a table
containing the needed messages. So, on balance it seems better to
make the application/framework responsible, rather than the server
or gateway.
7. Why is ``wsgi.run_once`` not guaranteed to run the app only once?
Because it's merely a suggestion to the application that it should
"rig for infrequent running". This is intended for application
frameworks that have multiple modes of operation for caching,
sessions, and so forth. In a "multiple run" mode, such frameworks
may preload caches, and may not write e.g. logs or session data to
disk after each request. In "single run" mode, such frameworks
avoid preloading and flush all necessary writes after each request.
However, in order to test an application or framework to verify
correct operation in the latter mode, it may be necessary (or at
least expedient) to invoke it more than once. Therefore, an
application should not assume that it will definitely not be run
again, just because it is called with ``wsgi.run_once`` set to
``True``.
8. Feature X (dictionaries, callables, etc.) are ugly for use in
application code; why don't we use objects instead?
All of these implementation choices of WSGI are specifically
intended to *decouple* features from one another; recombining these
features into encapsulated objects makes it somewhat harder to
write servers or gateways, and an order of magnitude harder to
write middleware that replaces or modifies only small portions of
the overall functionality.
In essence, middleware wants to have a "Chain of Responsibility"
pattern, whereby it can act as a "handler" for some functions,
while allowing others to remain unchanged. This is difficult to do
with ordinary Python objects, if the interface is to remain
extensible. For example, one must use ``__getattr__`` or
``__getattribute__`` overrides, to ensure that extensions (such as
attributes defined by future WSGI versions) are passed through.
This type of code is notoriously difficult to get 100% correct, and
few people will want to write it themselves. They will therefore
copy other people's implementations, but fail to update them when
the person they copied from corrects yet another corner case.
Further, this necessary boilerplate would be pure excise, a
developer tax paid by middleware developers to support a slightly
prettier API for application framework developers. But,
application framework developers will typically only be updating
*one* framework to support WSGI, and in a very limited part of
their framework as a whole. It will likely be their first (and
maybe their only) WSGI implementation, and thus they will likely
implement with this specification ready to hand. Thus, the effort
of making the API "prettier" with object attributes and suchlike
would likely be wasted for this audience.
We encourage those who want a prettier (or otherwise improved) WSGI
interface for use in direct web application programming (as opposed
to web framework development) to develop APIs or frameworks that
wrap WSGI for convenient use by application developers. In this
way, WSGI can remain conveniently low-level for server and
middleware authors, while not being "ugly" for application
developers.
Open Issues
===========
The format of the ``headers`` passed to the ``start_response``
callable has seen some debate. Currently, it is a sequence of tuples,
but other formats have been suggested, such as a dictionary of lists,
or an ``email.Message`` object (from the Python standard library's
``email`` package). For various practical reasons, the "dictionary of
lists" approach has been ruled out, but ``email.Message`` is still a
candidate, as it provides several advantages for many middleware
developers and some application or framework developers, without an
excessive burden to anyone else.
Specifically, ``email.Message`` objects offer a mutable data
structure, (not unlike a case-insensitive dictionary) for containing
MIME headers, such as those used in an HTTP response. This makes it
very easy to modify headers, or add multi-valued headers such as
``Set-Cookie`` headers. If the ``headers`` passed to
``start_response`` were an ``email.Message``, then it would be easy
for middleware and servers to modify response headers, e.g. to supply
defaults for missing headers. It also leads to cleaner-looking
application code in some cases, e.g.::
from email.Message import Message
def application(environ, start_response):
headers = Message()
headers.set_type("text/plain")
headers.add_header("Set-Cookie", "FOO=BAR", path="/foobar")
start("200 OK", headers)("Hello world!")
Some have pointed out that this requires the developers of existing
frameworks to convert whatever header format they use to an
``email.Message``. But this is only relevant if the format they
already use is a list of name/value pairs: in all other cases they
would have to perform some conversion anyway.
In the event that the ``email.Message`` format is *not* chosen,
however, application developers will still have the option of using it
as a helper class. For example, the code below works with the current
WSGI spec, by passing the message object's ``items()`` (a list of
tuples) to ``start_response()``:
def application(environ, start_response):
headers = Message()
headers.set_type("text/plain")
headers.add_header("Set-Cookie", "FOO=BAR", path="/foobar")
start_response("200 OK", headers.items())("Hello world!")
But this doesn't help middleware authors, who would have to convert
the response headers into a ``Message`` object and back again if they
needed to modify the headers.
One other issue that's been brought up in relation to
``email.Message`` is that its ``set_type()`` method also sets a
``MIME-Version`` header. In order to comply properly with the MIME
and HTTP specifications, it would then be necessary for server/gateway
authors to ensure the presence of a ``Content-Transfer-Encoding``,
e.g.::
if ('MIME-Version' in headers and
'Content-Transfer-Encoding' not in headers
):
headers['Content-Transfer-Encoding'] = "8bit"
Also, ``email.Message`` has various features unrelated to HTTP or WSGI
that should not be used, and might be distracting or confusing to
authors.
Acknowledgements
================
Thanks go to the many folks on the Web-SIG mailing list whose
thoughtful feedback made this revised draft possible. Especially:
* Gregory "Grisha" Trubetskoy, author of ``mod_python``, who beat up
on the first draft as not offering any advantages over "plain old
CGI", thus encouraging me to look for a better approach.
* Ian Bicking, who helped nag me into properly specifying the
multithreading and multiprocess options, as well as badgering me to
provide a mechanism for servers to supply custom extension data to
an application.
* Tony Lownds, who came up with the concept of a ``start_response``
function that took the status and headers, returning a ``write``
function.
References
==========
.. [1] The Python Wiki "Web Programming" topic
(http://www.python.org/cgi-bin/moinmoin/WebProgramming)
.. [2] The Common Gateway Interface Specification, v 1.1, 3rd Draft
(http://cgi-spec.golux.com/draft-coar-cgi-v11-03.txt)
.. [3] Hypertext Transfer Protocol -- HTTP/1.1, section 3.6.1
(http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1)
Copyright
=========
This document has been placed in the public domain.
..
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End: