Update Tornado
This commit is contained in:
@@ -25,5 +25,5 @@ from __future__ import absolute_import, division, print_function, with_statement
|
||||
# is zero for an official release, positive for a development branch,
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
version = "3.2.dev2"
|
||||
version_info = (3, 2, 0, -99)
|
||||
version = "3.2b1"
|
||||
version_info = (3, 2, 0, -98)
|
||||
|
||||
@@ -988,8 +988,8 @@ class GoogleOAuth2Mixin(OAuth2Mixin):
|
||||
})
|
||||
|
||||
http.fetch(self._OAUTH_ACCESS_TOKEN_URL,
|
||||
self.async_callback(self._on_access_token, callback),
|
||||
method="POST", headers={'Content-Type': 'application/x-www-form-urlencoded'}, body=body)
|
||||
self.async_callback(self._on_access_token, callback),
|
||||
method="POST", headers={'Content-Type': 'application/x-www-form-urlencoded'}, body=body)
|
||||
|
||||
def _on_access_token(self, future, response):
|
||||
"""Callback function for the exchange to the access token."""
|
||||
|
||||
@@ -124,11 +124,11 @@ class TracebackFuture(Future):
|
||||
self.__exc_info = exc_info
|
||||
self.set_exception(exc_info[1])
|
||||
|
||||
def result(self):
|
||||
def result(self, timeout=None):
|
||||
if self.__exc_info is not None:
|
||||
raise_exc_info(self.__exc_info)
|
||||
else:
|
||||
return super(TracebackFuture, self).result()
|
||||
return super(TracebackFuture, self).result(timeout=timeout)
|
||||
|
||||
|
||||
class DummyExecutor(object):
|
||||
@@ -151,6 +151,9 @@ def run_on_executor(fn):
|
||||
|
||||
The decorated method may be called with a ``callback`` keyword
|
||||
argument and returns a future.
|
||||
|
||||
This decorator should be used only on methods of objects with attributes
|
||||
``executor`` and ``io_loop``.
|
||||
"""
|
||||
@functools.wraps(fn)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
|
||||
@@ -318,10 +318,12 @@ def _curl_setup_request(curl, request, buffer, headers):
|
||||
[native_str("%s: %s" % i) for i in request.headers.items()])
|
||||
|
||||
if request.header_callback:
|
||||
curl.setopt(pycurl.HEADERFUNCTION, request.header_callback)
|
||||
curl.setopt(pycurl.HEADERFUNCTION,
|
||||
lambda line: request.header_callback(native_str(line)))
|
||||
else:
|
||||
curl.setopt(pycurl.HEADERFUNCTION,
|
||||
lambda line: _curl_header_callback(headers, line))
|
||||
lambda line: _curl_header_callback(headers,
|
||||
native_str(line)))
|
||||
if request.streaming_callback:
|
||||
write_function = request.streaming_callback
|
||||
else:
|
||||
|
||||
@@ -189,8 +189,10 @@ def utf8(value):
|
||||
"""
|
||||
if isinstance(value, _UTF8_TYPES):
|
||||
return value
|
||||
assert isinstance(value, unicode_type), \
|
||||
"Expected bytes, unicode, or None; got %r" % type(value)
|
||||
if not isinstance(value, unicode_type):
|
||||
raise TypeError(
|
||||
"Expected bytes, unicode, or None; got %r" % type(value)
|
||||
)
|
||||
return value.encode("utf-8")
|
||||
|
||||
_TO_UNICODE_TYPES = (unicode_type, type(None))
|
||||
@@ -204,8 +206,10 @@ def to_unicode(value):
|
||||
"""
|
||||
if isinstance(value, _TO_UNICODE_TYPES):
|
||||
return value
|
||||
assert isinstance(value, bytes_type), \
|
||||
"Expected bytes, unicode, or None; got %r" % type(value)
|
||||
if not isinstance(value, bytes_type):
|
||||
raise TypeError(
|
||||
"Expected bytes, unicode, or None; got %r" % type(value)
|
||||
)
|
||||
return value.decode("utf-8")
|
||||
|
||||
# to_unicode was previously named _unicode not because it was private,
|
||||
@@ -233,8 +237,10 @@ def to_basestring(value):
|
||||
"""
|
||||
if isinstance(value, _BASESTRING_TYPES):
|
||||
return value
|
||||
assert isinstance(value, bytes_type), \
|
||||
"Expected bytes, unicode, or None; got %r" % type(value)
|
||||
if not isinstance(value, bytes_type):
|
||||
raise TypeError(
|
||||
"Expected bytes, unicode, or None; got %r" % type(value)
|
||||
)
|
||||
return value.decode("utf-8")
|
||||
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ For more complicated interfaces, `Task` can be split into two parts:
|
||||
def get(self):
|
||||
http_client = AsyncHTTPClient()
|
||||
http_client.fetch("http://example.com",
|
||||
callback=(yield gen.Callback("key"))
|
||||
callback=(yield gen.Callback("key")))
|
||||
response = yield gen.Wait("key")
|
||||
do_something_with_response(response)
|
||||
self.render("template.html")
|
||||
@@ -390,16 +390,26 @@ class YieldFuture(YieldPoint):
|
||||
self.io_loop = io_loop or IOLoop.current()
|
||||
|
||||
def start(self, runner):
|
||||
self.runner = runner
|
||||
self.key = object()
|
||||
runner.register_callback(self.key)
|
||||
self.io_loop.add_future(self.future, runner.result_callback(self.key))
|
||||
if not self.future.done():
|
||||
self.runner = runner
|
||||
self.key = object()
|
||||
runner.register_callback(self.key)
|
||||
self.io_loop.add_future(self.future, runner.result_callback(self.key))
|
||||
else:
|
||||
self.runner = None
|
||||
self.result = self.future.result()
|
||||
|
||||
def is_ready(self):
|
||||
return self.runner.is_ready(self.key)
|
||||
if self.runner is not None:
|
||||
return self.runner.is_ready(self.key)
|
||||
else:
|
||||
return True
|
||||
|
||||
def get_result(self):
|
||||
return self.runner.pop_result(self.key).result()
|
||||
if self.runner is not None:
|
||||
return self.runner.pop_result(self.key).result()
|
||||
else:
|
||||
return self.result
|
||||
|
||||
|
||||
class Multi(YieldPoint):
|
||||
|
||||
@@ -335,10 +335,11 @@ class HTTPRequest(object):
|
||||
.. versionadded:: 3.1
|
||||
The ``auth_mode`` argument.
|
||||
"""
|
||||
if headers is None:
|
||||
headers = httputil.HTTPHeaders()
|
||||
# Note that some of these attributes go through property setters
|
||||
# defined below.
|
||||
self.headers = headers
|
||||
if if_modified_since:
|
||||
headers["If-Modified-Since"] = httputil.format_timestamp(
|
||||
self.headers["If-Modified-Since"] = httputil.format_timestamp(
|
||||
if_modified_since)
|
||||
self.proxy_host = proxy_host
|
||||
self.proxy_port = proxy_port
|
||||
@@ -346,8 +347,7 @@ class HTTPRequest(object):
|
||||
self.proxy_password = proxy_password
|
||||
self.url = url
|
||||
self.method = method
|
||||
self.headers = headers
|
||||
self.body = utf8(body)
|
||||
self.body = body
|
||||
self.auth_username = auth_username
|
||||
self.auth_password = auth_password
|
||||
self.auth_mode = auth_mode
|
||||
@@ -358,9 +358,9 @@ class HTTPRequest(object):
|
||||
self.user_agent = user_agent
|
||||
self.use_gzip = use_gzip
|
||||
self.network_interface = network_interface
|
||||
self.streaming_callback = stack_context.wrap(streaming_callback)
|
||||
self.header_callback = stack_context.wrap(header_callback)
|
||||
self.prepare_curl_callback = stack_context.wrap(prepare_curl_callback)
|
||||
self.streaming_callback = streaming_callback
|
||||
self.header_callback = header_callback
|
||||
self.prepare_curl_callback = prepare_curl_callback
|
||||
self.allow_nonstandard_methods = allow_nonstandard_methods
|
||||
self.validate_cert = validate_cert
|
||||
self.ca_certs = ca_certs
|
||||
@@ -369,6 +369,49 @@ class HTTPRequest(object):
|
||||
self.client_cert = client_cert
|
||||
self.start_time = time.time()
|
||||
|
||||
@property
|
||||
def headers(self):
|
||||
return self._headers
|
||||
|
||||
@headers.setter
|
||||
def headers(self, value):
|
||||
if value is None:
|
||||
self._headers = httputil.HTTPHeaders()
|
||||
else:
|
||||
self._headers = value
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
return self._body
|
||||
|
||||
@body.setter
|
||||
def body(self, value):
|
||||
self._body = utf8(value)
|
||||
|
||||
@property
|
||||
def streaming_callback(self):
|
||||
return self._streaming_callback
|
||||
|
||||
@streaming_callback.setter
|
||||
def streaming_callback(self, value):
|
||||
self._streaming_callback = stack_context.wrap(value)
|
||||
|
||||
@property
|
||||
def header_callback(self):
|
||||
return self._header_callback
|
||||
|
||||
@header_callback.setter
|
||||
def header_callback(self, value):
|
||||
self._header_callback = stack_context.wrap(value)
|
||||
|
||||
@property
|
||||
def prepare_curl_callback(self):
|
||||
return self._prepare_curl_callback
|
||||
|
||||
@prepare_curl_callback.setter
|
||||
def prepare_curl_callback(self, value):
|
||||
self._prepare_curl_callback = stack_context.wrap(value)
|
||||
|
||||
|
||||
class HTTPResponse(object):
|
||||
"""HTTP Response object.
|
||||
|
||||
@@ -598,100 +598,103 @@ class PollIOLoop(IOLoop):
|
||||
except ValueError: # non-main thread
|
||||
pass
|
||||
|
||||
while True:
|
||||
poll_timeout = _POLL_TIMEOUT
|
||||
try:
|
||||
while True:
|
||||
poll_timeout = _POLL_TIMEOUT
|
||||
|
||||
# Prevent IO event starvation by delaying new callbacks
|
||||
# to the next iteration of the event loop.
|
||||
with self._callback_lock:
|
||||
callbacks = self._callbacks
|
||||
self._callbacks = []
|
||||
for callback in callbacks:
|
||||
self._run_callback(callback)
|
||||
# Closures may be holding on to a lot of memory, so allow
|
||||
# them to be freed before we go into our poll wait.
|
||||
callbacks = callback = None
|
||||
# Prevent IO event starvation by delaying new callbacks
|
||||
# to the next iteration of the event loop.
|
||||
with self._callback_lock:
|
||||
callbacks = self._callbacks
|
||||
self._callbacks = []
|
||||
for callback in callbacks:
|
||||
self._run_callback(callback)
|
||||
# Closures may be holding on to a lot of memory, so allow
|
||||
# them to be freed before we go into our poll wait.
|
||||
callbacks = callback = None
|
||||
|
||||
if self._timeouts:
|
||||
now = self.time()
|
||||
while self._timeouts:
|
||||
if self._timeouts[0].callback is None:
|
||||
# the timeout was cancelled
|
||||
heapq.heappop(self._timeouts)
|
||||
self._cancellations -= 1
|
||||
elif self._timeouts[0].deadline <= now:
|
||||
timeout = heapq.heappop(self._timeouts)
|
||||
self._run_callback(timeout.callback)
|
||||
del timeout
|
||||
else:
|
||||
seconds = self._timeouts[0].deadline - now
|
||||
poll_timeout = min(seconds, poll_timeout)
|
||||
break
|
||||
if (self._cancellations > 512
|
||||
and self._cancellations > (len(self._timeouts) >> 1)):
|
||||
# Clean up the timeout queue when it gets large and it's
|
||||
# more than half cancellations.
|
||||
self._cancellations = 0
|
||||
self._timeouts = [x for x in self._timeouts
|
||||
if x.callback is not None]
|
||||
heapq.heapify(self._timeouts)
|
||||
if self._timeouts:
|
||||
now = self.time()
|
||||
while self._timeouts:
|
||||
if self._timeouts[0].callback is None:
|
||||
# the timeout was cancelled
|
||||
heapq.heappop(self._timeouts)
|
||||
self._cancellations -= 1
|
||||
elif self._timeouts[0].deadline <= now:
|
||||
timeout = heapq.heappop(self._timeouts)
|
||||
self._run_callback(timeout.callback)
|
||||
del timeout
|
||||
else:
|
||||
seconds = self._timeouts[0].deadline - now
|
||||
poll_timeout = min(seconds, poll_timeout)
|
||||
break
|
||||
if (self._cancellations > 512
|
||||
and self._cancellations > (len(self._timeouts) >> 1)):
|
||||
# Clean up the timeout queue when it gets large and it's
|
||||
# more than half cancellations.
|
||||
self._cancellations = 0
|
||||
self._timeouts = [x for x in self._timeouts
|
||||
if x.callback is not None]
|
||||
heapq.heapify(self._timeouts)
|
||||
|
||||
if self._callbacks:
|
||||
# If any callbacks or timeouts called add_callback,
|
||||
# we don't want to wait in poll() before we run them.
|
||||
poll_timeout = 0.0
|
||||
if self._callbacks:
|
||||
# If any callbacks or timeouts called add_callback,
|
||||
# we don't want to wait in poll() before we run them.
|
||||
poll_timeout = 0.0
|
||||
|
||||
if not self._running:
|
||||
break
|
||||
if not self._running:
|
||||
break
|
||||
|
||||
if self._blocking_signal_threshold is not None:
|
||||
# clear alarm so it doesn't fire while poll is waiting for
|
||||
# events.
|
||||
signal.setitimer(signal.ITIMER_REAL, 0, 0)
|
||||
if self._blocking_signal_threshold is not None:
|
||||
# clear alarm so it doesn't fire while poll is waiting for
|
||||
# events.
|
||||
signal.setitimer(signal.ITIMER_REAL, 0, 0)
|
||||
|
||||
try:
|
||||
event_pairs = self._impl.poll(poll_timeout)
|
||||
except Exception as e:
|
||||
# Depending on python version and IOLoop implementation,
|
||||
# different exception types may be thrown and there are
|
||||
# two ways EINTR might be signaled:
|
||||
# * e.errno == errno.EINTR
|
||||
# * e.args is like (errno.EINTR, 'Interrupted system call')
|
||||
if (getattr(e, 'errno', None) == errno.EINTR or
|
||||
(isinstance(getattr(e, 'args', None), tuple) and
|
||||
len(e.args) == 2 and e.args[0] == errno.EINTR)):
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
|
||||
if self._blocking_signal_threshold is not None:
|
||||
signal.setitimer(signal.ITIMER_REAL,
|
||||
self._blocking_signal_threshold, 0)
|
||||
|
||||
# Pop one fd at a time from the set of pending fds and run
|
||||
# its handler. Since that handler may perform actions on
|
||||
# other file descriptors, there may be reentrant calls to
|
||||
# this IOLoop that update self._events
|
||||
self._events.update(event_pairs)
|
||||
while self._events:
|
||||
fd, events = self._events.popitem()
|
||||
try:
|
||||
self._handlers[fd](fd, events)
|
||||
except (OSError, IOError) as e:
|
||||
if e.args[0] == errno.EPIPE:
|
||||
# Happens when the client closes the connection
|
||||
pass
|
||||
event_pairs = self._impl.poll(poll_timeout)
|
||||
except Exception as e:
|
||||
# Depending on python version and IOLoop implementation,
|
||||
# different exception types may be thrown and there are
|
||||
# two ways EINTR might be signaled:
|
||||
# * e.errno == errno.EINTR
|
||||
# * e.args is like (errno.EINTR, 'Interrupted system call')
|
||||
if (getattr(e, 'errno', None) == errno.EINTR or
|
||||
(isinstance(getattr(e, 'args', None), tuple) and
|
||||
len(e.args) == 2 and e.args[0] == errno.EINTR)):
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
|
||||
if self._blocking_signal_threshold is not None:
|
||||
signal.setitimer(signal.ITIMER_REAL,
|
||||
self._blocking_signal_threshold, 0)
|
||||
|
||||
# Pop one fd at a time from the set of pending fds and run
|
||||
# its handler. Since that handler may perform actions on
|
||||
# other file descriptors, there may be reentrant calls to
|
||||
# this IOLoop that update self._events
|
||||
self._events.update(event_pairs)
|
||||
while self._events:
|
||||
fd, events = self._events.popitem()
|
||||
try:
|
||||
self._handlers[fd](fd, events)
|
||||
except (OSError, IOError) as e:
|
||||
if e.args[0] == errno.EPIPE:
|
||||
# Happens when the client closes the connection
|
||||
pass
|
||||
else:
|
||||
self.handle_callback_exception(self._handlers.get(fd))
|
||||
except Exception:
|
||||
self.handle_callback_exception(self._handlers.get(fd))
|
||||
except Exception:
|
||||
self.handle_callback_exception(self._handlers.get(fd))
|
||||
# reset the stopped flag so another start/stop pair can be issued
|
||||
self._stopped = False
|
||||
if self._blocking_signal_threshold is not None:
|
||||
signal.setitimer(signal.ITIMER_REAL, 0, 0)
|
||||
IOLoop._current.instance = old_current
|
||||
if old_wakeup_fd is not None:
|
||||
signal.set_wakeup_fd(old_wakeup_fd)
|
||||
|
||||
finally:
|
||||
# reset the stopped flag so another start/stop pair can be issued
|
||||
self._stopped = False
|
||||
if self._blocking_signal_threshold is not None:
|
||||
signal.setitimer(signal.ITIMER_REAL, 0, 0)
|
||||
IOLoop._current.instance = old_current
|
||||
if old_wakeup_fd is not None:
|
||||
signal.set_wakeup_fd(old_wakeup_fd)
|
||||
|
||||
def stop(self):
|
||||
self._running = False
|
||||
|
||||
@@ -55,6 +55,7 @@ _ERRNO_WOULDBLOCK = (errno.EWOULDBLOCK, errno.EAGAIN)
|
||||
# They should be caught and handled less noisily than other errors.
|
||||
_ERRNO_CONNRESET = (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE)
|
||||
|
||||
|
||||
class StreamClosedError(IOError):
|
||||
"""Exception raised by `IOStream` methods when the stream is closed.
|
||||
|
||||
@@ -738,7 +739,7 @@ class IOStream(BaseIOStream):
|
||||
# localhost, so handle them the same way as an error
|
||||
# reported later in _handle_connect.
|
||||
if (e.args[0] != errno.EINPROGRESS and
|
||||
e.args[0] not in _ERRNO_WOULDBLOCK):
|
||||
e.args[0] not in _ERRNO_WOULDBLOCK):
|
||||
gen_log.warning("Connect error on fd %d: %s",
|
||||
self.socket.fileno(), e)
|
||||
self.close(exc_info=True)
|
||||
|
||||
@@ -286,8 +286,6 @@ class Locale(object):
|
||||
This method is primarily intended for dates in the past.
|
||||
For dates in the future, we fall back to full format.
|
||||
"""
|
||||
if self.code.startswith("ru"):
|
||||
relative = False
|
||||
if isinstance(date, numbers.Real):
|
||||
date = datetime.datetime.utcfromtimestamp(date)
|
||||
now = datetime.datetime.utcnow()
|
||||
|
||||
@@ -33,7 +33,6 @@ from __future__ import absolute_import, division, print_function, with_statement
|
||||
import logging
|
||||
import logging.handlers
|
||||
import sys
|
||||
import time
|
||||
|
||||
from tornado.escape import _unicode
|
||||
from tornado.util import unicode_type, basestring_type
|
||||
@@ -74,8 +73,21 @@ class LogFormatter(logging.Formatter):
|
||||
`tornado.options.parse_command_line` (unless ``--logging=none`` is
|
||||
used).
|
||||
"""
|
||||
def __init__(self, color=True, *args, **kwargs):
|
||||
logging.Formatter.__init__(self, *args, **kwargs)
|
||||
DEFAULT_PREFIX_FORMAT = '[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]'
|
||||
DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S'
|
||||
|
||||
def __init__(self, color=True, prefix_fmt=None, datefmt=None):
|
||||
r"""
|
||||
:arg bool color: Enables color support
|
||||
:arg string prefix_fmt: Log message prefix format.
|
||||
Prefix is a part of the log message, directly preceding the actual
|
||||
message text.
|
||||
:arg string datefmt: Datetime format.
|
||||
Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``.
|
||||
"""
|
||||
self.__prefix_fmt = prefix_fmt if prefix_fmt is not None else self.DEFAULT_PREFIX_FORMAT
|
||||
datefmt = datefmt if datefmt is not None else self.DEFAULT_DATE_FORMAT
|
||||
logging.Formatter.__init__(self, datefmt=datefmt)
|
||||
self._color = color and _stderr_supports_color()
|
||||
if self._color:
|
||||
# The curses module has some str/bytes confusion in
|
||||
@@ -107,10 +119,8 @@ class LogFormatter(logging.Formatter):
|
||||
except Exception as e:
|
||||
record.message = "Bad message (%r): %r" % (e, record.__dict__)
|
||||
assert isinstance(record.message, basestring_type) # guaranteed by logging
|
||||
record.asctime = time.strftime(
|
||||
"%y%m%d %H:%M:%S", self.converter(record.created))
|
||||
prefix = '[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]' % \
|
||||
record.__dict__
|
||||
record.asctime = self.formatTime(record, self.datefmt)
|
||||
prefix = self.__prefix_fmt % record.__dict__
|
||||
if self._color:
|
||||
prefix = (self._colors.get(record.levelno, self._normal) +
|
||||
prefix + self._normal)
|
||||
|
||||
@@ -27,7 +27,7 @@ import stat
|
||||
from tornado.concurrent import dummy_executor, run_on_executor
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.platform.auto import set_close_exec
|
||||
from tornado.util import Configurable
|
||||
from tornado.util import u, Configurable
|
||||
|
||||
if hasattr(ssl, 'match_hostname') and hasattr(ssl, 'CertificateError'): # python 3.2+
|
||||
ssl_match_hostname = ssl.match_hostname
|
||||
@@ -37,6 +37,14 @@ else:
|
||||
ssl_match_hostname = backports.ssl_match_hostname.match_hostname
|
||||
SSLCertificateError = backports.ssl_match_hostname.CertificateError
|
||||
|
||||
# ThreadedResolver runs getaddrinfo on a thread. If the hostname is unicode,
|
||||
# getaddrinfo attempts to import encodings.idna. If this is done at
|
||||
# module-import time, the import lock is already held by the main thread,
|
||||
# leading to deadlock. Avoid it by caching the idna encoder on the main
|
||||
# thread now.
|
||||
u('foo').encode('idna')
|
||||
|
||||
|
||||
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128, flags=None):
|
||||
"""Creates listening sockets bound to the given port and address.
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import os
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado import stack_context
|
||||
|
||||
|
||||
class BaseAsyncIOLoop(IOLoop):
|
||||
def initialize(self, asyncio_loop, close_loop=False):
|
||||
self.asyncio_loop = asyncio_loop
|
||||
@@ -104,7 +105,7 @@ class BaseAsyncIOLoop(IOLoop):
|
||||
else:
|
||||
raise TypeError("Unsupported deadline %r", deadline)
|
||||
return self.asyncio_loop.call_later(delay, self._run_callback,
|
||||
stack_context.wrap(callback))
|
||||
stack_context.wrap(callback))
|
||||
|
||||
def remove_timeout(self, timeout):
|
||||
timeout.cancel()
|
||||
@@ -114,8 +115,8 @@ class BaseAsyncIOLoop(IOLoop):
|
||||
raise RuntimeError("IOLoop is closing")
|
||||
if kwargs:
|
||||
self.asyncio_loop.call_soon_threadsafe(functools.partial(
|
||||
self._run_callback, stack_context.wrap(callback),
|
||||
*args, **kwargs))
|
||||
self._run_callback, stack_context.wrap(callback),
|
||||
*args, **kwargs))
|
||||
else:
|
||||
self.asyncio_loop.call_soon_threadsafe(
|
||||
self._run_callback, stack_context.wrap(callback), *args)
|
||||
@@ -128,6 +129,7 @@ class AsyncIOMainLoop(BaseAsyncIOLoop):
|
||||
super(AsyncIOMainLoop, self).initialize(asyncio.get_event_loop(),
|
||||
close_loop=False)
|
||||
|
||||
|
||||
class AsyncIOLoop(BaseAsyncIOLoop):
|
||||
def initialize(self):
|
||||
super(AsyncIOLoop, self).initialize(asyncio.new_event_loop(),
|
||||
|
||||
@@ -527,8 +527,10 @@ class TwistedResolver(Resolver):
|
||||
resolved_family = socket.AF_INET6
|
||||
else:
|
||||
deferred = self.resolver.getHostByName(utf8(host))
|
||||
resolved = yield gen.Task(deferred.addCallback)
|
||||
if twisted.internet.abstract.isIPAddress(resolved):
|
||||
resolved = yield gen.Task(deferred.addBoth)
|
||||
if isinstance(resolved, failure.Failure):
|
||||
resolved.raiseException()
|
||||
elif twisted.internet.abstract.isIPAddress(resolved):
|
||||
resolved_family = socket.AF_INET
|
||||
elif twisted.internet.abstract.isIPv6Address(resolved):
|
||||
resolved_family = socket.AF_INET6
|
||||
|
||||
@@ -94,9 +94,9 @@ class SimpleAsyncHTTPClient(AsyncHTTPClient):
|
||||
self.queue.append((key, request, callback))
|
||||
if not len(self.active) < self.max_clients:
|
||||
timeout_handle = self.io_loop.add_timeout(
|
||||
self.io_loop.time() + min(request.connect_timeout,
|
||||
request.request_timeout),
|
||||
functools.partial(self._on_timeout, key))
|
||||
self.io_loop.time() + min(request.connect_timeout,
|
||||
request.request_timeout),
|
||||
functools.partial(self._on_timeout, key))
|
||||
else:
|
||||
timeout_handle = None
|
||||
self.waiting[key] = (request, callback, timeout_handle)
|
||||
@@ -136,8 +136,8 @@ class SimpleAsyncHTTPClient(AsyncHTTPClient):
|
||||
request, callback, timeout_handle = self.waiting[key]
|
||||
self.queue.remove((key, request, callback))
|
||||
timeout_response = HTTPResponse(
|
||||
request, 599, error=HTTPError(599, "Timeout"),
|
||||
request_time=self.io_loop.time() - request.start_time)
|
||||
request, 599, error=HTTPError(599, "Timeout"),
|
||||
request_time=self.io_loop.time() - request.start_time)
|
||||
self.io_loop.add_callback(callback, timeout_response)
|
||||
del self.waiting[key]
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Basic usage looks like::
|
||||
t = template.Template("<html>{{ myvalue }}</html>")
|
||||
print t.generate(myvalue="XXX")
|
||||
|
||||
Loader is a class that loads templates from a root directory and caches
|
||||
`Loader` is a class that loads templates from a root directory and caches
|
||||
the compiled templates::
|
||||
|
||||
loader = template.Loader("/home/btaylor")
|
||||
@@ -56,16 +56,17 @@ interesting. Syntax for the templates::
|
||||
{% end %}
|
||||
|
||||
Unlike most other template systems, we do not put any restrictions on the
|
||||
expressions you can include in your statements. if and for blocks get
|
||||
translated exactly into Python, you can do complex expressions like::
|
||||
expressions you can include in your statements. ``if`` and ``for`` blocks get
|
||||
translated exactly into Python, so you can do complex expressions like::
|
||||
|
||||
{% for student in [p for p in people if p.student and p.age > 23] %}
|
||||
<li>{{ escape(student.name) }}</li>
|
||||
{% end %}
|
||||
|
||||
Translating directly to Python means you can apply functions to expressions
|
||||
easily, like the escape() function in the examples above. You can pass
|
||||
functions in to your template just like any other variable::
|
||||
easily, like the ``escape()`` function in the examples above. You can pass
|
||||
functions in to your template just like any other variable
|
||||
(In a `.RequestHandler`, override `.RequestHandler.get_template_namespace`)::
|
||||
|
||||
### Python code
|
||||
def add(x, y):
|
||||
@@ -75,8 +76,8 @@ functions in to your template just like any other variable::
|
||||
### The template
|
||||
{{ add(1, 2) }}
|
||||
|
||||
We provide the functions escape(), url_escape(), json_encode(), and squeeze()
|
||||
to all templates by default.
|
||||
We provide the functions `escape() <.xhtml_escape>`, `.url_escape()`,
|
||||
`.json_encode()`, and `.squeeze()` to all templates by default.
|
||||
|
||||
Typical applications do not create `Template` or `Loader` instances by
|
||||
hand, but instead use the `~.RequestHandler.render` and
|
||||
|
||||
@@ -447,7 +447,11 @@ class RequestHandler(object):
|
||||
The name of the argument is provided if known, but may be None
|
||||
(e.g. for unnamed groups in the url regex).
|
||||
"""
|
||||
return _unicode(value)
|
||||
try:
|
||||
return _unicode(value)
|
||||
except UnicodeDecodeError:
|
||||
raise HTTPError(400, "Invalid unicode in %s: %r" %
|
||||
(name or "url", value[:40]))
|
||||
|
||||
@property
|
||||
def cookies(self):
|
||||
@@ -1908,7 +1912,7 @@ class StaticFileHandler(RequestHandler):
|
||||
# content, or when a suffix with length 0 is specified
|
||||
self.set_status(416) # Range Not Satisfiable
|
||||
self.set_header("Content-Type", "text/plain")
|
||||
self.set_header("Content-Range", "bytes */%s" %(size, ))
|
||||
self.set_header("Content-Range", "bytes */%s" % (size, ))
|
||||
return
|
||||
if start is not None and start < 0:
|
||||
start += size
|
||||
|
||||
@@ -381,12 +381,12 @@ class WebSocketProtocol76(WebSocketProtocol):
|
||||
"Sec-WebSocket-Location: %(scheme)s://%(host)s%(uri)s\r\n"
|
||||
"%(subprotocol)s"
|
||||
"\r\n" % (dict(
|
||||
version=tornado.version,
|
||||
origin=self.request.headers["Origin"],
|
||||
scheme=scheme,
|
||||
host=self.request.host,
|
||||
uri=self.request.uri,
|
||||
subprotocol=subprotocol_header))))
|
||||
version=tornado.version,
|
||||
origin=self.request.headers["Origin"],
|
||||
scheme=scheme,
|
||||
host=self.request.host,
|
||||
uri=self.request.uri,
|
||||
subprotocol=subprotocol_header))))
|
||||
self.stream.read_bytes(8, self._handle_challenge)
|
||||
|
||||
def challenge_response(self, challenge):
|
||||
@@ -891,6 +891,7 @@ def websocket_connect(url, io_loop=None, callback=None, connect_timeout=None):
|
||||
io_loop.add_future(conn.connect_future, callback)
|
||||
return conn.connect_future
|
||||
|
||||
|
||||
def _websocket_mask_python(mask, data):
|
||||
"""Websocket masking function.
|
||||
|
||||
|
||||
@@ -294,7 +294,7 @@ class WSGIContainer(object):
|
||||
"REQUEST_METHOD": request.method,
|
||||
"SCRIPT_NAME": "",
|
||||
"PATH_INFO": to_wsgi_str(escape.url_unescape(
|
||||
request.path, encoding=None, plus=False)),
|
||||
request.path, encoding=None, plus=False)),
|
||||
"QUERY_STRING": request.query,
|
||||
"REMOTE_ADDR": request.remote_ip,
|
||||
"SERVER_NAME": host,
|
||||
|
||||
Reference in New Issue
Block a user