1137 lines
50 KiB
Plaintext
1137 lines
50 KiB
Plaintext
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, 27-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')]
|
||
start_response(status, headers)
|
||
return ['Hello world!\n']
|
||
|
||
|
||
class AppClass:
|
||
"""Produce the same output, but using a class
|
||
|
||
(Note: 'AppClass' is the "application" here, so calling it
|
||
returns an instance of 'AppClass', which is then the iterable
|
||
return value of the "application callable" as required by
|
||
the spec.
|
||
|
||
If we wanted to use *instances* of 'AppClass' as application
|
||
objects instead, we would have to implement a '__call__'
|
||
method, which would be invoked to execute the application,
|
||
and we would need to create an instance for use by the
|
||
server or gateway.
|
||
"""
|
||
|
||
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"
|
||
|
||
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 write(data):
|
||
sys.stdout.write(data)
|
||
sys.stdout.flush()
|
||
|
||
def start_response(status,headers):
|
||
sys.stdout.write("Status: %s\r\n" % status)
|
||
for key,val in headers:
|
||
sys.stdout.write("%s: %s\r\n" % (key,val))
|
||
sys.stdout.write("\r\n")
|
||
return write
|
||
|
||
result = application(environ, start_response)
|
||
try:
|
||
for data in result:
|
||
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. (Note: the ``write()`` callable is provided only
|
||
to support certain existing frameworks' imperative output APIs;
|
||
it should not be used by new applications or frameworks. See
|
||
the `Buffering and Streaming`_ section for more details.)
|
||
|
||
The application object must return an 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 must transmit these strings to the client in an
|
||
unbuffered fashion, completing the transmission of each string
|
||
before requesting another one. (See the `Buffering and Streaming`_
|
||
section below for more on how application output must be handled.)
|
||
|
||
The server or gateway must not modify supplied strings in any way;
|
||
they must be treated as binary byte sequences with no character
|
||
interpretation, line ending changes, or other modification. The
|
||
application is responsible for ensuring that the string(s) to be
|
||
written are in a format suitable for the client.
|
||
|
||
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 iterable returned by the application 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 other simple cases such as 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 the 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.)
|
||
|
||
Finally, servers **must not** directly use any other attributes of
|
||
the iterable returned by the application. For example, it the
|
||
iterable is a file object, it may have a ``read()`` method, but
|
||
the server **must not** utilize it. Only attributes specified
|
||
here, or accessed via e.g. the PEP 234 iteration APIs are
|
||
acceptable.
|
||
|
||
|
||
``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 the purpose of recording program
|
||
or other errors in a standardized and possibly
|
||
centralized location. For many servers, this
|
||
will be the server's main error log.
|
||
|
||
Alternatively, this may be ``sys.stderr``, or
|
||
a log file of some sort. The server's
|
||
documentation should include an explanation of
|
||
how to configure this or where to find the
|
||
recorded output. A server or gateway may
|
||
supply different error streams to different
|
||
applications, if this is desired.
|
||
|
||
``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 (see the `Buffering and Streaming`_
|
||
section, below).
|
||
|
||
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 list of ``(header_name,header_value)``
|
||
tuples. It must be a Python list; i.e. ``type(headers) is
|
||
ListType)``, and the server **may** change its contents in any way
|
||
it desires. 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.
|
||
|
||
(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!)
|
||
|
||
If the application supplies headers that would affect the persistence
|
||
of the client's connection (e.g. ``Connection:``, "keep-alives", etc.),
|
||
the server or gateway is permitted to discard or modify these headers,
|
||
if the server cannot or will not conform to the application's requested
|
||
semantics. E.g., if the application requests a persistent connection
|
||
but the server wishes transience, or vice versa.
|
||
|
||
However, if a server or gateway discards or overrides any application
|
||
header for any reason, it **must** record this action in a log (such as
|
||
the ``wsgi.errors`` log) for the benefit of the application author.
|
||
|
||
|
||
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``.
|
||
|
||
|
||
Buffering and Streaming
|
||
-----------------------
|
||
|
||
Generally speaking, applications will achieve the best throughput
|
||
by buffering their (modestly-sized) output and sending it all at
|
||
once. When this is the case, applications **should** simply
|
||
return a single-element iterable containing their entire output as
|
||
a single string.
|
||
|
||
(In addition to improved performance, buffering all of an application's
|
||
output has an advantage for error handling: the buffered output can
|
||
be discarded 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).)
|
||
|
||
For large files, however, or for specialized uses of HTTP streaming
|
||
(such as multipart "server push"), an application may need to provide
|
||
output in smaller blocks (e.g. to avoid loading a large file into
|
||
memory). It's also sometimes the case that part of a response may
|
||
be time-consuming to produce, but it would be useful to send ahead the
|
||
portion of the response that precedes it.
|
||
|
||
In these cases, applications **should** return an iterator (usually
|
||
a generator-iterator) that produces the output in a block-by-block
|
||
fashion. These blocks may be broken to coincide with mulitpart
|
||
boundaries (for "server push"), or just before time-consuming
|
||
tasks (such as reading another block of an on-disk file).
|
||
|
||
WSGI servers and gateways **must not** delay the transmission
|
||
of any block; they **must** either fully transmit the block to
|
||
the client, or guarantee that they will continue transmission
|
||
even while the application is producing its next block. A
|
||
server/gateway may provide this guarantee in one of two ways:
|
||
|
||
1. Send the entire block to the operating system (and request
|
||
that any O/S buffers be flushed) before returning control
|
||
to the application, OR
|
||
|
||
2. Use a different thread to ensure that the block continues
|
||
to be transmitted while the application produces the next
|
||
block.
|
||
|
||
By providing this guarantee, WSGI allows applications to ensure
|
||
that transmission will not become stalled at an arbitrary point
|
||
in their output data. This is critical for proper functioning
|
||
of e.g. multipart "server push" streaming, where data between
|
||
multipart boundaries should be transmitted in full to the client.
|
||
|
||
|
||
The ``write()`` Callable
|
||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Some existing application framework APIs support unbuffered
|
||
output in a different manner than WSGI. Specifically, they
|
||
provide a "write" function or method of some kind to write
|
||
an unbuffered block of data, or else they provide a buffered
|
||
"write" function and a "flush" mechanism to flush the buffer.
|
||
|
||
Unfortunately, such APIs cannot be implemented in terms of
|
||
WSGI's "iterable" application return value, unless threads
|
||
or other special mechanisms are used.
|
||
|
||
Therefore, to allow these frameworks to continue using an
|
||
imperative API, WSGI includes a special ``write()`` callable,
|
||
returned by the ``start_response`` callable.
|
||
|
||
New WSGI applications and frameworks **should not** use the
|
||
``write()`` callable if it is possible to avoid doing so. The
|
||
``write()`` callable is strictly a hack to support existing
|
||
frameworks' imperative APIs. In general, applications
|
||
should either be internally buffered, or produce iterable output.
|
||
|
||
The ``write()`` callable is returned by the ``start_response()``
|
||
callable, and it accepts a single parameter: a string to be
|
||
written as part of the HTTP response body, that is treated exactly
|
||
as though it had been yielded by the output iterable. In other
|
||
words, before ``write()`` returns, it must guarantee that the
|
||
passed-in string was either completely sent to the client, or
|
||
that it is buffered for transmission while the application
|
||
proceeds forward.
|
||
|
||
An application **may** return a non-empty iterable even if it
|
||
invokes ``write()``, and that output must be treated normally
|
||
by the server or gateway.
|
||
|
||
|
||
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.
|
||
|
||
|
||
Supporting Older (<2.2) Versions of Python
|
||
------------------------------------------
|
||
|
||
Some servers, gateways, or applications may wish to support older
|
||
(<2.2) versions of Python. This is especially important if Jython
|
||
is a target platform, since as of this writing a production-ready
|
||
version of Jython 2.2 is not yet available.
|
||
|
||
For servers and gateways, this is relatively straightforward:
|
||
servers and gateways targeting pre-2.2 versions of Python must
|
||
simply restrict themselves to using only a standard "for" loop to
|
||
iterate over any iterable returned by an application. This is the
|
||
only way to ensure source-level compatibility with both the pre-2.2
|
||
iterator protocol (discussed further below) and "today's" iterator
|
||
protocol (see PEP 234).
|
||
|
||
(Note that this technique necessarily applies only to servers,
|
||
gateways, or middleware that are written in Python. Discussion of
|
||
how to use iterator protocol(s) correctly from other languages is
|
||
outside the scope of this PEP.)
|
||
|
||
For applications, supporting pre-2.2 versions of Python is slightly
|
||
more complex:
|
||
|
||
* You may not return a file object and expect it to work as an iterable,
|
||
since before Python 2.2, files were not iterable. (Some servers
|
||
may loosen this guideline by checking for ``types.FileType``, but
|
||
this is an optional, server-specific extension. If you want your
|
||
application code to be used with pre-2.2 Pythons such as Jython,
|
||
you should *not* return a file object; use a pre-2.2 iterable
|
||
or a sequence instead.)
|
||
|
||
* If you return a custom iterable, it **must** implement the pre-2.2
|
||
iterator protocol. That is, provide a ``__getitem__`` method that
|
||
accepts an integer key, and raises ``IndexError`` when exhausted.
|
||
(Note that built-in sequence types are also acceptable, since they
|
||
also implement this protocol.)
|
||
|
||
Finally, middleware that wishes to support pre-2.2 versions of Python,
|
||
and iterates over application return values or itself returns an
|
||
iterable (or both), must follow the appropriate recommendations above.
|
||
|
||
(Note: It should go without saying that to support pre-2.2 versions
|
||
of Python, any server, gateway, application, or middleware must also
|
||
use only language features available in the target version, use
|
||
1 and 0 instead of ``True`` and ``False``, etc.)
|
||
|
||
|
||
|
||
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!
|
||
|
||
|
||
Optional Platform-Specific File Handling
|
||
----------------------------------------
|
||
|
||
If the application-returned iterable has a ``fileno`` attribute,
|
||
the server or gateway **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.
|
||
|
||
Note that an application **must not** return an iterable with a
|
||
``fileno`` attribute if it is anything other than a method returning
|
||
an **operating system file descriptor**. "File-like" objects
|
||
that do not possess a true operating system file descriptor number
|
||
are expressly forbidden. Servers running on platforms where file
|
||
descriptors do not exist, or where there is no meaningful API for
|
||
accelerating transmission from a file descriptor should ignore the
|
||
``fileno`` attribute.
|
||
|
||
On platforms that possess some analagous mechanism for fast
|
||
transmission of static files or pipes, a server or gateway **may**
|
||
offer a similar extension using a different method name, returning
|
||
an object of the appropriate type for that platform. Such servers
|
||
**should** document the method name to be used and the type of
|
||
object that it should return.
|
||
|
||
Please note that this optional extension does not excuse the
|
||
application from returning an iterable object. Returning an object
|
||
that is not iterable -- even if it implements ``fileno()`` or is
|
||
"file-like" -- is not acceptable, and will be rejected by servers
|
||
and gateways that do not support this optional extension.
|
||
|
||
|
||
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
|
||
===========
|
||
|
||
* Some persons have requested information about whether the
|
||
``HTTP_AUTHENTICATION`` header may be provided by the server.
|
||
That is, some web servers do not supply this information to
|
||
e.g. CGI applications, and they would like the application
|
||
to know that this is the case so it can use alternative
|
||
means of authentication.
|
||
|
||
* Error handling: strategies for effective error handling are
|
||
currently in discussion on the Web-SIG mailing list. In
|
||
particular, a mechanism for specifying what errors an
|
||
application or middleware should *not* trap (because they
|
||
indicate that the request should be aborted), and mechanisms
|
||
for servers, gateways, and middleware to handle exceptions
|
||
occurring at various phases of the response processing.
|
||
|
||
* Byte strings: future versions of Python may replace today's
|
||
8-bit strings with some kind of "byte array" type. Some sort
|
||
of future-proofing would be good to have, and strategies for
|
||
this should be discussed on Web-SIG and Python-Dev. Nearly
|
||
every string in WSGI is potentially affected by this, although
|
||
some contexts should perhaps continue to allow strings as long as
|
||
they're pure ASCII.
|
||
|
||
|
||
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:
|