Browse Source

Update Tornado

pull/2633/merge
Ruud 12 years ago
parent
commit
266429311b
  1. 4
      libs/tornado/__init__.py
  2. 4
      libs/tornado/auth.py
  3. 7
      libs/tornado/concurrent.py
  4. 6
      libs/tornado/curl_httpclient.py
  5. 18
      libs/tornado/escape.py
  6. 24
      libs/tornado/gen.py
  7. 59
      libs/tornado/httpclient.py
  8. 183
      libs/tornado/ioloop.py
  9. 3
      libs/tornado/iostream.py
  10. 2
      libs/tornado/locale.py
  11. 24
      libs/tornado/log.py
  12. 10
      libs/tornado/netutil.py
  13. 8
      libs/tornado/platform/asyncio.py
  14. 6
      libs/tornado/platform/twisted.py
  15. 10
      libs/tornado/simple_httpclient.py
  16. 15
      libs/tornado/template.py
  17. 8
      libs/tornado/web.py
  18. 13
      libs/tornado/websocket.py
  19. 2
      libs/tornado/wsgi.py

4
libs/tornado/__init__.py

@ -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, # is zero for an official release, positive for a development branch,
# or negative for a release candidate or beta (after the base version # or negative for a release candidate or beta (after the base version
# number has been incremented) # number has been incremented)
version = "3.2.dev2" version = "3.2b1"
version_info = (3, 2, 0, -99) version_info = (3, 2, 0, -98)

4
libs/tornado/auth.py

@ -988,8 +988,8 @@ class GoogleOAuth2Mixin(OAuth2Mixin):
}) })
http.fetch(self._OAUTH_ACCESS_TOKEN_URL, http.fetch(self._OAUTH_ACCESS_TOKEN_URL,
self.async_callback(self._on_access_token, callback), self.async_callback(self._on_access_token, callback),
method="POST", headers={'Content-Type': 'application/x-www-form-urlencoded'}, body=body) method="POST", headers={'Content-Type': 'application/x-www-form-urlencoded'}, body=body)
def _on_access_token(self, future, response): def _on_access_token(self, future, response):
"""Callback function for the exchange to the access token.""" """Callback function for the exchange to the access token."""

7
libs/tornado/concurrent.py

@ -124,11 +124,11 @@ class TracebackFuture(Future):
self.__exc_info = exc_info self.__exc_info = exc_info
self.set_exception(exc_info[1]) self.set_exception(exc_info[1])
def result(self): def result(self, timeout=None):
if self.__exc_info is not None: if self.__exc_info is not None:
raise_exc_info(self.__exc_info) raise_exc_info(self.__exc_info)
else: else:
return super(TracebackFuture, self).result() return super(TracebackFuture, self).result(timeout=timeout)
class DummyExecutor(object): class DummyExecutor(object):
@ -151,6 +151,9 @@ def run_on_executor(fn):
The decorated method may be called with a ``callback`` keyword The decorated method may be called with a ``callback`` keyword
argument and returns a future. argument and returns a future.
This decorator should be used only on methods of objects with attributes
``executor`` and ``io_loop``.
""" """
@functools.wraps(fn) @functools.wraps(fn)
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):

6
libs/tornado/curl_httpclient.py

@ -318,10 +318,12 @@ def _curl_setup_request(curl, request, buffer, headers):
[native_str("%s: %s" % i) for i in request.headers.items()]) [native_str("%s: %s" % i) for i in request.headers.items()])
if request.header_callback: if request.header_callback:
curl.setopt(pycurl.HEADERFUNCTION, request.header_callback) curl.setopt(pycurl.HEADERFUNCTION,
lambda line: request.header_callback(native_str(line)))
else: else:
curl.setopt(pycurl.HEADERFUNCTION, curl.setopt(pycurl.HEADERFUNCTION,
lambda line: _curl_header_callback(headers, line)) lambda line: _curl_header_callback(headers,
native_str(line)))
if request.streaming_callback: if request.streaming_callback:
write_function = request.streaming_callback write_function = request.streaming_callback
else: else:

18
libs/tornado/escape.py

