Add a space after comma and remove trailing spaces.
This commit is contained in:
parent
2fc8df834e
commit
c29c921482
281
pep-0333.txt
281
pep-0333.txt
|
@ -167,7 +167,7 @@ other is a class::
|
|||
def simple_app(environ, start_response):
|
||||
"""Simplest possible application object"""
|
||||
status = '200 OK'
|
||||
response_headers = [('Content-type','text/plain')]
|
||||
response_headers = [('Content-type', 'text/plain')]
|
||||
start_response(status, response_headers)
|
||||
return ['Hello world!\n']
|
||||
|
||||
|
@ -179,7 +179,7 @@ other is a class::
|
|||
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,
|
||||
|
@ -193,7 +193,7 @@ other is a class::
|
|||
|
||||
def __iter__(self):
|
||||
status = '200 OK'
|
||||
response_headers = [('Content-type','text/plain')]
|
||||
response_headers = [('Content-type', 'text/plain')]
|
||||
self.start(status, response_headers)
|
||||
yield "Hello world!\n"
|
||||
|
||||
|
@ -204,9 +204,9 @@ The Server/Gateway Side
|
|||
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. Note that this simple
|
||||
example has limited error handling, because by default an uncaught
|
||||
exception will be dumped to ``sys.stderr`` and logged by the web
|
||||
as a function taking an application object. Note that this simple
|
||||
example has limited error handling, because by default an uncaught
|
||||
exception will be dumped to ``sys.stderr`` and logged by the web
|
||||
server.
|
||||
|
||||
::
|
||||
|
@ -218,12 +218,12 @@ server.
|
|||
environ = dict(os.environ.items())
|
||||
environ['wsgi.input'] = sys.stdin
|
||||
environ['wsgi.errors'] = sys.stderr
|
||||
environ['wsgi.version'] = (1,0)
|
||||
environ['wsgi.version'] = (1, 0)
|
||||
environ['wsgi.multithread'] = False
|
||||
environ['wsgi.multiprocess'] = True
|
||||
environ['wsgi.run_once'] = True
|
||||
environ['wsgi.run_once'] = True
|
||||
|
||||
if environ.get('HTTPS','off') in ('on','1'):
|
||||
if environ.get('HTTPS', 'off') in ('on', '1'):
|
||||
environ['wsgi.url_scheme'] = 'https'
|
||||
else:
|
||||
environ['wsgi.url_scheme'] = 'http'
|
||||
|
@ -246,7 +246,7 @@ server.
|
|||
sys.stdout.write(data)
|
||||
sys.stdout.flush()
|
||||
|
||||
def start_response(status,response_headers,exc_info=None):
|
||||
def start_response(status, response_headers, exc_info=None):
|
||||
if exc_info:
|
||||
try:
|
||||
if headers_sent:
|
||||
|
@ -256,8 +256,8 @@ server.
|
|||
exc_info = None # avoid dangling circular ref
|
||||
elif headers_set:
|
||||
raise AssertionError("Headers already set!")
|
||||
|
||||
headers_set[:] = [status,response_headers]
|
||||
|
||||
headers_set[:] = [status, response_headers]
|
||||
return write
|
||||
|
||||
result = application(environ, start_response)
|
||||
|
@ -268,7 +268,7 @@ server.
|
|||
if not headers_sent:
|
||||
write('') # send headers now if body was empty
|
||||
finally:
|
||||
if hasattr(result,'close'):
|
||||
if hasattr(result, 'close'):
|
||||
result.close()
|
||||
|
||||
|
||||
|
@ -294,13 +294,13 @@ such functions as:
|
|||
The presence of middleware in general is transparent to both the
|
||||
"server/gateway" and the "application/framework" sides of the
|
||||
interface, and should require no special support. A user who
|
||||
desires to incorporate middleware into an application simply
|
||||
provides the middleware component to the server, as if it were
|
||||
desires to incorporate middleware into an application simply
|
||||
provides the middleware component to the server, as if it were
|
||||
an application, and configures the middleware component to
|
||||
invoke the application, as if the middleware component were a
|
||||
server. Of course, the "application" that the middleware wraps
|
||||
may in fact be another middleware component wrapping another
|
||||
application, and so on, creating what is referred to as a
|
||||
application, and so on, creating what is referred to as a
|
||||
"middleware stack".
|
||||
|
||||
For the most part, middleware must conform to the restrictions
|
||||
|
@ -311,7 +311,7 @@ and these points will be noted in the specification.
|
|||
|
||||
Here is a (tongue-in-cheek) example of a middleware component that
|
||||
converts ``text/plain`` responses to pig latin, using Joe Strout's
|
||||
``piglatin.py``. (Note: a "real" middleware component would
|
||||
``piglatin.py``. (Note: a "real" middleware component would
|
||||
probably use a more robust way of checking the content type, and
|
||||
should also check for a content encoding. Also, this simple
|
||||
example ignores the possibility that a word might be split across
|
||||
|
@ -320,17 +320,18 @@ a block boundary.)
|
|||
::
|
||||
|
||||
from piglatin import piglatin
|
||||
|
||||
|
||||
class LatinIter:
|
||||
|
||||
"""Transform iterated output to piglatin, if it's okay to do so
|
||||
|
||||
|
||||
Note that the "okayness" can change until the application yields
|
||||
its first non-empty string, so 'transform_ok' has to be a mutable
|
||||
truth value."""
|
||||
truth value.
|
||||
"""
|
||||
|
||||
def __init__(self,result,transform_ok):
|
||||
if hasattr(result,'close'):
|
||||
def __init__(self, result, transform_ok):
|
||||
if hasattr(result, 'close'):
|
||||
self.close = result.close
|
||||
self._next = iter(result).next
|
||||
self.transform_ok = transform_ok
|
||||
|
@ -347,31 +348,31 @@ a block boundary.)
|
|||
class Latinator:
|
||||
|
||||
# by default, don't transform output
|
||||
transform = False
|
||||
transform = False
|
||||
|
||||
def __init__(self, application):
|
||||
self.application = application
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
|
||||
|
||||
transform_ok = []
|
||||
|
||||
def start_latin(status,response_headers,exc_info=None):
|
||||
|
||||
def start_latin(status, response_headers, exc_info=None):
|
||||
|
||||
# Reset ok flag, in case this is a repeat call
|
||||
transform_ok[:]=[]
|
||||
transform_ok[:] = []
|
||||
|
||||
for name,value in response_headers:
|
||||
if name.lower()=='content-type' and value=='text/plain':
|
||||
for name, value in response_headers:
|
||||
if name.lower() == 'content-type' and value == 'text/plain':
|
||||
transform_ok.append(True)
|
||||
# Strip content-length if present, else it'll be wrong
|
||||
response_headers = [(name,value)
|
||||
for name,value in response_headers
|
||||
if name.lower()<>'content-length'
|
||||
response_headers = [(name, value)
|
||||
for name, value in response_headers
|
||||
if name.lower() <> 'content-length'
|
||||
]
|
||||
break
|
||||
|
||||
write = start_response(status,response_headers,exc_info)
|
||||
|
||||
write = start_response(status, response_headers, exc_info)
|
||||
|
||||
if transform_ok:
|
||||
def write_latin(data):
|
||||
|
@ -380,7 +381,7 @@ a block boundary.)
|
|||
else:
|
||||
return write
|
||||
|
||||
return LatinIter(self.application(environ,start_latin),transform_ok)
|
||||
return LatinIter(self.application(environ, start_latin), transform_ok)
|
||||
|
||||
|
||||
# Run foo_app under a Latinator's control, using the example CGI gateway
|
||||
|
@ -397,7 +398,7 @@ 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.)
|
||||
``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
|
||||
|
@ -414,25 +415,25 @@ of illustration, we have named these arguments ``status``,
|
|||
``response_headers``, and ``exc_info``, 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,response_headers)``).
|
||||
``start_response(status, response_headers)``).
|
||||
|
||||
The ``status`` parameter is a status string of the form
|
||||
``"999 Message here"``, and ``response_headers`` is a list of
|
||||
``(header_name,header_value)`` tuples describing the HTTP response
|
||||
``"999 Message here"``, and ``response_headers`` is a list of
|
||||
``(header_name, header_value)`` tuples describing the HTTP response
|
||||
header. The optional ``exc_info`` parameter is described below in the
|
||||
sections on `The start_response() Callable`_ and `Error Handling`_.
|
||||
It is used only when the application has trapped an error and is
|
||||
attempting to display an error message to the browser.
|
||||
|
||||
The ``start_response`` callable must return a ``write(body_data)``
|
||||
callable that takes one positional parameter: a string to be written
|
||||
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 if it
|
||||
can be avoided. See the `Buffering and Streaming`_ section for more
|
||||
details.)
|
||||
|
||||
When called by the server, the application object must return an
|
||||
When called by the server, the application object must return an
|
||||
iterable yielding zero or more strings. This can be accomplished in a
|
||||
variety of ways, such as by returning a list of strings, or by the
|
||||
application being a generator function that yields strings, or
|
||||
|
@ -440,10 +441,10 @@ by the application being a class whose instances are iterable.
|
|||
Regardless of how it is accomplished, the application object must
|
||||
always return an iterable yielding zero or more strings.
|
||||
|
||||
The server or gateway must transmit the yielded strings to the client
|
||||
in an unbuffered fashion, completing the transmission of each string
|
||||
The server or gateway must transmit the yielded strings to the client
|
||||
in an unbuffered fashion, completing the transmission of each string
|
||||
before requesting another one. (In other words, applications
|
||||
**should** perform their own buffering. See the `Buffering and
|
||||
**should** perform their own buffering. See the `Buffering and
|
||||
Streaming`_ section below for more on how application output must be
|
||||
handled.)
|
||||
|
||||
|
@ -456,21 +457,21 @@ other transformations for the purpose of implementing HTTP features
|
|||
such as byte-range transmission. See `Other HTTP Features`_, below,
|
||||
for more details.)
|
||||
|
||||
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__()``
|
||||
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. (See
|
||||
the `Handling the Content-Length Header`_ section for information
|
||||
on how this would normally be used.)
|
||||
|
||||
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
|
||||
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 complement PEP 325's
|
||||
generator support, and other common iterables with ``close()`` methods.
|
||||
|
||||
(Note: the application **must** invoke the ``start_response()``
|
||||
(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
|
||||
|
@ -480,8 +481,8 @@ before they begin iterating over the iterable.)
|
|||
Finally, servers and gateways **must not** directly use any other
|
||||
attributes of the iterable returned by the application, unless it is an
|
||||
instance of a type specific to that server or gateway, such as a "file
|
||||
wrapper" returned by ``wsgi.file_wrapper`` (see `Optional
|
||||
Platform-Specific File Handling`_). In the general case, only
|
||||
wrapper" returned by ``wsgi.file_wrapper`` (see `Optional
|
||||
Platform-Specific File Handling`_). In the general case, only
|
||||
attributes specified here, or accessed via e.g. the PEP 234 iteration
|
||||
APIs are acceptable.
|
||||
|
||||
|
@ -496,19 +497,19 @@ unless their value would be an empty string, in which case they
|
|||
**may** be omitted, except as otherwise noted below.
|
||||
|
||||
``REQUEST_METHOD``
|
||||
The HTTP request method, such as ``"GET"`` or ``"POST"``. This
|
||||
The HTTP request method, such as ``"GET"`` or ``"POST"``. This
|
||||
cannot ever be an empty string, and so is always required.
|
||||
|
||||
``SCRIPT_NAME``
|
||||
``SCRIPT_NAME``
|
||||
The initial portion of the request URL's "path" that corresponds to
|
||||
the application object, so that the application knows its virtual
|
||||
the application object, so that the application knows its virtual
|
||||
"location". This **may** be an empty string, if the application
|
||||
corresponds to the "root" of the server.
|
||||
corresponds to the "root" of the server.
|
||||
|
||||
``PATH_INFO``
|
||||
The remainder of the request URL's "path", designating the virtual
|
||||
The remainder of the request URL's "path", designating the virtual
|
||||
"location" of the request's target within the application. This
|
||||
**may** be an empty string, if the request URL targets the
|
||||
**may** be an empty string, if the request URL targets the
|
||||
application root and does not have a trailing slash.
|
||||
|
||||
``QUERY_STRING``
|
||||
|
@ -547,7 +548,7 @@ unless their value would be an empty string, in which case they
|
|||
absence of these variables should correspond with the presence or
|
||||
absence of the appropriate HTTP header in the request.
|
||||
|
||||
A server or gateway **should** attempt to provide as many other CGI
|
||||
A server or gateway **should** attempt to provide as many other CGI
|
||||
variables as are applicable. In addition, if SSL is in use, the server
|
||||
or gateway **should** also provide as many of the Apache SSL environment
|
||||
variables [5]_ as are applicable, such as ``HTTPS=on`` and
|
||||
|
@ -559,7 +560,7 @@ provide a meaningful ``DOCUMENT_ROOT`` or ``PATH_TRANSLATED``.)
|
|||
|
||||
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 variables they require, and
|
||||
**should** check for the presence of any 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
|
||||
|
@ -575,24 +576,24 @@ and **must** contain the following WSGI-defined variables:
|
|||
===================== ===============================================
|
||||
Variable Value
|
||||
===================== ===============================================
|
||||
``wsgi.version`` The tuple ``(1,0)``, representing WSGI
|
||||
``wsgi.version`` The tuple ``(1, 0)``, representing WSGI
|
||||
version 1.0.
|
||||
|
||||
``wsgi.url_scheme`` A string representing the "scheme" portion of
|
||||
the URL at which the application is being
|
||||
the URL at which the application is being
|
||||
invoked. Normally, this will have the value
|
||||
``"http"`` or ``"https"``, as appropriate.
|
||||
|
||||
``wsgi.input`` An input stream (file-like object) from which
|
||||
the HTTP request body can be read. (The server
|
||||
or gateway may perform reads on-demand as
|
||||
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 (file-like object) to which
|
||||
``wsgi.errors`` An output stream (file-like object) to which
|
||||
error output can be written, for the purpose of
|
||||
recording program or other errors in a
|
||||
standardized and possibly centralized location.
|
||||
|
@ -610,13 +611,13 @@ Variable Value
|
|||
or gateway may supply different error streams
|
||||
to different applications, if this is desired.
|
||||
|
||||
``wsgi.multithread`` This value should evaluate true if the
|
||||
``wsgi.multithread`` This value should evaluate true if the
|
||||
application object may be simultaneously
|
||||
invoked by another thread in the same process,
|
||||
and should evaluate false otherwise.
|
||||
|
||||
``wsgi.multiprocess`` This value should evaluate true if an
|
||||
equivalent application object may be
|
||||
``wsgi.multiprocess`` This value should evaluate true if an
|
||||
equivalent application object may be
|
||||
simultaneously invoked by another process,
|
||||
and should evaluate false otherwise.
|
||||
|
||||
|
@ -646,8 +647,8 @@ the following methods:
|
|||
Method Stream Notes
|
||||
=================== ========== ========
|
||||
``read(size)`` ``input`` 1
|
||||
``readline()`` ``input`` 1,2
|
||||
``readlines(hint)`` ``input`` 1,3
|
||||
``readline()`` ``input`` 1, 2
|
||||
``readlines(hint)`` ``input`` 1, 3
|
||||
``__iter__()`` ``input``
|
||||
``flush()`` ``errors`` 4
|
||||
``write(str)`` ``errors``
|
||||
|
@ -692,16 +693,16 @@ The ``start_response()`` Callable
|
|||
---------------------------------
|
||||
|
||||
The second parameter passed to the application object is a callable
|
||||
of the form ``start_response(status,response_headers,exc_info=None)``.
|
||||
of the form ``start_response(status, response_headers, exc_info=None)``.
|
||||
(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`_
|
||||
``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"``. That is, it is a string consisting of a
|
||||
Status-Code and a Reason-Phrase, in that order and separated by a
|
||||
or ``"404 Not Found"``. That is, it is a string consisting of a
|
||||
Status-Code and a Reason-Phrase, in that order and separated by a
|
||||
single space, with no surrounding whitespace or other characters.
|
||||
(See RFC 2616, Section 6.1.1 for more information.) The string
|
||||
**must not** contain control characters, and must not be terminated
|
||||
|
@ -733,11 +734,11 @@ examining application-supplied headers!)
|
|||
|
||||
Applications and middleware are forbidden from using HTTP/1.1
|
||||
"hop-by-hop" features or headers, any equivalent features in HTTP/1.0,
|
||||
or any headers that would affect the persistence of the client's
|
||||
or any headers that would affect the persistence of the client's
|
||||
connection to the web server. These features are the
|
||||
exclusive province of the actual web server, and a server or gateway
|
||||
**should** consider it a fatal error for an application to attempt
|
||||
sending them, and raise an error if they are supplied to
|
||||
sending them, and raise an error if they are supplied to
|
||||
``start_response()``. (For more specifics on "hop-by-hop" features and
|
||||
headers, please see the `Other HTTP Features`_ section below.)
|
||||
|
||||
|
@ -748,7 +749,7 @@ application return value that yields a non-empty string, or upon
|
|||
the application's first invocation of the ``write()`` callable. In
|
||||
other words, response headers must not be sent until there is actual
|
||||
body data available, or until the application's returned iterable is
|
||||
exhausted. (The only possible exception to this rule is if the
|
||||
exhausted. (The only possible exception to this rule is if the
|
||||
response headers explicitly include a ``Content-Length`` of zero.)
|
||||
|
||||
This delaying of response header transmission is to ensure that buffered
|
||||
|
@ -771,13 +772,13 @@ However, if ``exc_info`` is provided, and the HTTP headers have already
|
|||
been sent, ``start_response`` **must** raise an error, and **should**
|
||||
raise the ``exc_info`` tuple. That is::
|
||||
|
||||
raise exc_info[0],exc_info[1],exc_info[2]
|
||||
|
||||
raise exc_info[0], exc_info[1], exc_info[2]
|
||||
|
||||
This will re-raise the exception trapped by the application, and in
|
||||
principle should abort the application. (It is not safe for the
|
||||
principle should abort the application. (It is not safe for the
|
||||
application to attempt error output to the browser once the HTTP
|
||||
headers have already been sent.) The application **must not** trap
|
||||
any exceptions raised by ``start_response``, if it called
|
||||
any exceptions raised by ``start_response``, if it called
|
||||
``start_response`` with ``exc_info``. Instead, it should allow
|
||||
such exceptions to propagate back to the server or gateway. See
|
||||
`Error Handling`_ below, for more details.
|
||||
|
@ -790,12 +791,12 @@ current invocation of the application. (See the example CGI
|
|||
gateway above for an illustration of the correct logic.)
|
||||
|
||||
Note: servers, gateways, or middleware implementing ``start_response``
|
||||
**should** ensure that no reference is held to the ``exc_info``
|
||||
**should** ensure that no reference is held to the ``exc_info``
|
||||
parameter beyond the duration of the function's execution, to avoid
|
||||
creating a circular reference through the traceback and frames
|
||||
involved. The simplest way to do this is something like::
|
||||
|
||||
def start_response(status,response_headers,exc_info=None):
|
||||
def start_response(status, response_headers, exc_info=None):
|
||||
if exc_info:
|
||||
try:
|
||||
# do stuff w/exc_info here
|
||||
|
@ -833,7 +834,7 @@ dealing with the absence of ``Content-Length``.
|
|||
|
||||
(Note: applications and middleware **must not** apply any kind of
|
||||
``Transfer-Encoding`` to their output, such as chunking or gzipping;
|
||||
as "hop-by-hop" operations, these encodings are the province of the
|
||||
as "hop-by-hop" operations, these encodings are the province of the
|
||||
actual web server/gateway. See `Other HTTP Features`_ below, for
|
||||
more details.)
|
||||
|
||||
|
@ -842,7 +843,7 @@ Buffering and Streaming
|
|||
-----------------------
|
||||
|
||||
Generally speaking, applications will achieve the best throughput
|
||||
by buffering their (modestly-sized) output and sending it all at
|
||||
by buffering their (modestly-sized) output and sending it all at
|
||||
once. This is a common approach in existing frameworks such as
|
||||
Zope: the output is buffered in a StringIO or similar object, then
|
||||
transmitted all at once, along with the response headers.
|
||||
|
@ -850,37 +851,37 @@ transmitted all at once, along with the response headers.
|
|||
The corresponding approach in WSGI is for the application to simply
|
||||
return a single-element iterable (such as a list) containing the
|
||||
response body as a single string. This is the recommended approach
|
||||
for the vast majority of application functions, that render
|
||||
for the vast majority of application functions, that render
|
||||
HTML pages whose text easily fits in memory.
|
||||
|
||||
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
|
||||
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 will usually return an iterator (often
|
||||
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
|
||||
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, gateways, and middleware **must not** delay the
|
||||
WSGI servers, gateways, and middleware **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 or middleware may provide this guarantee in one of
|
||||
three ways:
|
||||
|
||||
1. Send the entire block to the operating system (and request
|
||||
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.
|
||||
|
||||
|
||||
3. (Middleware only) send the entire block to its parent
|
||||
gateway/server
|
||||
|
||||
|
@ -901,7 +902,7 @@ needs to accumulate more data from the application before it can
|
|||
produce any output, it **must** yield an empty string.
|
||||
|
||||
To put this requirement another way, a middleware component **must
|
||||
yield at least one value** each time its underlying application
|
||||
yield at least one value** each time its underlying application
|
||||
yields a value. If the middleware cannot yield any other value,
|
||||
it must yield an empty string.
|
||||
|
||||
|
@ -914,7 +915,7 @@ return an iterable as soon as its underlying application returns
|
|||
an iterable. It is also forbidden for middleware to use the
|
||||
``write()`` callable to transmit data that is yielded by an
|
||||
underlying application. Middleware may only use their parent
|
||||
server's ``write()`` callable to transmit data that the
|
||||
server's ``write()`` callable to transmit data that the
|
||||
underlying application sent using a middleware-provided ``write()``
|
||||
callable.
|
||||
|
||||
|
@ -936,7 +937,7 @@ 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
|
||||
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 imperative
|
||||
streaming APIs. In general, applications should produce their
|
||||
|
@ -956,7 +957,7 @@ proceeds onward.
|
|||
An application **must** return an iterable object, even if it
|
||||
uses ``write()`` to produce all or part of its response body.
|
||||
The returned iterable **may** be empty (i.e. yield no non-empty
|
||||
strings), but if it *does* yield non-empty strings, that output
|
||||
strings), but if it *does* yield non-empty strings, that output
|
||||
must be treated normally by the server or gateway (i.e., it must be
|
||||
sent or queued immediately). Applications **must not** invoke
|
||||
``write()`` from within their return iterable, and therefore any
|
||||
|
@ -970,7 +971,7 @@ Unicode Issues
|
|||
HTTP does not directly support Unicode, and neither does this
|
||||
interface. All encoding/decoding must be handled by the application;
|
||||
all strings passed to or from the server must be standard Python byte
|
||||
strings, not Unicode objects. The result of using a Unicode object
|
||||
strings, not Unicode objects. The result of using a Unicode object
|
||||
where a string object is required, is undefined.
|
||||
|
||||
Note also that strings passed to ``start_response()`` as a status or
|
||||
|
@ -980,9 +981,9 @@ MIME encoding.
|
|||
|
||||
On Python platforms where the ``str`` or ``StringType`` type is in
|
||||
fact Unicode-based (e.g. Jython, IronPython, Python 3000, etc.), all
|
||||
"strings" referred to in this specification must contain only
|
||||
"strings" referred to in this specification must contain only
|
||||
code points representable in ISO-8859-1 encoding (``\u0000`` through
|
||||
``\u00FF``, inclusive). It is a fatal error for an application to
|
||||
``\u00FF``, inclusive). It is a fatal error for an application to
|
||||
supply strings containing any other Unicode character or code point.
|
||||
Similarly, servers and gateways **must not** supply
|
||||
strings to an application containing any other Unicode characters.
|
||||
|
@ -1012,33 +1013,33 @@ of its use::
|
|||
try:
|
||||
# regular application code here
|
||||
status = "200 Froody"
|
||||
response_headers = [("content-type","text/plain")]
|
||||
response_headers = [("content-type", "text/plain")]
|
||||
start_response(status, response_headers)
|
||||
return ["normal body goes here"]
|
||||
return ["normal body goes here"]
|
||||
except:
|
||||
# XXX should trap runtime issues like MemoryError, KeyboardInterrupt
|
||||
# in a separate handler before this bare 'except:'...
|
||||
status = "500 Oops"
|
||||
response_headers = [("content-type","text/plain")]
|
||||
response_headers = [("content-type", "text/plain")]
|
||||
start_response(status, response_headers, sys.exc_info())
|
||||
return ["error body goes here"]
|
||||
|
||||
If no output has been written when an exception occurs, the call to
|
||||
``start_response`` will return normally, and the application will
|
||||
``start_response`` will return normally, and the application will
|
||||
return an error body to be sent to the browser. However, if any output
|
||||
has already been sent to the browser, ``start_response`` will reraise
|
||||
the provided exception. This exception **should not** be trapped by
|
||||
has already been sent to the browser, ``start_response`` will reraise
|
||||
the provided exception. This exception **should not** be trapped by
|
||||
the application, and so the application will abort. The server or
|
||||
gateway can then trap this (fatal) exception and abort the response.
|
||||
|
||||
Servers **should** trap and log any exception that aborts an
|
||||
application or the iteration of its return value. If a partial
|
||||
Servers **should** trap and log any exception that aborts an
|
||||
application or the iteration of its return value. If a partial
|
||||
response has already been written to the browser when an application
|
||||
error occurs, the server or gateway **may** attempt to add an error
|
||||
message to the output, if the already-sent headers indicate a
|
||||
``text/*`` content type that the server knows how to modify cleanly.
|
||||
|
||||
Some middleware may wish to provide additional exception handling
|
||||
Some middleware may wish to provide additional exception handling
|
||||
services, or intercept and replace application error messages. In
|
||||
such cases, middleware may choose to **not** re-raise the ``exc_info``
|
||||
supplied to ``start_response``, but instead raise a middleware-specific
|
||||
|
@ -1057,7 +1058,7 @@ long as application authors:
|
|||
HTTP 1.1 Expect/Continue
|
||||
------------------------
|
||||
|
||||
Servers and gateways that implement HTTP 1.1 **must** provide
|
||||
Servers and gateways that implement HTTP 1.1 **must** provide
|
||||
transparent support for HTTP 1.1's "expect/continue" mechanism. This
|
||||
may be done in any of several ways:
|
||||
|
||||
|
@ -1069,7 +1070,7 @@ may be done in any of several ways:
|
|||
response if/when the application first attempts to read from the
|
||||
input stream. The read request must then remain blocked until the
|
||||
client responds.
|
||||
|
||||
|
||||
3. Wait until the client decides that the server does not support
|
||||
expect/continue, and sends the request body on its own. (This
|
||||
is suboptimal, and is not recommended.)
|
||||
|
@ -1093,7 +1094,7 @@ a server should consider itself to be like an HTTP "gateway server",
|
|||
with the application being an HTTP "origin server". (See RFC 2616,
|
||||
section 1.3, for the definition of these terms.)
|
||||
|
||||
However, because WSGI servers and applications do not communicate via
|
||||
However, because WSGI servers and applications do not communicate via
|
||||
HTTP, what RFC 2616 calls "hop-by-hop" headers do not apply to WSGI
|
||||
internal communications. WSGI applications **must not** generate any
|
||||
"hop-by-hop" headers [4]_, attempt to use HTTP features that would
|
||||
|
@ -1103,7 +1104,7 @@ WSGI servers **must** handle any supported inbound "hop-by-hop" headers
|
|||
on their own, such as by decoding any inbound ``Transfer-Encoding``,
|
||||
including chunked encoding if applicable.
|
||||
|
||||
Applying these principles to a variety of HTTP features, it should be
|
||||
Applying these principles to a variety of HTTP features, it should be
|
||||
clear that a server **may** handle cache validation via the
|
||||
``If-None-Match`` and ``If-Modified-Since`` request headers and the
|
||||
``Last-Modified`` and ``ETag`` response headers. However, it is
|
||||
|
@ -1113,9 +1114,9 @@ the server/gateway is not required to do such validation.
|
|||
|
||||
Similarly, a server **may** re-encode or transport-encode an
|
||||
application's response, but the application **should** use a
|
||||
suitable content encoding on its own, and **must not** apply a
|
||||
suitable content encoding on its own, and **must not** apply a
|
||||
transport encoding. A server **may** transmit byte ranges of the
|
||||
application's response if requested by the client, and the
|
||||
application's response if requested by the client, and the
|
||||
application doesn't natively support byte ranges. Again, however,
|
||||
the application **should** perform this function on its own if desired.
|
||||
|
||||
|
@ -1124,7 +1125,7 @@ that every application must reimplement every HTTP feature; many HTTP
|
|||
features can be partially or fully implemented by middleware
|
||||
components, thus freeing both server and application authors from
|
||||
implementing the same features over and over again.
|
||||
|
||||
|
||||
|
||||
Thread Support
|
||||
--------------
|
||||
|
@ -1227,17 +1228,17 @@ principle can configure these externally to the server, or in the
|
|||
CGI case they may be able to be set via the server's configuration
|
||||
files.
|
||||
|
||||
Applications **should** try to keep such required variables to a
|
||||
minimum, since not all servers will support easy configuration of
|
||||
them. Of course, even in the worst case, persons deploying an
|
||||
Applications **should** try to keep such required variables to a
|
||||
minimum, since not all servers will support easy configuration of
|
||||
them. Of course, even in the worst case, persons deploying an
|
||||
application can create a script to supply the necessary configuration
|
||||
values::
|
||||
|
||||
from the_app import application
|
||||
|
||||
def new_app(environ,start_response):
|
||||
|
||||
def new_app(environ, start_response):
|
||||
environ['the_app.configval1'] = 'something'
|
||||
return application(environ,start_response)
|
||||
return application(environ, start_response)
|
||||
|
||||
But, most existing applications and frameworks will probably only need
|
||||
a single configuration value from ``environ``, to indicate the location
|
||||
|
@ -1267,8 +1268,8 @@ may do so using the following algorithm, contributed by Ian Bicking::
|
|||
if environ['SERVER_PORT'] != '80':
|
||||
url += ':' + environ['SERVER_PORT']
|
||||
|
||||
url += quote(environ.get('SCRIPT_NAME',''))
|
||||
url += quote(environ.get('PATH_INFO',''))
|
||||
url += quote(environ.get('SCRIPT_NAME', ''))
|
||||
url += quote(environ.get('PATH_INFO', ''))
|
||||
if environ.get('QUERY_STRING'):
|
||||
url += '?' + environ['QUERY_STRING']
|
||||
|
||||
|
@ -1317,7 +1318,7 @@ more complex:
|
|||
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
|
||||
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
|
||||
|
@ -1342,7 +1343,7 @@ into an iterable that it then returns, e.g.::
|
|||
return iter(lambda: filelike.read(block_size), '')
|
||||
|
||||
If the server or gateway supplies ``wsgi.file_wrapper``, it must be
|
||||
a callable that accepts one required positional parameter, and one
|
||||
a callable that accepts one required positional parameter, and one
|
||||
optional positional parameter. The first parameter is the file-like
|
||||
object to be sent, and the second parameter is an optional block
|
||||
size "suggestion" (which the server/gateway need not use). The
|
||||
|
@ -1367,7 +1368,7 @@ must occur **after** the application returns, and the server or
|
|||
gateway checks to see if a wrapper object was returned. (Again,
|
||||
because of the presence of middleware, error handlers, and the like,
|
||||
it is not guaranteed that any wrapper created will actually be used.)
|
||||
|
||||
|
||||
Apart from the handling of ``close()``, the semantics of returning a
|
||||
file wrapper from the application should be the same as if the
|
||||
application had returned ``iter(filelike.read, '')``. In other words,
|
||||
|
@ -1378,7 +1379,7 @@ reached.
|
|||
Of course, platform-specific file transmission APIs don't usually
|
||||
accept arbitrary "file-like" objects. Therefore, a
|
||||
``wsgi.file_wrapper`` has to introspect the supplied object for
|
||||
things such as a ``fileno()`` (Unix-like OSes) or a
|
||||
things such as a ``fileno()`` (Unix-like OSes) or a
|
||||
``java.nio.FileChannel`` (under Jython) in order to determine if
|
||||
the file-like object is suitable for use with the platform-specific
|
||||
API it supports.
|
||||
|
@ -1394,10 +1395,10 @@ file wrapper class, suitable for old (pre 2.2) and new Pythons alike::
|
|||
def __init__(self, filelike, blksize=8192):
|
||||
self.filelike = filelike
|
||||
self.blksize = blksize
|
||||
if hasattr(filelike,'close'):
|
||||
if hasattr(filelike, 'close'):
|
||||
self.close = filelike.close
|
||||
|
||||
def __getitem__(self,key):
|
||||
|
||||
def __getitem__(self, key):
|
||||
data = self.filelike.read(self.blksize)
|
||||
if data:
|
||||
return data
|
||||
|
@ -1408,9 +1409,9 @@ access to a platform-specific API::
|
|||
|
||||
environ['wsgi.file_wrapper'] = FileWrapper
|
||||
result = application(environ, start_response)
|
||||
|
||||
|
||||
try:
|
||||
if isinstance(result,FileWrapper):
|
||||
if isinstance(result, FileWrapper):
|
||||
# check if result.filelike is usable w/platform-specific
|
||||
# API, and if so, use that API to transmit the result.
|
||||
# If not, fall through to normal iterable handling
|
||||
|
@ -1418,10 +1419,10 @@ access to a platform-specific API::
|
|||
|
||||
for data in result:
|
||||
# etc.
|
||||
|
||||
|
||||
finally:
|
||||
if hasattr(result,'close'):
|
||||
result.close()
|
||||
if hasattr(result, 'close'):
|
||||
result.close()
|
||||
|
||||
|
||||
Questions and Answers
|
||||
|
@ -1578,15 +1579,15 @@ or are on the PEP author's "to-do" list:
|
|||
* Should ``wsgi.input`` be an iterator instead of a file? This would
|
||||
help for asynchronous applications and chunked-encoding input
|
||||
streams.
|
||||
|
||||
|
||||
* Optional extensions are being discussed for pausing iteration of an
|
||||
application's ouptut until input is available or until a callback
|
||||
occurs.
|
||||
|
||||
|
||||
* Add a section about synchronous vs. asynchronous apps and servers,
|
||||
the relevant threading models, and issues/design goals in these
|
||||
areas.
|
||||
|
||||
|
||||
|
||||
Acknowledgements
|
||||
================
|
||||
|
@ -1608,7 +1609,7 @@ thoughtful feedback made this revised draft possible. Especially:
|
|||
function. His input also guided the design of the exception handling
|
||||
facilities, especially in the area of allowing for middleware that
|
||||
overrides application error messages.
|
||||
|
||||
|
||||
* Alan Kennedy, whose courageous attempts to implement WSGI-on-Jython
|
||||
(well before the spec was finalized) helped to shape the "supporting
|
||||
older versions of Python" section, as well as the optional
|
||||
|
@ -1617,7 +1618,7 @@ thoughtful feedback made this revised draft possible. Especially:
|
|||
* Mark Nottingham, who reviewed the spec extensively for issues with
|
||||
HTTP RFC compliance, especially with regard to HTTP/1.1 features that
|
||||
I didn't even know existed until he pointed them out.
|
||||
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
@ -1631,7 +1632,7 @@ References
|
|||
.. [3] "Chunked Transfer Coding" -- HTTP/1.1, section 3.6.1
|
||||
(http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1)
|
||||
|
||||
.. [4] "End-to-end and Hop-by-hop Headers" -- HTTP/1.1, Section 13.5.1
|
||||
.. [4] "End-to-end and Hop-by-hop Headers" -- HTTP/1.1, Section 13.5.1
|
||||
(http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1)
|
||||
|
||||
.. [5] mod_ssl Reference, "Environment Variables"
|
||||
|
|
Loading…
Reference in New Issue