Update cherrpy to 17.4.2

This commit is contained in:
JonnyWong16 2019-11-23 18:55:19 -08:00
parent f28e741ad7
commit 4d6279a626
131 changed files with 15864 additions and 10389 deletions

View file

@ -59,7 +59,8 @@ tracebacks, if enabled).
If you are logging the access log and error log to the same source, then there
is a possibility that a specially crafted error message may replicate an access
log message as described in CWE-117. In this case it is the application
developer's responsibility to manually escape data before using CherryPy's log()
developer's responsibility to manually escape data before
using CherryPy's log()
functionality, or they may create an application that is vulnerable to CWE-117.
This would be achieved by using a custom handler escape any special characters,
and attached as described below.
@ -109,15 +110,18 @@ the "log.error_file" config entry, for example).
import datetime
import logging
# Silence the no-handlers "warning" (stderr write!) in stdlib logging
logging.Logger.manager.emittedNoHandlerWarning = 1
logfmt = logging.Formatter("%(message)s")
import os
import sys
import six
import cherrypy
from cherrypy import _cperror
from cherrypy._cpcompat import ntob, py3k
# Silence the no-handlers "warning" (stderr write!) in stdlib logging
logging.Logger.manager.emittedNoHandlerWarning = 1
logfmt = logging.Formatter('%(message)s')
class NullHandler(logging.Handler):
@ -151,12 +155,11 @@ class LogManager(object):
access_log = None
"""The actual :class:`logging.Logger` instance for access messages."""
if py3k:
access_log_format = \
'{h} {l} {u} {t} "{r}" {s} {b} "{f}" "{a}"'
else:
access_log_format = \
'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
access_log_format = (
'{h} {l} {u} {t} "{r}" {s} {b} "{f}" "{a}"'
if six.PY3 else
'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
)
logger_root = None
"""The "top-level" logger name.
@ -169,17 +172,17 @@ class LogManager(object):
cherrypy.access.<appid>
"""
def __init__(self, appid=None, logger_root="cherrypy"):
def __init__(self, appid=None, logger_root='cherrypy'):
self.logger_root = logger_root
self.appid = appid
if appid is None:
self.error_log = logging.getLogger("%s.error" % logger_root)
self.access_log = logging.getLogger("%s.access" % logger_root)
self.error_log = logging.getLogger('%s.error' % logger_root)
self.access_log = logging.getLogger('%s.access' % logger_root)
else:
self.error_log = logging.getLogger(
"%s.error.%s" % (logger_root, appid))
'%s.error.%s' % (logger_root, appid))
self.access_log = logging.getLogger(
"%s.access.%s" % (logger_root, appid))
'%s.access.%s' % (logger_root, appid))
self.error_log.setLevel(logging.INFO)
self.access_log.setLevel(logging.INFO)
@ -213,7 +216,11 @@ class LogManager(object):
if traceback:
exc_info = _cperror._exc_info()
self.error_log.log(severity, ' '.join((self.time(), context, msg)), exc_info=exc_info)
self.error_log.log(
severity,
' '.join((self.time(), context, msg)),
exc_info=exc_info,
)
def __call__(self, *args, **kwargs):
"""An alias for ``error``."""
@ -223,7 +230,8 @@ class LogManager(object):
"""Write to the access log (in Apache/NCSA Combined Log format).
See the
`apache documentation <http://httpd.apache.org/docs/current/logs.html#combined>`_
`apache documentation
<http://httpd.apache.org/docs/current/logs.html#combined>`_
for format details.
CherryPy calls this automatically for you. Note there are no arguments;
@ -243,24 +251,26 @@ class LogManager(object):
outheaders = response.headers
inheaders = request.headers
if response.output_status is None:
status = "-"
status = '-'
else:
status = response.output_status.split(ntob(" "), 1)[0]
if py3k:
status = response.output_status.split(b' ', 1)[0]
if six.PY3:
status = status.decode('ISO-8859-1')
atoms = {'h': remote.name or remote.ip,
'l': '-',
'u': getattr(request, "login", None) or "-",
'u': getattr(request, 'login', None) or '-',
't': self.time(),
'r': request.request_line,
's': status,
'b': dict.get(outheaders, 'Content-Length', '') or "-",
'b': dict.get(outheaders, 'Content-Length', '') or '-',
'f': dict.get(inheaders, 'Referer', ''),
'a': dict.get(inheaders, 'User-Agent', ''),
'o': dict.get(inheaders, 'Host', '-'),
'i': request.unique_id,
'z': LazyRfc3339UtcTime(),
}
if py3k:
if six.PY3:
for k, v in atoms.items():
if not isinstance(v, str):
v = str(v)
@ -280,11 +290,11 @@ class LogManager(object):
try:
self.access_log.log(
logging.INFO, self.access_log_format.format(**atoms))
except:
except Exception:
self(traceback=True)
else:
for k, v in atoms.items():
if isinstance(v, unicode):
if isinstance(v, six.text_type):
v = v.encode('utf8')
elif not isinstance(v, str):
v = str(v)
@ -297,7 +307,7 @@ class LogManager(object):
try:
self.access_log.log(
logging.INFO, self.access_log_format % atoms)
except:
except Exception:
self(traceback=True)
def time(self):
@ -311,48 +321,49 @@ class LogManager(object):
def _get_builtin_handler(self, log, key):
for h in log.handlers:
if getattr(h, "_cpbuiltin", None) == key:
if getattr(h, '_cpbuiltin', None) == key:
return h
# ------------------------- Screen handlers ------------------------- #
def _set_screen_handler(self, log, enable, stream=None):
h = self._get_builtin_handler(log, "screen")
h = self._get_builtin_handler(log, 'screen')
if enable:
if not h:
if stream is None:
stream = sys.stderr
h = logging.StreamHandler(stream)
h.setFormatter(logfmt)
h._cpbuiltin = "screen"
h._cpbuiltin = 'screen'
log.addHandler(h)
elif h:
log.handlers.remove(h)
def _get_screen(self):
h = self._get_builtin_handler
has_h = h(self.error_log, "screen") or h(self.access_log, "screen")
return bool(has_h)
def _set_screen(self, newvalue):
self._set_screen_handler(self.error_log, newvalue, stream=sys.stderr)
self._set_screen_handler(self.access_log, newvalue, stream=sys.stdout)
screen = property(_get_screen, _set_screen,
doc="""Turn stderr/stdout logging on or off.
@property
def screen(self):
"""Turn stderr/stdout logging on or off.
If you set this to True, it'll add the appropriate StreamHandler for
you. If you set it to False, it will remove the handler.
""")
"""
h = self._get_builtin_handler
has_h = h(self.error_log, 'screen') or h(self.access_log, 'screen')
return bool(has_h)
@screen.setter
def screen(self, newvalue):
self._set_screen_handler(self.error_log, newvalue, stream=sys.stderr)
self._set_screen_handler(self.access_log, newvalue, stream=sys.stdout)
# -------------------------- File handlers -------------------------- #
def _add_builtin_file_handler(self, log, fname):
h = logging.FileHandler(fname)
h.setFormatter(logfmt)
h._cpbuiltin = "file"
h._cpbuiltin = 'file'
log.addHandler(h)
def _set_file_handler(self, log, filename):
h = self._get_builtin_handler(log, "file")
h = self._get_builtin_handler(log, 'file')
if filename:
if h:
if h.baseFilename != os.path.abspath(filename):
@ -366,62 +377,65 @@ class LogManager(object):
h.close()
log.handlers.remove(h)
def _get_error_file(self):
h = self._get_builtin_handler(self.error_log, "file")
@property
def error_file(self):
"""The filename for self.error_log.
If you set this to a string, it'll add the appropriate FileHandler for
you. If you set it to ``None`` or ``''``, it will remove the handler.
"""
h = self._get_builtin_handler(self.error_log, 'file')
if h:
return h.baseFilename
return ''
def _set_error_file(self, newvalue):
@error_file.setter
def error_file(self, newvalue):
self._set_file_handler(self.error_log, newvalue)
error_file = property(_get_error_file, _set_error_file,
doc="""The filename for self.error_log.
@property
def access_file(self):
"""The filename for self.access_log.
If you set this to a string, it'll add the appropriate FileHandler for
you. If you set it to ``None`` or ``''``, it will remove the handler.
""")
def _get_access_file(self):
h = self._get_builtin_handler(self.access_log, "file")
"""
h = self._get_builtin_handler(self.access_log, 'file')
if h:
return h.baseFilename
return ''
def _set_access_file(self, newvalue):
@access_file.setter
def access_file(self, newvalue):
self._set_file_handler(self.access_log, newvalue)
access_file = property(_get_access_file, _set_access_file,
doc="""The filename for self.access_log.
If you set this to a string, it'll add the appropriate FileHandler for
you. If you set it to ``None`` or ``''``, it will remove the handler.
""")
# ------------------------- WSGI handlers ------------------------- #
def _set_wsgi_handler(self, log, enable):
h = self._get_builtin_handler(log, "wsgi")
h = self._get_builtin_handler(log, 'wsgi')
if enable:
if not h:
h = WSGIErrorHandler()
h.setFormatter(logfmt)
h._cpbuiltin = "wsgi"
h._cpbuiltin = 'wsgi'
log.addHandler(h)
elif h:
log.handlers.remove(h)
def _get_wsgi(self):
return bool(self._get_builtin_handler(self.error_log, "wsgi"))
def _set_wsgi(self, newvalue):
self._set_wsgi_handler(self.error_log, newvalue)
wsgi = property(_get_wsgi, _set_wsgi,
doc="""Write errors to wsgi.errors.
@property
def wsgi(self):
"""Write errors to wsgi.errors.
If you set this to True, it'll add the appropriate
:class:`WSGIErrorHandler<cherrypy._cplogging.WSGIErrorHandler>` for you
(which writes errors to ``wsgi.errors``).
If you set it to False, it will remove the handler.
""")
"""
return bool(self._get_builtin_handler(self.error_log, 'wsgi'))
@wsgi.setter
def wsgi(self, newvalue):
self._set_wsgi_handler(self.error_log, newvalue)
class WSGIErrorHandler(logging.Handler):
@ -446,16 +460,23 @@ class WSGIErrorHandler(logging.Handler):
else:
try:
msg = self.format(record)
fs = "%s\n"
fs = '%s\n'
import types
# if no unicode support...
if not hasattr(types, "UnicodeType"):
if not hasattr(types, 'UnicodeType'):
stream.write(fs % msg)
else:
try:
stream.write(fs % msg)
except UnicodeError:
stream.write(fs % msg.encode("UTF-8"))
stream.write(fs % msg.encode('UTF-8'))
self.flush()
except:
except Exception:
self.handleError(record)
class LazyRfc3339UtcTime(object):
def __str__(self):
"""Return now() in RFC3339 UTC Format."""
now = datetime.datetime.now()
return now.isoformat('T') + 'Z'