mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-07 05:31:15 -07:00
Update CherryPy to 5.1.0
This commit is contained in:
parent
f9825410dc
commit
b2304992e5
25 changed files with 2383 additions and 130 deletions
|
@ -56,10 +56,10 @@ with customized or extended components. The core API's are:
|
||||||
These API's are described in the `CherryPy specification <https://bitbucket.org/cherrypy/cherrypy/wiki/CherryPySpec>`_.
|
These API's are described in the `CherryPy specification <https://bitbucket.org/cherrypy/cherrypy/wiki/CherryPySpec>`_.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "3.8.0"
|
__version__ = "5.1.0"
|
||||||
|
|
||||||
from cherrypy._cpcompat import urljoin as _urljoin, urlencode as _urlencode
|
from cherrypy._cpcompat import urljoin as _urljoin, urlencode as _urlencode
|
||||||
from cherrypy._cpcompat import basestring, unicodestr, set
|
from cherrypy._cpcompat import basestring, unicodestr
|
||||||
|
|
||||||
from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect
|
from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect
|
||||||
from cherrypy._cperror import NotFound, CherryPyException, TimeoutError
|
from cherrypy._cperror import NotFound, CherryPyException, TimeoutError
|
||||||
|
|
|
@ -110,11 +110,6 @@ def assert_native(n):
|
||||||
if not isinstance(n, nativestr):
|
if not isinstance(n, nativestr):
|
||||||
raise TypeError("n must be a native str (got %s)" % type(n).__name__)
|
raise TypeError("n must be a native str (got %s)" % type(n).__name__)
|
||||||
|
|
||||||
try:
|
|
||||||
set = set
|
|
||||||
except NameError:
|
|
||||||
from sets import Set as set
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Python 3.1+
|
# Python 3.1+
|
||||||
from base64 import decodebytes as _base64_decodebytes
|
from base64 import decodebytes as _base64_decodebytes
|
||||||
|
@ -137,17 +132,6 @@ def base64_decode(n, encoding='ISO-8859-1'):
|
||||||
else:
|
else:
|
||||||
return b
|
return b
|
||||||
|
|
||||||
try:
|
|
||||||
# Python 2.5+
|
|
||||||
from hashlib import md5
|
|
||||||
except ImportError:
|
|
||||||
from md5 import new as md5
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Python 2.5+
|
|
||||||
from hashlib import sha1 as sha
|
|
||||||
except ImportError:
|
|
||||||
from sha import new as sha
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sorted = sorted
|
sorted = sorted
|
||||||
|
@ -333,18 +317,10 @@ except ImportError:
|
||||||
# In Python 3, pickle is the sped-up C version.
|
# In Python 3, pickle is the sped-up C version.
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
try:
|
import binascii
|
||||||
os.urandom(20)
|
|
||||||
import binascii
|
|
||||||
|
|
||||||
def random20():
|
def random20():
|
||||||
return binascii.hexlify(os.urandom(20)).decode('ascii')
|
return binascii.hexlify(os.urandom(20)).decode('ascii')
|
||||||
except (AttributeError, NotImplementedError):
|
|
||||||
import random
|
|
||||||
# os.urandom not available until Python 2.4. Fall back to random.random.
|
|
||||||
|
|
||||||
def random20():
|
|
||||||
return sha('%s' % random.random()).hexdigest()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from _thread import get_ident as get_thread_ident
|
from _thread import get_ident as get_thread_ident
|
||||||
|
|
|
@ -883,7 +883,7 @@ class Popen(object):
|
||||||
startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
|
startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
|
||||||
startupinfo.wShowWindow = _subprocess.SW_HIDE
|
startupinfo.wShowWindow = _subprocess.SW_HIDE
|
||||||
comspec = os.environ.get("COMSPEC", "cmd.exe")
|
comspec = os.environ.get("COMSPEC", "cmd.exe")
|
||||||
args = '{} /c "{}"'.format(comspec, args)
|
args = '{0} /c "{1}"'.format(comspec, args)
|
||||||
if (_subprocess.GetVersion() >= 0x80000000 or
|
if (_subprocess.GetVersion() >= 0x80000000 or
|
||||||
os.path.basename(comspec).lower() == "command.com"):
|
os.path.basename(comspec).lower() == "command.com"):
|
||||||
# Win9x, or using command.com on NT. We need to
|
# Win9x, or using command.com on NT. We need to
|
||||||
|
@ -1029,7 +1029,7 @@ class Popen(object):
|
||||||
elif sig == signal.CTRL_BREAK_EVENT:
|
elif sig == signal.CTRL_BREAK_EVENT:
|
||||||
os.kill(self.pid, signal.CTRL_BREAK_EVENT)
|
os.kill(self.pid, signal.CTRL_BREAK_EVENT)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported signal: {}".format(sig))
|
raise ValueError("Unsupported signal: {0}".format(sig))
|
||||||
|
|
||||||
def terminate(self):
|
def terminate(self):
|
||||||
"""Terminates the process
|
"""Terminates the process
|
||||||
|
|
|
@ -119,7 +119,7 @@ style) context manager.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
from cherrypy._cpcompat import set, basestring
|
from cherrypy._cpcompat import basestring
|
||||||
from cherrypy.lib import reprconf
|
from cherrypy.lib import reprconf
|
||||||
|
|
||||||
# Deprecated in CherryPy 3.2--remove in 3.3
|
# Deprecated in CherryPy 3.2--remove in 3.3
|
||||||
|
|
|
@ -18,7 +18,6 @@ except AttributeError:
|
||||||
classtype = type
|
classtype = type
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
from cherrypy._cpcompat import set
|
|
||||||
|
|
||||||
|
|
||||||
class PageHandler(object):
|
class PageHandler(object):
|
||||||
|
|
|
@ -296,7 +296,8 @@ class AppResponse(object):
|
||||||
"""Create a Request object using environ."""
|
"""Create a Request object using environ."""
|
||||||
env = self.environ.get
|
env = self.environ.get
|
||||||
|
|
||||||
local = httputil.Host('', int(env('SERVER_PORT', 80)),
|
local = httputil.Host('',
|
||||||
|
int(env('SERVER_PORT', 80) or -1),
|
||||||
env('SERVER_NAME', ''))
|
env('SERVER_NAME', ''))
|
||||||
remote = httputil.Host(env('REMOTE_ADDR', ''),
|
remote = httputil.Host(env('REMOTE_ADDR', ''),
|
||||||
int(env('REMOTE_PORT', -1) or -1),
|
int(env('REMOTE_PORT', -1) or -1),
|
||||||
|
|
|
@ -53,15 +53,12 @@ def start(configfiles=None, daemonize=False, environment=None,
|
||||||
cherrypy.server.unsubscribe()
|
cherrypy.server.unsubscribe()
|
||||||
|
|
||||||
addr = cherrypy.server.bind_addr
|
addr = cherrypy.server.bind_addr
|
||||||
if fastcgi:
|
cls = (
|
||||||
f = servers.FlupFCGIServer(application=cherrypy.tree,
|
servers.FlupFCGIServer if fastcgi else
|
||||||
bindAddress=addr)
|
servers.FlupSCGIServer if scgi else
|
||||||
elif scgi:
|
servers.FlupCGIServer
|
||||||
f = servers.FlupSCGIServer(application=cherrypy.tree,
|
)
|
||||||
bindAddress=addr)
|
f = cls(application=cherrypy.tree, bindAddress=addr)
|
||||||
else:
|
|
||||||
f = servers.FlupCGIServer(application=cherrypy.tree,
|
|
||||||
bindAddress=addr)
|
|
||||||
s = servers.ServerAdapter(engine, httpserver=f, bind_addr=addr)
|
s = servers.ServerAdapter(engine, httpserver=f, bind_addr=addr)
|
||||||
s.subscribe()
|
s.subscribe()
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,11 @@ __date__ = 'April 2009'
|
||||||
|
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
from hashlib import md5
|
||||||
from cherrypy._cpcompat import parse_http_list, parse_keqv_list
|
from cherrypy._cpcompat import parse_http_list, parse_keqv_list
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
from cherrypy._cpcompat import md5, ntob
|
from cherrypy._cpcompat import ntob
|
||||||
md5_hex = lambda s: md5(ntob(s)).hexdigest()
|
md5_hex = lambda s: md5(ntob(s)).hexdigest()
|
||||||
|
|
||||||
qop_auth = 'auth'
|
qop_auth = 'auth'
|
||||||
|
|
|
@ -210,6 +210,7 @@ def extrapolate_statistics(scope):
|
||||||
|
|
||||||
# -------------------- CherryPy Applications Statistics --------------------- #
|
# -------------------- CherryPy Applications Statistics --------------------- #
|
||||||
|
|
||||||
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -294,6 +295,11 @@ class ByteCountWrapper(object):
|
||||||
average_uriset_time = lambda s: s['Count'] and (s['Sum'] / s['Count']) or 0
|
average_uriset_time = lambda s: s['Count'] and (s['Sum'] / s['Count']) or 0
|
||||||
|
|
||||||
|
|
||||||
|
def _get_threading_ident():
|
||||||
|
if sys.version_info >= (3, 3):
|
||||||
|
return threading.get_ident()
|
||||||
|
return threading._get_ident()
|
||||||
|
|
||||||
class StatsTool(cherrypy.Tool):
|
class StatsTool(cherrypy.Tool):
|
||||||
|
|
||||||
"""Record various information about the current request."""
|
"""Record various information about the current request."""
|
||||||
|
@ -322,7 +328,7 @@ class StatsTool(cherrypy.Tool):
|
||||||
|
|
||||||
appstats['Current Requests'] += 1
|
appstats['Current Requests'] += 1
|
||||||
appstats['Total Requests'] += 1
|
appstats['Total Requests'] += 1
|
||||||
appstats['Requests'][threading._get_ident()] = {
|
appstats['Requests'][_get_threading_ident()] = {
|
||||||
'Bytes Read': None,
|
'Bytes Read': None,
|
||||||
'Bytes Written': None,
|
'Bytes Written': None,
|
||||||
# Use a lambda so the ip gets updated by tools.proxy later
|
# Use a lambda so the ip gets updated by tools.proxy later
|
||||||
|
@ -339,7 +345,7 @@ class StatsTool(cherrypy.Tool):
|
||||||
debug=False, **kwargs):
|
debug=False, **kwargs):
|
||||||
"""Record the end of a request."""
|
"""Record the end of a request."""
|
||||||
resp = cherrypy.serving.response
|
resp = cherrypy.serving.response
|
||||||
w = appstats['Requests'][threading._get_ident()]
|
w = appstats['Requests'][_get_threading_ident()]
|
||||||
|
|
||||||
r = cherrypy.request.rfile.bytes_read
|
r = cherrypy.request.rfile.bytes_read
|
||||||
w['Bytes Read'] = r
|
w['Bytes Read'] = r
|
||||||
|
@ -605,7 +611,13 @@ table.stats2 th {
|
||||||
"""Return ([headers], [rows]) for the given collection."""
|
"""Return ([headers], [rows]) for the given collection."""
|
||||||
# E.g., the 'Requests' dict.
|
# E.g., the 'Requests' dict.
|
||||||
headers = []
|
headers = []
|
||||||
for record in v.itervalues():
|
try:
|
||||||
|
# python2
|
||||||
|
vals = v.itervalues()
|
||||||
|
except AttributeError:
|
||||||
|
# python3
|
||||||
|
vals = v.values()
|
||||||
|
for record in vals:
|
||||||
for k3 in record:
|
for k3 in record:
|
||||||
format = formatting.get(k3, missing)
|
format = formatting.get(k3, missing)
|
||||||
if format is None:
|
if format is None:
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
from hashlib import md5
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
from cherrypy._cpcompat import basestring, md5, set, unicodestr
|
from cherrypy._cpcompat import basestring, unicodestr
|
||||||
from cherrypy.lib import httputil as _httputil
|
from cherrypy.lib import httputil as _httputil
|
||||||
from cherrypy.lib import is_iterator
|
from cherrypy.lib import is_iterator
|
||||||
|
|
||||||
|
@ -192,11 +193,10 @@ def proxy(base=None, local='X-Forwarded-Host', remote='X-Forwarded-For',
|
||||||
if lbase is not None:
|
if lbase is not None:
|
||||||
base = lbase.split(',')[0]
|
base = lbase.split(',')[0]
|
||||||
if not base:
|
if not base:
|
||||||
|
base = request.headers.get('Host', '127.0.0.1')
|
||||||
port = request.local.port
|
port = request.local.port
|
||||||
if port == 80:
|
if port != 80:
|
||||||
base = '127.0.0.1'
|
base += ':%s' % port
|
||||||
else:
|
|
||||||
base = '127.0.0.1:%s' % port
|
|
||||||
|
|
||||||
if base.find("://") == -1:
|
if base.find("://") == -1:
|
||||||
# add http:// or https:// if needed
|
# add http:// or https:// if needed
|
||||||
|
|
|
@ -2,7 +2,7 @@ import struct
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
from cherrypy._cpcompat import basestring, BytesIO, ntob, set, unicodestr
|
from cherrypy._cpcompat import basestring, BytesIO, ntob, unicodestr
|
||||||
from cherrypy.lib import file_generator
|
from cherrypy.lib import file_generator
|
||||||
from cherrypy.lib import is_closable_iterator
|
from cherrypy.lib import is_closable_iterator
|
||||||
from cherrypy.lib import set_vary_header
|
from cherrypy.lib import set_vary_header
|
||||||
|
|
|
@ -62,7 +62,9 @@ __all__ = ("digestAuth", "basicAuth", "doAuth", "checkResponse",
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
import time
|
import time
|
||||||
from cherrypy._cpcompat import base64_decode, ntob, md5
|
from hashlib import md5
|
||||||
|
|
||||||
|
from cherrypy._cpcompat import base64_decode, ntob
|
||||||
from cherrypy._cpcompat import parse_http_list, parse_keqv_list
|
from cherrypy._cpcompat import parse_http_list, parse_keqv_list
|
||||||
|
|
||||||
MD5 = "MD5"
|
MD5 = "MD5"
|
||||||
|
|
|
@ -8,7 +8,7 @@ You can profile any of your pages as follows::
|
||||||
from cherrypy.lib import profiler
|
from cherrypy.lib import profiler
|
||||||
|
|
||||||
class Root:
|
class Root:
|
||||||
p = profile.Profiler("/path/to/profile/dir")
|
p = profiler.Profiler("/path/to/profile/dir")
|
||||||
|
|
||||||
def index(self):
|
def index(self):
|
||||||
self.p.run(self._index)
|
self.p.run(self._index)
|
||||||
|
|
|
@ -281,13 +281,14 @@ class _Builder2:
|
||||||
# Everything else becomes args
|
# Everything else becomes args
|
||||||
else :
|
else :
|
||||||
args.append(self.build(child))
|
args.append(self.build(child))
|
||||||
|
|
||||||
return callee(*args, **kwargs)
|
return callee(*args, **kwargs)
|
||||||
|
|
||||||
def build_Keyword(self, o):
|
def build_Keyword(self, o):
|
||||||
key, value_obj = o.getChildren()
|
key, value_obj = o.getChildren()
|
||||||
value = self.build(value_obj)
|
value = self.build(value_obj)
|
||||||
kw_dict = {key: value}
|
kw_dict = {key: value}
|
||||||
return kw_dict
|
return kw_dict
|
||||||
|
|
||||||
def build_List(self, o):
|
def build_List(self, o):
|
||||||
return map(self.build, o.getChildren())
|
return map(self.build, o.getChildren())
|
||||||
|
@ -377,7 +378,39 @@ class _Builder3:
|
||||||
def build_Index(self, o):
|
def build_Index(self, o):
|
||||||
return self.build(o.value)
|
return self.build(o.value)
|
||||||
|
|
||||||
|
def _build_call35(self, o):
|
||||||
|
"""
|
||||||
|
Workaround for python 3.5 _ast.Call signature, docs found here
|
||||||
|
https://greentreesnakes.readthedocs.org/en/latest/nodes.html
|
||||||
|
"""
|
||||||
|
import ast
|
||||||
|
callee = self.build(o.func)
|
||||||
|
args = []
|
||||||
|
if o.args is not None:
|
||||||
|
for a in o.args:
|
||||||
|
if isinstance(a, ast.Starred):
|
||||||
|
args.append(self.build(a.value))
|
||||||
|
else:
|
||||||
|
args.append(self.build(a))
|
||||||
|
kwargs = {}
|
||||||
|
for kw in o.keywords:
|
||||||
|
if kw.arg is None: # double asterix `**`
|
||||||
|
rst = self.build(kw.value)
|
||||||
|
if not isinstance(rst, dict):
|
||||||
|
raise TypeError("Invalid argument for call."
|
||||||
|
"Must be a mapping object.")
|
||||||
|
# give preference to the keys set directly from arg=value
|
||||||
|
for k, v in rst.items():
|
||||||
|
if k not in kwargs:
|
||||||
|
kwargs[k] = v
|
||||||
|
else: # defined on the call as: arg=value
|
||||||
|
kwargs[kw.arg] = self.build(kw.value)
|
||||||
|
return callee(*args, **kwargs)
|
||||||
|
|
||||||
def build_Call(self, o):
|
def build_Call(self, o):
|
||||||
|
if sys.version_info >= (3, 5):
|
||||||
|
return self._build_call35(o)
|
||||||
|
|
||||||
callee = self.build(o.func)
|
callee = self.build(o.func)
|
||||||
|
|
||||||
if o.args is None:
|
if o.args is None:
|
||||||
|
@ -388,13 +421,16 @@ class _Builder3:
|
||||||
if o.starargs is None:
|
if o.starargs is None:
|
||||||
starargs = ()
|
starargs = ()
|
||||||
else:
|
else:
|
||||||
starargs = self.build(o.starargs)
|
starargs = tuple(self.build(o.starargs))
|
||||||
|
|
||||||
if o.kwargs is None:
|
if o.kwargs is None:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
else:
|
else:
|
||||||
kwargs = self.build(o.kwargs)
|
kwargs = self.build(o.kwargs)
|
||||||
|
if o.keywords is not None: # direct a=b keywords
|
||||||
|
for kw in o.keywords:
|
||||||
|
# preference because is a direct keyword against **kwargs
|
||||||
|
kwargs[kw.arg] = self.build(kw.value)
|
||||||
return callee(*(args + starargs), **kwargs)
|
return callee(*(args + starargs), **kwargs)
|
||||||
|
|
||||||
def build_List(self, o):
|
def build_List(self, o):
|
||||||
|
|
|
@ -49,7 +49,10 @@ def serve_file(path, content_type=None, disposition=None, name=None,
|
||||||
|
|
||||||
try:
|
try:
|
||||||
st = os.stat(path)
|
st = os.stat(path)
|
||||||
except OSError:
|
except (OSError, TypeError, ValueError):
|
||||||
|
# OSError when file fails to stat
|
||||||
|
# TypeError on Python 2 when there's a null byte
|
||||||
|
# ValueError on Python 3 when there's a null byte
|
||||||
if debug:
|
if debug:
|
||||||
cherrypy.log('os.stat(%r) failed' % path, 'TOOLS.STATIC')
|
cherrypy.log('os.stat(%r) failed' % path, 'TOOLS.STATIC')
|
||||||
raise cherrypy.NotFound()
|
raise cherrypy.NotFound()
|
||||||
|
|
|
@ -8,7 +8,7 @@ import time
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from cherrypy._cpcompat import basestring, get_daemon, get_thread_ident
|
from cherrypy._cpcompat import basestring, get_daemon, get_thread_ident
|
||||||
from cherrypy._cpcompat import ntob, set, Timer, SetDaemonProperty
|
from cherrypy._cpcompat import ntob, Timer, SetDaemonProperty
|
||||||
|
|
||||||
# _module__file__base is used by Autoreload to make
|
# _module__file__base is used by Autoreload to make
|
||||||
# absolute any filenames retrieved from sys.modules which are not
|
# absolute any filenames retrieved from sys.modules which are not
|
||||||
|
@ -109,12 +109,35 @@ class SignalHandler(object):
|
||||||
self.handlers['SIGINT'] = self._jython_SIGINT_handler
|
self.handlers['SIGINT'] = self._jython_SIGINT_handler
|
||||||
|
|
||||||
self._previous_handlers = {}
|
self._previous_handlers = {}
|
||||||
|
# used to determine is the process is a daemon in `self._is_daemonized`
|
||||||
|
self._original_pid = os.getpid()
|
||||||
|
|
||||||
|
|
||||||
def _jython_SIGINT_handler(self, signum=None, frame=None):
|
def _jython_SIGINT_handler(self, signum=None, frame=None):
|
||||||
# See http://bugs.jython.org/issue1313
|
# See http://bugs.jython.org/issue1313
|
||||||
self.bus.log('Keyboard Interrupt: shutting down bus')
|
self.bus.log('Keyboard Interrupt: shutting down bus')
|
||||||
self.bus.exit()
|
self.bus.exit()
|
||||||
|
|
||||||
|
def _is_daemonized(self):
|
||||||
|
"""Return boolean indicating if the current process is
|
||||||
|
running as a daemon.
|
||||||
|
|
||||||
|
The criteria to determine the `daemon` condition is to verify
|
||||||
|
if the current pid is not the same as the one that got used on
|
||||||
|
the initial construction of the plugin *and* the stdin is not
|
||||||
|
connected to a terminal.
|
||||||
|
|
||||||
|
The sole validation of the tty is not enough when the plugin
|
||||||
|
is executing inside other process like in a CI tool
|
||||||
|
(Buildbot, Jenkins).
|
||||||
|
"""
|
||||||
|
if (self._original_pid != os.getpid() and
|
||||||
|
not os.isatty(sys.stdin.fileno())):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def subscribe(self):
|
def subscribe(self):
|
||||||
"""Subscribe self.handlers to signals."""
|
"""Subscribe self.handlers to signals."""
|
||||||
for sig, func in self.handlers.items():
|
for sig, func in self.handlers.items():
|
||||||
|
@ -180,13 +203,13 @@ class SignalHandler(object):
|
||||||
|
|
||||||
def handle_SIGHUP(self):
|
def handle_SIGHUP(self):
|
||||||
"""Restart if daemonized, else exit."""
|
"""Restart if daemonized, else exit."""
|
||||||
if os.isatty(sys.stdin.fileno()):
|
if self._is_daemonized():
|
||||||
|
self.bus.log("SIGHUP caught while daemonized. Restarting.")
|
||||||
|
self.bus.restart()
|
||||||
|
else:
|
||||||
# not daemonized (may be foreground or background)
|
# not daemonized (may be foreground or background)
|
||||||
self.bus.log("SIGHUP caught but not daemonized. Exiting.")
|
self.bus.log("SIGHUP caught but not daemonized. Exiting.")
|
||||||
self.bus.exit()
|
self.bus.exit()
|
||||||
else:
|
|
||||||
self.bus.log("SIGHUP caught while daemonized. Restarting.")
|
|
||||||
self.bus.restart()
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -200,7 +223,7 @@ class DropPrivileges(SimplePlugin):
|
||||||
|
|
||||||
"""Drop privileges. uid/gid arguments not available on Windows.
|
"""Drop privileges. uid/gid arguments not available on Windows.
|
||||||
|
|
||||||
Special thanks to `Gavin Baker <http://antonym.org/2005/12/dropping-privileges-in-python.html>`_
|
Special thanks to `Gavin Baker <http://antonym.org/2005/12/dropping-privileges-in-python.html>`_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, bus, umask=None, uid=None, gid=None):
|
def __init__(self, bus, umask=None, uid=None, gid=None):
|
||||||
|
|
|
@ -183,8 +183,7 @@ class ServerAdapter(object):
|
||||||
if not self.httpserver:
|
if not self.httpserver:
|
||||||
return ''
|
return ''
|
||||||
host, port = self.bind_addr
|
host, port = self.bind_addr
|
||||||
if getattr(self.httpserver, 'ssl_certificate', None) or \
|
if getattr(self.httpserver, 'ssl_adapter', None):
|
||||||
getattr(self.httpserver, 'ssl_adapter', None):
|
|
||||||
scheme = "https"
|
scheme = "https"
|
||||||
if port != 443:
|
if port != 443:
|
||||||
host += ":%s" % port
|
host += ":%s" % port
|
||||||
|
|
|
@ -68,8 +68,6 @@ import time
|
||||||
import traceback as _traceback
|
import traceback as _traceback
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from cherrypy._cpcompat import set
|
|
||||||
|
|
||||||
# Here I save the value of os.getcwd(), which, if I am imported early enough,
|
# Here I save the value of os.getcwd(), which, if I am imported early enough,
|
||||||
# will be the directory from which the startup script was run. This is needed
|
# will be the directory from which the startup script was run. This is needed
|
||||||
# by _do_execv(), to change back to the original directory before execv()ing a
|
# by _do_execv(), to change back to the original directory before execv()ing a
|
||||||
|
|
22
lib/cherrypy/scaffold/apache-fcgi.conf
Normal file
22
lib/cherrypy/scaffold/apache-fcgi.conf
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Apache2 server conf file for using CherryPy with mod_fcgid.
|
||||||
|
|
||||||
|
# This doesn't have to be "C:/", but it has to be a directory somewhere, and
|
||||||
|
# MUST match the directory used in the FastCgiExternalServer directive, below.
|
||||||
|
DocumentRoot "C:/"
|
||||||
|
|
||||||
|
ServerName 127.0.0.1
|
||||||
|
Listen 80
|
||||||
|
LoadModule fastcgi_module modules/mod_fastcgi.dll
|
||||||
|
LoadModule rewrite_module modules/mod_rewrite.so
|
||||||
|
|
||||||
|
Options ExecCGI
|
||||||
|
SetHandler fastcgi-script
|
||||||
|
RewriteEngine On
|
||||||
|
# Send requests for any URI to our fastcgi handler.
|
||||||
|
RewriteRule ^(.*)$ /fastcgi.pyc [L]
|
||||||
|
|
||||||
|
# The FastCgiExternalServer directive defines filename as an external FastCGI application.
|
||||||
|
# If filename does not begin with a slash (/) then it is assumed to be relative to the ServerRoot.
|
||||||
|
# The filename does not have to exist in the local filesystem. URIs that Apache resolves to this
|
||||||
|
# filename will be handled by this external FastCGI application.
|
||||||
|
FastCgiExternalServer "C:/fastcgi.pyc" -host 127.0.0.1:8088
|
3
lib/cherrypy/scaffold/example.conf
Normal file
3
lib/cherrypy/scaffold/example.conf
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[/]
|
||||||
|
log.error_file: "error.log"
|
||||||
|
log.access_file: "access.log"
|
14
lib/cherrypy/scaffold/site.conf
Normal file
14
lib/cherrypy/scaffold/site.conf
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[global]
|
||||||
|
# Uncomment this when you're done developing
|
||||||
|
#environment: "production"
|
||||||
|
|
||||||
|
server.socket_host: "0.0.0.0"
|
||||||
|
server.socket_port: 8088
|
||||||
|
|
||||||
|
# Uncomment the following lines to run on HTTPS at the same time
|
||||||
|
#server.2.socket_host: "0.0.0.0"
|
||||||
|
#server.2.socket_port: 8433
|
||||||
|
#server.2.ssl_certificate: '../test/test.pem'
|
||||||
|
#server.2.ssl_private_key: '../test/test.pem'
|
||||||
|
|
||||||
|
tree.myapp: cherrypy.Application(scaffold.root, "/", "example.conf")
|
BIN
lib/cherrypy/scaffold/static/made_with_cherrypy_small.png
Normal file
BIN
lib/cherrypy/scaffold/static/made_with_cherrypy_small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
|
@ -68,7 +68,7 @@ class SSL_fileobject(wsgiserver.CP_fileobject):
|
||||||
time.sleep(self.ssl_retry)
|
time.sleep(self.ssl_retry)
|
||||||
except SSL.WantWriteError:
|
except SSL.WantWriteError:
|
||||||
time.sleep(self.ssl_retry)
|
time.sleep(self.ssl_retry)
|
||||||
except SSL.SysCallError, e:
|
except SSL.SysCallError as e:
|
||||||
if is_reader and e.args == (-1, 'Unexpected EOF'):
|
if is_reader and e.args == (-1, 'Unexpected EOF'):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ class SSL_fileobject(wsgiserver.CP_fileobject):
|
||||||
if is_reader and errnum in wsgiserver.socket_errors_to_ignore:
|
if is_reader and errnum in wsgiserver.socket_errors_to_ignore:
|
||||||
return ""
|
return ""
|
||||||
raise socket.error(errnum)
|
raise socket.error(errnum)
|
||||||
except SSL.Error, e:
|
except SSL.Error as e:
|
||||||
if is_reader and e.args == (-1, 'Unexpected EOF'):
|
if is_reader and e.args == (-1, 'Unexpected EOF'):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,8 @@ __all__ = ['HTTPRequest', 'HTTPConnection', 'HTTPServer',
|
||||||
'WorkerThread', 'ThreadPool', 'SSLAdapter',
|
'WorkerThread', 'ThreadPool', 'SSLAdapter',
|
||||||
'CherryPyWSGIServer',
|
'CherryPyWSGIServer',
|
||||||
'Gateway', 'WSGIGateway', 'WSGIGateway_10', 'WSGIGateway_u0',
|
'Gateway', 'WSGIGateway', 'WSGIGateway_10', 'WSGIGateway_u0',
|
||||||
'WSGIPathInfoDispatcher', 'get_ssl_adapter_class']
|
'WSGIPathInfoDispatcher', 'get_ssl_adapter_class',
|
||||||
|
'socket_errors_to_ignore']
|
||||||
|
|
||||||
import os
|
import os
|
||||||
try:
|
try:
|
||||||
|
@ -83,19 +84,33 @@ try:
|
||||||
except:
|
except:
|
||||||
import Queue as queue
|
import Queue as queue
|
||||||
import re
|
import re
|
||||||
import rfc822
|
import email.utils
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import traceback as traceback_
|
||||||
|
import operator
|
||||||
|
from urllib import unquote
|
||||||
|
import warnings
|
||||||
|
import errno
|
||||||
|
import logging
|
||||||
|
try:
|
||||||
|
# prefer slower Python-based io module
|
||||||
|
import _pyio as io
|
||||||
|
except ImportError:
|
||||||
|
# Python 2.6
|
||||||
|
import io
|
||||||
|
|
||||||
|
|
||||||
if 'win' in sys.platform and hasattr(socket, "AF_INET6"):
|
if 'win' in sys.platform and hasattr(socket, "AF_INET6"):
|
||||||
if not hasattr(socket, 'IPPROTO_IPV6'):
|
if not hasattr(socket, 'IPPROTO_IPV6'):
|
||||||
socket.IPPROTO_IPV6 = 41
|
socket.IPPROTO_IPV6 = 41
|
||||||
if not hasattr(socket, 'IPV6_V6ONLY'):
|
if not hasattr(socket, 'IPV6_V6ONLY'):
|
||||||
socket.IPV6_V6ONLY = 27
|
socket.IPV6_V6ONLY = 27
|
||||||
try:
|
|
||||||
import cStringIO as StringIO
|
|
||||||
except ImportError:
|
DEFAULT_BUFFER_SIZE = io.DEFAULT_BUFFER_SIZE
|
||||||
import StringIO
|
|
||||||
DEFAULT_BUFFER_SIZE = -1
|
|
||||||
|
|
||||||
|
|
||||||
class FauxSocket(object):
|
class FauxSocket(object):
|
||||||
|
@ -109,23 +124,6 @@ _fileobject_uses_str_type = isinstance(
|
||||||
socket._fileobject(FauxSocket())._rbuf, basestring)
|
socket._fileobject(FauxSocket())._rbuf, basestring)
|
||||||
del FauxSocket # this class is not longer required for anything.
|
del FauxSocket # this class is not longer required for anything.
|
||||||
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
|
|
||||||
def format_exc(limit=None):
|
|
||||||
"""Like print_exc() but return a string. Backport for Python 2.3."""
|
|
||||||
try:
|
|
||||||
etype, value, tb = sys.exc_info()
|
|
||||||
return ''.join(traceback.format_exception(etype, value, tb, limit))
|
|
||||||
finally:
|
|
||||||
etype = value = tb = None
|
|
||||||
|
|
||||||
import operator
|
|
||||||
|
|
||||||
from urllib import unquote
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 0):
|
if sys.version_info >= (3, 0):
|
||||||
bytestr = bytes
|
bytestr = bytes
|
||||||
|
@ -165,8 +163,6 @@ ASTERISK = ntob('*')
|
||||||
FORWARD_SLASH = ntob('/')
|
FORWARD_SLASH = ntob('/')
|
||||||
quoted_slash = re.compile(ntob("(?i)%2F"))
|
quoted_slash = re.compile(ntob("(?i)%2F"))
|
||||||
|
|
||||||
import errno
|
|
||||||
|
|
||||||
|
|
||||||
def plat_specific_errors(*errnames):
|
def plat_specific_errors(*errnames):
|
||||||
"""Return error numbers for all errors in errnames on this platform.
|
"""Return error numbers for all errors in errnames on this platform.
|
||||||
|
@ -210,7 +206,6 @@ comma_separated_headers = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
import logging
|
|
||||||
if not hasattr(logging, 'statistics'):
|
if not hasattr(logging, 'statistics'):
|
||||||
logging.statistics = {}
|
logging.statistics = {}
|
||||||
|
|
||||||
|
@ -674,6 +669,10 @@ class HTTPRequest(object):
|
||||||
|
|
||||||
# uri may be an abs_path (including "http://host.domain.tld");
|
# uri may be an abs_path (including "http://host.domain.tld");
|
||||||
scheme, authority, path = self.parse_request_uri(uri)
|
scheme, authority, path = self.parse_request_uri(uri)
|
||||||
|
if path is None:
|
||||||
|
self.simple_response("400 Bad Request",
|
||||||
|
"Invalid path in Request-URI.")
|
||||||
|
return False
|
||||||
if NUMBER_SIGN in path:
|
if NUMBER_SIGN in path:
|
||||||
self.simple_response("400 Bad Request",
|
self.simple_response("400 Bad Request",
|
||||||
"Illegal #fragment in Request-URI.")
|
"Illegal #fragment in Request-URI.")
|
||||||
|
@ -970,7 +969,7 @@ class HTTPRequest(object):
|
||||||
self.rfile.read(remaining)
|
self.rfile.read(remaining)
|
||||||
|
|
||||||
if "date" not in hkeys:
|
if "date" not in hkeys:
|
||||||
self.outheaders.append(("Date", rfc822.formatdate()))
|
self.outheaders.append(("Date", email.utils.formatdate()))
|
||||||
|
|
||||||
if "server" not in hkeys:
|
if "server" not in hkeys:
|
||||||
self.outheaders.append(("Server", self.server.server_name))
|
self.outheaders.append(("Server", self.server.server_name))
|
||||||
|
@ -1051,7 +1050,7 @@ class CP_fileobject(socket._fileobject):
|
||||||
if size < 0:
|
if size < 0:
|
||||||
# Read until EOF
|
# Read until EOF
|
||||||
# reset _rbuf. we consume it via buf.
|
# reset _rbuf. we consume it via buf.
|
||||||
self._rbuf = StringIO.StringIO()
|
self._rbuf = io.BytesIO()
|
||||||
while True:
|
while True:
|
||||||
data = self.recv(rbufsize)
|
data = self.recv(rbufsize)
|
||||||
if not data:
|
if not data:
|
||||||
|
@ -1066,12 +1065,12 @@ class CP_fileobject(socket._fileobject):
|
||||||
# return.
|
# return.
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
rv = buf.read(size)
|
rv = buf.read(size)
|
||||||
self._rbuf = StringIO.StringIO()
|
self._rbuf = io.BytesIO()
|
||||||
self._rbuf.write(buf.read())
|
self._rbuf.write(buf.read())
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
# reset _rbuf. we consume it via buf.
|
# reset _rbuf. we consume it via buf.
|
||||||
self._rbuf = StringIO.StringIO()
|
self._rbuf = io.BytesIO()
|
||||||
while True:
|
while True:
|
||||||
left = size - buf_len
|
left = size - buf_len
|
||||||
# recv() will malloc the amount of memory given as its
|
# recv() will malloc the amount of memory given as its
|
||||||
|
@ -1109,7 +1108,7 @@ class CP_fileobject(socket._fileobject):
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
bline = buf.readline(size)
|
bline = buf.readline(size)
|
||||||
if bline.endswith('\n') or len(bline) == size:
|
if bline.endswith('\n') or len(bline) == size:
|
||||||
self._rbuf = StringIO.StringIO()
|
self._rbuf = io.BytesIO()
|
||||||
self._rbuf.write(buf.read())
|
self._rbuf.write(buf.read())
|
||||||
return bline
|
return bline
|
||||||
del bline
|
del bline
|
||||||
|
@ -1120,7 +1119,7 @@ class CP_fileobject(socket._fileobject):
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
buffers = [buf.read()]
|
buffers = [buf.read()]
|
||||||
# reset _rbuf. we consume it via buf.
|
# reset _rbuf. we consume it via buf.
|
||||||
self._rbuf = StringIO.StringIO()
|
self._rbuf = io.BytesIO()
|
||||||
data = None
|
data = None
|
||||||
recv = self.recv
|
recv = self.recv
|
||||||
while data != "\n":
|
while data != "\n":
|
||||||
|
@ -1132,7 +1131,7 @@ class CP_fileobject(socket._fileobject):
|
||||||
|
|
||||||
buf.seek(0, 2) # seek end
|
buf.seek(0, 2) # seek end
|
||||||
# reset _rbuf. we consume it via buf.
|
# reset _rbuf. we consume it via buf.
|
||||||
self._rbuf = StringIO.StringIO()
|
self._rbuf = io.BytesIO()
|
||||||
while True:
|
while True:
|
||||||
data = self.recv(self._rbufsize)
|
data = self.recv(self._rbufsize)
|
||||||
if not data:
|
if not data:
|
||||||
|
@ -1154,11 +1153,11 @@ class CP_fileobject(socket._fileobject):
|
||||||
if buf_len >= size:
|
if buf_len >= size:
|
||||||
buf.seek(0)
|
buf.seek(0)
|
||||||
rv = buf.read(size)
|
rv = buf.read(size)
|
||||||
self._rbuf = StringIO.StringIO()
|
self._rbuf = io.BytesIO()
|
||||||
self._rbuf.write(buf.read())
|
self._rbuf.write(buf.read())
|
||||||
return rv
|
return rv
|
||||||
# reset _rbuf. we consume it via buf.
|
# reset _rbuf. we consume it via buf.
|
||||||
self._rbuf = StringIO.StringIO()
|
self._rbuf = io.BytesIO()
|
||||||
while True:
|
while True:
|
||||||
data = self.recv(self._rbufsize)
|
data = self.recv(self._rbufsize)
|
||||||
if not data:
|
if not data:
|
||||||
|
@ -1757,7 +1756,7 @@ class HTTPServer(object):
|
||||||
timeout = 10
|
timeout = 10
|
||||||
"""The timeout in seconds for accepted connections (default 10)."""
|
"""The timeout in seconds for accepted connections (default 10)."""
|
||||||
|
|
||||||
version = "CherryPy/3.8.0"
|
version = "CherryPy/5.1.0"
|
||||||
"""A version string for the HTTPServer."""
|
"""A version string for the HTTPServer."""
|
||||||
|
|
||||||
software = None
|
software = None
|
||||||
|
@ -1884,25 +1883,6 @@ class HTTPServer(object):
|
||||||
if self.software is None:
|
if self.software is None:
|
||||||
self.software = "%s Server" % self.version
|
self.software = "%s Server" % self.version
|
||||||
|
|
||||||
# SSL backward compatibility
|
|
||||||
if (self.ssl_adapter is None and
|
|
||||||
getattr(self, 'ssl_certificate', None) and
|
|
||||||
getattr(self, 'ssl_private_key', None)):
|
|
||||||
warnings.warn(
|
|
||||||
"SSL attributes are deprecated in CherryPy 3.2, and will "
|
|
||||||
"be removed in CherryPy 3.3. Use an ssl_adapter attribute "
|
|
||||||
"instead.",
|
|
||||||
DeprecationWarning
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
self.ssl_adapter = pyOpenSSLAdapter(
|
|
||||||
self.ssl_certificate, self.ssl_private_key,
|
|
||||||
getattr(self, 'ssl_certificate_chain', None))
|
|
||||||
|
|
||||||
# Select the appropriate socket
|
# Select the appropriate socket
|
||||||
if isinstance(self.bind_addr, basestring):
|
if isinstance(self.bind_addr, basestring):
|
||||||
# AF_UNIX socket
|
# AF_UNIX socket
|
||||||
|
@ -1915,7 +1895,7 @@ class HTTPServer(object):
|
||||||
|
|
||||||
# So everyone can access the socket...
|
# So everyone can access the socket...
|
||||||
try:
|
try:
|
||||||
os.chmod(self.bind_addr, 511) # 0777
|
os.chmod(self.bind_addr, 0o777)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -1984,7 +1964,7 @@ class HTTPServer(object):
|
||||||
sys.stderr.write(msg + '\n')
|
sys.stderr.write(msg + '\n')
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
if traceback:
|
if traceback:
|
||||||
tblines = format_exc()
|
tblines = traceback_.format_exc()
|
||||||
sys.stderr.write(tblines)
|
sys.stderr.write(tblines)
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
|
|
||||||
|
@ -2186,7 +2166,7 @@ ssl_adapters = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_ssl_adapter_class(name='pyopenssl'):
|
def get_ssl_adapter_class(name='builtin'):
|
||||||
"""Return an SSL adapter class for the given name."""
|
"""Return an SSL adapter class for the given name."""
|
||||||
adapter = ssl_adapters[name.lower()]
|
adapter = ssl_adapters[name.lower()]
|
||||||
if isinstance(adapter, basestring):
|
if isinstance(adapter, basestring):
|
||||||
|
|
2187
lib/cherrypy/wsgiserver/wsgiserver3.py
Normal file
2187
lib/cherrypy/wsgiserver/wsgiserver3.py
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue