1b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# -*- coding: utf-8 -*-
2b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik"""
3b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    webapp2
4b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    =======
5b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
6b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Taking Google App Engine's webapp to the next level!
7b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
8b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :copyright: 2011 by tipfy.org.
9b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :license: Apache Sotware License, see LICENSE for details.
10b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik"""
11b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikfrom __future__ import with_statement
12b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
13b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport cgi
14b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport inspect
15b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport logging
16b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport os
17b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport re
18b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport sys
19b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport threading
20b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport traceback
21b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport urllib
22b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport urlparse
23b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikfrom wsgiref import handlers
24b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
25b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport webob
26b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikfrom webob import exc
27b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
28b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_webapp = _webapp_util = _local = None
29b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
30b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craiktry: # pragma: no cover
31b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # WebOb < 1.0 (App Engine Python 2.5).
32b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    from webob.statusreasons import status_reasons
33b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    from webob.headerdict import HeaderDict as BaseResponseHeaders
34b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikexcept ImportError: # pragma: no cover
35b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # WebOb >= 1.0.
36b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    from webob.util import status_reasons
37b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    from webob.headers import ResponseHeaders as BaseResponseHeaders
38b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
39b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# google.appengine.ext.webapp imports webapp2 in the
40b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# App Engine Python 2.7 runtime.
41b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikif os.environ.get('APPENGINE_RUNTIME') != 'python27': # pragma: no cover
42b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    try:
43b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        from google.appengine.ext import webapp as _webapp
44b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    except ImportError: # pragma: no cover
45b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # Running webapp2 outside of GAE.
46b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        pass
47b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
48b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craiktry: # pragma: no cover
49b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # Thread-local variables container.
50b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    from webapp2_extras import local
51b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    _local = local.Local()
52b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikexcept ImportError: # pragma: no cover
53b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    logging.warning("webapp2_extras.local is not available "
54b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    "so webapp2 won't be thread-safe!")
55b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
56b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
57b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik__version_info__ = (2, 5, 1)
58b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik__version__ = '.'.join(str(n) for n in __version_info__)
59b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
60b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: Base HTTP exception, set here as public interface.
61b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris CraikHTTPException = exc.HTTPException
62b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
63b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: Regex for route definitions.
64b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_route_re = re.compile(r"""
65b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    \<               # The exact character "<"
66b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    ([a-zA-Z_]\w*)?  # The optional variable name
67b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    (?:\:([^\>]*))?  # The optional :regex part
68b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    \>               # The exact character ">"
69b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """, re.VERBOSE)
70b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: Regex extract charset from environ.
71b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_charset_re = re.compile(r';\s*charset=([^;]*)', re.I)
72b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
73b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: To show exceptions in debug mode.
74b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_debug_template = """<html>
75b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik  <head>
76b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    <title>Internal Server Error</title>
77b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    <style>
78b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik      body {
79b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        padding: 20px;
80b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        font-family: arial, sans-serif;
81b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        font-size: 14px;
82b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik      }
83b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik      pre {
84b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        background: #F2F2F2;
85b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        padding: 10px;
86b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik      }
87b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    </style>
88b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik  </head>
89b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik  <body>
90b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    <h1>Internal Server Error</h1>
91b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    <p>The server has either erred or is incapable of performing
92b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    the requested operation.</p>
93b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    <pre>%s</pre>
94b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik  </body>
95b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik</html>"""
96b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
97b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# Set same default messages from webapp plus missing ones.
98b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_webapp_status_reasons = {
99b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    203: 'Non-Authoritative Information',
100b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    302: 'Moved Temporarily',
101b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    306: 'Unused',
102b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    408: 'Request Time-out',
103b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    414: 'Request-URI Too Large',
104b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    504: 'Gateway Time-out',
105b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    505: 'HTTP Version not supported',
106b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik}
107b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikstatus_reasons.update(_webapp_status_reasons)
108b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikfor code, message in _webapp_status_reasons.iteritems():
109b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    cls = exc.status_map.get(code)
110b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if cls:
111b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        cls.title = message
112b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
113b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
114b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass Request(webob.Request):
115b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Abstraction for an HTTP request.
116b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
117b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Most extra methods and attributes are ported from webapp. Check the
118b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    `WebOb documentation <WebOb>`_ for the ones not listed here.
119b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
120b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
121b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A reference to the active :class:`WSGIApplication` instance.
122b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    app = None
123b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A reference to the active :class:`Response` instance.
124b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    response = None
125b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A reference to the matched :class:`Route`.
126b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    route = None
127b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The matched route positional arguments.
128b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    route_args = None
129b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The matched route keyword arguments.
130b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    route_kwargs = None
131b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A dictionary to register objects used during the request lifetime.
132b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    registry = None
133b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # Attributes from webapp.
134b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    request_body_tempfile_limit = 0
135b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    uri = property(lambda self: self.url)
136b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    query = property(lambda self: self.query_string)
137b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
138b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, environ, *args, **kwargs):
139b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Constructs a Request object from a WSGI environment.
140b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
141b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param environ:
142b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A WSGI-compliant environment dictionary.
143b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
144b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if kwargs.get('charset') is None and not hasattr(webob, '__version__'):
145b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # webob 0.9 didn't have a __version__ attribute and also defaulted
146b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # to None rather than UTF-8 if no charset was provided. Providing a
147b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # default charset is required for backwards compatibility.
148b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            match = _charset_re.search(environ.get('CONTENT_TYPE', ''))
149b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if match:
150b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                charset = match.group(1).lower().strip().strip('"').strip()
151b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
152b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                charset = 'utf-8'
153b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            kwargs['charset'] = charset
154b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
155b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        super(Request, self).__init__(environ, *args, **kwargs)
156b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.registry = {}
157b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
158b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get(self, argument_name, default_value='', allow_multiple=False):
159b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns the query or POST argument with the given name.
160b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
161b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        We parse the query string and POST payload lazily, so this will be a
162b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        slower operation on the first call.
163b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
164b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param argument_name:
165b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The name of the query or POST argument.
166b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param default_value:
167b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The value to return if the given argument is not present.
168b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param allow_multiple:
169b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Return a list of values with the given name (deprecated).
170b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
171b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            If allow_multiple is False (which it is by default), we return
172b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            the first value with the given name given in the request. If it
173b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            is True, we always return a list.
174b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
175b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        param_value = self.get_all(argument_name)
176b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if allow_multiple:
177b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            logging.warning('allow_multiple is a deprecated param. '
178b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                'Please use the Request.get_all() method instead.')
179b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
180b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if len(param_value) > 0:
181b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if allow_multiple:
182b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return param_value
183b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
184b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return param_value[0]
185b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
186b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if allow_multiple and not default_value:
187b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return []
188b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
189b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return default_value
190b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
191b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get_all(self, argument_name, default_value=None):
192b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a list of query or POST arguments with the given name.
193b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
194b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        We parse the query string and POST payload lazily, so this will be a
195b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        slower operation on the first call.
196b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
197b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param argument_name:
198b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The name of the query or POST argument.
199b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param default_value:
200b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The value to return if the given argument is not present,
201b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            None may not be used as a default, if it is then an empty
202b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            list will be returned instead.
203b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
204b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A (possibly empty) list of values.
205b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
206b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if self.charset:
207b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            argument_name = argument_name.encode(self.charset)
208b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
209b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if default_value is None:
210b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            default_value = []
211b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
212b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        param_value = self.params.getall(argument_name)
213b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
214b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if param_value is None or len(param_value) == 0:
215b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return default_value
216b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
217b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for i in xrange(len(param_value)):
218b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if isinstance(param_value[i], cgi.FieldStorage):
219b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                param_value[i] = param_value[i].value
220b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
221b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return param_value
222b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
223b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def arguments(self):
224b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a list of the arguments provided in the query and/or POST.
225b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
226b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The return value is a list of strings.
227b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
228b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return list(set(self.params.keys()))
229b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
230b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get_range(self, name, min_value=None, max_value=None, default=0):
231b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Parses the given int argument, limiting it to the given range.
232b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
233b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param name:
234b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The name of the argument.
235b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param min_value:
236b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The minimum int value of the argument (if any).
237b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param max_value:
238b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The maximum int value of the argument (if any).
239b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param default:
240b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The default value of the argument if it is not given.
241b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
242b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            An int within the given range for the argument.
243b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
244b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        value = self.get(name, default)
245b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if value is None:
246b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return value
247b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
248b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        try:
249b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            value = int(value)
250b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        except ValueError:
251b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            value = default
252b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if value is not None:
253b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                if max_value is not None:
254b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    value = min(value, max_value)
255b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
256b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                if min_value is not None:
257b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    value = max(value, min_value)
258b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
259b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return value
260b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
261b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    @classmethod
262b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def blank(cls, path, environ=None, base_url=None,
263b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              headers=None, **kwargs): # pragma: no cover
264b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Adds parameters compatible with WebOb >= 1.0: POST and **kwargs."""
265b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        try:
266b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return super(Request, cls).blank(path, environ=environ,
267b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                             base_url=base_url,
268b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                             headers=headers, **kwargs)
269b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        except TypeError:
270b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if not kwargs:
271b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                raise
272b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
273b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        data = kwargs.pop('POST', None)
274b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if data is not None:
275b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            from cStringIO import StringIO
276b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            environ = environ or {}
277b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            environ['REQUEST_METHOD'] = 'POST'
278b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if hasattr(data, 'items'):
279b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                data = data.items()
280b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if not isinstance(data, str):
281b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                data = urllib.urlencode(data)
282b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            environ['wsgi.input'] = StringIO(data)
283b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            environ['webob.is_body_seekable'] = True
284b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            environ['CONTENT_LENGTH'] = str(len(data))
285b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            environ['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
286b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
287b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        base = super(Request, cls).blank(path, environ=environ,
288b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                         base_url=base_url, headers=headers)
289b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if kwargs:
290b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            obj = cls(base.environ, **kwargs)
291b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            obj.headers.update(base.headers)
292b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return obj
293b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
294b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return base
295b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
296b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
297b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass ResponseHeaders(BaseResponseHeaders):
298b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Implements methods from ``wsgiref.headers.Headers``, used by webapp."""
299b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
300b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    get_all = BaseResponseHeaders.getall
301b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
302b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def add_header(self, _name, _value, **_params):
303b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Extended header setting.
304b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
305b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        _name is the header field to add.  keyword arguments can be used to set
306b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        additional parameters for the header field, with underscores converted
307b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        to dashes.  Normally the parameter will be added as key="value" unless
308b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        value is None, in which case only the key will be added.
309b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
310b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Example::
311b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
312b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            h.add_header('content-disposition', 'attachment',
313b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                         filename='bud.gif')
314b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
315b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Note that unlike the corresponding 'email.message' method, this does
316b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        *not* handle '(charset, language, value)' tuples: all values must be
317b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        strings or None.
318b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
319b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        parts = []
320b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if _value is not None:
321b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            parts.append(_value)
322b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
323b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for k, v in _params.items():
324b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            k = k.replace('_', '-')
325b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if v is not None and len(v) > 0:
326b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                v = v.replace('\\', '\\\\').replace('"', r'\"')
327b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                parts.append('%s="%s"' % (k, v))
328b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
329b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                parts.append(k)
330b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
331b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.add(_name, '; '.join(parts))
332b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
333b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __str__(self):
334b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns the formatted headers ready for HTTP transmission."""
335b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return '\r\n'.join(['%s: %s' % v for v in self.items()] + ['', ''])
336b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
337b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
338b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass Response(webob.Response):
339b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Abstraction for an HTTP response.
340b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
341b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Most extra methods and attributes are ported from webapp. Check the
342b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    `WebOb documentation <WebOb>`_ for the ones not listed here.
343b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
344b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Differences from webapp.Response:
345b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
346b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    - ``out`` is not a ``StringIO.StringIO`` instance. Instead it is the
347b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik      response itself, as it has the method ``write()``.
348b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    - As in WebOb, ``status`` is the code plus message, e.g., '200 OK', while
349b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik      in webapp it is the integer code. The status code as an integer is
350b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik      available in ``status_int``, and the status message is available in
351b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik      ``status_message``.
352b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    - ``response.headers`` raises an exception when a key that doesn't exist
353b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik      is accessed or deleted, differently from ``wsgiref.headers.Headers``.
354b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
355b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
356b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Default charset as in webapp.
357b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    default_charset = 'utf-8'
358b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
359b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, *args, **kwargs):
360b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Constructs a response with the default settings."""
361b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        super(Response, self).__init__(*args, **kwargs)
362b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.headers['Cache-Control'] = 'no-cache'
363b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
364b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    @property
365b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def out(self):
366b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """A reference to the Response instance itself, for compatibility with
367b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        webapp only: webapp uses `Response.out.write()`, so we point `out` to
368b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        `self` and it will use `Response.write()`.
369b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
370b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self
371b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
372b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def write(self, text):
373b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Appends a text to the response body."""
374b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # webapp uses StringIO as Response.out, so we need to convert anything
375b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # that is not str or unicode to string to keep same behavior.
376b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not isinstance(text, basestring):
377b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            text = unicode(text)
378b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
379b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if isinstance(text, unicode) and not self.charset:
380b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.charset = self.default_charset
381b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
382b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        super(Response, self).write(text)
383b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
384b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _set_status(self, value):
385b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """The status string, including code and message."""
386b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        message = None
387b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # Accept long because urlfetch in App Engine returns codes as longs.
388b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if isinstance(value, (int, long)):
389b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            code = int(value)
390b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
391b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if isinstance(value, unicode):
392b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                # Status messages have to be ASCII safe, so this is OK.
393b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                value = str(value)
394b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
395b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if not isinstance(value, str):
396b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                raise TypeError(
397b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    'You must set status to a string or integer (not %s)' %
398b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    type(value))
399b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
400b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            parts = value.split(' ', 1)
401b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            code = int(parts[0])
402b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if len(parts) == 2:
403b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                message = parts[1]
404b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
405b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        message = message or Response.http_status_message(code)
406b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self._status = '%d %s' % (code, message)
407b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
408b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _get_status(self):
409b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self._status
410b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
411b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    status = property(_get_status, _set_status, doc=_set_status.__doc__)
412b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
413b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def set_status(self, code, message=None):
414b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Sets the HTTP status code of this response.
415b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
416b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param code:
417b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The HTTP status string to use
418b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param message:
419b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A status string. If none is given, uses the default from the
420b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            HTTP/1.1 specification.
421b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
422b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if message:
423b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.status = '%d %s' % (code, message)
424b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
425b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.status = code
426b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
427b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _get_status_message(self):
428b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """The response status message, as a string."""
429b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.status.split(' ', 1)[1]
430b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
431b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _set_status_message(self, message):
432b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.status = '%d %s' % (self.status_int, message)
433b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
434b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    status_message = property(_get_status_message, _set_status_message,
435b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                              doc=_get_status_message.__doc__)
436b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
437b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _get_headers(self):
438b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """The headers as a dictionary-like object."""
439b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if self._headers is None:
440b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self._headers = ResponseHeaders.view_list(self.headerlist)
441b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
442b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self._headers
443b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
444b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _set_headers(self, value):
445b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if hasattr(value, 'items'):
446b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            value = value.items()
447b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        elif not isinstance(value, list):
448b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise TypeError('Response headers must be a list or dictionary.')
449b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
450b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.headerlist = value
451b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self._headers = None
452b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
453b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    headers = property(_get_headers, _set_headers, doc=_get_headers.__doc__)
454b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
455b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def has_error(self):
456b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Indicates whether the response was an error response."""
457b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.status_int >= 400
458b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
459b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def clear(self):
460b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Clears all data written to the output stream so that it is empty."""
461b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.body = ''
462b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
463b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def wsgi_write(self, start_response):
464b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Writes this response using using the given WSGI function.
465b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
466b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This is only here for compatibility with ``webapp.WSGIApplication``.
467b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
468b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param start_response:
469b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The WSGI-compatible start_response function.
470b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
471b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if (self.headers.get('Cache-Control') == 'no-cache' and
472b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            not self.headers.get('Expires')):
473b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT'
474b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.headers['Content-Length'] = str(len(self.body))
475b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
476b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        write = start_response(self.status, self.headerlist)
477b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        write(self.body)
478b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
479b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    @staticmethod
480b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def http_status_message(code):
481b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns the default HTTP status message for the given code.
482b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
483b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param code:
484b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The HTTP code for which we want a message.
485b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
486b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        message = status_reasons.get(code)
487b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not message:
488b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise KeyError('Invalid HTTP status code: %d' % code)
489b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
490b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return message
491b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
492b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
493b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass RequestHandler(object):
494b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Base HTTP request handler.
495b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
496b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Implements most of ``webapp.RequestHandler`` interface.
497b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
498b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
499b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A :class:`Request` instance.
500b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    request = None
501b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A :class:`Response` instance.
502b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    response = None
503b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A :class:`WSGIApplication` instance.
504b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    app = None
505b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
506b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, request=None, response=None):
507b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Initializes this request handler with the given WSGI application,
508b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Request and Response.
509b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
510b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        When instantiated by ``webapp.WSGIApplication``, request and response
511b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        are not set on instantiation. Instead, initialize() is called right
512b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        after the handler is created to set them.
513b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
514b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Also in webapp dispatching is done by the WSGI app, while webapp2
515b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        does it here to allow more flexibility in extended classes: handlers
516b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        can wrap :meth:`dispatch` to check for conditions before executing the
517b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        requested method and/or post-process the response.
518b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
519b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        .. note::
520b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik           Parameters are optional only to support webapp's constructor which
521b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik           doesn't take any arguments. Consider them as required.
522b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
523b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param request:
524b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Request` instance.
525b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param response:
526b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Response` instance.
527b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
528b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.initialize(request, response)
529b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
530b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def initialize(self, request, response):
531b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Initializes this request handler with the given WSGI application,
532b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Request and Response.
533b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
534b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param request:
535b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Request` instance.
536b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param response:
537b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Response` instance.
538b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
539b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.request = request
540b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.response = response
541b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.app = WSGIApplication.active_instance
542b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
543b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def dispatch(self):
544b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Dispatches the request.
545b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
546b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This will first check if there's a handler_method defined in the
547b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        matched route, and if not it'll use the method correspondent to the
548b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        request method (``get()``, ``post()`` etc).
549b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
550b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        request = self.request
551b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        method_name = request.route.handler_method
552b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not method_name:
553b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            method_name = _normalize_handler_method(request.method)
554b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
555b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        method = getattr(self, method_name, None)
556b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if method is None:
557b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # 405 Method Not Allowed.
558b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # The response MUST include an Allow header containing a
559b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # list of valid methods for the requested resource.
560b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.6
561b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            valid = ', '.join(_get_handler_methods(self))
562b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.abort(405, headers=[('Allow', valid)])
563b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
564b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # The handler only receives *args if no named variables are set.
565b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        args, kwargs = request.route_args, request.route_kwargs
566b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if kwargs:
567b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            args = ()
568b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
569b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        try:
570b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return method(*args, **kwargs)
571b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        except Exception, e:
572b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return self.handle_exception(e, self.app.debug)
573b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
574b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def error(self, code):
575b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Clears the response and sets the given HTTP status code.
576b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
577b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This doesn't stop code execution; for this, use :meth:`abort`.
578b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
579b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param code:
580b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            HTTP status error code (e.g., 501).
581b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
582b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.response.status = code
583b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.response.clear()
584b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
585b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def abort(self, code, *args, **kwargs):
586b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Raises an :class:`HTTPException`.
587b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
588b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This stops code execution, leaving the HTTP exception to be handled
589b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        by an exception handler.
590b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
591b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param code:
592b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            HTTP status code (e.g., 404).
593b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param args:
594b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Positional arguments to be passed to the exception class.
595b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param kwargs:
596b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Keyword arguments to be passed to the exception class.
597b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
598b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        abort(code, *args, **kwargs)
599b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
600b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def redirect(self, uri, permanent=False, abort=False, code=None,
601b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                 body=None):
602b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Issues an HTTP redirect to the given relative URI.
603b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
604b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The arguments are described in :func:`redirect`.
605b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
606b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return redirect(uri, permanent=permanent, abort=abort, code=code,
607b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                        body=body, request=self.request,
608b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                        response=self.response)
609b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
610b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def redirect_to(self, _name, _permanent=False, _abort=False, _code=None,
611b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    _body=None, *args, **kwargs):
612b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Convenience method mixing :meth:`redirect` and :meth:`uri_for`.
613b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
614b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The arguments are described in :func:`redirect` and :func:`uri_for`.
615b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
616b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        uri = self.uri_for(_name, *args, **kwargs)
617b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.redirect(uri, permanent=_permanent, abort=_abort,
618b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                             code=_code, body=_body)
619b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
620b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def uri_for(self, _name, *args, **kwargs):
621b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a URI for a named :class:`Route`.
622b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
623b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        .. seealso:: :meth:`Router.build`.
624b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
625b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.app.router.build(self.request, _name, args, kwargs)
626b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # Alias.
627b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    url_for = uri_for
628b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
629b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def handle_exception(self, exception, debug):
630b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Called if this handler throws an exception during execution.
631b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
632b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The default behavior is to re-raise the exception to be handled by
633b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :meth:`WSGIApplication.handle_exception`.
634b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
635b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param exception:
636b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The exception that was thrown.
637b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param debug_mode:
638b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            True if the web application is running in debug mode.
639b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
640b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise
641b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
642b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
643b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass RedirectHandler(RequestHandler):
644b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Redirects to the given URI for all GET requests.
645b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
646b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    This is intended to be used when defining URI routes. You must provide at
647b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    least the keyword argument *url* in the route default values. Example::
648b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
649b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        def get_redirect_url(handler, *args, **kwargs):
650b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return handler.uri_for('new-route-name')
651b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
652b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        app = WSGIApplication([
653b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Route('/old-url', RedirectHandler, defaults={'_uri': '/new-url'}),
654b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Route('/other-old-url', RedirectHandler, defaults={
655b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                  '_uri': get_redirect_url}),
656b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        ])
657b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
658b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Based on idea from `Tornado`_.
659b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
660b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
661b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get(self, *args, **kwargs):
662b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Performs a redirect.
663b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
664b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Two keyword arguments can be passed through the URI route:
665b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
666b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        - **_uri**: A URI string or a callable that returns a URI. The callable
667b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik          is called passing ``(handler, *args, **kwargs)`` as arguments.
668b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        - **_code**: The redirect status code. Default is 301 (permanent
669b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik          redirect).
670b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
671b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        uri = kwargs.pop('_uri', '/')
672b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        permanent = kwargs.pop('_permanent', True)
673b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        code = kwargs.pop('_code', None)
674b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
675b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        func = getattr(uri, '__call__', None)
676b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if func:
677b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            uri = func(self, *args, **kwargs)
678b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
679b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.redirect(uri, permanent=permanent, code=code)
680b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
681b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
682b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass cached_property(object):
683b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """A decorator that converts a function into a lazy property.
684b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
685b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    The function wrapped is called the first time to retrieve the result
686b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    and then that calculated result is used the next time you access
687b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    the value::
688b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
689b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        class Foo(object):
690b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
691b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            @cached_property
692b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            def foo(self):
693b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                # calculate something important here
694b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return 42
695b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
696b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    The class has to have a `__dict__` in order for this property to
697b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    work.
698b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
699b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    .. note:: Implementation detail: this property is implemented as non-data
700b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik       descriptor.  non-data descriptors are only invoked if there is
701b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik       no entry with the same name in the instance's __dict__.
702b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik       this allows us to completely get rid of the access function call
703b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik       overhead.  If one choses to invoke __get__ by hand the property
704b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik       will still work as expected because the lookup logic is replicated
705b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik       in __get__ for manual invocation.
706b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
707b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    This class was ported from `Werkzeug`_ and `Flask`_.
708b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
709b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
710b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    _default_value = object()
711b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
712b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, func, name=None, doc=None):
713b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.__name__ = name or func.__name__
714b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.__module__ = func.__module__
715b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.__doc__ = doc or func.__doc__
716b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.func = func
717b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.lock = threading.RLock()
718b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
719b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __get__(self, obj, type=None):
720b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if obj is None:
721b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return self
722b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
723b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        with self.lock:
724b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            value = obj.__dict__.get(self.__name__, self._default_value)
725b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if value is self._default_value:
726b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                value = self.func(obj)
727b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                obj.__dict__[self.__name__] = value
728b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
729b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return value
730b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
731b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
732b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass BaseRoute(object):
733b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Interface for URI routes."""
734b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
735b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The regex template.
736b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    template = None
737b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Route name, used to build URIs.
738b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    name = None
739b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: True if this route is only used for URI generation and never matches.
740b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    build_only = False
741b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The handler or string in dotted notation to be lazily imported.
742b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    handler = None
743b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The custom handler method, if handler is a class.
744b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    handler_method = None
745b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The handler, imported and ready for dispatching.
746b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    handler_adapter = None
747b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
748b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, template, handler=None, name=None, build_only=False):
749b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Initializes this route.
750b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
751b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param template:
752b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A regex to be matched.
753b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param handler:
754b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A callable or string in dotted notation to be lazily imported,
755b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            e.g., ``'my.module.MyHandler'`` or ``'my.module.my_function'``.
756b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param name:
757b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The name of this route, used to build URIs based on it.
758b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param build_only:
759b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            If True, this route never matches and is used only to build URIs.
760b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
761b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if build_only and name is None:
762b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise ValueError(
763b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                "Route %r is build_only but doesn't have a name." % self)
764b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
765b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.template = template
766b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.handler = handler
767b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.name = name
768b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.build_only = build_only
769b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
770b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def match(self, request):
771b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Matches all routes against a request object.
772b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
773b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The first one that matches is returned.
774b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
775b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param request:
776b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Request` instance.
777b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
778b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A tuple ``(route, args, kwargs)`` if a route matched, or None.
779b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
780b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise NotImplementedError()
781b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
782b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def build(self, request, args, kwargs):
783b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a URI for this route.
784b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
785b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param request:
786b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The current :class:`Request` object.
787b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param args:
788b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Tuple of positional arguments to build the URI.
789b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param kwargs:
790b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Dictionary of keyword arguments to build the URI.
791b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
792b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            An absolute or relative URI.
793b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
794b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise NotImplementedError()
795b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
796b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get_routes(self):
797b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Generator to get all routes from a route.
798b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
799b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :yields:
800b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            This route or all nested routes that it contains.
801b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
802b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        yield self
803b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
804b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get_match_routes(self):
805b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Generator to get all routes that can be matched from a route.
806b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
807b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Match routes must implement :meth:`match`.
808b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
809b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :yields:
810b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            This route or all nested routes that can be matched.
811b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
812b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not self.build_only:
813b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            yield self
814b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
815b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get_build_routes(self):
816b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Generator to get all routes that can be built from a route.
817b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
818b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Build routes must implement :meth:`build`.
819b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
820b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :yields:
821b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A tuple ``(name, route)`` for all nested routes that can be built.
822b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
823b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if self.name is not None:
824b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            yield self.name, self
825b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
826b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
827b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass SimpleRoute(BaseRoute):
828b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """A route that is compatible with webapp's routing mechanism.
829b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
830b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    URI building is not implemented as webapp has rudimentar support for it,
831b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    and this is the most unknown webapp feature anyway.
832b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
833b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
834b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    @cached_property
835b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def regex(self):
836b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Lazy regex compiler."""
837b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not self.template.startswith('^'):
838b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.template = '^' + self.template
839b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
840b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not self.template.endswith('$'):
841b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.template += '$'
842b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
843b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return re.compile(self.template)
844b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
845b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def match(self, request):
846b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Matches this route against the current request.
847b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
848b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        .. seealso:: :meth:`BaseRoute.match`.
849b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
850b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        match = self.regex.match(urllib.unquote(request.path))
851b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if match:
852b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return self, match.groups(), {}
853b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
854b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __repr__(self):
855b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return '<SimpleRoute(%r, %r)>' % (self.template, self.handler)
856b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
857b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
858b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass Route(BaseRoute):
859b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """A route definition that maps a URI path to a handler.
860b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
861b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    The initial concept was based on `Another Do-It-Yourself Framework`_, by
862b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Ian Bicking.
863b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
864b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
865b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Default parameters values.
866b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    defaults = None
867b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Sequence of allowed HTTP methods. If not set, all methods are allowed.
868b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    methods = None
869b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Sequence of allowed URI schemes. If not set, all schemes are allowed.
870b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    schemes = None
871b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # Lazy properties extracted from the route template.
872b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    regex = None
873b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    reverse_template = None
874b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    variables = None
875b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    args_count = 0
876b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    kwargs_count = 0
877b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
878b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, template, handler=None, name=None, defaults=None,
879b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                 build_only=False, handler_method=None, methods=None,
880b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                 schemes=None):
881b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Initializes this route.
882b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
883b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param template:
884b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A route template to match against the request path. A template
885b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            can have variables enclosed by ``<>`` that define a name, a
886b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            regular expression or both. Examples:
887b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
888b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              =================  ==================================
889b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              Format             Example
890b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              =================  ==================================
891b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              ``<name>``         ``'/blog/<year>/<month>'``
892b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              ``<:regex>``       ``'/blog/<:\d{4}>/<:\d{2}>'``
893b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              ``<name:regex>``   ``'/blog/<year:\d{4}>/<month:\d{2}>'``
894b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              =================  ==================================
895b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
896b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The same template can mix parts with name, regular expression or
897b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            both.
898b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
899b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            If the name is set, the value of the matched regular expression
900b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            is passed as keyword argument to the handler. Otherwise it is
901b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            passed as positional argument.
902b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
903b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            If only the name is set, it will match anything except a slash.
904b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            So these routes are equivalent::
905b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
906b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                Route('/<user_id>/settings', handler=SettingsHandler,
907b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                      name='user-settings')
908b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                Route('/<user_id:[^/]+>/settings', handler=SettingsHandler,
909b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                      name='user-settings')
910b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
911b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            .. note::
912b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik               The handler only receives ``*args`` if no named variables are
913b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik               set. Otherwise, the handler only receives ``**kwargs``. This
914b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik               allows you to set regular expressions that are not captured:
915b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik               just mix named and unnamed variables and the handler will
916b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik               only receive the named ones.
917b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
918b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param handler:
919b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A callable or string in dotted notation to be lazily imported,
920b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            e.g., ``'my.module.MyHandler'`` or ``'my.module.my_function'``.
921b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            It is possible to define a method if the callable is a class,
922b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            separating it by a colon: ``'my.module.MyHandler:my_method'``.
923b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            This is a shortcut and has the same effect as defining the
924b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            `handler_method` parameter.
925b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param name:
926b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The name of this route, used to build URIs based on it.
927b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param defaults:
928b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Default or extra keywords to be returned by this route. Values
929b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            also present in the route variables are used to build the URI
930b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            when they are missing.
931b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param build_only:
932b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            If True, this route never matches and is used only to build URIs.
933b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param handler_method:
934b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The name of a custom handler method to be called, in case `handler`
935b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            is a class. If not defined, the default behavior is to call the
936b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            handler method correspondent to the HTTP request method in lower
937b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            case (e.g., `get()`, `post()` etc).
938b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param methods:
939b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A sequence of HTTP methods. If set, the route will only match if
940b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            the request method is allowed.
941b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param schemes:
942b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A sequence of URI schemes, e.g., ``['http']`` or ``['https']``.
943b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            If set, the route will only match requests with these schemes.
944b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
945b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        super(Route, self).__init__(template, handler=handler, name=name,
946b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                    build_only=build_only)
947b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.defaults = defaults or {}
948b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.methods = methods
949b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.schemes = schemes
950b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if isinstance(handler, basestring) and ':' in handler:
951b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if handler_method:
952b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                raise ValueError(
953b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    "If handler_method is defined in a Route, handler "
954b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    "can't have a colon (got %r)." % handler)
955b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
956b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                self.handler, self.handler_method = handler.rsplit(':', 1)
957b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
958b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.handler_method = handler_method
959b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
960b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    @cached_property
961b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def regex(self):
962b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Lazy route template parser."""
963b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        regex, self.reverse_template, self.args_count, self.kwargs_count, \
964b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.variables = _parse_route_template(self.template,
965b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                                   default_sufix='[^/]+')
966b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return regex
967b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
968b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def match(self, request):
969b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Matches this route against the current request.
970b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
971b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :raises:
972b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``exc.HTTPMethodNotAllowed`` if the route defines :attr:`methods`
973b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            and the request method isn't allowed.
974b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
975b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        .. seealso:: :meth:`BaseRoute.match`.
976b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
977b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        match = self.regex.match(urllib.unquote(request.path))
978b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not match or self.schemes and request.scheme not in self.schemes:
979b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return None
980b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
981b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if self.methods and request.method not in self.methods:
982b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # This will be caught by the router, so routes with different
983b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # methods can be tried.
984b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise exc.HTTPMethodNotAllowed()
985b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
986b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        args, kwargs = _get_route_variables(match, self.defaults.copy())
987b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self, args, kwargs
988b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
989b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def build(self, request, args, kwargs):
990b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a URI for this route.
991b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
992b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        .. seealso:: :meth:`Router.build`.
993b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
994b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        scheme = kwargs.pop('_scheme', None)
995b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        netloc = kwargs.pop('_netloc', None)
996b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        anchor = kwargs.pop('_fragment', None)
997b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        full = kwargs.pop('_full', False) and not scheme and not netloc
998b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
999b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if full or scheme or netloc:
1000b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            netloc = netloc or request.host
1001b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            scheme = scheme or request.scheme
1002b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1003b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        path, query = self._build(args, kwargs)
1004b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return _urlunsplit(scheme, netloc, path, query, anchor)
1005b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1006b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _build(self, args, kwargs):
1007b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns the URI path for this route.
1008b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1009b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
1010b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A tuple ``(path, kwargs)`` with the built URI path and extra
1011b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            keywords to be used as URI query arguments.
1012b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1013b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # Access self.regex just to set the lazy properties.
1014b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        regex = self.regex
1015b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        variables = self.variables
1016b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if self.args_count:
1017b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            for index, value in enumerate(args):
1018b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                key = '__%d__' % index
1019b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                if key in variables:
1020b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    kwargs[key] = value
1021b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1022b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        values = {}
1023b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for name, regex in variables.iteritems():
1024b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            value = kwargs.pop(name, self.defaults.get(name))
1025b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if value is None:
1026b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                raise KeyError('Missing argument "%s" to build URI.' % \
1027b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    name.strip('_'))
1028b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1029b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if not isinstance(value, basestring):
1030b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                value = str(value)
1031b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1032b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if not regex.match(value):
1033b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                raise ValueError('URI buiding error: Value "%s" is not '
1034b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    'supported for argument "%s".' % (value, name.strip('_')))
1035b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1036b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            values[name] = value
1037b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1038b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return (self.reverse_template % values, kwargs)
1039b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1040b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __repr__(self):
1041b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return '<Route(%r, %r, name=%r, defaults=%r, build_only=%r)>' % \
1042b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            (self.template, self.handler, self.name, self.defaults,
1043b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.build_only)
1044b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1045b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1046b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass BaseHandlerAdapter(object):
1047b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """A basic adapter to dispatch a handler.
1048b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1049b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    This is used when the handler is a simple function: it just calls the
1050b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    handler and returns the resulted response.
1051b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1052b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1053b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The handler to be dispatched.
1054b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    handler = None
1055b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1056b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, handler):
1057b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.handler = handler
1058b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1059b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __call__(self, request, response):
1060b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # The handler only receives *args if no named variables are set.
1061b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        args, kwargs = request.route_args, request.route_kwargs
1062b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if kwargs:
1063b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            args = ()
1064b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1065b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.handler(request, *args, **kwargs)
1066b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1067b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1068b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass WebappHandlerAdapter(BaseHandlerAdapter):
1069b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """An adapter to dispatch a ``webapp.RequestHandler``.
1070b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1071b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Like in webapp, the handler is constructed, then ``initialize()`` is
1072b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    called, then the method corresponding to the HTTP request method is called.
1073b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1074b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1075b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __call__(self, request, response):
1076b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        handler = self.handler()
1077b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        handler.initialize(request, response)
1078b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        method_name = _normalize_handler_method(request.method)
1079b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        method = getattr(handler, method_name, None)
1080b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not method:
1081b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            abort(501)
1082b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1083b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # The handler only receives *args if no named variables are set.
1084b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        args, kwargs = request.route_args, request.route_kwargs
1085b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if kwargs:
1086b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            args = ()
1087b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1088b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        try:
1089b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            method(*args, **kwargs)
1090b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        except Exception, e:
1091b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            handler.handle_exception(e, request.app.debug)
1092b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1093b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1094b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass Webapp2HandlerAdapter(BaseHandlerAdapter):
1095b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """An adapter to dispatch a ``webapp2.RequestHandler``.
1096b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1097b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    The handler is constructed then ``dispatch()`` is called.
1098b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1099b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1100b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __call__(self, request, response):
1101b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        handler = self.handler(request, response)
1102b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return handler.dispatch()
1103b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1104b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1105b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass Router(object):
1106b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """A URI router used to match, dispatch and build URIs."""
1107b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1108b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Class used when the route is set as a tuple.
1109b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    route_class = SimpleRoute
1110b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: All routes that can be matched.
1111b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    match_routes = None
1112b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: All routes that can be built.
1113b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    build_routes = None
1114b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Handler classes imported lazily.
1115b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    handlers = None
1116b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1117b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, routes=None):
1118b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Initializes the router.
1119b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1120b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param routes:
1121b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A sequence of :class:`Route` instances or, for simple routes,
1122b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            tuples ``(regex, handler)``.
1123b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1124b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.match_routes = []
1125b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.build_routes = {}
1126b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.handlers = {}
1127b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if routes:
1128b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            for route in routes:
1129b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                self.add(route)
1130b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1131b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def add(self, route):
1132b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Adds a route to this router.
1133b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1134b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param route:
1135b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Route` instance or, for simple routes, a tuple
1136b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``(regex, handler)``.
1137b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1138b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if isinstance(route, tuple):
1139b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # Exceptional case: simple routes defined as a tuple.
1140b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            route = self.route_class(*route)
1141b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1142b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for r in route.get_match_routes():
1143b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.match_routes.append(r)
1144b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1145b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for name, r in route.get_build_routes():
1146b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.build_routes[name] = r
1147b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1148b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def set_matcher(self, func):
1149b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Sets the function called to match URIs.
1150b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1151b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param func:
1152b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A function that receives ``(router, request)`` and returns
1153b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            a tuple ``(route, args, kwargs)`` if any route matches, or
1154b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise ``exc.HTTPNotFound`` if no route matched or
1155b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``exc.HTTPMethodNotAllowed`` if a route matched but the HTTP
1156b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            method was not allowed.
1157b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1158b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # Functions are descriptors, so bind it to this instance with __get__.
1159b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.match = func.__get__(self, self.__class__)
1160b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1161b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def set_builder(self, func):
1162b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Sets the function called to build URIs.
1163b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1164b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param func:
1165b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A function that receives ``(router, request, name, args, kwargs)``
1166b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            and returns a URI.
1167b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1168b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.build = func.__get__(self, self.__class__)
1169b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1170b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def set_dispatcher(self, func):
1171b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Sets the function called to dispatch the handler.
1172b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1173b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param func:
1174b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A function that receives ``(router, request, response)``
1175b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            and returns the value returned by the dispatched handler.
1176b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1177b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.dispatch = func.__get__(self, self.__class__)
1178b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1179b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def set_adapter(self, func):
1180b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Sets the function that adapts loaded handlers for dispatching.
1181b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1182b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param func:
1183b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A function that receives ``(router, handler)`` and returns a
1184b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            handler callable.
1185b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1186b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.adapt = func.__get__(self, self.__class__)
1187b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1188b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def default_matcher(self, request):
1189b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Matches all routes against a request object.
1190b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1191b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The first one that matches is returned.
1192b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1193b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param request:
1194b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Request` instance.
1195b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
1196b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A tuple ``(route, args, kwargs)`` if a route matched, or None.
1197b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :raises:
1198b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``exc.HTTPNotFound`` if no route matched or
1199b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``exc.HTTPMethodNotAllowed`` if a route matched but the HTTP
1200b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            method was not allowed.
1201b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1202b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        method_not_allowed = False
1203b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for route in self.match_routes:
1204b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            try:
1205b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                match = route.match(request)
1206b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                if match:
1207b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    return match
1208b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            except exc.HTTPMethodNotAllowed:
1209b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                method_not_allowed = True
1210b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1211b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if method_not_allowed:
1212b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise exc.HTTPMethodNotAllowed()
1213b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1214b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise exc.HTTPNotFound()
1215b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1216b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def default_builder(self, request, name, args, kwargs):
1217b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a URI for a named :class:`Route`.
1218b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1219b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param request:
1220b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The current :class:`Request` object.
1221b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param name:
1222b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The route name.
1223b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param args:
1224b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Tuple of positional arguments to build the URI. All positional
1225b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            variables defined in the route must be passed and must conform
1226b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            to the format set in the route. Extra arguments are ignored.
1227b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param kwargs:
1228b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Dictionary of keyword arguments to build the URI. All variables
1229b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            not set in the route default values must be passed and must
1230b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            conform to the format set in the route. Extra keywords are
1231b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            appended as a query string.
1232b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1233b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A few keywords have special meaning:
1234b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1235b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - **_full**: If True, builds an absolute URI.
1236b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - **_scheme**: URI scheme, e.g., `http` or `https`. If defined,
1237b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              an absolute URI is always returned.
1238b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - **_netloc**: Network location, e.g., `www.google.com`. If
1239b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              defined, an absolute URI is always returned.
1240b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - **_fragment**: If set, appends a fragment (or "anchor") to the
1241b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik              generated URI.
1242b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
1243b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            An absolute or relative URI.
1244b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1245b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        route = self.build_routes.get(name)
1246b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if route is None:
1247b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise KeyError('Route named %r is not defined.' % name)
1248b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1249b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return route.build(request, args, kwargs)
1250b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1251b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def default_dispatcher(self, request, response):
1252b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Dispatches a handler.
1253b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1254b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param request:
1255b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Request` instance.
1256b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param response:
1257b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Response` instance.
1258b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :raises:
1259b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``exc.HTTPNotFound`` if no route matched or
1260b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``exc.HTTPMethodNotAllowed`` if a route matched but the HTTP
1261b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            method was not allowed.
1262b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
1263b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The returned value from the handler.
1264b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1265b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        route, args, kwargs = rv = self.match(request)
1266b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        request.route, request.route_args, request.route_kwargs = rv
1267b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1268b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if route.handler_adapter is None:
1269b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            handler = route.handler
1270b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if isinstance(handler, basestring):
1271b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                if handler not in self.handlers:
1272b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    self.handlers[handler] = handler = import_string(handler)
1273b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                else:
1274b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    handler = self.handlers[handler]
1275b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1276b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            route.handler_adapter = self.adapt(handler)
1277b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1278b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return route.handler_adapter(request, response)
1279b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1280b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def default_adapter(self, handler):
1281b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Adapts a handler for dispatching.
1282b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1283b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Because handlers use or implement different dispatching mechanisms,
1284b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        they can be wrapped to use a unified API for dispatching.
1285b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This way webapp2 can support, for example, a :class:`RequestHandler`
1286b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        class and function views or, for compatibility purposes, a
1287b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        ``webapp.RequestHandler`` class. The adapters follow the same router
1288b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        dispatching API but dispatch each handler type differently.
1289b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1290b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param handler:
1291b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A handler callable.
1292b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
1293b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A wrapped handler callable.
1294b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1295b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if inspect.isclass(handler):
1296b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if _webapp and issubclass(handler, _webapp.RequestHandler):
1297b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                # Compatible with webapp.RequestHandler.
1298b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                adapter = WebappHandlerAdapter
1299b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
1300b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                # Default, compatible with webapp2.RequestHandler.
1301b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                adapter = Webapp2HandlerAdapter
1302b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
1303b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # A "view" function.
1304b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            adapter = BaseHandlerAdapter
1305b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1306b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return adapter(handler)
1307b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1308b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __repr__(self):
1309b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        routes = self.match_routes + [v for k, v in \
1310b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.build_routes.iteritems() if v not in self.match_routes]
1311b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1312b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return '<Router(%r)>' % routes
1313b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1314b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # Default matcher, builder, dispatcher and adapter.
1315b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    match = default_matcher
1316b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    build = default_builder
1317b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    dispatch = default_dispatcher
1318b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    adapt = default_adapter
1319b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1320b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1321b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass Config(dict):
1322b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """A simple configuration dictionary for the :class:`WSGIApplication`."""
1323b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1324b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Loaded configurations.
1325b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    loaded = None
1326b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1327b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, defaults=None):
1328b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        dict.__init__(self, defaults or ())
1329b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.loaded = []
1330b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1331b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def load_config(self, key, default_values=None, user_values=None,
1332b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    required_keys=None):
1333b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a configuration for a given key.
1334b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1335b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This can be used by objects that define a default configuration. It
1336b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        will update the app configuration with the default values the first
1337b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        time it is requested, and mark the key as loaded.
1338b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1339b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param key:
1340b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A configuration key.
1341b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param default_values:
1342b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Default values defined by a module or class.
1343b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param user_values:
1344b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            User values, used when an object can be initialized with
1345b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            configuration. This overrides the app configuration.
1346b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param required_keys:
1347b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Keys that can not be None.
1348b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :raises:
1349b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Exception, when a required key is not set or is None.
1350b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1351b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if key in self.loaded:
1352b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            config = self[key]
1353b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
1354b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            config = dict(default_values or ())
1355b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if key in self:
1356b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                config.update(self[key])
1357b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1358b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self[key] = config
1359b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.loaded.append(key)
1360b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if required_keys and not user_values:
1361b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                self._validate_required(key, config, required_keys)
1362b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1363b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if user_values:
1364b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            config = config.copy()
1365b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            config.update(user_values)
1366b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if required_keys:
1367b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                self._validate_required(key, config, required_keys)
1368b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1369b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return config
1370b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1371b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _validate_required(self, key, config, required_keys):
1372b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        missing = [k for k in required_keys if config.get(k) is None]
1373b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if missing:
1374b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise Exception(
1375b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                'Missing configuration keys for %r: %r.' % (key, missing))
1376b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1377b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1378b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass RequestContext(object):
1379b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Context for a single request.
1380b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1381b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    The context is responsible for setting and cleaning global variables for
1382b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    a request.
1383b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1384b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1385b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A :class:`WSGIApplication` instance.
1386b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    app = None
1387b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: WSGI environment dictionary.
1388b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    environ = None
1389b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1390b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, app, environ):
1391b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Initializes the request context.
1392b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1393b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param app:
1394b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            An :class:`WSGIApplication` instance.
1395b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param environ:
1396b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A WSGI environment dictionary.
1397b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1398b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.app = app
1399b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.environ = environ
1400b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1401b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __enter__(self):
1402b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Enters the request context.
1403b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1404b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
1405b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A tuple ``(request, response)``.
1406b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1407b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # Build request and response.
1408b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        request = self.app.request_class(self.environ)
1409b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        response = self.app.response_class()
1410b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # Make active app and response available through the request object.
1411b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        request.app = self.app
1412b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        request.response = response
1413b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # Register global variables.
1414b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.app.set_globals(app=self.app, request=request)
1415b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return request, response
1416b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1417b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __exit__(self, exc_type, exc_value, traceback):
1418b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Exits the request context.
1419b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1420b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This release the context locals except if an exception is caught
1421b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        in debug mode. In this case they are kept to be inspected.
1422b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1423b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if exc_type is None or not self.app.debug:
1424b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # Unregister global variables.
1425b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.app.clear_globals()
1426b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1427b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1428b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass WSGIApplication(object):
1429b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """A WSGI-compliant application."""
1430b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1431b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Allowed request methods.
1432b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    allowed_methods = frozenset(('GET', 'POST', 'HEAD', 'OPTIONS', 'PUT',
1433b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                 'DELETE', 'TRACE'))
1434b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Class used for the request object.
1435b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    request_class = Request
1436b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Class used for the response object.
1437b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    response_class = Response
1438b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Class used for the router object.
1439b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    router_class = Router
1440b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Class used for the request context object.
1441b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    request_context_class = RequestContext
1442b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Class used for the configuration object.
1443b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    config_class = Config
1444b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A general purpose flag to indicate development mode: if True, uncaught
1445b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: exceptions are raised instead of using ``HTTPInternalServerError``.
1446b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    debug = False
1447b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A :class:`Router` instance with all URIs registered for the application.
1448b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    router = None
1449b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A :class:`Config` instance with the application configuration.
1450b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    config = None
1451b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A dictionary to register objects used during the app lifetime.
1452b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    registry = None
1453b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A dictionary mapping HTTP error codes to callables to handle those
1454b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: HTTP exceptions. See :meth:`handle_exception`.
1455b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    error_handlers = None
1456b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Active :class:`WSGIApplication` instance. See :meth:`set_globals`.
1457b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    app = None
1458b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Active :class:`Request` instance. See :meth:`set_globals`.
1459b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    request = None
1460b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Same as :attr:`app`, for webapp compatibility. See :meth:`set_globals`.
1461b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    active_instance = None
1462b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1463b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, routes=None, debug=False, config=None):
1464b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Initializes the WSGI application.
1465b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1466b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param routes:
1467b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A sequence of :class:`Route` instances or, for simple routes,
1468b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            tuples ``(regex, handler)``.
1469b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param debug:
1470b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            True to enable debug mode, False otherwise.
1471b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param config:
1472b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A configuration dictionary for the application.
1473b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1474b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.debug = debug
1475b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.registry = {}
1476b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.error_handlers = {}
1477b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.set_globals(app=self)
1478b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.config = self.config_class(config)
1479b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.router = self.router_class(routes)
1480b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1481b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def set_globals(self, app=None, request=None):
1482b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Registers the global variables for app and request.
1483b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1484b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        If :mod:`webapp2_extras.local` is available the app and request
1485b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        class attributes are assigned to a proxy object that returns them
1486b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        using thread-local, making the application thread-safe. This can also
1487b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        be used in environments that don't support threading.
1488b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1489b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        If :mod:`webapp2_extras.local` is not available app and request will
1490b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        be assigned directly as class attributes. This should only be used in
1491b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        non-threaded environments (e.g., App Engine Python 2.5).
1492b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1493b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param app:
1494b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`WSGIApplication` instance.
1495b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param request:
1496b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Request` instance.
1497b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1498b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if _local is not None: # pragma: no cover
1499b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            _local.app = app
1500b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            _local.request = request
1501b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else: # pragma: no cover
1502b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            WSGIApplication.app = WSGIApplication.active_instance = app
1503b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            WSGIApplication.request = request
1504b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1505b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def clear_globals(self):
1506b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Clears global variables. See :meth:`set_globals`."""
1507b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if _local is not None: # pragma: no cover
1508b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            _local.__release_local__()
1509b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else: # pragma: no cover
1510b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            WSGIApplication.app = WSGIApplication.active_instance = None
1511b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            WSGIApplication.request = None
1512b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1513b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __call__(self, environ, start_response):
1514b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Called by WSGI when a request comes in.
1515b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1516b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param environ:
1517b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A WSGI environment.
1518b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param start_response:
1519b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A callable accepting a status code, a list of headers and an
1520b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            optional exception context to start the response.
1521b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
1522b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            An iterable with the response to return to the client.
1523b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1524b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        with self.request_context_class(self, environ) as (request, response):
1525b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            try:
1526b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                if request.method not in self.allowed_methods:
1527b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    # 501 Not Implemented.
1528b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    raise exc.HTTPNotImplemented()
1529b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1530b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                rv = self.router.dispatch(request, response)
1531b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                if rv is not None:
1532b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    response = rv
1533b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            except Exception, e:
1534b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                try:
1535b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    # Try to handle it with a custom error handler.
1536b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    rv = self.handle_exception(request, response, e)
1537b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    if rv is not None:
1538b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                        response = rv
1539b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                except HTTPException, e:
1540b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    # Use the HTTP exception as response.
1541b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    response = e
1542b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                except Exception, e:
1543b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    # Error wasn't handled so we have nothing else to do.
1544b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    response = self._internal_error(e)
1545b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1546b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            try:
1547b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return response(environ, start_response)
1548b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            except Exception, e:
1549b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return self._internal_error(e)(environ, start_response)
1550b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1551b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _internal_error(self, exception):
1552b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Last resource error for :meth:`__call__`."""
1553b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        logging.exception(exception)
1554b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if self.debug:
1555b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            lines = ''.join(traceback.format_exception(*sys.exc_info()))
1556b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            html = _debug_template % (cgi.escape(lines, quote=True))
1557b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return Response(body=html, status=500)
1558b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1559b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return exc.HTTPInternalServerError()
1560b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1561b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def handle_exception(self, request, response, e):
1562b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Handles a uncaught exception occurred in :meth:`__call__`.
1563b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1564b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Uncaught exceptions can be handled by error handlers registered in
1565b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :attr:`error_handlers`. This is a dictionary that maps HTTP status
1566b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        codes to callables that will handle the corresponding error code.
1567b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        If the exception is not an ``HTTPException``, the status code 500
1568b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        is used.
1569b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1570b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The error handlers receive (request, response, exception) and can be
1571b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        a callable or a string in dotted notation to be lazily imported.
1572b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1573b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        If no error handler is found, the exception is re-raised.
1574b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1575b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Based on idea from `Flask`_.
1576b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1577b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param request:
1578b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Request` instance.
1579b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param response:
1580b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Response` instance.
1581b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param e:
1582b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The uncaught exception.
1583b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
1584b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The returned value from the error handler.
1585b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1586b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if isinstance(e, HTTPException):
1587b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            code = e.code
1588b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
1589b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            code = 500
1590b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1591b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        handler = self.error_handlers.get(code)
1592b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if handler:
1593b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if isinstance(handler, basestring):
1594b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                self.error_handlers[code] = handler = import_string(handler)
1595b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1596b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return handler(request, response, e)
1597b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
1598b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # Re-raise it to be caught by the WSGI app.
1599b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise
1600b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1601b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def run(self, bare=False):
1602b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Runs this WSGI-compliant application in a CGI environment.
1603b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1604b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This uses functions provided by ``google.appengine.ext.webapp.util``,
1605b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if available: ``run_bare_wsgi_app`` and ``run_wsgi_app``.
1606b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1607b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Otherwise, it uses ``wsgiref.handlers.CGIHandler().run()``.
1608b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1609b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param bare:
1610b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            If True, doesn't add registered WSGI middleware: use
1611b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``run_bare_wsgi_app`` instead of ``run_wsgi_app``.
1612b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1613b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if _webapp_util:
1614b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if bare:
1615b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                _webapp_util.run_bare_wsgi_app(self)
1616b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
1617b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                _webapp_util.run_wsgi_app(self)
1618b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else: # pragma: no cover
1619b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            handlers.CGIHandler().run(self)
1620b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1621b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get_response(self, *args, **kwargs):
1622b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Creates a request and returns a response for this app.
1623b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1624b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This is a convenience for unit testing purposes. It receives
1625b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        parameters to build a request and calls the application, returning
1626b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        the resulting response::
1627b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1628b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            class HelloHandler(webapp2.RequestHandler):
1629b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                def get(self):
1630b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    self.response.write('Hello, world!')
1631b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1632b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            app = webapp2.WSGIapplication([('/', HelloHandler)])
1633b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1634b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # Test the app, passing parameters to build a request.
1635b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            response = app.get_response('/')
1636b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            assert response.status_int == 200
1637b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            assert response.body == 'Hello, world!'
1638b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1639b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param args:
1640b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Positional arguments to be passed to ``Request.blank()``.
1641b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param kwargs:
1642b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Keyword arguments to be passed to ``Request.blank()``.
1643b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
1644b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`Response` object.
1645b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
1646b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.request_class.blank(*args, **kwargs).get_response(self)
1647b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1648b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1649b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_import_string_error = """\
1650b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport_string() failed for %r. Possible reasons are:
1651b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1652b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik- missing __init__.py in a package;
1653b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik- package or module path not included in sys.path;
1654b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik- duplicated package or module name taking precedence in sys.path;
1655b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik- missing module, class, function or variable;
1656b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1657b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris CraikOriginal exception:
1658b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1659b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik%s: %s
1660b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1661b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris CraikDebugged import:
1662b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1663b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik%s"""
1664b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1665b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1666b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass ImportStringError(Exception):
1667b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Provides information about a failed :func:`import_string` attempt."""
1668b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1669b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: String in dotted notation that failed to be imported.
1670b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    import_name = None
1671b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Wrapped exception.
1672b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    exception = None
1673b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1674b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, import_name, exception):
1675b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.import_name = import_name
1676b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.exception = exception
1677b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        msg = _import_string_error
1678b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        name = ''
1679b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        tracked = []
1680b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for part in import_name.split('.'):
1681b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            name += (name and '.') + part
1682b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            imported = import_string(name, silent=True)
1683b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if imported:
1684b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                tracked.append((name, imported.__file__))
1685b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
1686b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                track = ['- %r found in %r.' % rv for rv in tracked]
1687b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                track.append('- %r not found.' % name)
1688b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                msg = msg % (import_name, exception.__class__.__name__,
1689b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                             str(exception), '\n'.join(track))
1690b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                break
1691b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1692b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Exception.__init__(self, msg)
1693b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1694b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1695b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_get_app_error = 'WSGIApplication global variable is not set.'
1696b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_get_request_error = 'Request global variable is not set.'
1697b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1698b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1699b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef get_app():
1700b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Returns the active app instance.
1701b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1702b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :returns:
1703b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A :class:`WSGIApplication` instance.
1704b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1705b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if _local:
1706b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        assert getattr(_local, 'app', None) is not None, _get_app_error
1707b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
1708b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        assert WSGIApplication.app is not None, _get_app_error
1709b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1710b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return WSGIApplication.app
1711b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1712b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1713b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef get_request():
1714b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Returns the active request instance.
1715b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1716b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :returns:
1717b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A :class:`Request` instance.
1718b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1719b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if _local:
1720b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        assert getattr(_local, 'request', None) is not None, _get_request_error
1721b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
1722b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        assert WSGIApplication.request is not None, _get_request_error
1723b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1724b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return WSGIApplication.request
1725b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1726b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1727b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef uri_for(_name, _request=None, *args, **kwargs):
1728b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """A standalone uri_for version that can be passed to templates.
1729b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1730b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    .. seealso:: :meth:`Router.build`.
1731b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1732b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    request = _request or get_request()
1733b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return request.app.router.build(request, _name, args, kwargs)
1734b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1735b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1736b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef redirect(uri, permanent=False, abort=False, code=None, body=None,
1737b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik             request=None, response=None):
1738b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Issues an HTTP redirect to the given relative URI.
1739b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1740b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    This won't stop code execution unless **abort** is True. A common
1741b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    practice is to return when calling this method::
1742b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1743b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return redirect('/some-path')
1744b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1745b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param uri:
1746b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A relative or absolute URI (e.g., ``'../flowers.html'``).
1747b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param permanent:
1748b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        If True, uses a 301 redirect instead of a 302 redirect.
1749b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param abort:
1750b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        If True, raises an exception to perform the redirect.
1751b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param code:
1752b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The redirect status code. Supported codes are 301, 302, 303, 305,
1753b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        and 307.  300 is not supported because it's not a real redirect
1754b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        and 304 because it's the answer for a request with defined
1755b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        ``If-Modified-Since`` headers.
1756b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param body:
1757b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Response body, if any.
1758b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param request:
1759b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Optional request object. If not set, uses :func:`get_request`.
1760b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param response:
1761b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Optional response object. If not set, a new response is created.
1762b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :returns:
1763b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A :class:`Response` instance.
1764b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1765b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if uri.startswith(('.', '/')):
1766b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        request = request or get_request()
1767b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        uri = str(urlparse.urljoin(request.url, uri))
1768b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1769b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if code is None:
1770b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if permanent:
1771b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            code = 301
1772b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
1773b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            code = 302
1774b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1775b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    assert code in (301, 302, 303, 305, 307), \
1776b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'Invalid redirect status code.'
1777b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1778b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if abort:
1779b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        _abort(code, headers=[('Location', uri)])
1780b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1781b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if response is None:
1782b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        request = request or get_request()
1783b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        response = request.app.response_class()
1784b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
1785b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        response.clear()
1786b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1787b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    response.headers['Location'] = uri
1788b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    response.status = code
1789b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if body is not None:
1790b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        response.write(body)
1791b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1792b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return response
1793b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1794b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1795b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef redirect_to(_name, _permanent=False, _abort=False, _code=None,
1796b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                _body=None, _request=None, _response=None, *args, **kwargs):
1797b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Convenience function mixing :func:`redirect` and :func:`uri_for`.
1798b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1799b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Issues an HTTP redirect to a named URI built using :func:`uri_for`.
1800b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1801b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param _name:
1802b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The route name to redirect to.
1803b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param args:
1804b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Positional arguments to build the URI.
1805b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param kwargs:
1806b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Keyword arguments to build the URI.
1807b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :returns:
1808b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A :class:`Response` instance.
1809b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1810b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    The other arguments are described in :func:`redirect`.
1811b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1812b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    uri = uri_for(_name, _request=_request, *args, **kwargs)
1813b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return redirect(uri, permanent=_permanent, abort=_abort, code=_code,
1814b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    body=_body, request=_request, response=_response)
1815b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1816b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1817b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef abort(code, *args, **kwargs):
1818b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Raises an ``HTTPException``.
1819b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1820b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param code:
1821b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        An integer that represents a valid HTTP status code.
1822b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param args:
1823b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Positional arguments to instantiate the exception.
1824b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param kwargs:
1825b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Keyword arguments to instantiate the exception.
1826b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1827b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    cls = exc.status_map.get(code)
1828b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if not cls:
1829b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise KeyError('No exception is defined for code %r.' % code)
1830b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1831b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    raise cls(*args, **kwargs)
1832b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1833b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1834b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef import_string(import_name, silent=False):
1835b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Imports an object based on a string in dotted notation.
1836b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1837b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Simplified version of the function with same name from `Werkzeug`_.
1838b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1839b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param import_name:
1840b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        String in dotted notation of the object to be imported.
1841b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param silent:
1842b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        If True, import or attribute errors are ignored and None is returned
1843b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        instead of raising an exception.
1844b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :returns:
1845b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The imported object.
1846b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1847b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    import_name = _to_utf8(import_name)
1848b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    try:
1849b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if '.' in import_name:
1850b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            module, obj = import_name.rsplit('.', 1)
1851b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return getattr(__import__(module, None, None, [obj]), obj)
1852b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
1853b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return __import__(import_name)
1854b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    except (ImportError, AttributeError), e:
1855b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not silent:
1856b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise ImportStringError(import_name, e), None, sys.exc_info()[2]
1857b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1858b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1859b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef _urlunsplit(scheme=None, netloc=None, path=None, query=None,
1860b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                fragment=None):
1861b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Like ``urlparse.urlunsplit``, but will escape values and urlencode and
1862b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    sort query arguments.
1863b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1864b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param scheme:
1865b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        URI scheme, e.g., `http` or `https`.
1866b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param netloc:
1867b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Network location, e.g., `localhost:8080` or `www.google.com`.
1868b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param path:
1869b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        URI path.
1870b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param query:
1871b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        URI query as an escaped string, or a dictionary or list of key-values
1872b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        tuples to build a query.
1873b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param fragment:
1874b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Fragment identifier, also known as "anchor".
1875b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :returns:
1876b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        An assembled absolute or relative URI.
1877b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1878b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if not scheme or not netloc:
1879b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        scheme = None
1880b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        netloc = None
1881b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1882b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if path:
1883b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        path = urllib.quote(_to_utf8(path))
1884b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1885b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if query and not isinstance(query, basestring):
1886b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if isinstance(query, dict):
1887b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            query = query.iteritems()
1888b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1889b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # Sort args: commonly needed to build signatures for services.
1890b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        query = urllib.urlencode(sorted(query))
1891b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1892b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if fragment:
1893b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        fragment = urllib.quote(_to_utf8(fragment))
1894b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1895b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
1896b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1897b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1898b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef _get_handler_methods(handler):
1899b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Returns a list of HTTP methods supported by a handler.
1900b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1901b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param handler:
1902b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A :class:`RequestHandler` instance.
1903b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :returns:
1904b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A list of HTTP methods supported by the handler.
1905b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
1906b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    methods = []
1907b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    for method in get_app().allowed_methods:
1908b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if getattr(handler, _normalize_handler_method(method), None):
1909b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            methods.append(method)
1910b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1911b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return methods
1912b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1913b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1914b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef _normalize_handler_method(method):
1915b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Transforms an HTTP method into a valid Python identifier."""
1916b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return method.lower().replace('-', '_')
1917b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1918b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1919b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef _to_utf8(value):
1920b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Encodes a unicode value to UTF-8 if not yet encoded."""
1921b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if isinstance(value, str):
1922b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return value
1923b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1924b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return value.encode('utf-8')
1925b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1926b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1927b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef _parse_route_template(template, default_sufix=''):
1928b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Lazy route template parser."""
1929b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    variables = {}
1930b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    reverse_template = pattern = ''
1931b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    args_count = last = 0
1932b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    for match in _route_re.finditer(template):
1933b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        part = template[last:match.start()]
1934b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        name = match.group(1)
1935b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        expr = match.group(2) or default_sufix
1936b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        last = match.end()
1937b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1938b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not name:
1939b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            name = '__%d__' % args_count
1940b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            args_count += 1
1941b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1942b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        pattern += '%s(?P<%s>%s)' % (re.escape(part), name, expr)
1943b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        reverse_template += '%s%%(%s)s' % (part, name)
1944b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        variables[name] = re.compile('^%s$' % expr)
1945b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1946b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    part = template[last:]
1947b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    kwargs_count = len(variables) - args_count
1948b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    reverse_template += part
1949b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    regex = re.compile('^%s%s$' % (pattern, re.escape(part)))
1950b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return regex, reverse_template, args_count, kwargs_count, variables
1951b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1952b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1953b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef _get_route_variables(match, default_kwargs=None):
1954b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Returns (args, kwargs) for a route match."""
1955b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    kwargs = default_kwargs or {}
1956b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    kwargs.update(match.groupdict())
1957b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if kwargs:
1958b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        args = tuple(value[1] for value in sorted(
1959b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            (int(key[2:-2]), kwargs.pop(key)) for key in kwargs.keys() \
1960b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if key.startswith('__') and key.endswith('__')))
1961b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
1962b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        args = ()
1963b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1964b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return args, kwargs
1965b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1966b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1967b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef _set_thread_safe_app():
1968b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Assigns WSGIApplication globals to a proxy pointing to thread-local."""
1969b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if _local is not None: # pragma: no cover
1970b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        WSGIApplication.app = WSGIApplication.active_instance = _local('app')
1971b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        WSGIApplication.request = _local('request')
1972b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1973b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1974b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris CraikRequest.ResponseClass = Response
1975b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris CraikResponse.RequestClass = Request
1976b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# Alias.
1977b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_abort = abort
1978b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# Thread-safety support.
1979b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_set_thread_safe_app()
1980b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
1981b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# Defer importing google.appengine.ext.webapp.util until every public symbol
1982b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# has been defined since google.appengine.ext.webapp in App Engine Python 2.7
1983b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# runtime imports this module to provide its public interface.
1984b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craiktry:
1985b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    from google.appengine.ext.webapp import util as _webapp_util
1986b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikexcept ImportError: # pragma: no cover
1987b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    pass
1988