@ -189,8 +189,10 @@ def utf8(value):
""" """
if isinstance(value, _UTF8_TYPES): if isinstance(value, _UTF8_TYPES):
return value return value
assert isinstance(value, unicode_type), \ if not isinstance(value, unicode_type):
"Expected bytes, unicode, or None; got %r" % type(value) raise TypeError(
"Expected bytes, unicode, or None; got %r" % type(value)
)
return value.encode("utf-8") return value.encode("utf-8")
_TO_UNICODE_TYPES = (unicode_type, type(None)) _TO_UNICODE_TYPES = (unicode_type, type(None))
@ -204,8 +206,10 @@ def to_unicode(value):
""" """
if isinstance(value, _TO_UNICODE_TYPES): if isinstance(value, _TO_UNICODE_TYPES):
return value return value
assert isinstance(value, bytes_type), \ if not isinstance(value, bytes_type):
"Expected bytes, unicode, or None; got %r" % type(value) raise TypeError(
"Expected bytes, unicode, or None; got %r" % type(value)
)
return value.decode("utf-8") return value.decode("utf-8")
# to_unicode was previously named _unicode not because it was private, # to_unicode was previously named _unicode not because it was private,
@ -233,8 +237,10 @@ def to_basestring(value):
""" """
if isinstance(value, _BASESTRING_TYPES): if isinstance(value, _BASESTRING_TYPES):
return value return value
assert isinstance(value, bytes_type), \ if not isinstance(value, bytes_type):
"Expected bytes, unicode, or None; got %r" % type(value) raise TypeError(
"Expected bytes, unicode, or None; got %r" % type(value)
)
return value.decode("utf-8") return value.decode("utf-8")

24
libs/tornado/gen.py

@ -64,7 +64,7 @@ For more complicated interfaces, `Task` can be split into two parts:
def get(self): def get(self):
http_client = AsyncHTTPClient() http_client = AsyncHTTPClient()
http_client.fetch("http://example.com", http_client.fetch("http://example.com",
callback=(yield gen.Callback("key")) callback=(yield gen.Callback("key")))
response = yield gen.Wait("key") response = yield gen.Wait("key")
do_something_with_response(response) do_something_with_response(response)
self.render("template.html") self.render("template.html")
@ -390,16 +390,26 @@ class YieldFuture(YieldPoint):
self.io_loop = io_loop or IOLoop.current() self.io_loop = io_loop or IOLoop.current()
def start(self, runner): def start(self, runner):
self.runner = runner if not self.future.done():
self.key = object() self.runner = runner
runner.register_callback(self.key) self.key = object()
self.io_loop.add_future(self.future, runner.result_callback(self.key)) 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): 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): 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): class Multi(YieldPoint):

59
libs/tornado/httpclient.py

@ -335,10 +335,11 @@ class HTTPRequest(object):
.. versionadded:: 3.1 .. versionadded:: 3.1
The ``auth_mode`` argument. The ``auth_mode`` argument.
""" """
if headers is None: # Note that some of these attributes go through property setters
headers = httputil.HTTPHeaders() # defined below.
self.headers = headers
if if_modified_since: if if_modified_since:
headers["If-Modified-Since"] = httputil.format_timestamp( self.headers["If-Modified-Since"] = httputil.format_timestamp(
if_modified_since) if_modified_since)
self.proxy_host = proxy_host self.proxy_host = proxy_host
self.proxy_port = proxy_port self.proxy_port = proxy_port
@ -346,8 +347,7 @@ class HTTPRequest(object):
self.proxy_password = proxy_password self.proxy_password = proxy_password
self.url = url self.url = url
self.method = method self.method = method
self.headers = headers self.body = body
self.body = utf8(body)
self.auth_username = auth_username self.auth_username = auth_username
self.auth_password = auth_password self.auth_password = auth_password
self.auth_mode = auth_mode self.auth_mode = auth_mode
@ -358,9 +358,9 @@ class HTTPRequest(object):
self.user_agent = user_agent self.user_agent = user_agent
self.use_gzip = use_gzip self.use_gzip = use_gzip
self.network_interface = network_interface self.network_interface = network_interface
self.streaming_callback = stack_context.wrap(streaming_callback) self.streaming_callback = streaming_callback
self.header_callback = stack_context.wrap(header_callback) self.header_callback = header_callback
self.prepare_curl_callback = stack_context.wrap(prepare_curl_callback) self.prepare_curl_callback = prepare_curl_callback
self.allow_nonstandard_methods = allow_nonstandard_methods self.allow_nonstandard_methods = allow_nonstandard_methods
self.validate_cert = validate_cert self.validate_cert = validate_cert
self.ca_certs = ca_certs self.ca_certs = ca_certs
@ -369,6 +369,49 @@ class HTTPRequest(object):
self.client_cert = client_cert self.client_cert = client_cert
self.start_time = time.time() 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): class HTTPResponse(object):
"""HTTP Response object. """HTTP Response object.

