Imported from SVN by Bitbucket
This commit is contained in:
240
Paste-1.7.5.1-py2.6.egg/paste/response.py
Executable file
240
Paste-1.7.5.1-py2.6.egg/paste/response.py
Executable file
@@ -0,0 +1,240 @@
|
||||
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
|
||||
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
|
||||
"""Routines to generate WSGI responses"""
|
||||
|
||||
############################################################
|
||||
## Headers
|
||||
############################################################
|
||||
import warnings
|
||||
|
||||
class HeaderDict(dict):
|
||||
|
||||
"""
|
||||
This represents response headers. It handles the headers as a
|
||||
dictionary, with case-insensitive keys.
|
||||
|
||||
Also there is an ``.add(key, value)`` method, which sets the key,
|
||||
or adds the value to the current value (turning it into a list if
|
||||
necessary).
|
||||
|
||||
For passing to WSGI there is a ``.headeritems()`` method which is
|
||||
like ``.items()`` but unpacks value that are lists. It also
|
||||
handles encoding -- all headers are encoded in ASCII (if they are
|
||||
unicode).
|
||||
|
||||
@@: Should that encoding be ISO-8859-1 or UTF-8? I'm not sure
|
||||
what the spec says.
|
||||
"""
|
||||
|
||||
def __getitem__(self, key):
|
||||
return dict.__getitem__(self, self.normalize(key))
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
dict.__setitem__(self, self.normalize(key), value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
dict.__delitem__(self, self.normalize(key))
|
||||
|
||||
def __contains__(self, key):
|
||||
return dict.__contains__(self, self.normalize(key))
|
||||
|
||||
has_key = __contains__
|
||||
|
||||
def get(self, key, failobj=None):
|
||||
return dict.get(self, self.normalize(key), failobj)
|
||||
|
||||
def setdefault(self, key, failobj=None):
|
||||
return dict.setdefault(self, self.normalize(key), failobj)
|
||||
|
||||
def pop(self, key, *args):
|
||||
return dict.pop(self, self.normalize(key), *args)
|
||||
|
||||
def update(self, other):
|
||||
for key in other:
|
||||
self[self.normalize(key)] = other[key]
|
||||
|
||||
def normalize(self, key):
|
||||
return str(key).lower().strip()
|
||||
|
||||
def add(self, key, value):
|
||||
key = self.normalize(key)
|
||||
if key in self:
|
||||
if isinstance(self[key], list):
|
||||
self[key].append(value)
|
||||
else:
|
||||
self[key] = [self[key], value]
|
||||
else:
|
||||
self[key] = value
|
||||
|
||||
def headeritems(self):
|
||||
result = []
|
||||
for key, value in self.items():
|
||||
if isinstance(value, list):
|
||||
for v in value:
|
||||
result.append((key, str(v)))
|
||||
else:
|
||||
result.append((key, str(value)))
|
||||
return result
|
||||
|
||||
#@classmethod
|
||||
def fromlist(cls, seq):
|
||||
self = cls()
|
||||
for name, value in seq:
|
||||
self.add(name, value)
|
||||
return self
|
||||
|
||||
fromlist = classmethod(fromlist)
|
||||
|
||||
def has_header(headers, name):
|
||||
"""
|
||||
Is header named ``name`` present in headers?
|
||||
"""
|
||||
name = name.lower()
|
||||
for header, value in headers:
|
||||
if header.lower() == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def header_value(headers, name):
|
||||
"""
|
||||
Returns the header's value, or None if no such header. If a
|
||||
header appears more than once, all the values of the headers
|
||||
are joined with ','. Note that this is consistent /w RFC 2616
|
||||
section 4.2 which states:
|
||||
|
||||
It MUST be possible to combine the multiple header fields
|
||||
into one "field-name: field-value" pair, without changing
|
||||
the semantics of the message, by appending each subsequent
|
||||
field-value to the first, each separated by a comma.
|
||||
|
||||
However, note that the original netscape usage of 'Set-Cookie',
|
||||
especially in MSIE which contains an 'expires' date will is not
|
||||
compatible with this particular concatination method.
|
||||
"""
|
||||
name = name.lower()
|
||||
result = [value for header, value in headers
|
||||
if header.lower() == name]
|
||||
if result:
|
||||
return ','.join(result)
|
||||
else:
|
||||
return None
|
||||
|
||||
def remove_header(headers, name):
|
||||
"""
|
||||
Removes the named header from the list of headers. Returns the
|
||||
value of that header, or None if no header found. If multiple
|
||||
headers are found, only the last one is returned.
|
||||
"""
|
||||
name = name.lower()
|
||||
i = 0
|
||||
result = None
|
||||
while i < len(headers):
|
||||
if headers[i][0].lower() == name:
|
||||
result = headers[i][1]
|
||||
del headers[i]
|
||||
continue
|
||||
i += 1
|
||||
return result
|
||||
|
||||
def replace_header(headers, name, value):
|
||||
"""
|
||||
Updates the headers replacing the first occurance of the given name
|
||||
with the value provided; asserting that no further occurances
|
||||
happen. Note that this is _not_ the same as remove_header and then
|
||||
append, as two distinct operations (del followed by an append) are
|
||||
not atomic in a threaded environment. Returns the previous header
|
||||
value for the provided name, if any. Clearly one should not use
|
||||
this function with ``set-cookie`` or other names that may have more
|
||||
than one occurance in the headers.
|
||||
"""
|
||||
name = name.lower()
|
||||
i = 0
|
||||
result = None
|
||||
while i < len(headers):
|
||||
if headers[i][0].lower() == name:
|
||||
assert not result, "two values for the header '%s' found" % name
|
||||
result = headers[i][1]
|
||||
headers[i] = (name, value)
|
||||
i += 1
|
||||
if not result:
|
||||
headers.append((name, value))
|
||||
return result
|
||||
|
||||
|
||||
############################################################
|
||||
## Deprecated methods
|
||||
############################################################
|
||||
|
||||
def error_body_response(error_code, message, __warn=True):
|
||||
"""
|
||||
Returns a standard HTML response page for an HTTP error.
|
||||
**Note:** Deprecated
|
||||
"""
|
||||
if __warn:
|
||||
warnings.warn(
|
||||
'wsgilib.error_body_response is deprecated; use the '
|
||||
'wsgi_application method on an HTTPException object '
|
||||
'instead', DeprecationWarning, 2)
|
||||
return '''\
|
||||
<html>
|
||||
<head>
|
||||
<title>%(error_code)s</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>%(error_code)s</h1>
|
||||
%(message)s
|
||||
</body>
|
||||
</html>''' % {
|
||||
'error_code': error_code,
|
||||
'message': message,
|
||||
}
|
||||
|
||||
|
||||
def error_response(environ, error_code, message,
|
||||
debug_message=None, __warn=True):
|
||||
"""
|
||||
Returns the status, headers, and body of an error response.
|
||||
|
||||
Use like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
status, headers, body = wsgilib.error_response(
|
||||
'301 Moved Permanently', 'Moved to <a href="%s">%s</a>'
|
||||
% (url, url))
|
||||
start_response(status, headers)
|
||||
return [body]
|
||||
|
||||
**Note:** Deprecated
|
||||
"""
|
||||
if __warn:
|
||||
warnings.warn(
|
||||
'wsgilib.error_response is deprecated; use the '
|
||||
'wsgi_application method on an HTTPException object '
|
||||
'instead', DeprecationWarning, 2)
|
||||
if debug_message and environ.get('paste.config', {}).get('debug'):
|
||||
message += '\n\n<!-- %s -->' % debug_message
|
||||
body = error_body_response(error_code, message, __warn=False)
|
||||
headers = [('content-type', 'text/html'),
|
||||
('content-length', str(len(body)))]
|
||||
return error_code, headers, body
|
||||
|
||||
def error_response_app(error_code, message, debug_message=None,
|
||||
__warn=True):
|
||||
"""
|
||||
An application that emits the given error response.
|
||||
|
||||
**Note:** Deprecated
|
||||
"""
|
||||
if __warn:
|
||||
warnings.warn(
|
||||
'wsgilib.error_response_app is deprecated; use the '
|
||||
'wsgi_application method on an HTTPException object '
|
||||
'instead', DeprecationWarning, 2)
|
||||
def application(environ, start_response):
|
||||
status, headers, body = error_response(
|
||||
environ, error_code, message,
|
||||
debug_message=debug_message, __warn=False)
|
||||
start_response(status, headers)
|
||||
return [body]
|
||||
return application
|
||||
Reference in New Issue
Block a user