1b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
2b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
3b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik"""Routines to generate WSGI responses"""
4b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
5b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik############################################################
6b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik## Headers
7b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik############################################################
8b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport warnings
9b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
10b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass HeaderDict(dict):
11b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
12b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
13b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    This represents response headers.  It handles the headers as a
14b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    dictionary, with case-insensitive keys.
15b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
16b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Also there is an ``.add(key, value)`` method, which sets the key,
17b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    or adds the value to the current value (turning it into a list if
18b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    necessary).
19b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
20b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    For passing to WSGI there is a ``.headeritems()`` method which is
21b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    like ``.items()`` but unpacks value that are lists.  It also
22b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    handles encoding -- all headers are encoded in ASCII (if they are
23b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    unicode).
24b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
25b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    @@: Should that encoding be ISO-8859-1 or UTF-8?  I'm not sure
26b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    what the spec says.
27b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
28b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
29b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __getitem__(self, key):
30b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dict.__getitem__(self, self.normalize(key))
31b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
32b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __setitem__(self, key, value):
33b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        dict.__setitem__(self, self.normalize(key), value)
34b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
35b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __delitem__(self, key):
36b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        dict.__delitem__(self, self.normalize(key))
37b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
38b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __contains__(self, key):
39b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dict.__contains__(self, self.normalize(key))
40b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
41b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    has_key = __contains__
42b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
43b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get(self, key, failobj=None):
44b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dict.get(self, self.normalize(key), failobj)
45b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
46b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def setdefault(self, key, failobj=None):
47b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dict.setdefault(self, self.normalize(key), failobj)
48b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
49b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def pop(self, key, *args):
50b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dict.pop(self, self.normalize(key), *args)
51b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
52b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def update(self, other):
53b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for key in other:
54b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self[self.normalize(key)] = other[key]
55b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
56b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def normalize(self, key):
57b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return str(key).lower().strip()
58b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
59b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def add(self, key, value):
60b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        key = self.normalize(key)
61b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if key in self:
62b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if isinstance(self[key], list):
63b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                self[key].append(value)
64b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
65b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                self[key] = [self[key], value]
66b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
67b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self[key] = value
68b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
69b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def headeritems(self):
70b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        result = []
71b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for key, value in self.items():
72b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if isinstance(value, list):
73b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                for v in value:
74b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    result.append((key, str(v)))
75b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
76b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                result.append((key, str(value)))
77b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return result
78b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
79b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #@classmethod
80b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def fromlist(cls, seq):
81b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self = cls()
82b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for name, value in seq:
83b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.add(name, value)
84b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self
85b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
86b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    fromlist = classmethod(fromlist)
87b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
88b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef has_header(headers, name):
89b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
90b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Is header named ``name`` present in headers?
91b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
92b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    name = name.lower()
93b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    for header, value in headers:
94b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if header.lower() == name:
95b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return True
96b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return False
97b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
98b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef header_value(headers, name):
99b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
100b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Returns the header's value, or None if no such header.  If a
101b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    header appears more than once, all the values of the headers
102b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    are joined with ','.   Note that this is consistent /w RFC 2616
103b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    section 4.2 which states:
104b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
105b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        It MUST be possible to combine the multiple header fields
106b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        into one "field-name: field-value" pair, without changing
107b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        the semantics of the message, by appending each subsequent
108b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        field-value to the first, each separated by a comma.
109b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
110b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    However, note that the original netscape usage of 'Set-Cookie',
111b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    especially in MSIE which contains an 'expires' date will is not
112b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    compatible with this particular concatination method.
113b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
114b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    name = name.lower()
115b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    result = [value for header, value in headers
116b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              if header.lower() == name]
117b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if result:
118b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return ','.join(result)
119b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
120b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return None
121b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
122b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef remove_header(headers, name):
123b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
124b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Removes the named header from the list of headers.  Returns the
125b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    value of that header, or None if no header found.  If multiple
126b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    headers are found, only the last one is returned.
127b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
128b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    name = name.lower()
129b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    i = 0
130b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    result = None
131b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    while i < len(headers):
132b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if headers[i][0].lower() == name:
133b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            result = headers[i][1]
134b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            del headers[i]
135b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            continue
136b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        i += 1
137b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return result
138b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
139b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef replace_header(headers, name, value):
140b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
141b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Updates the headers replacing the first occurance of the given name
142b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    with the value provided; asserting that no further occurances
143b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    happen. Note that this is _not_ the same as remove_header and then
144b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    append, as two distinct operations (del followed by an append) are
145b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    not atomic in a threaded environment. Returns the previous header
146b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    value for the provided name, if any.   Clearly one should not use
147b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    this function with ``set-cookie`` or other names that may have more
148b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    than one occurance in the headers.
149b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
150b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    name = name.lower()
151b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    i = 0
152b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    result = None
153b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    while i < len(headers):
154b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if headers[i][0].lower() == name:
155b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            assert not result, "two values for the header '%s' found" % name
156b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            result = headers[i][1]
157b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            headers[i] = (name, value)
158b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        i += 1
159b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if not result:
160b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        headers.append((name, value))
161b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return result
162b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
163b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
164b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik############################################################
165b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik## Deprecated methods
166b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik############################################################
167b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
168b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef error_body_response(error_code, message, __warn=True):
169b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
170b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Returns a standard HTML response page for an HTTP error.
171b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    **Note:** Deprecated
172b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
173b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if __warn:
174b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        warnings.warn(
175b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            'wsgilib.error_body_response is deprecated; use the '
176b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            'wsgi_application method on an HTTPException object '
177b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            'instead', DeprecationWarning, 2)
178b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return '''\
179b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik<html>
180b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik  <head>
181b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    <title>%(error_code)s</title>
182b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik  </head>
183b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik  <body>
184b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik  <h1>%(error_code)s</h1>
185b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik  %(message)s
186b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik  </body>
187b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik</html>''' % {
188b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'error_code': error_code,
189b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'message': message,
190b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        }
191b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
192b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
193b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef error_response(environ, error_code, message,
194b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                   debug_message=None, __warn=True):
195b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
196b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Returns the status, headers, and body of an error response.
197b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
198b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Use like:
199b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
200b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    .. code-block:: python
201b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
202b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        status, headers, body = wsgilib.error_response(
203b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            '301 Moved Permanently', 'Moved to <a href="%s">%s</a>'
204b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            % (url, url))
205b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        start_response(status, headers)
206b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return [body]
207b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
208b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    **Note:** Deprecated
209b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
210b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if __warn:
211b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        warnings.warn(
212b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            'wsgilib.error_response is deprecated; use the '
213b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            'wsgi_application method on an HTTPException object '
214b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            'instead', DeprecationWarning, 2)
215b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if debug_message and environ.get('paste.config', {}).get('debug'):
216b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        message += '\n\n<!-- %s -->' % debug_message
217b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    body = error_body_response(error_code, message, __warn=False)
218b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    headers = [('content-type', 'text/html'),
219b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik               ('content-length', str(len(body)))]
220b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return error_code, headers, body
221b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
222b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef error_response_app(error_code, message, debug_message=None,
223b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                       __warn=True):
224b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
225b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    An application that emits the given error response.
226b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
227b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    **Note:** Deprecated
228b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
229b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if __warn:
230b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        warnings.warn(
231b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            'wsgilib.error_response_app is deprecated; use the '
232b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            'wsgi_application method on an HTTPException object '
233b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            'instead', DeprecationWarning, 2)
234b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def application(environ, start_response):
235b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        status, headers, body = error_response(
236b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            environ, error_code, message,
237b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            debug_message=debug_message, __warn=False)
238b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        start_response(status, headers)
239b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return [body]
240b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return application
241