183
libs/tornado/ioloop.py

@ -598,100 +598,103 @@ class PollIOLoop(IOLoop):
except ValueError: # non-main thread except ValueError: # non-main thread
pass pass
while True: try:
poll_timeout = _POLL_TIMEOUT while True:
poll_timeout = _POLL_TIMEOUT
# Prevent IO event starvation by delaying new callbacks
# to the next iteration of the event loop. # Prevent IO event starvation by delaying new callbacks
with self._callback_lock: # to the next iteration of the event loop.
callbacks = self._callbacks with self._callback_lock:
self._callbacks = [] callbacks = self._callbacks
for callback in callbacks: self._callbacks = []
self._run_callback(callback) for callback in callbacks:
# Closures may be holding on to a lot of memory, so allow self._run_callback(callback)
# them to be freed before we go into our poll wait. # Closures may be holding on to a lot of memory, so allow
callbacks = callback = None # them to be freed before we go into our poll wait.
callbacks = callback = None
if self._timeouts:
now = self.time() if self._timeouts:
while self._timeouts: now = self.time()
if self._timeouts[0].callback is None: while self._timeouts:
# the timeout was cancelled if self._timeouts[0].callback is None:
heapq.heappop(self._timeouts) # the timeout was cancelled
self._cancellations -= 1 heapq.heappop(self._timeouts)
elif self._timeouts[0].deadline <= now: self._cancellations -= 1
timeout = heapq.heappop(self._timeouts) elif self._timeouts[0].deadline <= now:
self._run_callback(timeout.callback) timeout = heapq.heappop(self._timeouts)
del timeout self._run_callback(timeout.callback)
else: del timeout
seconds = self._timeouts[0].deadline - now else:
poll_timeout = min(seconds, poll_timeout) seconds = self._timeouts[0].deadline - now
break poll_timeout = min(seconds, poll_timeout)
if (self._cancellations > 512 break
and self._cancellations > (len(self._timeouts) >> 1)): if (self._cancellations > 512
# Clean up the timeout queue when it gets large and it's and self._cancellations > (len(self._timeouts) >> 1)):
# more than half cancellations. # Clean up the timeout queue when it gets large and it's
self._cancellations = 0 # more than half cancellations.
self._timeouts = [x for x in self._timeouts self._cancellations = 0
if x.callback is not None] self._timeouts = [x for x in self._timeouts
heapq.heapify(self._timeouts) if x.callback is not None]
heapq.heapify(self._timeouts)
if self._callbacks:
# If any callbacks or timeouts called add_callback, if self._callbacks:
# we don't want to wait in poll() before we run them. # If any callbacks or timeouts called add_callback,
poll_timeout = 0.0 # 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 if self._blocking_signal_threshold is not None:
# events. # clear alarm so it doesn't fire while poll is waiting for
signal.setitimer(signal.ITIMER_REAL, 0, 0) # 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: try:
self._handlers[fd](fd, events) event_pairs = self._impl.poll(poll_timeout)
except (OSError, IOError) as e: except Exception as e:
if e.args[0] == errno.EPIPE: # Depending on python version and IOLoop implementation,
# Happens when the client closes the connection # different exception types may be thrown and there are
pass # 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: 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)) self.handle_callback_exception(self._handlers.get(fd))
except Exception:
self.handle_callback_exception(self._handlers.get(fd)) finally:
# reset the stopped flag so another start/stop pair can be issued # reset the stopped flag so another start/stop pair can be issued
self._stopped = False self._stopped = False
if self._blocking_signal_threshold is not None: if self._blocking_signal_threshold is not None:
signal.setitimer(signal.ITIMER_REAL, 0, 0) signal.setitimer(signal.ITIMER_REAL, 0, 0)
IOLoop._current.instance = old_current IOLoop._current.instance = old_current
if old_wakeup_fd is not None: if old_wakeup_fd is not None:
signal.set_wakeup_fd(old_wakeup_fd) signal.set_wakeup_fd(old_wakeup_fd)
def stop(self): def stop(self):
self._running = False self._running = False

3
libs/tornado/iostream.py

@ -55,6 +55,7 @@ _ERRNO_WOULDBLOCK = (errno.EWOULDBLOCK, errno.EAGAIN)
# They should be caught and handled less noisily than other errors. # They should be caught and handled less noisily than other errors.
_ERRNO_CONNRESET = (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE) _ERRNO_CONNRESET = (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE)
class StreamClosedError(IOError): class StreamClosedError(IOError):
"""Exception raised by `IOStream` methods when the stream is closed. """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 # localhost, so handle them the same way as an error
# reported later in _handle_connect. # reported later in _handle_connect.
if (e.args[0] != errno.EINPROGRESS and 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", gen_log.warning("Connect error on fd %d: %s",
self.socket.fileno(), e) self.socket.fileno(), e)
self.close(exc_info=True) self.close(exc_info=True)

