Flask update
This commit is contained in:
1 parent
168a9a2f95
commit
f7d72dd5a9
114 files changed
+1540
-3835
No files matched your search
Regular → Executable
+100
-35
@@ -35,6 +35,8 @@
|
||||
:copyright: (c) 2011 by the Werkzeug Team, see AUTHORS for more details.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
from __future__ import with_statement
|
||||
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
@@ -177,6 +179,7 @@ class WSGIRequestHandler(BaseHTTPRequestHandler, object):
|
||||
|
||||
def handle(self):
|
||||
"""Handles a request ignoring dropped connections."""
|
||||
rv = None
|
||||
try:
|
||||
rv = BaseHTTPRequestHandler.handle(self)
|
||||
except (socket.error, socket.timeout), e:
|
||||
@@ -192,9 +195,11 @@ class WSGIRequestHandler(BaseHTTPRequestHandler, object):
|
||||
"""A horrible, horrible way to kill the server for Python 2.6 and
|
||||
later. It's the best we can do.
|
||||
"""
|
||||
# Windows does not provide SIGKILL, go with SIGTERM then.
|
||||
sig = getattr(signal, 'SIGKILL', signal.SIGTERM)
|
||||
# reloader active
|
||||
if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
|
||||
os.kill(os.getpid(), signal.SIGKILL)
|
||||
os.kill(os.getpid(), sig)
|
||||
# python 2.7
|
||||
self.server._BaseServer__shutdown_request = True
|
||||
# python 2.6
|
||||
@@ -247,10 +252,13 @@ class WSGIRequestHandler(BaseHTTPRequestHandler, object):
|
||||
BaseRequestHandler = WSGIRequestHandler
|
||||
|
||||
|
||||
def generate_adhoc_ssl_context():
|
||||
"""Generates an adhoc SSL context for the development server."""
|
||||
def generate_adhoc_ssl_pair(cn=None):
|
||||
from random import random
|
||||
from OpenSSL import crypto, SSL
|
||||
from OpenSSL import crypto
|
||||
|
||||
# pretty damn sure that this is not actually accepted by anyone
|
||||
if cn is None:
|
||||
cn = '*'
|
||||
|
||||
cert = crypto.X509()
|
||||
cert.set_serial_number(int(random() * sys.maxint))
|
||||
@@ -258,7 +266,7 @@ def generate_adhoc_ssl_context():
|
||||
cert.gmtime_adj_notAfter(60 * 60 * 24 * 365)
|
||||
|
||||
subject = cert.get_subject()
|
||||
subject.CN = '*'
|
||||
subject.CN = cn
|
||||
subject.O = 'Dummy Certificate'
|
||||
|
||||
issuer = cert.get_issuer()
|
||||
@@ -270,10 +278,59 @@ def generate_adhoc_ssl_context():
|
||||
cert.set_pubkey(pkey)
|
||||
cert.sign(pkey, 'md5')
|
||||
|
||||
return cert, pkey
|
||||
|
||||
|
||||
def make_ssl_devcert(base_path, host=None, cn=None):
|
||||
"""Creates an SSL key for development. This should be used instead of
|
||||
the ``'adhoc'`` key which generates a new cert on each server start.
|
||||
It accepts a path for where it should store the key and cert and
|
||||
either a host or CN. If a host is given it will use the CN
|
||||
``*.host/CN=host``.
|
||||
|
||||
For more information see :func:`run_simple`.
|
||||
|
||||
.. versionadded:: 0.9
|
||||
|
||||
:param base_path: the path to the certificate and key. The extension
|
||||
``.crt`` is added for the certificate, ``.key`` is
|
||||
added for the key.
|
||||
:param host: the name of the host. This can be used as an alternative
|
||||
for the `cn`.
|
||||
:param cn: the `CN` to use.
|
||||
"""
|
||||
from OpenSSL import crypto
|
||||
if host is not None:
|
||||
cn = '*.%s/CN=%s' % (host, host)
|
||||
cert, pkey = generate_adhoc_ssl_pair(cn=cn)
|
||||
|
||||
cert_file = base_path + '.crt'
|
||||
pkey_file = base_path + '.key'
|
||||
|
||||
with open(cert_file, 'w') as f:
|
||||
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
|
||||
with open(pkey_file, 'w') as f:
|
||||
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
|
||||
|
||||
return cert_file, pkey_file
|
||||
|
||||
|
||||
def generate_adhoc_ssl_context():
|
||||
"""Generates an adhoc SSL context for the development server."""
|
||||
from OpenSSL import SSL
|
||||
pkey, cert = generate_adhoc_ssl_pair()
|
||||
ctx = SSL.Context(SSL.SSLv23_METHOD)
|
||||
ctx.use_privatekey(pkey)
|
||||
ctx.use_certificate(cert)
|
||||
return ctx
|
||||
|
||||
|
||||
def load_ssl_context(cert_file, pkey_file):
|
||||
"""Loads an SSL context from a certificate and private key file."""
|
||||
from OpenSSL import SSL
|
||||
ctx = SSL.Context(SSL.SSLv23_METHOD)
|
||||
ctx.use_certificate_file(cert_file)
|
||||
ctx.use_privatekey_file(pkey_file)
|
||||
return ctx
|
||||
|
||||
|
||||
@@ -297,6 +354,9 @@ class _SSLConnectionFix(object):
|
||||
def __getattr__(self, attrib):
|
||||
return getattr(self._con, attrib)
|
||||
|
||||
def shutdown(self, arg=None):
|
||||
self._con.shutdown()
|
||||
|
||||
|
||||
def select_ip_version(host, port):
|
||||
"""Returns AF_INET4 or AF_INET6 depending on where to connect to."""
|
||||
@@ -339,6 +399,8 @@ class BaseWSGIServer(HTTPServer, object):
|
||||
except ImportError:
|
||||
raise TypeError('SSL is not available if the OpenSSL '
|
||||
'library is not installed.')
|
||||
if isinstance(ssl_context, tuple):
|
||||
ssl_context = load_ssl_context(*ssl_context)
|
||||
if ssl_context == 'adhoc':
|
||||
ssl_context = generate_adhoc_ssl_context()
|
||||
self.socket = tsafe.Connection(ssl_context, self.socket)
|
||||
@@ -405,7 +467,23 @@ def make_server(host, port, app=None, threaded=False, processes=1,
|
||||
passthrough_errors, ssl_context)
|
||||
|
||||
|
||||
def reloader_loop(extra_files=None, interval=1):
|
||||
def _iter_module_files():
|
||||
for module in sys.modules.values():
|
||||
filename = getattr(module, '__file__', None)
|
||||
if filename:
|
||||
old = None
|
||||
while not os.path.isfile(filename):
|
||||
old = filename
|
||||
filename = os.path.dirname(filename)
|
||||
if filename == old:
|
||||
break
|
||||
else:
|
||||
if filename[-4:] in ('.pyc', '.pyo'):
|
||||
filename = filename[:-1]
|
||||
yield filename
|
||||
|
||||
|
||||
def _reloader_stat_loop(extra_files=None, interval=1):
|
||||
"""When this function is run from the main thread, it will force other
|
||||
threads to exit when any modules currently loaded change.
|
||||
|
||||
@@ -414,32 +492,10 @@ def reloader_loop(extra_files=None, interval=1):
|
||||
|
||||
:param extra_files: a list of additional files it should watch.
|
||||
"""
|
||||
def iter_module_files():
|
||||
for module in sys.modules.values():
|
||||
filename = getattr(module, '__file__', None)
|
||||
if filename:
|
||||
old = None
|
||||
while not os.path.isfile(filename):
|
||||
old = filename
|
||||
filename = os.path.dirname(filename)
|
||||
if filename == old:
|
||||
break
|
||||
else:
|
||||
if filename[-4:] in ('.pyc', '.pyo'):
|
||||
filename = filename[:-1]
|
||||
yield filename
|
||||
|
||||
fnames = []
|
||||
fnames.extend(iter_module_files())
|
||||
fnames.extend(extra_files or ())
|
||||
|
||||
reloader(fnames, interval=interval)
|
||||
|
||||
|
||||
def _reloader_stat_loop(fnames, interval=1):
|
||||
from itertools import chain
|
||||
mtimes = {}
|
||||
while 1:
|
||||
for filename in fnames:
|
||||
for filename in chain(_iter_module_files(), extra_files or ()):
|
||||
try:
|
||||
mtime = os.stat(filename).st_mtime
|
||||
except OSError:
|
||||
@@ -455,7 +511,7 @@ def _reloader_stat_loop(fnames, interval=1):
|
||||
time.sleep(interval)
|
||||
|
||||
|
||||
def _reloader_inotify(fnames, interval=None):
|
||||
def _reloader_inotify(extra_files=None, interval=None):
|
||||
# Mutated by inotify loop when changes occur.
|
||||
changed = [False]
|
||||
|
||||
@@ -478,13 +534,16 @@ def _reloader_inotify(fnames, interval=None):
|
||||
_log('info', ' * Detected change in %r, reloading' % event.path)
|
||||
changed[:] = [True]
|
||||
|
||||
for fname in fnames:
|
||||
for fname in extra_files or ():
|
||||
wm.add_watch(fname, mask, signal_changed)
|
||||
|
||||
# ... And now we wait...
|
||||
notif = Notifier(wm)
|
||||
try:
|
||||
while not changed[0]:
|
||||
# always reiterate through sys.modules, adding them
|
||||
for fname in _iter_module_files():
|
||||
wm.add_watch(fname, mask, signal_changed)
|
||||
notif.process_events()
|
||||
if notif.check_events(timeout=interval):
|
||||
notif.read_events()
|
||||
@@ -497,7 +556,7 @@ def _reloader_inotify(fnames, interval=None):
|
||||
# currently we always use the stat loop reloader for the simple reason
|
||||
# that the inotify one does not respond to added files properly. Also
|
||||
# it's quite buggy and the API is a mess.
|
||||
reloader = _reloader_stat_loop
|
||||
reloader_loop = _reloader_stat_loop
|
||||
|
||||
|
||||
def restart_with_reloader():
|
||||
@@ -555,6 +614,10 @@ def run_simple(hostname, port, application, use_reloader=False,
|
||||
.. versionadded:: 0.6
|
||||
support for SSL was added.
|
||||
|
||||
.. versionadded:: 0.8
|
||||
Added support for automatically loading a SSL context from certificate
|
||||
file and private key.
|
||||
|
||||
:param hostname: The host for the application. eg: ``'localhost'``
|
||||
:param port: The port for the server. eg: ``8080``
|
||||
:param application: the WSGI application to execute
|
||||
@@ -582,7 +645,8 @@ def run_simple(hostname, port, application, use_reloader=False,
|
||||
This means that the server will die on errors but
|
||||
it can be useful to hook debuggers in (pdb etc.)
|
||||
:param ssl_context: an SSL context for the connection. Either an OpenSSL
|
||||
context, the string ``'adhoc'`` if the server should
|
||||
context, a tuple in the form ``(cert_file, pkey_file)``,
|
||||
the string ``'adhoc'`` if the server should
|
||||
automatically create one, or `None` to disable SSL
|
||||
(which is the default).
|
||||
"""
|
||||
@@ -607,7 +671,8 @@ def run_simple(hostname, port, application, use_reloader=False,
|
||||
if use_reloader:
|
||||
# Create and destroy a socket so that any exceptions are raised before
|
||||
# we spawn a separate Python interpreter and lose this ability.
|
||||
test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
address_family = select_ip_version(hostname, port)
|
||||
test_socket = socket.socket(address_family, socket.SOCK_STREAM)
|
||||
test_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
test_socket.bind((hostname, port))
|
||||
test_socket.close()
|
||||
|
||||
Reference in new issue
Block a user