Tornado update
This commit is contained in:
+101
-98
@@ -49,21 +49,18 @@ threads it is important to use IOLoop.add_callback to transfer control
|
||||
back to the main thread before finishing the request.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, with_statement
|
||||
from __future__ import absolute_import, division, print_function, with_statement
|
||||
|
||||
import Cookie
|
||||
import base64
|
||||
import binascii
|
||||
import calendar
|
||||
import datetime
|
||||
import email.utils
|
||||
import functools
|
||||
import gzip
|
||||
import hashlib
|
||||
import hmac
|
||||
import httplib
|
||||
import itertools
|
||||
import mimetypes
|
||||
import numbers
|
||||
import os.path
|
||||
import re
|
||||
import stat
|
||||
@@ -73,23 +70,37 @@ import time
|
||||
import tornado
|
||||
import traceback
|
||||
import types
|
||||
import urllib
|
||||
import urlparse
|
||||
import uuid
|
||||
|
||||
from tornado import escape
|
||||
from tornado import httputil
|
||||
from tornado import locale
|
||||
from tornado.log import access_log, app_log, gen_log
|
||||
from tornado import stack_context
|
||||
from tornado import template
|
||||
from tornado.escape import utf8, _unicode
|
||||
from tornado.util import b, bytes_type, import_object, ObjectDict, raise_exc_info
|
||||
from tornado.util import bytes_type, import_object, ObjectDict, raise_exc_info, unicode_type
|
||||
|
||||
try:
|
||||
from io import BytesIO # python 3
|
||||
except ImportError:
|
||||
from cStringIO import StringIO as BytesIO # python 2
|
||||
|
||||
try:
|
||||
import Cookie # py2
|
||||
except ImportError:
|
||||
import http.cookies as Cookie # py3
|
||||
|
||||
try:
|
||||
import urlparse # py2
|
||||
except ImportError:
|
||||
import urllib.parse as urlparse # py3
|
||||
|
||||
try:
|
||||
from urllib import urlencode # py2
|
||||
except ImportError:
|
||||
from urllib.parse import urlencode # py3
|
||||
|
||||
|
||||
class RequestHandler(object):
|
||||
"""Subclass this class and define get() or post() to make a handler.
|
||||
@@ -103,6 +114,7 @@ class RequestHandler(object):
|
||||
|
||||
_template_loaders = {} # {path: template.BaseLoader}
|
||||
_template_loader_lock = threading.Lock()
|
||||
_remove_control_chars_regex = re.compile(r"[\x00-\x08\x0e-\x1f]")
|
||||
|
||||
def __init__(self, application, request, **kwargs):
|
||||
super(RequestHandler, self).__init__()
|
||||
@@ -116,19 +128,19 @@ class RequestHandler(object):
|
||||
self.path_args = None
|
||||
self.path_kwargs = None
|
||||
self.ui = ObjectDict((n, self._ui_method(m)) for n, m in
|
||||
application.ui_methods.iteritems())
|
||||
application.ui_methods.items())
|
||||
# UIModules are available as both `modules` and `_modules` in the
|
||||
# template namespace. Historically only `modules` was available
|
||||
# but could be clobbered by user additions to the namespace.
|
||||
# The template {% module %} directive looks in `_modules` to avoid
|
||||
# possible conflicts.
|
||||
self.ui["_modules"] = ObjectDict((n, self._ui_module(n, m)) for n, m in
|
||||
application.ui_modules.iteritems())
|
||||
application.ui_modules.items())
|
||||
self.ui["modules"] = self.ui["_modules"]
|
||||
self.clear()
|
||||
# Check since connection is not available in WSGI
|
||||
if getattr(self.request, "connection", None):
|
||||
self.request.connection.stream.set_close_callback(
|
||||
self.request.connection.set_close_callback(
|
||||
self.on_connection_close)
|
||||
self.initialize(**kwargs)
|
||||
|
||||
@@ -215,25 +227,18 @@ class RequestHandler(object):
|
||||
|
||||
def clear(self):
|
||||
"""Resets all headers and content for this response."""
|
||||
# The performance cost of tornado.httputil.HTTPHeaders is significant
|
||||
# (slowing down a benchmark with a trivial handler by more than 10%),
|
||||
# and its case-normalization is not generally necessary for
|
||||
# headers we generate on the server side, so use a plain dict
|
||||
# and list instead.
|
||||
self._headers = {
|
||||
"Server": "TornadoServer/%s" % tornado.version,
|
||||
"Content-Type": "text/html; charset=UTF-8",
|
||||
"Date": datetime.datetime.utcnow().strftime(
|
||||
"%a, %d %b %Y %H:%M:%S GMT"),
|
||||
}
|
||||
self._list_headers = []
|
||||
self._headers = httputil.HTTPHeaders({
|
||||
"Server": "TornadoServer/%s" % tornado.version,
|
||||
"Content-Type": "text/html; charset=UTF-8",
|
||||
"Date": httputil.format_timestamp(time.gmtime()),
|
||||
})
|
||||
self.set_default_headers()
|
||||
if not self.request.supports_http_1_1():
|
||||
if self.request.headers.get("Connection") == "Keep-Alive":
|
||||
self.set_header("Connection", "Keep-Alive")
|
||||
self._write_buffer = []
|
||||
self._status_code = 200
|
||||
self._reason = httplib.responses[200]
|
||||
self._reason = httputil.responses[200]
|
||||
|
||||
def set_default_headers(self):
|
||||
"""Override this to set HTTP headers at the beginning of the request.
|
||||
@@ -258,7 +263,7 @@ class RequestHandler(object):
|
||||
self._reason = escape.native_str(reason)
|
||||
else:
|
||||
try:
|
||||
self._reason = httplib.responses[status_code]
|
||||
self._reason = httputil.responses[status_code]
|
||||
except KeyError:
|
||||
raise ValueError("unknown status code %d", status_code)
|
||||
|
||||
@@ -281,7 +286,7 @@ class RequestHandler(object):
|
||||
Unlike `set_header`, `add_header` may be called multiple times
|
||||
to return multiple values for the same header.
|
||||
"""
|
||||
self._list_headers.append((name, self._convert_header_value(value)))
|
||||
self._headers.add(name, self._convert_header_value(value))
|
||||
|
||||
def clear_header(self, name):
|
||||
"""Clears an outgoing header, undoing a previous `set_header` call.
|
||||
@@ -295,20 +300,19 @@ class RequestHandler(object):
|
||||
def _convert_header_value(self, value):
|
||||
if isinstance(value, bytes_type):
|
||||
pass
|
||||
elif isinstance(value, unicode):
|
||||
elif isinstance(value, unicode_type):
|
||||
value = value.encode('utf-8')
|
||||
elif isinstance(value, (int, long)):
|
||||
elif isinstance(value, numbers.Integral):
|
||||
# return immediately since we know the converted value will be safe
|
||||
return str(value)
|
||||
elif isinstance(value, datetime.datetime):
|
||||
t = calendar.timegm(value.utctimetuple())
|
||||
return email.utils.formatdate(t, localtime=False, usegmt=True)
|
||||
return httputil.format_timestamp(value)
|
||||
else:
|
||||
raise TypeError("Unsupported header value %r" % value)
|
||||
# If \n is allowed into the header, it is possible to inject
|
||||
# additional headers or split the request. Also cap length to
|
||||
# prevent obviously erroneous values.
|
||||
if len(value) > 4000 or re.search(b(r"[\x00-\x1f]"), value):
|
||||
if len(value) > 4000 or re.search(br"[\x00-\x1f]", value):
|
||||
raise ValueError("Unsafe header value %r", value)
|
||||
return value
|
||||
|
||||
@@ -339,13 +343,14 @@ class RequestHandler(object):
|
||||
|
||||
The returned values are always unicode.
|
||||
"""
|
||||
|
||||
values = []
|
||||
for v in self.request.arguments.get(name, []):
|
||||
v = self.decode_argument(v, name=name)
|
||||
if isinstance(v, unicode):
|
||||
if isinstance(v, unicode_type):
|
||||
# Get rid of any weird control chars (unless decoding gave
|
||||
# us bytes, in which case leave it alone)
|
||||
v = re.sub(r"[\x00-\x08\x0e-\x1f]", " ", v)
|
||||
v = RequestHandler._remove_control_chars_regex.sub(" ", v)
|
||||
if strip:
|
||||
v = v.strip()
|
||||
values.append(v)
|
||||
@@ -403,12 +408,10 @@ class RequestHandler(object):
|
||||
expires = datetime.datetime.utcnow() + datetime.timedelta(
|
||||
days=expires_days)
|
||||
if expires:
|
||||
timestamp = calendar.timegm(expires.utctimetuple())
|
||||
morsel["expires"] = email.utils.formatdate(
|
||||
timestamp, localtime=False, usegmt=True)
|
||||
morsel["expires"] = httputil.format_timestamp(expires)
|
||||
if path:
|
||||
morsel["path"] = path
|
||||
for k, v in kwargs.iteritems():
|
||||
for k, v in kwargs.items():
|
||||
if k == 'max_age':
|
||||
k = 'max-age'
|
||||
morsel[k] = v
|
||||
@@ -421,7 +424,7 @@ class RequestHandler(object):
|
||||
|
||||
def clear_all_cookies(self):
|
||||
"""Deletes all the cookies the user sent with this request."""
|
||||
for name in self.request.cookies.iterkeys():
|
||||
for name in self.request.cookies:
|
||||
self.clear_cookie(name)
|
||||
|
||||
def set_secure_cookie(self, name, value, expires_days=30, **kwargs):
|
||||
@@ -482,7 +485,7 @@ class RequestHandler(object):
|
||||
assert isinstance(status, int) and 300 <= status <= 399
|
||||
self.set_status(status)
|
||||
# Remove whitespace
|
||||
url = re.sub(b(r"[\x00-\x20]+"), "", utf8(url))
|
||||
url = re.sub(br"[\x00-\x20]+", "", utf8(url))
|
||||
self.set_header("Location", urlparse.urljoin(utf8(self.request.uri),
|
||||
url))
|
||||
self.finish()
|
||||
@@ -523,13 +526,13 @@ class RequestHandler(object):
|
||||
css_files = []
|
||||
html_heads = []
|
||||
html_bodies = []
|
||||
for module in getattr(self, "_active_modules", {}).itervalues():
|
||||
for module in getattr(self, "_active_modules", {}).values():
|
||||
embed_part = module.embedded_javascript()
|
||||
if embed_part:
|
||||
js_embed.append(utf8(embed_part))
|
||||
file_part = module.javascript_files()
|
||||
if file_part:
|
||||
if isinstance(file_part, (unicode, bytes_type)):
|
||||
if isinstance(file_part, (unicode_type, bytes_type)):
|
||||
js_files.append(file_part)
|
||||
else:
|
||||
js_files.extend(file_part)
|
||||
@@ -538,7 +541,7 @@ class RequestHandler(object):
|
||||
css_embed.append(utf8(embed_part))
|
||||
file_part = module.css_files()
|
||||
if file_part:
|
||||
if isinstance(file_part, (unicode, bytes_type)):
|
||||
if isinstance(file_part, (unicode_type, bytes_type)):
|
||||
css_files.append(file_part)
|
||||
else:
|
||||
css_files.extend(file_part)
|
||||
@@ -564,13 +567,13 @@ class RequestHandler(object):
|
||||
js = ''.join('<script src="' + escape.xhtml_escape(p) +
|
||||
'" type="text/javascript"></script>'
|
||||
for p in paths)
|
||||
sloc = html.rindex(b('</body>'))
|
||||
html = html[:sloc] + utf8(js) + b('\n') + html[sloc:]
|
||||
sloc = html.rindex(b'</body>')
|
||||
html = html[:sloc] + utf8(js) + b'\n' + html[sloc:]
|
||||
if js_embed:
|
||||
js = b('<script type="text/javascript">\n//<![CDATA[\n') + \
|
||||
b('\n').join(js_embed) + b('\n//]]>\n</script>')
|
||||
sloc = html.rindex(b('</body>'))
|
||||
html = html[:sloc] + js + b('\n') + html[sloc:]
|
||||
js = b'<script type="text/javascript">\n//<![CDATA[\n' + \
|
||||
b'\n'.join(js_embed) + b'\n//]]>\n</script>'
|
||||
sloc = html.rindex(b'</body>')
|
||||
html = html[:sloc] + js + b'\n' + html[sloc:]
|
||||
if css_files:
|
||||
paths = []
|
||||
unique_paths = set()
|
||||
@@ -583,19 +586,19 @@ class RequestHandler(object):
|
||||
css = ''.join('<link href="' + escape.xhtml_escape(p) + '" '
|
||||
'type="text/css" rel="stylesheet"/>'
|
||||
for p in paths)
|
||||
hloc = html.index(b('</head>'))
|
||||
html = html[:hloc] + utf8(css) + b('\n') + html[hloc:]
|
||||
hloc = html.index(b'</head>')
|
||||
html = html[:hloc] + utf8(css) + b'\n' + html[hloc:]
|
||||
if css_embed:
|
||||
css = b('<style type="text/css">\n') + b('\n').join(css_embed) + \
|
||||
b('\n</style>')
|
||||
hloc = html.index(b('</head>'))
|
||||
html = html[:hloc] + css + b('\n') + html[hloc:]
|
||||
css = b'<style type="text/css">\n' + b'\n'.join(css_embed) + \
|
||||
b'\n</style>'
|
||||
hloc = html.index(b'</head>')
|
||||
html = html[:hloc] + css + b'\n' + html[hloc:]
|
||||
if html_heads:
|
||||
hloc = html.index(b('</head>'))
|
||||
html = html[:hloc] + b('').join(html_heads) + b('\n') + html[hloc:]
|
||||
hloc = html.index(b'</head>')
|
||||
html = html[:hloc] + b''.join(html_heads) + b'\n' + html[hloc:]
|
||||
if html_bodies:
|
||||
hloc = html.index(b('</body>'))
|
||||
html = html[:hloc] + b('').join(html_bodies) + b('\n') + html[hloc:]
|
||||
hloc = html.index(b'</body>')
|
||||
html = html[:hloc] + b''.join(html_bodies) + b'\n' + html[hloc:]
|
||||
self.finish(html)
|
||||
|
||||
def render_string(self, template_name, **kwargs):
|
||||
@@ -675,19 +678,19 @@ class RequestHandler(object):
|
||||
if self.application._wsgi:
|
||||
raise Exception("WSGI applications do not support flush()")
|
||||
|
||||
chunk = b("").join(self._write_buffer)
|
||||
chunk = b"".join(self._write_buffer)
|
||||
self._write_buffer = []
|
||||
if not self._headers_written:
|
||||
self._headers_written = True
|
||||
for transform in self._transforms:
|
||||
self._status_code, self._headers, chunk = \
|
||||
transform.transform_first_chunk(
|
||||
self._status_code, self._headers, chunk, include_footers)
|
||||
self._status_code, self._headers, chunk, include_footers)
|
||||
headers = self._generate_headers()
|
||||
else:
|
||||
for transform in self._transforms:
|
||||
chunk = transform.transform_chunk(chunk, include_footers)
|
||||
headers = b("")
|
||||
headers = b""
|
||||
|
||||
# Ignore the chunk and only write the headers for HEAD requests
|
||||
if self.request.method == "HEAD":
|
||||
@@ -712,7 +715,7 @@ class RequestHandler(object):
|
||||
if not self._headers_written:
|
||||
if (self._status_code == 200 and
|
||||
self.request.method in ("GET", "HEAD") and
|
||||
"Etag" not in self._headers):
|
||||
"Etag" not in self._headers):
|
||||
etag = self.compute_etag()
|
||||
if etag is not None:
|
||||
self.set_header("Etag", etag)
|
||||
@@ -812,9 +815,9 @@ class RequestHandler(object):
|
||||
else:
|
||||
self.finish("<html><title>%(code)d: %(message)s</title>"
|
||||
"<body>%(code)d: %(message)s</body></html>" % {
|
||||
"code": status_code,
|
||||
"message": self._reason,
|
||||
})
|
||||
"code": status_code,
|
||||
"message": self._reason,
|
||||
})
|
||||
|
||||
@property
|
||||
def locale(self):
|
||||
@@ -861,7 +864,7 @@ class RequestHandler(object):
|
||||
score = 1.0
|
||||
locales.append((parts[0], score))
|
||||
if locales:
|
||||
locales.sort(key=lambda (l, s): s, reverse=True)
|
||||
locales.sort(key=lambda pair: pair[1], reverse=True)
|
||||
codes = [l[0] for l in locales]
|
||||
return locale.get(*codes)
|
||||
return locale.get(default)
|
||||
@@ -1007,7 +1010,7 @@ class RequestHandler(object):
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return callback(*args, **kwargs)
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
if self._headers_written:
|
||||
app_log.error("Exception after headers written",
|
||||
exc_info=True)
|
||||
@@ -1055,11 +1058,11 @@ class RequestHandler(object):
|
||||
raise HTTPError(405)
|
||||
self.path_args = [self.decode_argument(arg) for arg in args]
|
||||
self.path_kwargs = dict((k, self.decode_argument(v, name=k))
|
||||
for (k, v) in kwargs.iteritems())
|
||||
for (k, v) in kwargs.items())
|
||||
# If XSRF cookies are turned on, reject form submissions without
|
||||
# the proper cookie
|
||||
if self.request.method not in ("GET", "HEAD", "OPTIONS") and \
|
||||
self.application.settings.get("xsrf_cookies"):
|
||||
self.application.settings.get("xsrf_cookies"):
|
||||
self.check_xsrf_cookie()
|
||||
self.prepare()
|
||||
if not self._finished:
|
||||
@@ -1067,7 +1070,7 @@ class RequestHandler(object):
|
||||
*self.path_args, **self.path_kwargs)
|
||||
if self._auto_finish and not self._finished:
|
||||
self.finish()
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
self._handle_request_exception(e)
|
||||
|
||||
def _generate_headers(self):
|
||||
@@ -1075,12 +1078,12 @@ class RequestHandler(object):
|
||||
lines = [utf8(self.request.version + " " +
|
||||
str(self._status_code) +
|
||||
" " + reason)]
|
||||
lines.extend([(utf8(n) + b(": ") + utf8(v)) for n, v in
|
||||
itertools.chain(self._headers.iteritems(), self._list_headers)])
|
||||
lines.extend([utf8(n) + b": " + utf8(v) for n, v in self._headers.get_all()])
|
||||
|
||||
if hasattr(self, "_new_cookie"):
|
||||
for cookie in self._new_cookie.values():
|
||||
lines.append(utf8("Set-Cookie: " + cookie.OutputString(None)))
|
||||
return b("\r\n").join(lines) + b("\r\n\r\n")
|
||||
return b"\r\n".join(lines) + b"\r\n\r\n"
|
||||
|
||||
def _log(self):
|
||||
"""Logs the current request.
|
||||
@@ -1101,7 +1104,7 @@ class RequestHandler(object):
|
||||
format = "%d %s: " + e.log_message
|
||||
args = [e.status_code, self._request_summary()] + list(e.args)
|
||||
gen_log.warning(format, *args)
|
||||
if e.status_code not in httplib.responses and not e.reason:
|
||||
if e.status_code not in httputil.responses and not e.reason:
|
||||
gen_log.error("Bad HTTP status code: %d", e.status_code)
|
||||
self.send_error(500, exc_info=sys.exc_info())
|
||||
else:
|
||||
@@ -1161,7 +1164,7 @@ def asynchronous(method):
|
||||
raise Exception("@asynchronous is not supported for WSGI apps")
|
||||
self._auto_finish = False
|
||||
with stack_context.ExceptionStackContext(
|
||||
self._stack_context_handle_exception):
|
||||
self._stack_context_handle_exception):
|
||||
return method(self, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
@@ -1334,7 +1337,7 @@ class Application(object):
|
||||
self.handlers.append((re.compile(host_pattern), handlers))
|
||||
|
||||
for spec in host_handlers:
|
||||
if type(spec) is type(()):
|
||||
if isinstance(spec, type(())):
|
||||
assert len(spec) in (2, 3)
|
||||
pattern = spec[0]
|
||||
handler = spec[1]
|
||||
@@ -1375,20 +1378,20 @@ class Application(object):
|
||||
return matches or None
|
||||
|
||||
def _load_ui_methods(self, methods):
|
||||
if type(methods) is types.ModuleType:
|
||||
if isinstance(methods, types.ModuleType):
|
||||
self._load_ui_methods(dict((n, getattr(methods, n))
|
||||
for n in dir(methods)))
|
||||
elif isinstance(methods, list):
|
||||
for m in methods:
|
||||
self._load_ui_methods(m)
|
||||
else:
|
||||
for name, fn in methods.iteritems():
|
||||
for name, fn in methods.items():
|
||||
if not name.startswith("_") and hasattr(fn, "__call__") \
|
||||
and name[0].lower() == name[0]:
|
||||
and name[0].lower() == name[0]:
|
||||
self.ui_methods[name] = fn
|
||||
|
||||
def _load_ui_modules(self, modules):
|
||||
if type(modules) is types.ModuleType:
|
||||
if isinstance(modules, types.ModuleType):
|
||||
self._load_ui_modules(dict((n, getattr(modules, n))
|
||||
for n in dir(modules)))
|
||||
elif isinstance(modules, list):
|
||||
@@ -1396,7 +1399,7 @@ class Application(object):
|
||||
self._load_ui_modules(m)
|
||||
else:
|
||||
assert isinstance(modules, dict)
|
||||
for name, cls in modules.iteritems():
|
||||
for name, cls in modules.items():
|
||||
try:
|
||||
if issubclass(cls, UIModule):
|
||||
self.ui_modules[name] = cls
|
||||
@@ -1434,7 +1437,7 @@ class Application(object):
|
||||
if spec.regex.groupindex:
|
||||
kwargs = dict(
|
||||
(str(k), unquote(v))
|
||||
for (k, v) in match.groupdict().iteritems())
|
||||
for (k, v) in match.groupdict().items())
|
||||
else:
|
||||
args = [unquote(s) for s in match.groups()]
|
||||
break
|
||||
@@ -1510,7 +1513,7 @@ class HTTPError(Exception):
|
||||
def __str__(self):
|
||||
message = "HTTP %d: %s" % (
|
||||
self.status_code,
|
||||
self.reason or httplib.responses.get(self.status_code, 'Unknown'))
|
||||
self.reason or httputil.responses.get(self.status_code, 'Unknown'))
|
||||
if self.log_message:
|
||||
return message + " (" + (self.log_message % self.args) + ")"
|
||||
else:
|
||||
@@ -1618,7 +1621,7 @@ class StaticFileHandler(RequestHandler):
|
||||
|
||||
if cache_time > 0:
|
||||
self.set_header("Expires", datetime.datetime.utcnow() +
|
||||
datetime.timedelta(seconds=cache_time))
|
||||
datetime.timedelta(seconds=cache_time))
|
||||
self.set_header("Cache-Control", "max-age=" + str(cache_time))
|
||||
|
||||
self.set_extra_headers(path)
|
||||
@@ -1771,9 +1774,9 @@ class GZipContentEncoding(OutputTransform):
|
||||
|
||||
def transform_first_chunk(self, status_code, headers, chunk, finishing):
|
||||
if 'Vary' in headers:
|
||||
headers['Vary'] += b(', Accept-Encoding')
|
||||
headers['Vary'] += b', Accept-Encoding'
|
||||
else:
|
||||
headers['Vary'] = b('Accept-Encoding')
|
||||
headers['Vary'] = b'Accept-Encoding'
|
||||
if self._gzipping:
|
||||
ctype = _unicode(headers.get("Content-Type", "")).split(";")[0]
|
||||
self._gzipping = (ctype in self.CONTENT_TYPES) and \
|
||||
@@ -1827,9 +1830,9 @@ class ChunkedTransferEncoding(OutputTransform):
|
||||
# Don't write out empty chunks because that means END-OF-STREAM
|
||||
# with chunked encoding
|
||||
if block:
|
||||
block = utf8("%x" % len(block)) + b("\r\n") + block + b("\r\n")
|
||||
block = utf8("%x" % len(block)) + b"\r\n" + block + b"\r\n"
|
||||
if finishing:
|
||||
block += b("0\r\n\r\n")
|
||||
block += b"0\r\n\r\n"
|
||||
return block
|
||||
|
||||
|
||||
@@ -1846,7 +1849,7 @@ def authenticated(method):
|
||||
next_url = self.request.full_url()
|
||||
else:
|
||||
next_url = self.request.uri
|
||||
url += "?" + urllib.urlencode(dict(next=next_url))
|
||||
url += "?" + urlencode(dict(next=next_url))
|
||||
self.redirect(url)
|
||||
return
|
||||
raise HTTPError(403)
|
||||
@@ -1954,7 +1957,7 @@ class TemplateModule(UIModule):
|
||||
def javascript_files(self):
|
||||
result = []
|
||||
for f in self._get_resources("javascript_files"):
|
||||
if isinstance(f, (unicode, bytes_type)):
|
||||
if isinstance(f, (unicode_type, bytes_type)):
|
||||
result.append(f)
|
||||
else:
|
||||
result.extend(f)
|
||||
@@ -1966,7 +1969,7 @@ class TemplateModule(UIModule):
|
||||
def css_files(self):
|
||||
result = []
|
||||
for f in self._get_resources("css_files"):
|
||||
if isinstance(f, (unicode, bytes_type)):
|
||||
if isinstance(f, (unicode_type, bytes_type)):
|
||||
result.append(f)
|
||||
else:
|
||||
result.extend(f)
|
||||
@@ -2011,8 +2014,8 @@ class URLSpec(object):
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %s, kwargs=%r, name=%r)' % \
|
||||
(self.__class__.__name__, self.regex.pattern,
|
||||
self.handler_class, self.kwargs, self.name)
|
||||
(self.__class__.__name__, self.regex.pattern,
|
||||
self.handler_class, self.kwargs, self.name)
|
||||
|
||||
def _find_groups(self):
|
||||
"""Returns a tuple (reverse string, group count) for a url.
|
||||
@@ -2051,7 +2054,7 @@ class URLSpec(object):
|
||||
return self._path
|
||||
converted_args = []
|
||||
for a in args:
|
||||
if not isinstance(a, (unicode, bytes_type)):
|
||||
if not isinstance(a, (unicode_type, bytes_type)):
|
||||
a = str(a)
|
||||
converted_args.append(escape.url_escape(utf8(a)))
|
||||
return self._path % tuple(converted_args)
|
||||
@@ -2066,7 +2069,7 @@ else:
|
||||
if len(a) != len(b):
|
||||
return False
|
||||
result = 0
|
||||
if type(a[0]) is int: # python3 byte strings
|
||||
if isinstance(a[0], int): # python3 byte strings
|
||||
for x, y in zip(a, b):
|
||||
result |= x ^ y
|
||||
else: # python2
|
||||
@@ -2079,14 +2082,14 @@ def create_signed_value(secret, name, value):
|
||||
timestamp = utf8(str(int(time.time())))
|
||||
value = base64.b64encode(utf8(value))
|
||||
signature = _create_signature(secret, name, value, timestamp)
|
||||
value = b("|").join([value, timestamp, signature])
|
||||
value = b"|".join([value, timestamp, signature])
|
||||
return value
|
||||
|
||||
|
||||
def decode_signed_value(secret, name, value, max_age_days=31):
|
||||
if not value:
|
||||
return None
|
||||
parts = utf8(value).split(b("|"))
|
||||
parts = utf8(value).split(b"|")
|
||||
if len(parts) != 3:
|
||||
return None
|
||||
signature = _create_signature(secret, name, parts[0], parts[1])
|
||||
@@ -2105,7 +2108,7 @@ def decode_signed_value(secret, name, value, max_age_days=31):
|
||||
# here instead of modifying _cookie_signature.
|
||||
gen_log.warning("Cookie timestamp in future; possible tampering %r", value)
|
||||
return None
|
||||
if parts[1].startswith(b("0")):
|
||||
if parts[1].startswith(b"0"):
|
||||
gen_log.warning("Tampered cookie %r", value)
|
||||
return None
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user