2
libs/tornado/locale.py

@ -286,8 +286,6 @@ class Locale(object):
This method is primarily intended for dates in the past. This method is primarily intended for dates in the past.
For dates in the future, we fall back to full format. For dates in the future, we fall back to full format.
""" """
if self.code.startswith("ru"):
relative = False
if isinstance(date, numbers.Real): if isinstance(date, numbers.Real):
date = datetime.datetime.utcfromtimestamp(date) date = datetime.datetime.utcfromtimestamp(date)
now = datetime.datetime.utcnow() now = datetime.datetime.utcnow()

24
libs/tornado/log.py

@ -33,7 +33,6 @@ from __future__ import absolute_import, division, print_function, with_statement
import logging import logging
import logging.handlers import logging.handlers
import sys import sys
import time
from tornado.escape import _unicode from tornado.escape import _unicode
from tornado.util import unicode_type, basestring_type 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 `tornado.options.parse_command_line` (unless ``--logging=none`` is
used). used).
""" """
def __init__(self, color=True, *args, **kwargs): DEFAULT_PREFIX_FORMAT = '[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]'
logging.Formatter.__init__(self, *args, **kwargs) 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() self._color = color and _stderr_supports_color()
if self._color: if self._color:
# The curses module has some str/bytes confusion in # The curses module has some str/bytes confusion in
@ -107,10 +119,8 @@ class LogFormatter(logging.Formatter):
except Exception as e: except Exception as e:
record.message = "Bad message (%r): %r" % (e, record.__dict__) record.message = "Bad message (%r): %r" % (e, record.__dict__)
assert isinstance(record.message, basestring_type) # guaranteed by logging assert isinstance(record.message, basestring_type) # guaranteed by logging
record.asctime = time.strftime( record.asctime = self.formatTime(record, self.datefmt)
"%y%m%d %H:%M:%S", self.converter(record.created)) prefix = self.__prefix_fmt % record.__dict__
prefix = '[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]' % \
record.__dict__
if self._color: if self._color:
prefix = (self._colors.get(record.levelno, self._normal) + prefix = (self._colors.get(record.levelno, self._normal) +
prefix + self._normal) prefix + self._normal)

10
libs/tornado/netutil.py

@ -27,7 +27,7 @@ import stat
from tornado.concurrent import dummy_executor, run_on_executor from tornado.concurrent import dummy_executor, run_on_executor
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
from tornado.platform.auto import set_close_exec 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+ if hasattr(ssl, 'match_hostname') and hasattr(ssl, 'CertificateError'): # python 3.2+
ssl_match_hostname = ssl.match_hostname ssl_match_hostname = ssl.match_hostname
@ -37,6 +37,14 @@ else:
ssl_match_hostname = backports.ssl_match_hostname.match_hostname ssl_match_hostname = backports.ssl_match_hostname.match_hostname
SSLCertificateError = backports.ssl_match_hostname.CertificateError 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): def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128, flags=None):
"""Creates listening sockets bound to the given port and address. """Creates listening sockets bound to the given port and address.

8
libs/tornado/platform/asyncio.py

