web.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # Copyright 2009 Facebook
00004 #
00005 # Licensed under the Apache License, Version 2.0 (the "License"); you may
00006 # not use this file except in compliance with the License. You may obtain
00007 # a copy of the License at
00008 #
00009 #     http://www.apache.org/licenses/LICENSE-2.0
00010 #
00011 # Unless required by applicable law or agreed to in writing, software
00012 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
00014 # License for the specific language governing permissions and limitations
00015 # under the License.
00016 
00017 """``tornado.web`` provides a simple web framework with asynchronous
00018 features that allow it to scale to large numbers of open connections,
00019 making it ideal for `long polling
00020 <http://en.wikipedia.org/wiki/Push_technology#Long_polling>`_.
00021 
00022 Here is a simple "Hello, world" example app::
00023 
00024     import tornado.ioloop
00025     import tornado.web
00026 
00027     class MainHandler(tornado.web.RequestHandler):
00028         def get(self):
00029             self.write("Hello, world")
00030 
00031     if __name__ == "__main__":
00032         application = tornado.web.Application([
00033             (r"/", MainHandler),
00034         ])
00035         application.listen(8888)
00036         tornado.ioloop.IOLoop.instance().start()
00037 
00038 See the :doc:`guide` for additional information.
00039 
00040 Thread-safety notes
00041 -------------------
00042 
00043 In general, methods on `RequestHandler` and elsewhere in Tornado are
00044 not thread-safe.  In particular, methods such as
00045 `~RequestHandler.write()`, `~RequestHandler.finish()`, and
00046 `~RequestHandler.flush()` must only be called from the main thread.  If
00047 you use multiple threads it is important to use `.IOLoop.add_callback`
00048 to transfer control back to the main thread before finishing the
00049 request.
00050 
00051 """
00052 
00053 from __future__ import absolute_import, division, print_function, with_statement
00054 
00055 
00056 import base64
00057 import binascii
00058 import datetime
00059 import email.utils
00060 import functools
00061 import gzip
00062 import hashlib
00063 import hmac
00064 import mimetypes
00065 import numbers
00066 import os.path
00067 import re
00068 import stat
00069 import sys
00070 import threading
00071 import time
00072 import tornado
00073 import traceback
00074 import types
00075 
00076 from tornado.concurrent import Future, is_future
00077 from tornado import escape
00078 from tornado import gen
00079 from tornado import httputil
00080 from tornado import iostream
00081 from tornado import locale
00082 from tornado.log import access_log, app_log, gen_log
00083 from tornado import stack_context
00084 from tornado import template
00085 from tornado.escape import utf8, _unicode
00086 from tornado.util import bytes_type, import_object, ObjectDict, raise_exc_info, unicode_type, _websocket_mask
00087 
00088 try:
00089     from io import BytesIO  # python 3
00090 except ImportError:
00091     from cStringIO import StringIO as BytesIO  # python 2
00092 
00093 try:
00094     import Cookie  # py2
00095 except ImportError:
00096     import http.cookies as Cookie  # py3
00097 
00098 try:
00099     import urlparse  # py2
00100 except ImportError:
00101     import urllib.parse as urlparse  # py3
00102 
00103 try:
00104     from urllib import urlencode  # py2
00105 except ImportError:
00106     from urllib.parse import urlencode  # py3
00107 
00108 
00109 MIN_SUPPORTED_SIGNED_VALUE_VERSION = 1
00110 """The oldest signed value version supported by this version of Tornado.
00111 
00112 Signed values older than this version cannot be decoded.
00113 
00114 .. versionadded:: 3.2.1
00115 """
00116 
00117 MAX_SUPPORTED_SIGNED_VALUE_VERSION = 2
00118 """The newest signed value version supported by this version of Tornado.
00119 
00120 Signed values newer than this version cannot be decoded.
00121 
00122 .. versionadded:: 3.2.1
00123 """
00124 
00125 DEFAULT_SIGNED_VALUE_VERSION = 2
00126 """The signed value version produced by `.RequestHandler.create_signed_value`.
00127 
00128 May be overridden by passing a ``version`` keyword argument.
00129 
00130 .. versionadded:: 3.2.1
00131 """
00132 
00133 DEFAULT_SIGNED_VALUE_MIN_VERSION = 1
00134 """The oldest signed value accepted by `.RequestHandler.get_secure_cookie`.
00135 
00136 May be overrided by passing a ``min_version`` keyword argument.
00137 
00138 .. versionadded:: 3.2.1
00139 """
00140 
00141 
00142 class RequestHandler(object):
00143     """Subclass this class and define `get()` or `post()` to make a handler.
00144 
00145     If you want to support more methods than the standard GET/HEAD/POST, you
00146     should override the class variable ``SUPPORTED_METHODS`` in your
00147     `RequestHandler` subclass.
00148     """
00149     SUPPORTED_METHODS = ("GET", "HEAD", "POST", "DELETE", "PATCH", "PUT",
00150                          "OPTIONS")
00151 
00152     _template_loaders = {}  # {path: template.BaseLoader}
00153     _template_loader_lock = threading.Lock()
00154     _remove_control_chars_regex = re.compile(r"[\x00-\x08\x0e-\x1f]")
00155 
00156     def __init__(self, application, request, **kwargs):
00157         super(RequestHandler, self).__init__()
00158 
00159         self.application = application
00160         self.request = request
00161         self._headers_written = False
00162         self._finished = False
00163         self._auto_finish = True
00164         self._transforms = None  # will be set in _execute
00165         self._prepared_future = None
00166         self.path_args = None
00167         self.path_kwargs = None
00168         self.ui = ObjectDict((n, self._ui_method(m)) for n, m in
00169                              application.ui_methods.items())
00170         # UIModules are available as both `modules` and `_tt_modules` in the
00171         # template namespace.  Historically only `modules` was available
00172         # but could be clobbered by user additions to the namespace.
00173         # The template {% module %} directive looks in `_tt_modules` to avoid
00174         # possible conflicts.
00175         self.ui["_tt_modules"] = _UIModuleNamespace(self,
00176                                                     application.ui_modules)
00177         self.ui["modules"] = self.ui["_tt_modules"]
00178         self.clear()
00179         self.request.connection.set_close_callback(self.on_connection_close)
00180         self.initialize(**kwargs)
00181 
00182     def initialize(self):
00183         """Hook for subclass initialization.
00184 
00185         A dictionary passed as the third argument of a url spec will be
00186         supplied as keyword arguments to initialize().
00187 
00188         Example::
00189 
00190             class ProfileHandler(RequestHandler):
00191                 def initialize(self, database):
00192                     self.database = database
00193 
00194                 def get(self, username):
00195                     ...
00196 
00197             app = Application([
00198                 (r'/user/(.*)', ProfileHandler, dict(database=database)),
00199                 ])
00200         """
00201         pass
00202 
00203     @property
00204     def settings(self):
00205         """An alias for `self.application.settings <Application.settings>`."""
00206         return self.application.settings
00207 
00208     def head(self, *args, **kwargs):
00209         raise HTTPError(405)
00210 
00211     def get(self, *args, **kwargs):
00212         raise HTTPError(405)
00213 
00214     def post(self, *args, **kwargs):
00215         raise HTTPError(405)
00216 
00217     def delete(self, *args, **kwargs):
00218         raise HTTPError(405)
00219 
00220     def patch(self, *args, **kwargs):
00221         raise HTTPError(405)
00222 
00223     def put(self, *args, **kwargs):
00224         raise HTTPError(405)
00225 
00226     def options(self, *args, **kwargs):
00227         raise HTTPError(405)
00228 
00229     def prepare(self):
00230         """Called at the beginning of a request before  `get`/`post`/etc.
00231 
00232         Override this method to perform common initialization regardless
00233         of the request method.
00234 
00235         Asynchronous support: Decorate this method with `.gen.coroutine`
00236         or `.return_future` to make it asynchronous (the
00237         `asynchronous` decorator cannot be used on `prepare`).
00238         If this method returns a `.Future` execution will not proceed
00239         until the `.Future` is done.
00240 
00241         .. versionadded:: 3.1
00242            Asynchronous support.
00243         """
00244         pass
00245 
00246     def on_finish(self):
00247         """Called after the end of a request.
00248 
00249         Override this method to perform cleanup, logging, etc.
00250         This method is a counterpart to `prepare`.  ``on_finish`` may
00251         not produce any output, as it is called after the response
00252         has been sent to the client.
00253         """
00254         pass
00255 
00256     def on_connection_close(self):
00257         """Called in async handlers if the client closed the connection.
00258 
00259         Override this to clean up resources associated with
00260         long-lived connections.  Note that this method is called only if
00261         the connection was closed during asynchronous processing; if you
00262         need to do cleanup after every request override `on_finish`
00263         instead.
00264 
00265         Proxies may keep a connection open for a time (perhaps
00266         indefinitely) after the client has gone away, so this method
00267         may not be called promptly after the end user closes their
00268         connection.
00269         """
00270         if _has_stream_request_body(self.__class__):
00271             if not self.request.body.done():
00272                 self.request.body.set_exception(iostream.StreamClosedError())
00273 
00274     def clear(self):
00275         """Resets all headers and content for this response."""
00276         self._headers = httputil.HTTPHeaders({
00277             "Server": "TornadoServer/%s" % tornado.version,
00278             "Content-Type": "text/html; charset=UTF-8",
00279             "Date": httputil.format_timestamp(time.time()),
00280         })
00281         self.set_default_headers()
00282         self._write_buffer = []
00283         self._status_code = 200
00284         self._reason = httputil.responses[200]
00285 
00286     def set_default_headers(self):
00287         """Override this to set HTTP headers at the beginning of the request.
00288 
00289         For example, this is the place to set a custom ``Server`` header.
00290         Note that setting such headers in the normal flow of request
00291         processing may not do what you want, since headers may be reset
00292         during error handling.
00293         """
00294         pass
00295 
00296     def set_status(self, status_code, reason=None):
00297         """Sets the status code for our response.
00298 
00299         :arg int status_code: Response status code. If ``reason`` is ``None``,
00300             it must be present in `httplib.responses <http.client.responses>`.
00301         :arg string reason: Human-readable reason phrase describing the status
00302             code. If ``None``, it will be filled in from
00303             `httplib.responses <http.client.responses>`.
00304         """
00305         self._status_code = status_code
00306         if reason is not None:
00307             self._reason = escape.native_str(reason)
00308         else:
00309             try:
00310                 self._reason = httputil.responses[status_code]
00311             except KeyError:
00312                 raise ValueError("unknown status code %d", status_code)
00313 
00314     def get_status(self):
00315         """Returns the status code for our response."""
00316         return self._status_code
00317 
00318     def set_header(self, name, value):
00319         """Sets the given response header name and value.
00320 
00321         If a datetime is given, we automatically format it according to the
00322         HTTP specification. If the value is not a string, we convert it to
00323         a string. All header values are then encoded as UTF-8.
00324         """
00325         self._headers[name] = self._convert_header_value(value)
00326 
00327     def add_header(self, name, value):
00328         """Adds the given response header and value.
00329 
00330         Unlike `set_header`, `add_header` may be called multiple times
00331         to return multiple values for the same header.
00332         """
00333         self._headers.add(name, self._convert_header_value(value))
00334 
00335     def clear_header(self, name):
00336         """Clears an outgoing header, undoing a previous `set_header` call.
00337 
00338         Note that this method does not apply to multi-valued headers
00339         set by `add_header`.
00340         """
00341         if name in self._headers:
00342             del self._headers[name]
00343 
00344     _INVALID_HEADER_CHAR_RE = re.compile(br"[\x00-\x1f]")
00345 
00346     def _convert_header_value(self, value):
00347         if isinstance(value, bytes_type):
00348             pass
00349         elif isinstance(value, unicode_type):
00350             value = value.encode('utf-8')
00351         elif isinstance(value, numbers.Integral):
00352             # return immediately since we know the converted value will be safe
00353             return str(value)
00354         elif isinstance(value, datetime.datetime):
00355             return httputil.format_timestamp(value)
00356         else:
00357             raise TypeError("Unsupported header value %r" % value)
00358         # If \n is allowed into the header, it is possible to inject
00359         # additional headers or split the request. Also cap length to
00360         # prevent obviously erroneous values.
00361         if (len(value) > 4000 or
00362                 RequestHandler._INVALID_HEADER_CHAR_RE.search(value)):
00363             raise ValueError("Unsafe header value %r", value)
00364         return value
00365 
00366     _ARG_DEFAULT = []
00367 
00368     def get_argument(self, name, default=_ARG_DEFAULT, strip=True):
00369         """Returns the value of the argument with the given name.
00370 
00371         If default is not provided, the argument is considered to be
00372         required, and we raise a `MissingArgumentError` if it is missing.
00373 
00374         If the argument appears in the url more than once, we return the
00375         last value.
00376 
00377         The returned value is always unicode.
00378         """
00379         return self._get_argument(name, default, self.request.arguments, strip)
00380 
00381     def get_arguments(self, name, strip=True):
00382         """Returns a list of the arguments with the given name.
00383 
00384         If the argument is not present, returns an empty list.
00385 
00386         The returned values are always unicode.
00387         """
00388         return self._get_arguments(name, self.request.arguments, strip)
00389 
00390     def get_body_argument(self, name, default=_ARG_DEFAULT, strip=True):
00391         """Returns the value of the argument with the given name
00392         from the request body.
00393 
00394         If default is not provided, the argument is considered to be
00395         required, and we raise a `MissingArgumentError` if it is missing.
00396 
00397         If the argument appears in the url more than once, we return the
00398         last value.
00399 
00400         The returned value is always unicode.
00401 
00402         .. versionadded:: 3.2
00403         """
00404         return self._get_argument(name, default, self.request.body_arguments, strip)
00405 
00406     def get_body_arguments(self, name, strip=True):
00407         """Returns a list of the body arguments with the given name.
00408 
00409         If the argument is not present, returns an empty list.
00410 
00411         The returned values are always unicode.
00412 
00413         .. versionadded:: 3.2
00414         """
00415         return self._get_arguments(name, self.request.body_arguments, strip)
00416 
00417     def get_query_argument(self, name, default=_ARG_DEFAULT, strip=True):
00418         """Returns the value of the argument with the given name
00419         from the request query string.
00420 
00421         If default is not provided, the argument is considered to be
00422         required, and we raise a `MissingArgumentError` if it is missing.
00423 
00424         If the argument appears in the url more than once, we return the
00425         last value.
00426 
00427         The returned value is always unicode.
00428 
00429         .. versionadded:: 3.2
00430         """
00431         return self._get_argument(name, default, self.request.query_arguments, strip)
00432 
00433     def get_query_arguments(self, name, strip=True):
00434         """Returns a list of the query arguments with the given name.
00435 
00436         If the argument is not present, returns an empty list.
00437 
00438         The returned values are always unicode.
00439 
00440         .. versionadded:: 3.2
00441         """
00442         return self._get_arguments(name, self.request.query_arguments, strip)
00443 
00444     def _get_argument(self, name, default, source, strip=True):
00445         args = self._get_arguments(name, source, strip=strip)
00446         if not args:
00447             if default is self._ARG_DEFAULT:
00448                 raise MissingArgumentError(name)
00449             return default
00450         return args[-1]
00451 
00452     def _get_arguments(self, name, source, strip=True):
00453         values = []
00454         for v in source.get(name, []):
00455             v = self.decode_argument(v, name=name)
00456             if isinstance(v, unicode_type):
00457                 # Get rid of any weird control chars (unless decoding gave
00458                 # us bytes, in which case leave it alone)
00459                 v = RequestHandler._remove_control_chars_regex.sub(" ", v)
00460             if strip:
00461                 v = v.strip()
00462             values.append(v)
00463         return values
00464 
00465     def decode_argument(self, value, name=None):
00466         """Decodes an argument from the request.
00467 
00468         The argument has been percent-decoded and is now a byte string.
00469         By default, this method decodes the argument as utf-8 and returns
00470         a unicode string, but this may be overridden in subclasses.
00471 
00472         This method is used as a filter for both `get_argument()` and for
00473         values extracted from the url and passed to `get()`/`post()`/etc.
00474 
00475         The name of the argument is provided if known, but may be None
00476         (e.g. for unnamed groups in the url regex).
00477         """
00478         try:
00479             return _unicode(value)
00480         except UnicodeDecodeError:
00481             raise HTTPError(400, "Invalid unicode in %s: %r" %
00482                             (name or "url", value[:40]))
00483 
00484     @property
00485     def cookies(self):
00486         """An alias for `self.request.cookies <.httputil.HTTPServerRequest.cookies>`."""
00487         return self.request.cookies
00488 
00489     def get_cookie(self, name, default=None):
00490         """Gets the value of the cookie with the given name, else default."""
00491         if self.request.cookies is not None and name in self.request.cookies:
00492             return self.request.cookies[name].value
00493         return default
00494 
00495     def set_cookie(self, name, value, domain=None, expires=None, path="/",
00496                    expires_days=None, **kwargs):
00497         """Sets the given cookie name/value with the given options.
00498 
00499         Additional keyword arguments are set on the Cookie.Morsel
00500         directly.
00501         See http://docs.python.org/library/cookie.html#morsel-objects
00502         for available attributes.
00503         """
00504         # The cookie library only accepts type str, in both python 2 and 3
00505         name = escape.native_str(name)
00506         value = escape.native_str(value)
00507         if re.search(r"[\x00-\x20]", name + value):
00508             # Don't let us accidentally inject bad stuff
00509             raise ValueError("Invalid cookie %r: %r" % (name, value))
00510         if not hasattr(self, "_new_cookie"):
00511             self._new_cookie = Cookie.SimpleCookie()
00512         if name in self._new_cookie:
00513             del self._new_cookie[name]
00514         self._new_cookie[name] = value
00515         morsel = self._new_cookie[name]
00516         if domain:
00517             morsel["domain"] = domain
00518         if expires_days is not None and not expires:
00519             expires = datetime.datetime.utcnow() + datetime.timedelta(
00520                 days=expires_days)
00521         if expires:
00522             morsel["expires"] = httputil.format_timestamp(expires)
00523         if path:
00524             morsel["path"] = path
00525         for k, v in kwargs.items():
00526             if k == 'max_age':
00527                 k = 'max-age'
00528             morsel[k] = v
00529 
00530     def clear_cookie(self, name, path="/", domain=None):
00531         """Deletes the cookie with the given name.
00532 
00533         Due to limitations of the cookie protocol, you must pass the same
00534         path and domain to clear a cookie as were used when that cookie
00535         was set (but there is no way to find out on the server side
00536         which values were used for a given cookie).
00537         """
00538         expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)
00539         self.set_cookie(name, value="", path=path, expires=expires,
00540                         domain=domain)
00541 
00542     def clear_all_cookies(self, path="/", domain=None):
00543         """Deletes all the cookies the user sent with this request.
00544 
00545         See `clear_cookie` for more information on the path and domain
00546         parameters.
00547 
00548         .. versionchanged:: 3.2
00549 
00550            Added the ``path`` and ``domain`` parameters.
00551         """
00552         for name in self.request.cookies:
00553             self.clear_cookie(name, path=path, domain=domain)
00554 
00555     def set_secure_cookie(self, name, value, expires_days=30, version=None,
00556                           **kwargs):
00557         """Signs and timestamps a cookie so it cannot be forged.
00558 
00559         You must specify the ``cookie_secret`` setting in your Application
00560         to use this method. It should be a long, random sequence of bytes
00561         to be used as the HMAC secret for the signature.
00562 
00563         To read a cookie set with this method, use `get_secure_cookie()`.
00564 
00565         Note that the ``expires_days`` parameter sets the lifetime of the
00566         cookie in the browser, but is independent of the ``max_age_days``
00567         parameter to `get_secure_cookie`.
00568 
00569         Secure cookies may contain arbitrary byte values, not just unicode
00570         strings (unlike regular cookies)
00571 
00572         .. versionchanged:: 3.2.1
00573 
00574            Added the ``version`` argument.  Introduced cookie version 2
00575            and made it the default.
00576         """
00577         self.set_cookie(name, self.create_signed_value(name, value,
00578                                                        version=version),
00579                         expires_days=expires_days, **kwargs)
00580 
00581     def create_signed_value(self, name, value, version=None):
00582         """Signs and timestamps a string so it cannot be forged.
00583 
00584         Normally used via set_secure_cookie, but provided as a separate
00585         method for non-cookie uses.  To decode a value not stored
00586         as a cookie use the optional value argument to get_secure_cookie.
00587 
00588         .. versionchanged:: 3.2.1
00589 
00590            Added the ``version`` argument.  Introduced cookie version 2
00591            and made it the default.
00592         """
00593         self.require_setting("cookie_secret", "secure cookies")
00594         return create_signed_value(self.application.settings["cookie_secret"],
00595                                    name, value, version=version)
00596 
00597     def get_secure_cookie(self, name, value=None, max_age_days=31,
00598                           min_version=None):
00599         """Returns the given signed cookie if it validates, or None.
00600 
00601         The decoded cookie value is returned as a byte string (unlike
00602         `get_cookie`).
00603 
00604         .. versionchanged:: 3.2.1
00605 
00606            Added the ``min_version`` argument.  Introduced cookie version 2;
00607            both versions 1 and 2 are accepted by default.
00608         """
00609         self.require_setting("cookie_secret", "secure cookies")
00610         if value is None:
00611             value = self.get_cookie(name)
00612         return decode_signed_value(self.application.settings["cookie_secret"],
00613                                    name, value, max_age_days=max_age_days,
00614                                    min_version=min_version)
00615 
00616     def redirect(self, url, permanent=False, status=None):
00617         """Sends a redirect to the given (optionally relative) URL.
00618 
00619         If the ``status`` argument is specified, that value is used as the
00620         HTTP status code; otherwise either 301 (permanent) or 302
00621         (temporary) is chosen based on the ``permanent`` argument.
00622         The default is 302 (temporary).
00623         """
00624         if self._headers_written:
00625             raise Exception("Cannot redirect after headers have been written")
00626         if status is None:
00627             status = 301 if permanent else 302
00628         else:
00629             assert isinstance(status, int) and 300 <= status <= 399
00630         self.set_status(status)
00631         self.set_header("Location", urlparse.urljoin(utf8(self.request.uri),
00632                                                      utf8(url)))
00633         self.finish()
00634 
00635     def write(self, chunk):
00636         """Writes the given chunk to the output buffer.
00637 
00638         To write the output to the network, use the flush() method below.
00639 
00640         If the given chunk is a dictionary, we write it as JSON and set
00641         the Content-Type of the response to be ``application/json``.
00642         (if you want to send JSON as a different ``Content-Type``, call
00643         set_header *after* calling write()).
00644 
00645         Note that lists are not converted to JSON because of a potential
00646         cross-site security vulnerability.  All JSON output should be
00647         wrapped in a dictionary.  More details at
00648         http://haacked.com/archive/2009/06/25/json-hijacking.aspx/ and
00649         https://github.com/facebook/tornado/issues/1009
00650         """
00651         if self._finished:
00652             raise RuntimeError("Cannot write() after finish().  May be caused "
00653                                "by using async operations without the "
00654                                "@asynchronous decorator.")
00655         if not isinstance(chunk, (bytes_type, unicode_type, dict)):
00656             raise TypeError("write() only accepts bytes, unicode, and dict objects")
00657         if isinstance(chunk, dict):
00658             chunk = escape.json_encode(chunk)
00659             self.set_header("Content-Type", "application/json; charset=UTF-8")
00660         chunk = utf8(chunk)
00661         self._write_buffer.append(chunk)
00662 
00663     def render(self, template_name, **kwargs):
00664         """Renders the template with the given arguments as the response."""
00665         html = self.render_string(template_name, **kwargs)
00666 
00667         # Insert the additional JS and CSS added by the modules on the page
00668         js_embed = []
00669         js_files = []
00670         css_embed = []
00671         css_files = []
00672         html_heads = []
00673         html_bodies = []
00674         for module in getattr(self, "_active_modules", {}).values():
00675             embed_part = module.embedded_javascript()
00676             if embed_part:
00677                 js_embed.append(utf8(embed_part))
00678             file_part = module.javascript_files()
00679             if file_part:
00680                 if isinstance(file_part, (unicode_type, bytes_type)):
00681                     js_files.append(file_part)
00682                 else:
00683                     js_files.extend(file_part)
00684             embed_part = module.embedded_css()
00685             if embed_part:
00686                 css_embed.append(utf8(embed_part))
00687             file_part = module.css_files()
00688             if file_part:
00689                 if isinstance(file_part, (unicode_type, bytes_type)):
00690                     css_files.append(file_part)
00691                 else:
00692                     css_files.extend(file_part)
00693             head_part = module.html_head()
00694             if head_part:
00695                 html_heads.append(utf8(head_part))
00696             body_part = module.html_body()
00697             if body_part:
00698                 html_bodies.append(utf8(body_part))
00699 
00700         def is_absolute(path):
00701             return any(path.startswith(x) for x in ["/", "http:", "https:"])
00702         if js_files:
00703             # Maintain order of JavaScript files given by modules
00704             paths = []
00705             unique_paths = set()
00706             for path in js_files:
00707                 if not is_absolute(path):
00708                     path = self.static_url(path)
00709                 if path not in unique_paths:
00710                     paths.append(path)
00711                     unique_paths.add(path)
00712             js = ''.join('<script src="' + escape.xhtml_escape(p) +
00713                          '" type="text/javascript"></script>'
00714                          for p in paths)
00715             sloc = html.rindex(b'</body>')
00716             html = html[:sloc] + utf8(js) + b'\n' + html[sloc:]
00717         if js_embed:
00718             js = b'<script type="text/javascript">\n//<![CDATA[\n' + \
00719                 b'\n'.join(js_embed) + b'\n//]]>\n</script>'
00720             sloc = html.rindex(b'</body>')
00721             html = html[:sloc] + js + b'\n' + html[sloc:]
00722         if css_files:
00723             paths = []
00724             unique_paths = set()
00725             for path in css_files:
00726                 if not is_absolute(path):
00727                     path = self.static_url(path)
00728                 if path not in unique_paths:
00729                     paths.append(path)
00730                     unique_paths.add(path)
00731             css = ''.join('<link href="' + escape.xhtml_escape(p) + '" '
00732                           'type="text/css" rel="stylesheet"/>'
00733                           for p in paths)
00734             hloc = html.index(b'</head>')
00735             html = html[:hloc] + utf8(css) + b'\n' + html[hloc:]
00736         if css_embed:
00737             css = b'<style type="text/css">\n' + b'\n'.join(css_embed) + \
00738                 b'\n</style>'
00739             hloc = html.index(b'</head>')
00740             html = html[:hloc] + css + b'\n' + html[hloc:]
00741         if html_heads:
00742             hloc = html.index(b'</head>')
00743             html = html[:hloc] + b''.join(html_heads) + b'\n' + html[hloc:]
00744         if html_bodies:
00745             hloc = html.index(b'</body>')
00746             html = html[:hloc] + b''.join(html_bodies) + b'\n' + html[hloc:]
00747         self.finish(html)
00748 
00749     def render_string(self, template_name, **kwargs):
00750         """Generate the given template with the given arguments.
00751 
00752         We return the generated byte string (in utf8). To generate and
00753         write a template as a response, use render() above.
00754         """
00755         # If no template_path is specified, use the path of the calling file
00756         template_path = self.get_template_path()
00757         if not template_path:
00758             frame = sys._getframe(0)
00759             web_file = frame.f_code.co_filename
00760             while frame.f_code.co_filename == web_file:
00761                 frame = frame.f_back
00762             template_path = os.path.dirname(frame.f_code.co_filename)
00763         with RequestHandler._template_loader_lock:
00764             if template_path not in RequestHandler._template_loaders:
00765                 loader = self.create_template_loader(template_path)
00766                 RequestHandler._template_loaders[template_path] = loader
00767             else:
00768                 loader = RequestHandler._template_loaders[template_path]
00769         t = loader.load(template_name)
00770         namespace = self.get_template_namespace()
00771         namespace.update(kwargs)
00772         return t.generate(**namespace)
00773 
00774     def get_template_namespace(self):
00775         """Returns a dictionary to be used as the default template namespace.
00776 
00777         May be overridden by subclasses to add or modify values.
00778 
00779         The results of this method will be combined with additional
00780         defaults in the `tornado.template` module and keyword arguments
00781         to `render` or `render_string`.
00782         """
00783         namespace = dict(
00784             handler=self,
00785             request=self.request,
00786             current_user=self.current_user,
00787             locale=self.locale,
00788             _=self.locale.translate,
00789             static_url=self.static_url,
00790             xsrf_form_html=self.xsrf_form_html,
00791             reverse_url=self.reverse_url
00792         )
00793         namespace.update(self.ui)
00794         return namespace
00795 
00796     def create_template_loader(self, template_path):
00797         """Returns a new template loader for the given path.
00798 
00799         May be overridden by subclasses.  By default returns a
00800         directory-based loader on the given path, using the
00801         ``autoescape`` application setting.  If a ``template_loader``
00802         application setting is supplied, uses that instead.
00803         """
00804         settings = self.application.settings
00805         if "template_loader" in settings:
00806             return settings["template_loader"]
00807         kwargs = {}
00808         if "autoescape" in settings:
00809             # autoescape=None means "no escaping", so we have to be sure
00810             # to only pass this kwarg if the user asked for it.
00811             kwargs["autoescape"] = settings["autoescape"]
00812         return template.Loader(template_path, **kwargs)
00813 
00814     def flush(self, include_footers=False, callback=None):
00815         """Flushes the current output buffer to the network.
00816 
00817         The ``callback`` argument, if given, can be used for flow control:
00818         it will be run when all flushed data has been written to the socket.
00819         Note that only one flush callback can be outstanding at a time;
00820         if another flush occurs before the previous flush's callback
00821         has been run, the previous callback will be discarded.
00822 
00823         .. versionchanged:: 4.0
00824            Now returns a `.Future` if no callback is given.
00825         """
00826         chunk = b"".join(self._write_buffer)
00827         self._write_buffer = []
00828         if not self._headers_written:
00829             self._headers_written = True
00830             for transform in self._transforms:
00831                 self._status_code, self._headers, chunk = \
00832                     transform.transform_first_chunk(
00833                         self._status_code, self._headers, chunk, include_footers)
00834             # Ignore the chunk and only write the headers for HEAD requests
00835             if self.request.method == "HEAD":
00836                 chunk = None
00837 
00838             # Finalize the cookie headers (which have been stored in a side
00839             # object so an outgoing cookie could be overwritten before it
00840             # is sent).
00841             if hasattr(self, "_new_cookie"):
00842                 for cookie in self._new_cookie.values():
00843                     self.add_header("Set-Cookie", cookie.OutputString(None))
00844 
00845             start_line = httputil.ResponseStartLine(self.request.version,
00846                                                     self._status_code,
00847                                                     self._reason)
00848             return self.request.connection.write_headers(
00849                 start_line, self._headers, chunk, callback=callback)
00850         else:
00851             for transform in self._transforms:
00852                 chunk = transform.transform_chunk(chunk, include_footers)
00853             # Ignore the chunk and only write the headers for HEAD requests
00854             if self.request.method != "HEAD":
00855                 return self.request.connection.write(chunk, callback=callback)
00856             else:
00857                 future = Future()
00858                 future.set_result(None)
00859                 return future
00860 
00861     def finish(self, chunk=None):
00862         """Finishes this response, ending the HTTP request."""
00863         if self._finished:
00864             raise RuntimeError("finish() called twice.  May be caused "
00865                                "by using async operations without the "
00866                                "@asynchronous decorator.")
00867 
00868         if chunk is not None:
00869             self.write(chunk)
00870 
00871         # Automatically support ETags and add the Content-Length header if
00872         # we have not flushed any content yet.
00873         if not self._headers_written:
00874             if (self._status_code == 200 and
00875                 self.request.method in ("GET", "HEAD") and
00876                     "Etag" not in self._headers):
00877                 self.set_etag_header()
00878                 if self.check_etag_header():
00879                     self._write_buffer = []
00880                     self.set_status(304)
00881             if self._status_code == 304:
00882                 assert not self._write_buffer, "Cannot send body with 304"
00883                 self._clear_headers_for_304()
00884             elif "Content-Length" not in self._headers:
00885                 content_length = sum(len(part) for part in self._write_buffer)
00886                 self.set_header("Content-Length", content_length)
00887 
00888         if hasattr(self.request, "connection"):
00889             # Now that the request is finished, clear the callback we
00890             # set on the HTTPConnection (which would otherwise prevent the
00891             # garbage collection of the RequestHandler when there
00892             # are keepalive connections)
00893             self.request.connection.set_close_callback(None)
00894 
00895         self.flush(include_footers=True)
00896         self.request.finish()
00897         self._log()
00898         self._finished = True
00899         self.on_finish()
00900         # Break up a reference cycle between this handler and the
00901         # _ui_module closures to allow for faster GC on CPython.
00902         self.ui = None
00903 
00904     def send_error(self, status_code=500, **kwargs):
00905         """Sends the given HTTP error code to the browser.
00906 
00907         If `flush()` has already been called, it is not possible to send
00908         an error, so this method will simply terminate the response.
00909         If output has been written but not yet flushed, it will be discarded
00910         and replaced with the error page.
00911 
00912         Override `write_error()` to customize the error page that is returned.
00913         Additional keyword arguments are passed through to `write_error`.
00914         """
00915         if self._headers_written:
00916             gen_log.error("Cannot send error response after headers written")
00917             if not self._finished:
00918                 self.finish()
00919             return
00920         self.clear()
00921 
00922         reason = None
00923         if 'exc_info' in kwargs:
00924             exception = kwargs['exc_info'][1]
00925             if isinstance(exception, HTTPError) and exception.reason:
00926                 reason = exception.reason
00927         self.set_status(status_code, reason=reason)
00928         try:
00929             self.write_error(status_code, **kwargs)
00930         except Exception:
00931             app_log.error("Uncaught exception in write_error", exc_info=True)
00932         if not self._finished:
00933             self.finish()
00934 
00935     def write_error(self, status_code, **kwargs):
00936         """Override to implement custom error pages.
00937 
00938         ``write_error`` may call `write`, `render`, `set_header`, etc
00939         to produce output as usual.
00940 
00941         If this error was caused by an uncaught exception (including
00942         HTTPError), an ``exc_info`` triple will be available as
00943         ``kwargs["exc_info"]``.  Note that this exception may not be
00944         the "current" exception for purposes of methods like
00945         ``sys.exc_info()`` or ``traceback.format_exc``.
00946         """
00947         if self.settings.get("serve_traceback") and "exc_info" in kwargs:
00948             # in debug mode, try to send a traceback
00949             self.set_header('Content-Type', 'text/plain')
00950             for line in traceback.format_exception(*kwargs["exc_info"]):
00951                 self.write(line)
00952             self.finish()
00953         else:
00954             self.finish("<html><title>%(code)d: %(message)s</title>"
00955                         "<body>%(code)d: %(message)s</body></html>" % {
00956                             "code": status_code,
00957                             "message": self._reason,
00958                         })
00959 
00960     @property
00961     def locale(self):
00962         """The local for the current session.
00963 
00964         Determined by either `get_user_locale`, which you can override to
00965         set the locale based on, e.g., a user preference stored in a
00966         database, or `get_browser_locale`, which uses the ``Accept-Language``
00967         header.
00968         """
00969         if not hasattr(self, "_locale"):
00970             self._locale = self.get_user_locale()
00971             if not self._locale:
00972                 self._locale = self.get_browser_locale()
00973                 assert self._locale
00974         return self._locale
00975 
00976     def get_user_locale(self):
00977         """Override to determine the locale from the authenticated user.
00978 
00979         If None is returned, we fall back to `get_browser_locale()`.
00980 
00981         This method should return a `tornado.locale.Locale` object,
00982         most likely obtained via a call like ``tornado.locale.get("en")``
00983         """
00984         return None
00985 
00986     def get_browser_locale(self, default="en_US"):
00987         """Determines the user's locale from ``Accept-Language`` header.
00988 
00989         See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
00990         """
00991         if "Accept-Language" in self.request.headers:
00992             languages = self.request.headers["Accept-Language"].split(",")
00993             locales = []
00994             for language in languages:
00995                 parts = language.strip().split(";")
00996                 if len(parts) > 1 and parts[1].startswith("q="):
00997                     try:
00998                         score = float(parts[1][2:])
00999                     except (ValueError, TypeError):
01000                         score = 0.0
01001                 else:
01002                     score = 1.0
01003                 locales.append((parts[0], score))
01004             if locales:
01005                 locales.sort(key=lambda pair: pair[1], reverse=True)
01006                 codes = [l[0] for l in locales]
01007                 return locale.get(*codes)
01008         return locale.get(default)
01009 
01010     @property
01011     def current_user(self):
01012         """The authenticated user for this request.
01013 
01014         This is a cached version of `get_current_user`, which you can
01015         override to set the user based on, e.g., a cookie. If that
01016         method is not overridden, this method always returns None.
01017 
01018         We lazy-load the current user the first time this method is called
01019         and cache the result after that.
01020         """
01021         if not hasattr(self, "_current_user"):
01022             self._current_user = self.get_current_user()
01023         return self._current_user
01024 
01025     @current_user.setter
01026     def current_user(self, value):
01027         self._current_user = value
01028 
01029     def get_current_user(self):
01030         """Override to determine the current user from, e.g., a cookie."""
01031         return None
01032 
01033     def get_login_url(self):
01034         """Override to customize the login URL based on the request.
01035 
01036         By default, we use the ``login_url`` application setting.
01037         """
01038         self.require_setting("login_url", "@tornado.web.authenticated")
01039         return self.application.settings["login_url"]
01040 
01041     def get_template_path(self):
01042         """Override to customize template path for each handler.
01043 
01044         By default, we use the ``template_path`` application setting.
01045         Return None to load templates relative to the calling file.
01046         """
01047         return self.application.settings.get("template_path")
01048 
01049     @property
01050     def xsrf_token(self):
01051         """The XSRF-prevention token for the current user/session.
01052 
01053         To prevent cross-site request forgery, we set an '_xsrf' cookie
01054         and include the same '_xsrf' value as an argument with all POST
01055         requests. If the two do not match, we reject the form submission
01056         as a potential forgery.
01057 
01058         See http://en.wikipedia.org/wiki/Cross-site_request_forgery
01059 
01060         .. versionchanged:: 3.2.2
01061            The xsrf token will now be have a random mask applied in every
01062            request, which makes it safe to include the token in pages
01063            that are compressed.  See http://breachattack.com for more
01064            information on the issue fixed by this change.  Old (version 1)
01065            cookies will be converted to version 2 when this method is called
01066            unless the ``xsrf_cookie_version`` `Application` setting is
01067            set to 1.
01068         """
01069         if not hasattr(self, "_xsrf_token"):
01070             version, token, timestamp = self._get_raw_xsrf_token()
01071             output_version = self.settings.get("xsrf_cookie_version", 2)
01072             if output_version == 1:
01073                 self._xsrf_token = binascii.b2a_hex(token)
01074             elif output_version == 2:
01075                 mask = os.urandom(4)
01076                 self._xsrf_token = b"|".join([
01077                     b"2",
01078                     binascii.b2a_hex(mask),
01079                     binascii.b2a_hex(_websocket_mask(mask, token)),
01080                     utf8(str(int(timestamp)))])
01081             else:
01082                 raise ValueError("unknown xsrf cookie version %d",
01083                                  output_version)
01084             if version is None:
01085                 expires_days = 30 if self.current_user else None
01086                 self.set_cookie("_xsrf", self._xsrf_token,
01087                                 expires_days=expires_days)
01088         return self._xsrf_token
01089 
01090     def _get_raw_xsrf_token(self):
01091         """Read or generate the xsrf token in its raw form.
01092 
01093         The raw_xsrf_token is a tuple containing:
01094 
01095         * version: the version of the cookie from which this token was read,
01096           or None if we generated a new token in this request.
01097         * token: the raw token data; random (non-ascii) bytes.
01098         * timestamp: the time this token was generated (will not be accurate
01099           for version 1 cookies)
01100         """
01101         if not hasattr(self, '_raw_xsrf_token'):
01102             cookie = self.get_cookie("_xsrf")
01103             if cookie:
01104                 version, token, timestamp = self._decode_xsrf_token(cookie)
01105             else:
01106                 version, token, timestamp = None, None, None
01107             if token is None:
01108                 version = None
01109                 token = os.urandom(16)
01110                 timestamp = time.time()
01111             self._raw_xsrf_token = (version, token, timestamp)
01112         return self._raw_xsrf_token
01113 
01114     def _decode_xsrf_token(self, cookie):
01115         """Convert a cookie string into a the tuple form returned by
01116         _get_raw_xsrf_token.
01117         """
01118         m = _signed_value_version_re.match(utf8(cookie))
01119         if m:
01120             version = int(m.group(1))
01121             if version == 2:
01122                 _, mask, masked_token, timestamp = cookie.split("|")
01123                 mask = binascii.a2b_hex(utf8(mask))
01124                 token = _websocket_mask(
01125                     mask, binascii.a2b_hex(utf8(masked_token)))
01126                 timestamp = int(timestamp)
01127                 return version, token, timestamp
01128             else:
01129                 # Treat unknown versions as not present instead of failing.
01130                 return None, None, None
01131         else:
01132             version = 1
01133             try:
01134                 token = binascii.a2b_hex(utf8(cookie))
01135             except (binascii.Error, TypeError):
01136                 token = utf8(cookie)
01137             # We don't have a usable timestamp in older versions.
01138             timestamp = int(time.time())
01139             return (version, token, timestamp)
01140 
01141     def check_xsrf_cookie(self):
01142         """Verifies that the ``_xsrf`` cookie matches the ``_xsrf`` argument.
01143 
01144         To prevent cross-site request forgery, we set an ``_xsrf``
01145         cookie and include the same value as a non-cookie
01146         field with all ``POST`` requests. If the two do not match, we
01147         reject the form submission as a potential forgery.
01148 
01149         The ``_xsrf`` value may be set as either a form field named ``_xsrf``
01150         or in a custom HTTP header named ``X-XSRFToken`` or ``X-CSRFToken``
01151         (the latter is accepted for compatibility with Django).
01152 
01153         See http://en.wikipedia.org/wiki/Cross-site_request_forgery
01154 
01155         Prior to release 1.1.1, this check was ignored if the HTTP header
01156         ``X-Requested-With: XMLHTTPRequest`` was present.  This exception
01157         has been shown to be insecure and has been removed.  For more
01158         information please see
01159         http://www.djangoproject.com/weblog/2011/feb/08/security/
01160         http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails
01161 
01162         .. versionchanged:: 3.2.2
01163            Added support for cookie version 2.  Both versions 1 and 2 are
01164            supported.
01165         """
01166         token = (self.get_argument("_xsrf", None) or
01167                  self.request.headers.get("X-Xsrftoken") or
01168                  self.request.headers.get("X-Csrftoken"))
01169         if not token:
01170             raise HTTPError(403, "'_xsrf' argument missing from POST")
01171         _, token, _ = self._decode_xsrf_token(token)
01172         _, expected_token, _ = self._get_raw_xsrf_token()
01173         if not _time_independent_equals(utf8(token), utf8(expected_token)):
01174             raise HTTPError(403, "XSRF cookie does not match POST argument")
01175 
01176     def xsrf_form_html(self):
01177         """An HTML ``<input/>`` element to be included with all POST forms.
01178 
01179         It defines the ``_xsrf`` input value, which we check on all POST
01180         requests to prevent cross-site request forgery. If you have set
01181         the ``xsrf_cookies`` application setting, you must include this
01182         HTML within all of your HTML forms.
01183 
01184         In a template, this method should be called with ``{% module
01185         xsrf_form_html() %}``
01186 
01187         See `check_xsrf_cookie()` above for more information.
01188         """
01189         return '<input type="hidden" name="_xsrf" value="' + \
01190             escape.xhtml_escape(self.xsrf_token) + '"/>'
01191 
01192     def static_url(self, path, include_host=None, **kwargs):
01193         """Returns a static URL for the given relative static file path.
01194 
01195         This method requires you set the ``static_path`` setting in your
01196         application (which specifies the root directory of your static
01197         files).
01198 
01199         This method returns a versioned url (by default appending
01200         ``?v=<signature>``), which allows the static files to be
01201         cached indefinitely.  This can be disabled by passing
01202         ``include_version=False`` (in the default implementation;
01203         other static file implementations are not required to support
01204         this, but they may support other options).
01205 
01206         By default this method returns URLs relative to the current
01207         host, but if ``include_host`` is true the URL returned will be
01208         absolute.  If this handler has an ``include_host`` attribute,
01209         that value will be used as the default for all `static_url`
01210         calls that do not pass ``include_host`` as a keyword argument.
01211 
01212         """
01213         self.require_setting("static_path", "static_url")
01214         get_url = self.settings.get("static_handler_class",
01215                                     StaticFileHandler).make_static_url
01216 
01217         if include_host is None:
01218             include_host = getattr(self, "include_host", False)
01219 
01220         if include_host:
01221             base = self.request.protocol + "://" + self.request.host
01222         else:
01223             base = ""
01224 
01225         return base + get_url(self.settings, path, **kwargs)
01226 
01227     def require_setting(self, name, feature="this feature"):
01228         """Raises an exception if the given app setting is not defined."""
01229         if not self.application.settings.get(name):
01230             raise Exception("You must define the '%s' setting in your "
01231                             "application to use %s" % (name, feature))
01232 
01233     def reverse_url(self, name, *args):
01234         """Alias for `Application.reverse_url`."""
01235         return self.application.reverse_url(name, *args)
01236 
01237     def compute_etag(self):
01238         """Computes the etag header to be used for this request.
01239 
01240         By default uses a hash of the content written so far.
01241 
01242         May be overridden to provide custom etag implementations,
01243         or may return None to disable tornado's default etag support.
01244         """
01245         hasher = hashlib.sha1()
01246         for part in self._write_buffer:
01247             hasher.update(part)
01248         return '"%s"' % hasher.hexdigest()
01249 
01250     def set_etag_header(self):
01251         """Sets the response's Etag header using ``self.compute_etag()``.
01252 
01253         Note: no header will be set if ``compute_etag()`` returns ``None``.
01254 
01255         This method is called automatically when the request is finished.
01256         """
01257         etag = self.compute_etag()
01258         if etag is not None:
01259             self.set_header("Etag", etag)
01260 
01261     def check_etag_header(self):
01262         """Checks the ``Etag`` header against requests's ``If-None-Match``.
01263 
01264         Returns ``True`` if the request's Etag matches and a 304 should be
01265         returned. For example::
01266 
01267             self.set_etag_header()
01268             if self.check_etag_header():
01269                 self.set_status(304)
01270                 return
01271 
01272         This method is called automatically when the request is finished,
01273         but may be called earlier for applications that override
01274         `compute_etag` and want to do an early check for ``If-None-Match``
01275         before completing the request.  The ``Etag`` header should be set
01276         (perhaps with `set_etag_header`) before calling this method.
01277         """
01278         etag = self._headers.get("Etag")
01279         inm = utf8(self.request.headers.get("If-None-Match", ""))
01280         return bool(etag and inm and inm.find(etag) >= 0)
01281 
01282     def _stack_context_handle_exception(self, type, value, traceback):
01283         try:
01284             # For historical reasons _handle_request_exception only takes
01285             # the exception value instead of the full triple,
01286             # so re-raise the exception to ensure that it's in
01287             # sys.exc_info()
01288             raise_exc_info((type, value, traceback))
01289         except Exception:
01290             self._handle_request_exception(value)
01291         return True
01292 
01293     @gen.coroutine
01294     def _execute(self, transforms, *args, **kwargs):
01295         """Executes this request with the given output transforms."""
01296         self._transforms = transforms
01297         try:
01298             if self.request.method not in self.SUPPORTED_METHODS:
01299                 raise HTTPError(405)
01300             self.path_args = [self.decode_argument(arg) for arg in args]
01301             self.path_kwargs = dict((k, self.decode_argument(v, name=k))
01302                                     for (k, v) in kwargs.items())
01303             # If XSRF cookies are turned on, reject form submissions without
01304             # the proper cookie
01305             if self.request.method not in ("GET", "HEAD", "OPTIONS") and \
01306                     self.application.settings.get("xsrf_cookies"):
01307                 self.check_xsrf_cookie()
01308 
01309             result = self.prepare()
01310             if is_future(result):
01311                 result = yield result
01312             if result is not None:
01313                 raise TypeError("Expected None, got %r" % result)
01314             if self._prepared_future is not None:
01315                 # Tell the Application we've finished with prepare()
01316                 # and are ready for the body to arrive.
01317                 self._prepared_future.set_result(None)
01318             if self._finished:
01319                 return
01320 
01321             if _has_stream_request_body(self.__class__):
01322                 # In streaming mode request.body is a Future that signals
01323                 # the body has been completely received.  The Future has no
01324                 # result; the data has been passed to self.data_received
01325                 # instead.
01326                 try:
01327                     yield self.request.body
01328                 except iostream.StreamClosedError:
01329                     return
01330 
01331             method = getattr(self, self.request.method.lower())
01332             result = method(*self.path_args, **self.path_kwargs)
01333             if is_future(result):
01334                 result = yield result
01335             if result is not None:
01336                 raise TypeError("Expected None, got %r" % result)
01337             if self._auto_finish and not self._finished:
01338                 self.finish()
01339         except Exception as e:
01340             self._handle_request_exception(e)
01341             if (self._prepared_future is not None and
01342                     not self._prepared_future.done()):
01343                 # In case we failed before setting _prepared_future, do it
01344                 # now (to unblock the HTTP server).  Note that this is not
01345                 # in a finally block to avoid GC issues prior to Python 3.4.
01346                 self._prepared_future.set_result(None)
01347 
01348     def data_received(self, chunk):
01349         """Implement this method to handle streamed request data.
01350 
01351         Requires the `.stream_request_body` decorator.
01352         """
01353         raise NotImplementedError()
01354 
01355     def _log(self):
01356         """Logs the current request.
01357 
01358         Sort of deprecated since this functionality was moved to the
01359         Application, but left in place for the benefit of existing apps
01360         that have overridden this method.
01361         """
01362         self.application.log_request(self)
01363 
01364     def _request_summary(self):
01365         return self.request.method + " " + self.request.uri + \
01366             " (" + self.request.remote_ip + ")"
01367 
01368     def _handle_request_exception(self, e):
01369         if isinstance(e, Finish):
01370             # Not an error; just finish the request without logging.
01371             if not self._finished:
01372                 self.finish()
01373             return
01374         self.log_exception(*sys.exc_info())
01375         if self._finished:
01376             # Extra errors after the request has been finished should
01377             # be logged, but there is no reason to continue to try and
01378             # send a response.
01379             return
01380         if isinstance(e, HTTPError):
01381             if e.status_code not in httputil.responses and not e.reason:
01382                 gen_log.error("Bad HTTP status code: %d", e.status_code)
01383                 self.send_error(500, exc_info=sys.exc_info())
01384             else:
01385                 self.send_error(e.status_code, exc_info=sys.exc_info())
01386         else:
01387             self.send_error(500, exc_info=sys.exc_info())
01388 
01389     def log_exception(self, typ, value, tb):
01390         """Override to customize logging of uncaught exceptions.
01391 
01392         By default logs instances of `HTTPError` as warnings without
01393         stack traces (on the ``tornado.general`` logger), and all
01394         other exceptions as errors with stack traces (on the
01395         ``tornado.application`` logger).
01396 
01397         .. versionadded:: 3.1
01398         """
01399         if isinstance(value, HTTPError):
01400             if value.log_message:
01401                 format = "%d %s: " + value.log_message
01402                 args = ([value.status_code, self._request_summary()] +
01403                         list(value.args))
01404                 gen_log.warning(format, *args)
01405         else:
01406             app_log.error("Uncaught exception %s\n%r", self._request_summary(),
01407                           self.request, exc_info=(typ, value, tb))
01408 
01409     def _ui_module(self, name, module):
01410         def render(*args, **kwargs):
01411             if not hasattr(self, "_active_modules"):
01412                 self._active_modules = {}
01413             if name not in self._active_modules:
01414                 self._active_modules[name] = module(self)
01415             rendered = self._active_modules[name].render(*args, **kwargs)
01416             return rendered
01417         return render
01418 
01419     def _ui_method(self, method):
01420         return lambda *args, **kwargs: method(self, *args, **kwargs)
01421 
01422     def _clear_headers_for_304(self):
01423         # 304 responses should not contain entity headers (defined in
01424         # http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.1)
01425         # not explicitly allowed by
01426         # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
01427         headers = ["Allow", "Content-Encoding", "Content-Language",
01428                    "Content-Length", "Content-MD5", "Content-Range",
01429                    "Content-Type", "Last-Modified"]
01430         for h in headers:
01431             self.clear_header(h)
01432 
01433 
01434 def asynchronous(method):
01435     """Wrap request handler methods with this if they are asynchronous.
01436 
01437     This decorator is unnecessary if the method is also decorated with
01438     ``@gen.coroutine`` (it is legal but unnecessary to use the two
01439     decorators together, in which case ``@asynchronous`` must be
01440     first).
01441 
01442     This decorator should only be applied to the :ref:`HTTP verb
01443     methods <verbs>`; its behavior is undefined for any other method.
01444     This decorator does not *make* a method asynchronous; it tells
01445     the framework that the method *is* asynchronous.  For this decorator
01446     to be useful the method must (at least sometimes) do something
01447     asynchronous.
01448 
01449     If this decorator is given, the response is not finished when the
01450     method returns. It is up to the request handler to call
01451     `self.finish() <RequestHandler.finish>` to finish the HTTP
01452     request. Without this decorator, the request is automatically
01453     finished when the ``get()`` or ``post()`` method returns. Example::
01454 
01455        class MyRequestHandler(web.RequestHandler):
01456            @web.asynchronous
01457            def get(self):
01458               http = httpclient.AsyncHTTPClient()
01459               http.fetch("http://friendfeed.com/", self._on_download)
01460 
01461            def _on_download(self, response):
01462               self.write("Downloaded!")
01463               self.finish()
01464 
01465     .. versionadded:: 3.1
01466        The ability to use ``@gen.coroutine`` without ``@asynchronous``.
01467     """
01468     # Delay the IOLoop import because it's not available on app engine.
01469     from tornado.ioloop import IOLoop
01470     @functools.wraps(method)
01471     def wrapper(self, *args, **kwargs):
01472         self._auto_finish = False
01473         with stack_context.ExceptionStackContext(
01474                 self._stack_context_handle_exception):
01475             result = method(self, *args, **kwargs)
01476             if isinstance(result, Future):
01477                 # If @asynchronous is used with @gen.coroutine, (but
01478                 # not @gen.engine), we can automatically finish the
01479                 # request when the future resolves.  Additionally,
01480                 # the Future will swallow any exceptions so we need
01481                 # to throw them back out to the stack context to finish
01482                 # the request.
01483                 def future_complete(f):
01484                     f.result()
01485                     if not self._finished:
01486                         self.finish()
01487                 IOLoop.current().add_future(result, future_complete)
01488                 # Once we have done this, hide the Future from our
01489                 # caller (i.e. RequestHandler._when_complete), which
01490                 # would otherwise set up its own callback and
01491                 # exception handler (resulting in exceptions being
01492                 # logged twice).
01493                 return None
01494             return result
01495     return wrapper
01496 
01497 
01498 def stream_request_body(cls):
01499     """Apply to `RequestHandler` subclasses to enable streaming body support.
01500 
01501     This decorator implies the following changes:
01502 
01503     * `.HTTPServerRequest.body` is undefined, and body arguments will not
01504       be included in `RequestHandler.get_argument`.
01505     * `RequestHandler.prepare` is called when the request headers have been
01506       read instead of after the entire body has been read.
01507     * The subclass must define a method ``data_received(self, data):``, which
01508       will be called zero or more times as data is available.  Note that
01509       if the request has an empty body, ``data_received`` may not be called.
01510     * ``prepare`` and ``data_received`` may return Futures (such as via
01511       ``@gen.coroutine``, in which case the next method will not be called
01512       until those futures have completed.
01513     * The regular HTTP method (``post``, ``put``, etc) will be called after
01514       the entire body has been read.
01515 
01516     There is a subtle interaction between ``data_received`` and asynchronous
01517     ``prepare``: The first call to ``data_recieved`` may occur at any point
01518     after the call to ``prepare`` has returned *or yielded*.
01519     """
01520     if not issubclass(cls, RequestHandler):
01521         raise TypeError("expected subclass of RequestHandler, got %r", cls)
01522     cls._stream_request_body = True
01523     return cls
01524 
01525 
01526 def _has_stream_request_body(cls):
01527     if not issubclass(cls, RequestHandler):
01528         raise TypeError("expected subclass of RequestHandler, got %r", cls)
01529     return getattr(cls, '_stream_request_body', False)
01530 
01531 
01532 def removeslash(method):
01533     """Use this decorator to remove trailing slashes from the request path.
01534 
01535     For example, a request to ``/foo/`` would redirect to ``/foo`` with this
01536     decorator. Your request handler mapping should use a regular expression
01537     like ``r'/foo/*'`` in conjunction with using the decorator.
01538     """
01539     @functools.wraps(method)
01540     def wrapper(self, *args, **kwargs):
01541         if self.request.path.endswith("/"):
01542             if self.request.method in ("GET", "HEAD"):
01543                 uri = self.request.path.rstrip("/")
01544                 if uri:  # don't try to redirect '/' to ''
01545                     if self.request.query:
01546                         uri += "?" + self.request.query
01547                     self.redirect(uri, permanent=True)
01548                     return
01549             else:
01550                 raise HTTPError(404)
01551         return method(self, *args, **kwargs)
01552     return wrapper
01553 
01554 
01555 def addslash(method):
01556     """Use this decorator to add a missing trailing slash to the request path.
01557 
01558     For example, a request to ``/foo`` would redirect to ``/foo/`` with this
01559     decorator. Your request handler mapping should use a regular expression
01560     like ``r'/foo/?'`` in conjunction with using the decorator.
01561     """
01562     @functools.wraps(method)
01563     def wrapper(self, *args, **kwargs):
01564         if not self.request.path.endswith("/"):
01565             if self.request.method in ("GET", "HEAD"):
01566                 uri = self.request.path + "/"
01567                 if self.request.query:
01568                     uri += "?" + self.request.query
01569                 self.redirect(uri, permanent=True)
01570                 return
01571             raise HTTPError(404)
01572         return method(self, *args, **kwargs)
01573     return wrapper
01574 
01575 
01576 class Application(httputil.HTTPServerConnectionDelegate):
01577     """A collection of request handlers that make up a web application.
01578 
01579     Instances of this class are callable and can be passed directly to
01580     HTTPServer to serve the application::
01581 
01582         application = web.Application([
01583             (r"/", MainPageHandler),
01584         ])
01585         http_server = httpserver.HTTPServer(application)
01586         http_server.listen(8080)
01587         ioloop.IOLoop.instance().start()
01588 
01589     The constructor for this class takes in a list of `URLSpec` objects
01590     or (regexp, request_class) tuples. When we receive requests, we
01591     iterate over the list in order and instantiate an instance of the
01592     first request class whose regexp matches the request path.
01593     The request class can be specified as either a class object or a
01594     (fully-qualified) name.
01595 
01596     Each tuple can contain additional elements, which correspond to the
01597     arguments to the `URLSpec` constructor.  (Prior to Tornado 3.2, this
01598     only tuples of two or three elements were allowed).
01599 
01600     A dictionary may be passed as the third element of the tuple,
01601     which will be used as keyword arguments to the handler's
01602     constructor and `~RequestHandler.initialize` method.  This pattern
01603     is used for the `StaticFileHandler` in this example (note that a
01604     `StaticFileHandler` can be installed automatically with the
01605     static_path setting described below)::
01606 
01607         application = web.Application([
01608             (r"/static/(.*)", web.StaticFileHandler, {"path": "/var/www"}),
01609         ])
01610 
01611     We support virtual hosts with the `add_handlers` method, which takes in
01612     a host regular expression as the first argument::
01613 
01614         application.add_handlers(r"www\.myhost\.com", [
01615             (r"/article/([0-9]+)", ArticleHandler),
01616         ])
01617 
01618     You can serve static files by sending the ``static_path`` setting
01619     as a keyword argument. We will serve those files from the
01620     ``/static/`` URI (this is configurable with the
01621     ``static_url_prefix`` setting), and we will serve ``/favicon.ico``
01622     and ``/robots.txt`` from the same directory.  A custom subclass of
01623     `StaticFileHandler` can be specified with the
01624     ``static_handler_class`` setting.
01625 
01626     """
01627     def __init__(self, handlers=None, default_host="", transforms=None,
01628                  **settings):
01629         if transforms is None:
01630             self.transforms = []
01631             if settings.get("compress_response") or settings.get("gzip"):
01632                 self.transforms.append(GZipContentEncoding)
01633         else:
01634             self.transforms = transforms
01635         self.handlers = []
01636         self.named_handlers = {}
01637         self.default_host = default_host
01638         self.settings = settings
01639         self.ui_modules = {'linkify': _linkify,
01640                            'xsrf_form_html': _xsrf_form_html,
01641                            'Template': TemplateModule,
01642                            }
01643         self.ui_methods = {}
01644         self._load_ui_modules(settings.get("ui_modules", {}))
01645         self._load_ui_methods(settings.get("ui_methods", {}))
01646         if self.settings.get("static_path"):
01647             path = self.settings["static_path"]
01648             handlers = list(handlers or [])
01649             static_url_prefix = settings.get("static_url_prefix",
01650                                              "/static/")
01651             static_handler_class = settings.get("static_handler_class",
01652                                                 StaticFileHandler)
01653             static_handler_args = settings.get("static_handler_args", {})
01654             static_handler_args['path'] = path
01655             for pattern in [re.escape(static_url_prefix) + r"(.*)",
01656                             r"/(favicon\.ico)", r"/(robots\.txt)"]:
01657                 handlers.insert(0, (pattern, static_handler_class,
01658                                     static_handler_args))
01659         if handlers:
01660             self.add_handlers(".*$", handlers)
01661 
01662         if self.settings.get('debug'):
01663             self.settings.setdefault('autoreload', True)
01664             self.settings.setdefault('compiled_template_cache', False)
01665             self.settings.setdefault('static_hash_cache', False)
01666             self.settings.setdefault('serve_traceback', True)
01667 
01668         # Automatically reload modified modules
01669         if self.settings.get('autoreload'):
01670             from tornado import autoreload
01671             autoreload.start()
01672 
01673     def listen(self, port, address="", **kwargs):
01674         """Starts an HTTP server for this application on the given port.
01675 
01676         This is a convenience alias for creating an `.HTTPServer`
01677         object and calling its listen method.  Keyword arguments not
01678         supported by `HTTPServer.listen <.TCPServer.listen>` are passed to the
01679         `.HTTPServer` constructor.  For advanced uses
01680         (e.g. multi-process mode), do not use this method; create an
01681         `.HTTPServer` and call its
01682         `.TCPServer.bind`/`.TCPServer.start` methods directly.
01683 
01684         Note that after calling this method you still need to call
01685         ``IOLoop.instance().start()`` to start the server.
01686         """
01687         # import is here rather than top level because HTTPServer
01688         # is not importable on appengine
01689         from tornado.httpserver import HTTPServer
01690         server = HTTPServer(self, **kwargs)
01691         server.listen(port, address)
01692 
01693     def add_handlers(self, host_pattern, host_handlers):
01694         """Appends the given handlers to our handler list.
01695 
01696         Host patterns are processed sequentially in the order they were
01697         added. All matching patterns will be considered.
01698         """
01699         if not host_pattern.endswith("$"):
01700             host_pattern += "$"
01701         handlers = []
01702         # The handlers with the wildcard host_pattern are a special
01703         # case - they're added in the constructor but should have lower
01704         # precedence than the more-precise handlers added later.
01705         # If a wildcard handler group exists, it should always be last
01706         # in the list, so insert new groups just before it.
01707         if self.handlers and self.handlers[-1][0].pattern == '.*$':
01708             self.handlers.insert(-1, (re.compile(host_pattern), handlers))
01709         else:
01710             self.handlers.append((re.compile(host_pattern), handlers))
01711 
01712         for spec in host_handlers:
01713             if isinstance(spec, (tuple, list)):
01714                 assert len(spec) in (2, 3, 4)
01715                 spec = URLSpec(*spec)
01716             handlers.append(spec)
01717             if spec.name:
01718                 if spec.name in self.named_handlers:
01719                     app_log.warning(
01720                         "Multiple handlers named %s; replacing previous value",
01721                         spec.name)
01722                 self.named_handlers[spec.name] = spec
01723 
01724     def add_transform(self, transform_class):
01725         self.transforms.append(transform_class)
01726 
01727     def _get_host_handlers(self, request):
01728         host = request.host.lower().split(':')[0]
01729         matches = []
01730         for pattern, handlers in self.handlers:
01731             if pattern.match(host):
01732                 matches.extend(handlers)
01733         # Look for default host if not behind load balancer (for debugging)
01734         if not matches and "X-Real-Ip" not in request.headers:
01735             for pattern, handlers in self.handlers:
01736                 if pattern.match(self.default_host):
01737                     matches.extend(handlers)
01738         return matches or None
01739 
01740     def _load_ui_methods(self, methods):
01741         if isinstance(methods, types.ModuleType):
01742             self._load_ui_methods(dict((n, getattr(methods, n))
01743                                        for n in dir(methods)))
01744         elif isinstance(methods, list):
01745             for m in methods:
01746                 self._load_ui_methods(m)
01747         else:
01748             for name, fn in methods.items():
01749                 if not name.startswith("_") and hasattr(fn, "__call__") \
01750                         and name[0].lower() == name[0]:
01751                     self.ui_methods[name] = fn
01752 
01753     def _load_ui_modules(self, modules):
01754         if isinstance(modules, types.ModuleType):
01755             self._load_ui_modules(dict((n, getattr(modules, n))
01756                                        for n in dir(modules)))
01757         elif isinstance(modules, list):
01758             for m in modules:
01759                 self._load_ui_modules(m)
01760         else:
01761             assert isinstance(modules, dict)
01762             for name, cls in modules.items():
01763                 try:
01764                     if issubclass(cls, UIModule):
01765                         self.ui_modules[name] = cls
01766                 except TypeError:
01767                     pass
01768 
01769     def start_request(self, connection):
01770         # Modern HTTPServer interface
01771         return _RequestDispatcher(self, connection)
01772 
01773     def __call__(self, request):
01774         # Legacy HTTPServer interface
01775         dispatcher = _RequestDispatcher(self, None)
01776         dispatcher.set_request(request)
01777         return dispatcher.execute()
01778 
01779     def reverse_url(self, name, *args):
01780         """Returns a URL path for handler named ``name``
01781 
01782         The handler must be added to the application as a named `URLSpec`.
01783 
01784         Args will be substituted for capturing groups in the `URLSpec` regex.
01785         They will be converted to strings if necessary, encoded as utf8,
01786         and url-escaped.
01787         """
01788         if name in self.named_handlers:
01789             return self.named_handlers[name].reverse(*args)
01790         raise KeyError("%s not found in named urls" % name)
01791 
01792     def log_request(self, handler):
01793         """Writes a completed HTTP request to the logs.
01794 
01795         By default writes to the python root logger.  To change
01796         this behavior either subclass Application and override this method,
01797         or pass a function in the application settings dictionary as
01798         ``log_function``.
01799         """
01800         if "log_function" in self.settings:
01801             self.settings["log_function"](handler)
01802             return
01803         if handler.get_status() < 400:
01804             log_method = access_log.info
01805         elif handler.get_status() < 500:
01806             log_method = access_log.warning
01807         else:
01808             log_method = access_log.error
01809         request_time = 1000.0 * handler.request.request_time()
01810         log_method("%d %s %.2fms", handler.get_status(),
01811                    handler._request_summary(), request_time)
01812 
01813 
01814 class _RequestDispatcher(httputil.HTTPMessageDelegate):
01815     def __init__(self, application, connection):
01816         self.application = application
01817         self.connection = connection
01818         self.request = None
01819         self.chunks = []
01820         self.handler_class = None
01821         self.handler_kwargs = None
01822         self.path_args = []
01823         self.path_kwargs = {}
01824 
01825     def headers_received(self, start_line, headers):
01826         self.set_request(httputil.HTTPServerRequest(
01827             connection=self.connection, start_line=start_line, headers=headers))
01828         if self.stream_request_body:
01829             self.request.body = Future()
01830             return self.execute()
01831 
01832     def set_request(self, request):
01833         self.request = request
01834         self._find_handler()
01835         self.stream_request_body = _has_stream_request_body(self.handler_class)
01836 
01837     def _find_handler(self):
01838         # Identify the handler to use as soon as we have the request.
01839         # Save url path arguments for later.
01840         app = self.application
01841         handlers = app._get_host_handlers(self.request)
01842         if not handlers:
01843             self.handler_class = RedirectHandler
01844             self.handler_kwargs = dict(url="http://" + app.default_host + "/")
01845             return
01846         for spec in handlers:
01847             match = spec.regex.match(self.request.path)
01848             if match:
01849                 self.handler_class = spec.handler_class
01850                 self.handler_kwargs = spec.kwargs
01851                 if spec.regex.groups:
01852                     # Pass matched groups to the handler.  Since
01853                     # match.groups() includes both named and
01854                     # unnamed groups, we want to use either groups
01855                     # or groupdict but not both.
01856                     if spec.regex.groupindex:
01857                         self.path_kwargs = dict(
01858                             (str(k), _unquote_or_none(v))
01859                             for (k, v) in match.groupdict().items())
01860                     else:
01861                         self.path_args = [_unquote_or_none(s)
01862                                           for s in match.groups()]
01863                 return
01864         if app.settings.get('default_handler_class'):
01865             self.handler_class = app.settings['default_handler_class']
01866             self.handler_kwargs = app.settings.get(
01867                 'default_handler_args', {})
01868         else:
01869             self.handler_class = ErrorHandler
01870             self.handler_kwargs = dict(status_code=404)
01871 
01872     def data_received(self, data):
01873         if self.stream_request_body:
01874             return self.handler.data_received(data)
01875         else:
01876             self.chunks.append(data)
01877 
01878     def finish(self):
01879         if self.stream_request_body:
01880             self.request.body.set_result(None)
01881         else:
01882             self.request.body = b''.join(self.chunks)
01883             self.request._parse_body()
01884             self.execute()
01885 
01886     def on_connection_close(self):
01887         if self.stream_request_body:
01888             self.handler.on_connection_close()
01889         else:
01890             self.chunks = None
01891 
01892     def execute(self):
01893         # If template cache is disabled (usually in the debug mode),
01894         # re-compile templates and reload static files on every
01895         # request so you don't need to restart to see changes
01896         if not self.application.settings.get("compiled_template_cache", True):
01897             with RequestHandler._template_loader_lock:
01898                 for loader in RequestHandler._template_loaders.values():
01899                     loader.reset()
01900         if not self.application.settings.get('static_hash_cache', True):
01901             StaticFileHandler.reset()
01902 
01903         self.handler = self.handler_class(self.application, self.request,
01904                                           **self.handler_kwargs)
01905         transforms = [t(self.request) for t in self.application.transforms]
01906 
01907         if self.stream_request_body:
01908             self.handler._prepared_future = Future()
01909         # Note that if an exception escapes handler._execute it will be
01910         # trapped in the Future it returns (which we are ignoring here).
01911         # However, that shouldn't happen because _execute has a blanket
01912         # except handler, and we cannot easily access the IOLoop here to
01913         # call add_future.
01914         self.handler._execute(transforms, *self.path_args, **self.path_kwargs)
01915         # If we are streaming the request body, then execute() is finished
01916         # when the handler has prepared to receive the body.  If not,
01917         # it doesn't matter when execute() finishes (so we return None)
01918         return self.handler._prepared_future
01919 
01920 
01921 class HTTPError(Exception):
01922     """An exception that will turn into an HTTP error response.
01923 
01924     Raising an `HTTPError` is a convenient alternative to calling
01925     `RequestHandler.send_error` since it automatically ends the
01926     current function.
01927 
01928     To customize the response sent with an `HTTPError`, override
01929     `RequestHandler.write_error`.
01930 
01931     :arg int status_code: HTTP status code.  Must be listed in
01932         `httplib.responses <http.client.responses>` unless the ``reason``
01933         keyword argument is given.
01934     :arg string log_message: Message to be written to the log for this error
01935         (will not be shown to the user unless the `Application` is in debug
01936         mode).  May contain ``%s``-style placeholders, which will be filled
01937         in with remaining positional parameters.
01938     :arg string reason: Keyword-only argument.  The HTTP "reason" phrase
01939         to pass in the status line along with ``status_code``.  Normally
01940         determined automatically from ``status_code``, but can be used
01941         to use a non-standard numeric code.
01942     """
01943     def __init__(self, status_code, log_message=None, *args, **kwargs):
01944         self.status_code = status_code
01945         self.log_message = log_message
01946         self.args = args
01947         self.reason = kwargs.get('reason', None)
01948 
01949     def __str__(self):
01950         message = "HTTP %d: %s" % (
01951             self.status_code,
01952             self.reason or httputil.responses.get(self.status_code, 'Unknown'))
01953         if self.log_message:
01954             return message + " (" + (self.log_message % self.args) + ")"
01955         else:
01956             return message
01957 
01958 
01959 class Finish(Exception):
01960     """An exception that ends the request without producing an error response.
01961 
01962     When `Finish` is raised in a `RequestHandler`, the request will end
01963     (calling `RequestHandler.finish` if it hasn't already been called),
01964     but the outgoing response will not be modified and the error-handling
01965     methods (including `RequestHandler.write_error`) will not be called.
01966 
01967     This can be a more convenient way to implement custom error pages
01968     than overriding ``write_error`` (especially in library code)::
01969 
01970         if self.current_user is None:
01971             self.set_status(401)
01972             self.set_header('WWW-Authenticate', 'Basic realm="something"')
01973             raise Finish()
01974     """
01975     pass
01976 
01977 
01978 class MissingArgumentError(HTTPError):
01979     """Exception raised by `RequestHandler.get_argument`.
01980 
01981     This is a subclass of `HTTPError`, so if it is uncaught a 400 response
01982     code will be used instead of 500 (and a stack trace will not be logged).
01983 
01984     .. versionadded:: 3.1
01985     """
01986     def __init__(self, arg_name):
01987         super(MissingArgumentError, self).__init__(
01988             400, 'Missing argument %s' % arg_name)
01989         self.arg_name = arg_name
01990 
01991 
01992 class ErrorHandler(RequestHandler):
01993     """Generates an error response with ``status_code`` for all requests."""
01994     def initialize(self, status_code):
01995         self.set_status(status_code)
01996 
01997     def prepare(self):
01998         raise HTTPError(self._status_code)
01999 
02000     def check_xsrf_cookie(self):
02001         # POSTs to an ErrorHandler don't actually have side effects,
02002         # so we don't need to check the xsrf token.  This allows POSTs
02003         # to the wrong url to return a 404 instead of 403.
02004         pass
02005 
02006 
02007 class RedirectHandler(RequestHandler):
02008     """Redirects the client to the given URL for all GET requests.
02009 
02010     You should provide the keyword argument ``url`` to the handler, e.g.::
02011 
02012         application = web.Application([
02013             (r"/oldpath", web.RedirectHandler, {"url": "/newpath"}),
02014         ])
02015     """
02016     def initialize(self, url, permanent=True):
02017         self._url = url
02018         self._permanent = permanent
02019 
02020     def get(self):
02021         self.redirect(self._url, permanent=self._permanent)
02022 
02023 
02024 class StaticFileHandler(RequestHandler):
02025     """A simple handler that can serve static content from a directory.
02026 
02027     A `StaticFileHandler` is configured automatically if you pass the
02028     ``static_path`` keyword argument to `Application`.  This handler
02029     can be customized with the ``static_url_prefix``, ``static_handler_class``,
02030     and ``static_handler_args`` settings.
02031 
02032     To map an additional path to this handler for a static data directory
02033     you would add a line to your application like::
02034 
02035         application = web.Application([
02036             (r"/content/(.*)", web.StaticFileHandler, {"path": "/var/www"}),
02037         ])
02038 
02039     The handler constructor requires a ``path`` argument, which specifies the
02040     local root directory of the content to be served.
02041 
02042     Note that a capture group in the regex is required to parse the value for
02043     the ``path`` argument to the get() method (different than the constructor
02044     argument above); see `URLSpec` for details.
02045 
02046     To maximize the effectiveness of browser caching, this class supports
02047     versioned urls (by default using the argument ``?v=``).  If a version
02048     is given, we instruct the browser to cache this file indefinitely.
02049     `make_static_url` (also available as `RequestHandler.static_url`) can
02050     be used to construct a versioned url.
02051 
02052     This handler is intended primarily for use in development and light-duty
02053     file serving; for heavy traffic it will be more efficient to use
02054     a dedicated static file server (such as nginx or Apache).  We support
02055     the HTTP ``Accept-Ranges`` mechanism to return partial content (because
02056     some browsers require this functionality to be present to seek in
02057     HTML5 audio or video), but this handler should not be used with
02058     files that are too large to fit comfortably in memory.
02059 
02060     **Subclassing notes**
02061 
02062     This class is designed to be extensible by subclassing, but because
02063     of the way static urls are generated with class methods rather than
02064     instance methods, the inheritance patterns are somewhat unusual.
02065     Be sure to use the ``@classmethod`` decorator when overriding a
02066     class method.  Instance methods may use the attributes ``self.path``
02067     ``self.absolute_path``, and ``self.modified``.
02068 
02069     Subclasses should only override methods discussed in this section;
02070     overriding other methods is error-prone.  Overriding
02071     ``StaticFileHandler.get`` is particularly problematic due to the
02072     tight coupling with ``compute_etag`` and other methods.
02073 
02074     To change the way static urls are generated (e.g. to match the behavior
02075     of another server or CDN), override `make_static_url`, `parse_url_path`,
02076     `get_cache_time`, and/or `get_version`.
02077 
02078     To replace all interaction with the filesystem (e.g. to serve
02079     static content from a database), override `get_content`,
02080     `get_content_size`, `get_modified_time`, `get_absolute_path`, and
02081     `validate_absolute_path`.
02082 
02083     .. versionchanged:: 3.1
02084        Many of the methods for subclasses were added in Tornado 3.1.
02085     """
02086     CACHE_MAX_AGE = 86400 * 365 * 10  # 10 years
02087 
02088     _static_hashes = {}
02089     _lock = threading.Lock()  # protects _static_hashes
02090 
02091     def initialize(self, path, default_filename=None):
02092         self.root = path
02093         self.default_filename = default_filename
02094 
02095     @classmethod
02096     def reset(cls):
02097         with cls._lock:
02098             cls._static_hashes = {}
02099 
02100     def head(self, path):
02101         return self.get(path, include_body=False)
02102 
02103     @gen.coroutine
02104     def get(self, path, include_body=True):
02105         # Set up our path instance variables.
02106         self.path = self.parse_url_path(path)
02107         del path  # make sure we don't refer to path instead of self.path again
02108         absolute_path = self.get_absolute_path(self.root, self.path)
02109         self.absolute_path = self.validate_absolute_path(
02110             self.root, absolute_path)
02111         if self.absolute_path is None:
02112             return
02113 
02114         self.modified = self.get_modified_time()
02115         self.set_headers()
02116 
02117         if self.should_return_304():
02118             self.set_status(304)
02119             return
02120 
02121         request_range = None
02122         range_header = self.request.headers.get("Range")
02123         if range_header:
02124             # As per RFC 2616 14.16, if an invalid Range header is specified,
02125             # the request will be treated as if the header didn't exist.
02126             request_range = httputil._parse_request_range(range_header)
02127 
02128         size = self.get_content_size()
02129         if request_range:
02130             start, end = request_range
02131             if (start is not None and start >= size) or end == 0:
02132                 # As per RFC 2616 14.35.1, a range is not satisfiable only: if
02133                 # the first requested byte is equal to or greater than the
02134                 # content, or when a suffix with length 0 is specified
02135                 self.set_status(416)  # Range Not Satisfiable
02136                 self.set_header("Content-Type", "text/plain")
02137                 self.set_header("Content-Range", "bytes */%s" % (size, ))
02138                 return
02139             if start is not None and start < 0:
02140                 start += size
02141             if end is not None and end > size:
02142                 # Clients sometimes blindly use a large range to limit their
02143                 # download size; cap the endpoint at the actual file size.
02144                 end = size
02145             # Note: only return HTTP 206 if less than the entire range has been
02146             # requested. Not only is this semantically correct, but Chrome
02147             # refuses to play audio if it gets an HTTP 206 in response to
02148             # ``Range: bytes=0-``.
02149             if size != (end or size) - (start or 0):
02150                 self.set_status(206)  # Partial Content
02151                 self.set_header("Content-Range",
02152                                 httputil._get_content_range(start, end, size))
02153         else:
02154             start = end = None
02155 
02156         if start is not None and end is not None:
02157             content_length = end - start
02158         elif end is not None:
02159             content_length = end
02160         elif start is not None:
02161             content_length = size - start
02162         else:
02163             content_length = size
02164         self.set_header("Content-Length", content_length)
02165 
02166         if include_body:
02167             content = self.get_content(self.absolute_path, start, end)
02168             if isinstance(content, bytes_type):
02169                 content = [content]
02170             for chunk in content:
02171                 self.write(chunk)
02172                 yield self.flush()
02173         else:
02174             assert self.request.method == "HEAD"
02175 
02176     def compute_etag(self):
02177         """Sets the ``Etag`` header based on static url version.
02178 
02179         This allows efficient ``If-None-Match`` checks against cached
02180         versions, and sends the correct ``Etag`` for a partial response
02181         (i.e. the same ``Etag`` as the full file).
02182 
02183         .. versionadded:: 3.1
02184         """
02185         version_hash = self._get_cached_version(self.absolute_path)
02186         if not version_hash:
02187             return None
02188         return '"%s"' % (version_hash, )
02189 
02190     def set_headers(self):
02191         """Sets the content and caching headers on the response.
02192 
02193         .. versionadded:: 3.1
02194         """
02195         self.set_header("Accept-Ranges", "bytes")
02196         self.set_etag_header()
02197 
02198         if self.modified is not None:
02199             self.set_header("Last-Modified", self.modified)
02200 
02201         content_type = self.get_content_type()
02202         if content_type:
02203             self.set_header("Content-Type", content_type)
02204 
02205         cache_time = self.get_cache_time(self.path, self.modified, content_type)
02206         if cache_time > 0:
02207             self.set_header("Expires", datetime.datetime.utcnow() +
02208                             datetime.timedelta(seconds=cache_time))
02209             self.set_header("Cache-Control", "max-age=" + str(cache_time))
02210 
02211         self.set_extra_headers(self.path)
02212 
02213     def should_return_304(self):
02214         """Returns True if the headers indicate that we should return 304.
02215 
02216         .. versionadded:: 3.1
02217         """
02218         if self.check_etag_header():
02219             return True
02220 
02221         # Check the If-Modified-Since, and don't send the result if the
02222         # content has not been modified
02223         ims_value = self.request.headers.get("If-Modified-Since")
02224         if ims_value is not None:
02225             date_tuple = email.utils.parsedate(ims_value)
02226             if date_tuple is not None:
02227                 if_since = datetime.datetime(*date_tuple[:6])
02228                 if if_since >= self.modified:
02229                     return True
02230 
02231         return False
02232 
02233     @classmethod
02234     def get_absolute_path(cls, root, path):
02235         """Returns the absolute location of ``path`` relative to ``root``.
02236 
02237         ``root`` is the path configured for this `StaticFileHandler`
02238         (in most cases the ``static_path`` `Application` setting).
02239 
02240         This class method may be overridden in subclasses.  By default
02241         it returns a filesystem path, but other strings may be used
02242         as long as they are unique and understood by the subclass's
02243         overridden `get_content`.
02244 
02245         .. versionadded:: 3.1
02246         """
02247         abspath = os.path.abspath(os.path.join(root, path))
02248         return abspath
02249 
02250     def validate_absolute_path(self, root, absolute_path):
02251         """Validate and return the absolute path.
02252 
02253         ``root`` is the configured path for the `StaticFileHandler`,
02254         and ``path`` is the result of `get_absolute_path`
02255 
02256         This is an instance method called during request processing,
02257         so it may raise `HTTPError` or use methods like
02258         `RequestHandler.redirect` (return None after redirecting to
02259         halt further processing).  This is where 404 errors for missing files
02260         are generated.
02261 
02262         This method may modify the path before returning it, but note that
02263         any such modifications will not be understood by `make_static_url`.
02264 
02265         In instance methods, this method's result is available as
02266         ``self.absolute_path``.
02267 
02268         .. versionadded:: 3.1
02269         """
02270         root = os.path.abspath(root)
02271         # os.path.abspath strips a trailing /
02272         # it needs to be temporarily added back for requests to root/
02273         if not (absolute_path + os.path.sep).startswith(root):
02274             raise HTTPError(403, "%s is not in root static directory",
02275                             self.path)
02276         if (os.path.isdir(absolute_path) and
02277                 self.default_filename is not None):
02278             # need to look at the request.path here for when path is empty
02279             # but there is some prefix to the path that was already
02280             # trimmed by the routing
02281             if not self.request.path.endswith("/"):
02282                 self.redirect(self.request.path + "/", permanent=True)
02283                 return
02284             absolute_path = os.path.join(absolute_path, self.default_filename)
02285         if not os.path.exists(absolute_path):
02286             raise HTTPError(404)
02287         if not os.path.isfile(absolute_path):
02288             raise HTTPError(403, "%s is not a file", self.path)
02289         return absolute_path
02290 
02291     @classmethod
02292     def get_content(cls, abspath, start=None, end=None):
02293         """Retrieve the content of the requested resource which is located
02294         at the given absolute path.
02295 
02296         This class method may be overridden by subclasses.  Note that its
02297         signature is different from other overridable class methods
02298         (no ``settings`` argument); this is deliberate to ensure that
02299         ``abspath`` is able to stand on its own as a cache key.
02300 
02301         This method should either return a byte string or an iterator
02302         of byte strings.  The latter is preferred for large files
02303         as it helps reduce memory fragmentation.
02304 
02305         .. versionadded:: 3.1
02306         """
02307         with open(abspath, "rb") as file:
02308             if start is not None:
02309                 file.seek(start)
02310             if end is not None:
02311                 remaining = end - (start or 0)
02312             else:
02313                 remaining = None
02314             while True:
02315                 chunk_size = 64 * 1024
02316                 if remaining is not None and remaining < chunk_size:
02317                     chunk_size = remaining
02318                 chunk = file.read(chunk_size)
02319                 if chunk:
02320                     if remaining is not None:
02321                         remaining -= len(chunk)
02322                     yield chunk
02323                 else:
02324                     if remaining is not None:
02325                         assert remaining == 0
02326                     return
02327 
02328     @classmethod
02329     def get_content_version(cls, abspath):
02330         """Returns a version string for the resource at the given path.
02331 
02332         This class method may be overridden by subclasses.  The
02333         default implementation is a hash of the file's contents.
02334 
02335         .. versionadded:: 3.1
02336         """
02337         data = cls.get_content(abspath)
02338         hasher = hashlib.md5()
02339         if isinstance(data, bytes_type):
02340             hasher.update(data)
02341         else:
02342             for chunk in data:
02343                 hasher.update(chunk)
02344         return hasher.hexdigest()
02345 
02346     def _stat(self):
02347         if not hasattr(self, '_stat_result'):
02348             self._stat_result = os.stat(self.absolute_path)
02349         return self._stat_result
02350 
02351     def get_content_size(self):
02352         """Retrieve the total size of the resource at the given path.
02353 
02354         This method may be overridden by subclasses.
02355 
02356         .. versionadded:: 3.1
02357 
02358         .. versionchanged:: 4.0
02359            This method is now always called, instead of only when
02360            partial results are requested.
02361         """
02362         stat_result = self._stat()
02363         return stat_result[stat.ST_SIZE]
02364 
02365     def get_modified_time(self):
02366         """Returns the time that ``self.absolute_path`` was last modified.
02367 
02368         May be overridden in subclasses.  Should return a `~datetime.datetime`
02369         object or None.
02370 
02371         .. versionadded:: 3.1
02372         """
02373         stat_result = self._stat()
02374         modified = datetime.datetime.utcfromtimestamp(stat_result[stat.ST_MTIME])
02375         return modified
02376 
02377     def get_content_type(self):
02378         """Returns the ``Content-Type`` header to be used for this request.
02379 
02380         .. versionadded:: 3.1
02381         """
02382         mime_type, encoding = mimetypes.guess_type(self.absolute_path)
02383         return mime_type
02384 
02385     def set_extra_headers(self, path):
02386         """For subclass to add extra headers to the response"""
02387         pass
02388 
02389     def get_cache_time(self, path, modified, mime_type):
02390         """Override to customize cache control behavior.
02391 
02392         Return a positive number of seconds to make the result
02393         cacheable for that amount of time or 0 to mark resource as
02394         cacheable for an unspecified amount of time (subject to
02395         browser heuristics).
02396 
02397         By default returns cache expiry of 10 years for resources requested
02398         with ``v`` argument.
02399         """
02400         return self.CACHE_MAX_AGE if "v" in self.request.arguments else 0
02401 
02402     @classmethod
02403     def make_static_url(cls, settings, path, include_version=True):
02404         """Constructs a versioned url for the given path.
02405 
02406         This method may be overridden in subclasses (but note that it
02407         is a class method rather than an instance method).  Subclasses
02408         are only required to implement the signature
02409         ``make_static_url(cls, settings, path)``; other keyword
02410         arguments may be passed through `~RequestHandler.static_url`
02411         but are not standard.
02412 
02413         ``settings`` is the `Application.settings` dictionary.  ``path``
02414         is the static path being requested.  The url returned should be
02415         relative to the current host.
02416 
02417         ``include_version`` determines whether the generated URL should
02418         include the query string containing the version hash of the
02419         file corresponding to the given ``path``.
02420 
02421         """
02422         url = settings.get('static_url_prefix', '/static/') + path
02423         if not include_version:
02424             return url
02425 
02426         version_hash = cls.get_version(settings, path)
02427         if not version_hash:
02428             return url
02429 
02430         return '%s?v=%s' % (url, version_hash)
02431 
02432     def parse_url_path(self, url_path):
02433         """Converts a static URL path into a filesystem path.
02434 
02435         ``url_path`` is the path component of the URL with
02436         ``static_url_prefix`` removed.  The return value should be
02437         filesystem path relative to ``static_path``.
02438 
02439         This is the inverse of `make_static_url`.
02440         """
02441         if os.path.sep != "/":
02442             url_path = url_path.replace("/", os.path.sep)
02443         return url_path
02444 
02445     @classmethod
02446     def get_version(cls, settings, path):
02447         """Generate the version string to be used in static URLs.
02448 
02449         ``settings`` is the `Application.settings` dictionary and ``path``
02450         is the relative location of the requested asset on the filesystem.
02451         The returned value should be a string, or ``None`` if no version
02452         could be determined.
02453 
02454         .. versionchanged:: 3.1
02455            This method was previously recommended for subclasses to override;
02456            `get_content_version` is now preferred as it allows the base
02457            class to handle caching of the result.
02458         """
02459         abs_path = cls.get_absolute_path(settings['static_path'], path)
02460         return cls._get_cached_version(abs_path)
02461 
02462     @classmethod
02463     def _get_cached_version(cls, abs_path):
02464         with cls._lock:
02465             hashes = cls._static_hashes
02466             if abs_path not in hashes:
02467                 try:
02468                     hashes[abs_path] = cls.get_content_version(abs_path)
02469                 except Exception:
02470                     gen_log.error("Could not open static file %r", abs_path)
02471                     hashes[abs_path] = None
02472             hsh = hashes.get(abs_path)
02473             if hsh:
02474                 return hsh
02475         return None
02476 
02477 
02478 class FallbackHandler(RequestHandler):
02479     """A `RequestHandler` that wraps another HTTP server callback.
02480 
02481     The fallback is a callable object that accepts an
02482     `~.httputil.HTTPServerRequest`, such as an `Application` or
02483     `tornado.wsgi.WSGIContainer`.  This is most useful to use both
02484     Tornado ``RequestHandlers`` and WSGI in the same server.  Typical
02485     usage::
02486 
02487         wsgi_app = tornado.wsgi.WSGIContainer(
02488             django.core.handlers.wsgi.WSGIHandler())
02489         application = tornado.web.Application([
02490             (r"/foo", FooHandler),
02491             (r".*", FallbackHandler, dict(fallback=wsgi_app),
02492         ])
02493     """
02494     def initialize(self, fallback):
02495         self.fallback = fallback
02496 
02497     def prepare(self):
02498         self.fallback(self.request)
02499         self._finished = True
02500 
02501 
02502 class OutputTransform(object):
02503     """A transform modifies the result of an HTTP request (e.g., GZip encoding)
02504 
02505     Applications are not expected to create their own OutputTransforms
02506     or interact with them directly; the framework chooses which transforms
02507     (if any) to apply.
02508     """
02509     def __init__(self, request):
02510         pass
02511 
02512     def transform_first_chunk(self, status_code, headers, chunk, finishing):
02513         return status_code, headers, chunk
02514 
02515     def transform_chunk(self, chunk, finishing):
02516         return chunk
02517 
02518 
02519 class GZipContentEncoding(OutputTransform):
02520     """Applies the gzip content encoding to the response.
02521 
02522     See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11
02523 
02524     .. versionchanged:: 4.0
02525         Now compresses all mime types beginning with ``text/``, instead
02526         of just a whitelist. (the whitelist is still used for certain
02527         non-text mime types).
02528     """
02529     # Whitelist of compressible mime types (in addition to any types
02530     # beginning with "text/").
02531     CONTENT_TYPES = set(["application/javascript", "application/x-javascript",
02532                          "application/xml", "application/atom+xml",
02533                          "application/json", "application/xhtml+xml"])
02534     MIN_LENGTH = 5
02535 
02536     def __init__(self, request):
02537         self._gzipping = "gzip" in request.headers.get("Accept-Encoding", "")
02538 
02539     def _compressible_type(self, ctype):
02540         return ctype.startswith('text/') or ctype in self.CONTENT_TYPES
02541 
02542     def transform_first_chunk(self, status_code, headers, chunk, finishing):
02543         if 'Vary' in headers:
02544             headers['Vary'] += b', Accept-Encoding'
02545         else:
02546             headers['Vary'] = b'Accept-Encoding'
02547         if self._gzipping:
02548             ctype = _unicode(headers.get("Content-Type", "")).split(";")[0]
02549             self._gzipping = self._compressible_type(ctype) and \
02550                 (not finishing or len(chunk) >= self.MIN_LENGTH) and \
02551                 ("Content-Encoding" not in headers)
02552         if self._gzipping:
02553             headers["Content-Encoding"] = "gzip"
02554             self._gzip_value = BytesIO()
02555             self._gzip_file = gzip.GzipFile(mode="w", fileobj=self._gzip_value)
02556             chunk = self.transform_chunk(chunk, finishing)
02557             if "Content-Length" in headers:
02558                 # The original content length is no longer correct.
02559                 # If this is the last (and only) chunk, we can set the new
02560                 # content-length; otherwise we remove it and fall back to
02561                 # chunked encoding.
02562                 if finishing:
02563                     headers["Content-Length"] = str(len(chunk))
02564                 else:
02565                     del headers["Content-Length"]
02566         return status_code, headers, chunk
02567 
02568     def transform_chunk(self, chunk, finishing):
02569         if self._gzipping:
02570             self._gzip_file.write(chunk)
02571             if finishing:
02572                 self._gzip_file.close()
02573             else:
02574                 self._gzip_file.flush()
02575             chunk = self._gzip_value.getvalue()
02576             self._gzip_value.truncate(0)
02577             self._gzip_value.seek(0)
02578         return chunk
02579 
02580 
02581 def authenticated(method):
02582     """Decorate methods with this to require that the user be logged in.
02583 
02584     If the user is not logged in, they will be redirected to the configured
02585     `login url <RequestHandler.get_login_url>`.
02586 
02587     If you configure a login url with a query parameter, Tornado will
02588     assume you know what you're doing and use it as-is.  If not, it
02589     will add a `next` parameter so the login page knows where to send
02590     you once you're logged in.
02591     """
02592     @functools.wraps(method)
02593     def wrapper(self, *args, **kwargs):
02594         if not self.current_user:
02595             if self.request.method in ("GET", "HEAD"):
02596                 url = self.get_login_url()
02597                 if "?" not in url:
02598                     if urlparse.urlsplit(url).scheme:
02599                         # if login url is absolute, make next absolute too
02600                         next_url = self.request.full_url()
02601                     else:
02602                         next_url = self.request.uri
02603                     url += "?" + urlencode(dict(next=next_url))
02604                 self.redirect(url)
02605                 return
02606             raise HTTPError(403)
02607         return method(self, *args, **kwargs)
02608     return wrapper
02609 
02610 
02611 class UIModule(object):
02612     """A re-usable, modular UI unit on a page.
02613 
02614     UI modules often execute additional queries, and they can include
02615     additional CSS and JavaScript that will be included in the output
02616     page, which is automatically inserted on page render.
02617     """
02618     def __init__(self, handler):
02619         self.handler = handler
02620         self.request = handler.request
02621         self.ui = handler.ui
02622         self.locale = handler.locale
02623 
02624     @property
02625     def current_user(self):
02626         return self.handler.current_user
02627 
02628     def render(self, *args, **kwargs):
02629         """Overridden in subclasses to return this module's output."""
02630         raise NotImplementedError()
02631 
02632     def embedded_javascript(self):
02633         """Returns a JavaScript string that will be embedded in the page."""
02634         return None
02635 
02636     def javascript_files(self):
02637         """Returns a list of JavaScript files required by this module."""
02638         return None
02639 
02640     def embedded_css(self):
02641         """Returns a CSS string that will be embedded in the page."""
02642         return None
02643 
02644     def css_files(self):
02645         """Returns a list of CSS files required by this module."""
02646         return None
02647 
02648     def html_head(self):
02649         """Returns a CSS string that will be put in the <head/> element"""
02650         return None
02651 
02652     def html_body(self):
02653         """Returns an HTML string that will be put in the <body/> element"""
02654         return None
02655 
02656     def render_string(self, path, **kwargs):
02657         """Renders a template and returns it as a string."""
02658         return self.handler.render_string(path, **kwargs)
02659 
02660 
02661 class _linkify(UIModule):
02662     def render(self, text, **kwargs):
02663         return escape.linkify(text, **kwargs)
02664 
02665 
02666 class _xsrf_form_html(UIModule):
02667     def render(self):
02668         return self.handler.xsrf_form_html()
02669 
02670 
02671 class TemplateModule(UIModule):
02672     """UIModule that simply renders the given template.
02673 
02674     {% module Template("foo.html") %} is similar to {% include "foo.html" %},
02675     but the module version gets its own namespace (with kwargs passed to
02676     Template()) instead of inheriting the outer template's namespace.
02677 
02678     Templates rendered through this module also get access to UIModule's
02679     automatic javascript/css features.  Simply call set_resources
02680     inside the template and give it keyword arguments corresponding to
02681     the methods on UIModule: {{ set_resources(js_files=static_url("my.js")) }}
02682     Note that these resources are output once per template file, not once
02683     per instantiation of the template, so they must not depend on
02684     any arguments to the template.
02685     """
02686     def __init__(self, handler):
02687         super(TemplateModule, self).__init__(handler)
02688         # keep resources in both a list and a dict to preserve order
02689         self._resource_list = []
02690         self._resource_dict = {}
02691 
02692     def render(self, path, **kwargs):
02693         def set_resources(**kwargs):
02694             if path not in self._resource_dict:
02695                 self._resource_list.append(kwargs)
02696                 self._resource_dict[path] = kwargs
02697             else:
02698                 if self._resource_dict[path] != kwargs:
02699                     raise ValueError("set_resources called with different "
02700                                      "resources for the same template")
02701             return ""
02702         return self.render_string(path, set_resources=set_resources,
02703                                   **kwargs)
02704 
02705     def _get_resources(self, key):
02706         return (r[key] for r in self._resource_list if key in r)
02707 
02708     def embedded_javascript(self):
02709         return "\n".join(self._get_resources("embedded_javascript"))
02710 
02711     def javascript_files(self):
02712         result = []
02713         for f in self._get_resources("javascript_files"):
02714             if isinstance(f, (unicode_type, bytes_type)):
02715                 result.append(f)
02716             else:
02717                 result.extend(f)
02718         return result
02719 
02720     def embedded_css(self):
02721         return "\n".join(self._get_resources("embedded_css"))
02722 
02723     def css_files(self):
02724         result = []
02725         for f in self._get_resources("css_files"):
02726             if isinstance(f, (unicode_type, bytes_type)):
02727                 result.append(f)
02728             else:
02729                 result.extend(f)
02730         return result
02731 
02732     def html_head(self):
02733         return "".join(self._get_resources("html_head"))
02734 
02735     def html_body(self):
02736         return "".join(self._get_resources("html_body"))
02737 
02738 
02739 class _UIModuleNamespace(object):
02740     """Lazy namespace which creates UIModule proxies bound to a handler."""
02741     def __init__(self, handler, ui_modules):
02742         self.handler = handler
02743         self.ui_modules = ui_modules
02744 
02745     def __getitem__(self, key):
02746         return self.handler._ui_module(key, self.ui_modules[key])
02747 
02748     def __getattr__(self, key):
02749         try:
02750             return self[key]
02751         except KeyError as e:
02752             raise AttributeError(str(e))
02753 
02754 
02755 class URLSpec(object):
02756     """Specifies mappings between URLs and handlers."""
02757     def __init__(self, pattern, handler, kwargs=None, name=None):
02758         """Parameters:
02759 
02760         * ``pattern``: Regular expression to be matched.  Any groups
02761           in the regex will be passed in to the handler's get/post/etc
02762           methods as arguments.
02763 
02764         * ``handler``: `RequestHandler` subclass to be invoked.
02765 
02766         * ``kwargs`` (optional): A dictionary of additional arguments
02767           to be passed to the handler's constructor.
02768 
02769         * ``name`` (optional): A name for this handler.  Used by
02770           `Application.reverse_url`.
02771         """
02772         if not pattern.endswith('$'):
02773             pattern += '$'
02774         self.regex = re.compile(pattern)
02775         assert len(self.regex.groupindex) in (0, self.regex.groups), \
02776             ("groups in url regexes must either be all named or all "
02777              "positional: %r" % self.regex.pattern)
02778 
02779         if isinstance(handler, str):
02780             # import the Module and instantiate the class
02781             # Must be a fully qualified name (module.ClassName)
02782             handler = import_object(handler)
02783 
02784         self.handler_class = handler
02785         self.kwargs = kwargs or {}
02786         self.name = name
02787         self._path, self._group_count = self._find_groups()
02788 
02789     def __repr__(self):
02790         return '%s(%r, %s, kwargs=%r, name=%r)' % \
02791             (self.__class__.__name__, self.regex.pattern,
02792              self.handler_class, self.kwargs, self.name)
02793 
02794     def _find_groups(self):
02795         """Returns a tuple (reverse string, group count) for a url.
02796 
02797         For example: Given the url pattern /([0-9]{4})/([a-z-]+)/, this method
02798         would return ('/%s/%s/', 2).
02799         """
02800         pattern = self.regex.pattern
02801         if pattern.startswith('^'):
02802             pattern = pattern[1:]
02803         if pattern.endswith('$'):
02804             pattern = pattern[:-1]
02805 
02806         if self.regex.groups != pattern.count('('):
02807             # The pattern is too complicated for our simplistic matching,
02808             # so we can't support reversing it.
02809             return (None, None)
02810 
02811         pieces = []
02812         for fragment in pattern.split('('):
02813             if ')' in fragment:
02814                 paren_loc = fragment.index(')')
02815                 if paren_loc >= 0:
02816                     pieces.append('%s' + fragment[paren_loc + 1:])
02817             else:
02818                 pieces.append(fragment)
02819 
02820         return (''.join(pieces), self.regex.groups)
02821 
02822     def reverse(self, *args):
02823         assert self._path is not None, \
02824             "Cannot reverse url regex " + self.regex.pattern
02825         assert len(args) == self._group_count, "required number of arguments "\
02826             "not found"
02827         if not len(args):
02828             return self._path
02829         converted_args = []
02830         for a in args:
02831             if not isinstance(a, (unicode_type, bytes_type)):
02832                 a = str(a)
02833             converted_args.append(escape.url_escape(utf8(a), plus=False))
02834         return self._path % tuple(converted_args)
02835 
02836 url = URLSpec
02837 
02838 
02839 if hasattr(hmac, 'compare_digest'):  # python 3.3
02840     _time_independent_equals = hmac.compare_digest
02841 else:
02842     def _time_independent_equals(a, b):
02843         if len(a) != len(b):
02844             return False
02845         result = 0
02846         if isinstance(a[0], int):  # python3 byte strings
02847             for x, y in zip(a, b):
02848                 result |= x ^ y
02849         else:  # python2
02850             for x, y in zip(a, b):
02851                 result |= ord(x) ^ ord(y)
02852         return result == 0
02853 
02854 
02855 def create_signed_value(secret, name, value, version=None, clock=None):
02856     if version is None:
02857         version = DEFAULT_SIGNED_VALUE_VERSION
02858     if clock is None:
02859         clock = time.time
02860     timestamp = utf8(str(int(clock())))
02861     value = base64.b64encode(utf8(value))
02862     if version == 1:
02863         signature = _create_signature_v1(secret, name, value, timestamp)
02864         value = b"|".join([value, timestamp, signature])
02865         return value
02866     elif version == 2:
02867         # The v2 format consists of a version number and a series of
02868         # length-prefixed fields "%d:%s", the last of which is a
02869         # signature, all separated by pipes.  All numbers are in
02870         # decimal format with no leading zeros.  The signature is an
02871         # HMAC-SHA256 of the whole string up to that point, including
02872         # the final pipe.
02873         #
02874         # The fields are:
02875         # - format version (i.e. 2; no length prefix)
02876         # - key version (currently 0; reserved for future key rotation features)
02877         # - timestamp (integer seconds since epoch)
02878         # - name (not encoded; assumed to be ~alphanumeric)
02879         # - value (base64-encoded)
02880         # - signature (hex-encoded; no length prefix)
02881         def format_field(s):
02882             return utf8("%d:" % len(s)) + utf8(s)
02883         to_sign = b"|".join([
02884             b"2|1:0",
02885             format_field(timestamp),
02886             format_field(name),
02887             format_field(value),
02888             b''])
02889         signature = _create_signature_v2(secret, to_sign)
02890         return to_sign + signature
02891     else:
02892         raise ValueError("Unsupported version %d" % version)
02893 
02894 # A leading version number in decimal with no leading zeros, followed by a pipe.
02895 _signed_value_version_re = re.compile(br"^([1-9][0-9]*)\|(.*)$")
02896 
02897 
02898 def decode_signed_value(secret, name, value, max_age_days=31, clock=None, min_version=None):
02899     if clock is None:
02900         clock = time.time
02901     if min_version is None:
02902         min_version = DEFAULT_SIGNED_VALUE_MIN_VERSION
02903     if min_version > 2:
02904         raise ValueError("Unsupported min_version %d" % min_version)
02905     if not value:
02906         return None
02907 
02908     # Figure out what version this is.  Version 1 did not include an
02909     # explicit version field and started with arbitrary base64 data,
02910     # which makes this tricky.
02911     value = utf8(value)
02912     m = _signed_value_version_re.match(value)
02913     if m is None:
02914         version = 1
02915     else:
02916         try:
02917             version = int(m.group(1))
02918             if version > 999:
02919                 # Certain payloads from the version-less v1 format may
02920                 # be parsed as valid integers.  Due to base64 padding
02921                 # restrictions, this can only happen for numbers whose
02922                 # length is a multiple of 4, so we can treat all
02923                 # numbers up to 999 as versions, and for the rest we
02924                 # fall back to v1 format.
02925                 version = 1
02926         except ValueError:
02927             version = 1
02928 
02929     if version < min_version:
02930         return None
02931     if version == 1:
02932         return _decode_signed_value_v1(secret, name, value, max_age_days, clock)
02933     elif version == 2:
02934         return _decode_signed_value_v2(secret, name, value, max_age_days, clock)
02935     else:
02936         return None
02937 
02938 
02939 def _decode_signed_value_v1(secret, name, value, max_age_days, clock):
02940     parts = utf8(value).split(b"|")
02941     if len(parts) != 3:
02942         return None
02943     signature = _create_signature_v1(secret, name, parts[0], parts[1])
02944     if not _time_independent_equals(parts[2], signature):
02945         gen_log.warning("Invalid cookie signature %r", value)
02946         return None
02947     timestamp = int(parts[1])
02948     if timestamp < clock() - max_age_days * 86400:
02949         gen_log.warning("Expired cookie %r", value)
02950         return None
02951     if timestamp > clock() + 31 * 86400:
02952         # _cookie_signature does not hash a delimiter between the
02953         # parts of the cookie, so an attacker could transfer trailing
02954         # digits from the payload to the timestamp without altering the
02955         # signature.  For backwards compatibility, sanity-check timestamp
02956         # here instead of modifying _cookie_signature.
02957         gen_log.warning("Cookie timestamp in future; possible tampering %r", value)
02958         return None
02959     if parts[1].startswith(b"0"):
02960         gen_log.warning("Tampered cookie %r", value)
02961         return None
02962     try:
02963         return base64.b64decode(parts[0])
02964     except Exception:
02965         return None
02966 
02967 
02968 def _decode_signed_value_v2(secret, name, value, max_age_days, clock):
02969     def _consume_field(s):
02970         length, _, rest = s.partition(b':')
02971         n = int(length)
02972         field_value = rest[:n]
02973         # In python 3, indexing bytes returns small integers; we must
02974         # use a slice to get a byte string as in python 2.
02975         if rest[n:n + 1] != b'|':
02976             raise ValueError("malformed v2 signed value field")
02977         rest = rest[n + 1:]
02978         return field_value, rest
02979     rest = value[2:]  # remove version number
02980     try:
02981         key_version, rest = _consume_field(rest)
02982         timestamp, rest = _consume_field(rest)
02983         name_field, rest = _consume_field(rest)
02984         value_field, rest = _consume_field(rest)
02985     except ValueError:
02986         return None
02987     passed_sig = rest
02988     signed_string = value[:-len(passed_sig)]
02989     expected_sig = _create_signature_v2(secret, signed_string)
02990     if not _time_independent_equals(passed_sig, expected_sig):
02991         return None
02992     if name_field != utf8(name):
02993         return None
02994     timestamp = int(timestamp)
02995     if timestamp < clock() - max_age_days * 86400:
02996         # The signature has expired.
02997         return None
02998     try:
02999         return base64.b64decode(value_field)
03000     except Exception:
03001         return None
03002 
03003 
03004 def _create_signature_v1(secret, *parts):
03005     hash = hmac.new(utf8(secret), digestmod=hashlib.sha1)
03006     for part in parts:
03007         hash.update(utf8(part))
03008     return utf8(hash.hexdigest())
03009 
03010 
03011 def _create_signature_v2(secret, s):
03012     hash = hmac.new(utf8(secret), digestmod=hashlib.sha256)
03013     hash.update(utf8(s))
03014     return utf8(hash.hexdigest())
03015 
03016 
03017 def _unquote_or_none(s):
03018     """None-safe wrapper around url_unescape to handle unamteched optional
03019     groups correctly.
03020 
03021     Note that args are passed as bytes so the handler can decide what
03022     encoding to use.
03023     """
03024     if s is None:
03025         return s
03026     return escape.url_unescape(s, encoding=None, plus=False)


rosbridge_server
Author(s): Jonathan Mace
autogenerated on Thu Jun 6 2019 21:51:51