@ -16,6 +16,7 @@ import os
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
from tornado import stack_context from tornado import stack_context
class BaseAsyncIOLoop(IOLoop): class BaseAsyncIOLoop(IOLoop):
def initialize(self, asyncio_loop, close_loop=False): def initialize(self, asyncio_loop, close_loop=False):
self.asyncio_loop = asyncio_loop self.asyncio_loop = asyncio_loop
@ -104,7 +105,7 @@ class BaseAsyncIOLoop(IOLoop):
else: else:
raise TypeError("Unsupported deadline %r", deadline) raise TypeError("Unsupported deadline %r", deadline)
return self.asyncio_loop.call_later(delay, self._run_callback, return self.asyncio_loop.call_later(delay, self._run_callback,
stack_context.wrap(callback)) stack_context.wrap(callback))
def remove_timeout(self, timeout): def remove_timeout(self, timeout):
timeout.cancel() timeout.cancel()
@ -114,8 +115,8 @@ class BaseAsyncIOLoop(IOLoop):
raise RuntimeError("IOLoop is closing") raise RuntimeError("IOLoop is closing")
if kwargs: if kwargs:
self.asyncio_loop.call_soon_threadsafe(functools.partial( self.asyncio_loop.call_soon_threadsafe(functools.partial(
self._run_callback, stack_context.wrap(callback), self._run_callback, stack_context.wrap(callback),
*args, **kwargs)) *args, **kwargs))
else: else:
self.asyncio_loop.call_soon_threadsafe( self.asyncio_loop.call_soon_threadsafe(
self._run_callback, stack_context.wrap(callback), *args) self._run_callback, stack_context.wrap(callback), *args)
@ -128,6 +129,7 @@ class AsyncIOMainLoop(BaseAsyncIOLoop):
super(AsyncIOMainLoop, self).initialize(asyncio.get_event_loop(), super(AsyncIOMainLoop, self).initialize(asyncio.get_event_loop(),
close_loop=False) close_loop=False)
class AsyncIOLoop(BaseAsyncIOLoop): class AsyncIOLoop(BaseAsyncIOLoop):
def initialize(self): def initialize(self):
super(AsyncIOLoop, self).initialize(asyncio.new_event_loop(), super(AsyncIOLoop, self).initialize(asyncio.new_event_loop(),

6
libs/tornado/platform/twisted.py

@ -527,8 +527,10 @@ class TwistedResolver(Resolver):
resolved_family = socket.AF_INET6 resolved_family = socket.AF_INET6
else: else:
deferred = self.resolver.getHostByName(utf8(host)) deferred = self.resolver.getHostByName(utf8(host))
resolved = yield gen.Task(deferred.addCallback) resolved = yield gen.Task(deferred.addBoth)
if twisted.internet.abstract.isIPAddress(resolved): if isinstance(resolved, failure.Failure):
resolved.raiseException()
elif twisted.internet.abstract.isIPAddress(resolved):
resolved_family = socket.AF_INET resolved_family = socket.AF_INET
elif twisted.internet.abstract.isIPv6Address(resolved): elif twisted.internet.abstract.isIPv6Address(resolved):
resolved_family = socket.AF_INET6 resolved_family = socket.AF_INET6

10
libs/tornado/simple_httpclient.py

@ -94,9 +94,9 @@ class SimpleAsyncHTTPClient(AsyncHTTPClient):
self.queue.append((key, request, callback)) self.queue.append((key, request, callback))
if not len(self.active) < self.max_clients: if not len(self.active) < self.max_clients:
timeout_handle = self.io_loop.add_timeout( timeout_handle = self.io_loop.add_timeout(
self.io_loop.time() + min(request.connect_timeout, self.io_loop.time() + min(request.connect_timeout,
request.request_timeout), request.request_timeout),
functools.partial(self._on_timeout, key)) functools.partial(self._on_timeout, key))
else: else:
timeout_handle = None timeout_handle = None
self.waiting[key] = (request, callback, timeout_handle) self.waiting[key] = (request, callback, timeout_handle)
@ -136,8 +136,8 @@ class SimpleAsyncHTTPClient(AsyncHTTPClient):
request, callback, timeout_handle = self.waiting[key] request, callback, timeout_handle = self.waiting[key]
self.queue.remove((key, request, callback)) self.queue.remove((key, request, callback))
timeout_response = HTTPResponse( timeout_response = HTTPResponse(
request, 599, error=HTTPError(599, "Timeout"), request, 599, error=HTTPError(599, "Timeout"),
request_time=self.io_loop.time() - request.start_time) request_time=self.io_loop.time() - request.start_time)
self.io_loop.add_callback(callback, timeout_response) self.io_loop.add_callback(callback, timeout_response)
del self.waiting[key] del self.waiting[key]

15
libs/tornado/template.py

@ -21,7 +21,7 @@ Basic usage looks like::
t = template.Template("<html>{{ myvalue }}</html>") t = template.Template("<html>{{ myvalue }}</html>")
print t.generate(myvalue="XXX") 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:: the compiled templates::
loader = template.Loader("/home/btaylor") loader = template.Loader("/home/btaylor")
@ -56,16 +56,17 @@ interesting. Syntax for the templates::
{% end %} {% end %}
Unlike most other template systems, we do not put any restrictions on the 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 expressions you can include in your statements. ``if`` and ``for`` blocks get
translated exactly into Python, you can do complex expressions like:: 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] %} {% for student in [p for p in people if p.student and p.age > 23] %}
<li>{{ escape(student.name) }}</li> <li>{{ escape(student.name) }}</li>
{% end %} {% end %}
Translating directly to Python means you can apply functions to expressions Translating directly to Python means you can apply functions to expressions
easily, like the escape() function in the examples above. You can pass easily, like the ``escape()`` function in the examples above. You can pass
functions in to your template just like any other variable:: functions in to your template just like any other variable
(In a `.RequestHandler`, override `.RequestHandler.get_template_namespace`)::
### Python code ### Python code
def add(x, y): def add(x, y):
@ -75,8 +76,8 @@ functions in to your template just like any other variable::
### The template ### The template
{{ add(1, 2) }} {{ add(1, 2) }}
We provide the functions escape(), url_escape(), json_encode(), and squeeze() We provide the functions `escape() <.xhtml_escape>`, `.url_escape()`,
to all templates by default. `.json_encode()`, and `.squeeze()` to all templates by default.
Typical applications do not create `Template` or `Loader` instances by Typical applications do not create `Template` or `Loader` instances by
hand, but instead use the `~.RequestHandler.render` and hand, but instead use the `~.RequestHandler.render` and

8
libs/tornado/web.py

@ -447,7 +447,11 @@ class RequestHandler(object):
The name of the argument is provided if known, but may be None The name of the argument is provided if known, but may be None
(e.g. for unnamed groups in the url regex). (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 @property
def cookies(self): def cookies(self):
@ -1908,7 +1912,7 @@ class StaticFileHandler(RequestHandler):
# content, or when a suffix with length 0 is specified # content, or when a suffix with length 0 is specified
self.set_status(416) # Range Not Satisfiable self.set_status(416) # Range Not Satisfiable
self.set_header("Content-Type", "text/plain") self.set_header("Content-Type", "text/plain")
self.set_header("Content-Range", "bytes */%s" %(size, )) self.set_header("Content-Range", "bytes */%s" % (size, ))
return return
if start is not None and start < 0: if start is not None and start < 0:
start += size start += size

13
libs/tornado/websocket.py

@ -381,12 +381,12 @@ class WebSocketProtocol76(WebSocketProtocol):
"Sec-WebSocket-Location: %(scheme)s://%(host)s%(uri)s\r\n" "Sec-WebSocket-Location: %(scheme)s://%(host)s%(uri)s\r\n"
"%(subprotocol)s" "%(subprotocol)s"
"\r\n" % (dict( "\r\n" % (dict(
version=tornado.version, version=tornado.version,
origin=self.request.headers["Origin"], origin=self.request.headers["Origin"],
scheme=scheme, scheme=scheme,
host=self.request.host, host=self.request.host,
uri=self.request.uri, uri=self.request.uri,
subprotocol=subprotocol_header)))) subprotocol=subprotocol_header))))
self.stream.read_bytes(8, self._handle_challenge) self.stream.read_bytes(8, self._handle_challenge)
def challenge_response(self, 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) io_loop.add_future(conn.connect_future, callback)
return conn.connect_future return conn.connect_future
def _websocket_mask_python(mask, data): def _websocket_mask_python(mask, data):
"""Websocket masking function. """Websocket masking function.

2
libs/tornado/wsgi.py

@ -294,7 +294,7 @@ class WSGIContainer(object):
"REQUEST_METHOD": request.method, "REQUEST_METHOD": request.method,
"SCRIPT_NAME": "", "SCRIPT_NAME": "",
"PATH_INFO": to_wsgi_str(escape.url_unescape( "PATH_INFO": to_wsgi_str(escape.url_unescape(
request.path, encoding=None, plus=False)), request.path, encoding=None, plus=False)),
"QUERY_STRING": request.query, "QUERY_STRING": request.query,
"REMOTE_ADDR": request.remote_ip, "REMOTE_ADDR": request.remote_ip,
"SERVER_NAME": host, "SERVER_NAME": host,

Loading…
Cancel
Save