[Zope3-checkins] SVN: Zope3/trunk/ Fixed issue 546: non-ASCII
docstring cause System Error in RootErrorReportingUtility
Dmitry Vasiliev
dima at hlabs.spb.ru
Mon Feb 20 08:18:39 EST 2006
Log message for revision 41712:
Fixed issue 546: non-ASCII docstring cause System Error in RootErrorReportingUtility
Changed:
U Zope3/trunk/doc/CHANGES.txt
U Zope3/trunk/src/zope/app/error/error.py
U Zope3/trunk/src/zope/app/error/tests.py
-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt 2006-02-20 11:28:00 UTC (rev 41711)
+++ Zope3/trunk/doc/CHANGES.txt 2006-02-20 13:18:38 UTC (rev 41712)
@@ -41,6 +41,9 @@
Bug Fixes
+ - Fixed issue 546: non-ASCII docstring cause
+ System Error in RootErrorReportingUtility.
+
- Fixed issue 547: return 'add_content' for backward-compatibility.
Removed 'zope.app.container.browser.adding.ContentAdding'.
Modified: Zope3/trunk/src/zope/app/error/error.py
===================================================================
--- Zope3/trunk/src/zope/app/error/error.py 2006-02-20 11:28:00 UTC (rev 41711)
+++ Zope3/trunk/src/zope/app/error/error.py 2006-02-20 13:18:38 UTC (rev 41712)
@@ -53,6 +53,41 @@
logger = logging.getLogger('SiteError')
+def getPrintable(value):
+ # A call to unicode(obj) could raise anything at all.
+ # We'll ignore these errors, and print something
+ # useful instead, but also log the error.
+ try:
+ printable = unicode(value)
+ except:
+ logger.exception(
+ "Error in ErrorReportingUtility while getting a unicode"
+ " representation of an object")
+ printable = u"<unprintable %s object>" % type(value).__name__
+ if type(value) is str:
+ try:
+ r = repr(value)
+ except:
+ pass
+ else:
+ try:
+ printable = unicode(r)
+ except:
+ pass
+ return printable
+
+def getFormattedException(info, as_html=False):
+ lines = []
+ for line in format_exception(as_html=as_html, *info):
+ line = getPrintable(line)
+ if not line.endswith("\n"):
+ if not as_html:
+ line += "\n"
+ else:
+ line += "<br />\n"
+ lines.append(line)
+ return u"".join(lines)
+
class ErrorReportingUtility(Persistent, Contained):
"""Error Reporting Utility"""
implements(IErrorReportingUtility, ILocalErrorReportingUtility)
@@ -72,6 +107,47 @@
_temp_logs[self._p_oid] = log
return log
+ def _getUsername(self, request):
+ username = None
+
+ principal = getattr(request, "principal", None)
+ if principal is None:
+ return username
+
+ # UnauthenticatedPrincipal does not have getLogin()
+ getLogin = getattr(principal, "getLogin", None)
+ if getLogin is None:
+ login = "unauthenticated"
+ else:
+ try:
+ login = getLogin()
+ except:
+ logger.exception("Error in ErrorReportingUtility while"
+ " getting login of the principal")
+ login = u"<error getting login>"
+
+ parts = []
+ for part in [
+ login,
+ getattr(principal, "id",
+ u"<error getting 'principal.id'>"),
+ getattr(principal, "title",
+ u"<error getting 'principal.title'>"),
+ getattr(principal, "description",
+ u"<error getting 'principal.description'>")
+ ]:
+ part = getPrintable(part)
+ parts.append(part)
+ username = u", ".join(parts)
+ return username
+
+ def _getRequestAsHTML(self, request):
+ lines = []
+ for key, value in request.items():
+ lines.append(u"%s: %s<br />\n" % (
+ getPrintable(key), getPrintable(value)))
+ return u"".join(lines)
+
# Exceptions that happen all the time, so we dont need
# to log them. Eventually this should be configured
# through-the-web.
@@ -81,18 +157,17 @@
"""
now = time.time()
try:
- tb_text = None
- tb_html = None
-
- strtype = str(getattr(info[0], '__name__', info[0]))
+ strtype = unicode(getattr(info[0], '__name__', info[0]))
if strtype in self._ignored_exceptions:
return
+ tb_text = None
+ tb_html = None
if not isinstance(info[2], StringTypes):
- tb_text = ''.join(format_exception(as_html=0, *info))
- tb_html = ''.join(format_exception(as_html=1, *info))
+ tb_text = getFormattedException(info)
+ tb_html = getFormattedException(info, True)
else:
- tb_text = info[2]
+ tb_text = getPrintable(info[2])
url = None
username = None
@@ -102,41 +177,10 @@
# just too HTTPRequest-specific.
if hasattr(request, 'URL'):
url = request.URL
- try:
- # UnauthenticatedPrincipal does not have getLogin()
- if hasattr(request.principal, 'getLogin'):
- login = request.principal.getLogin()
- else:
- login = 'unauthenticated'
- username = ', '.join([unicode(s) for s in (login,
- request.principal.id,
- request.principal.title,
- request.principal.description
- )])
- # When there's an unauthorized access, request.principal is
- # not set, so we get an AttributeError
- # ??? Is this right? Surely request.principal should be set!
- # !!! Yes. Catching AttributeError is correct for the simple
- # reason that UnauthenticatedUser (which I always use during
- # coding), has no 'getLogin()' method. However, for some reason
- # this except does **NOT** catch these errors.
- except AttributeError:
- pass
+ username = self._getUsername(request)
+ req_html = self._getRequestAsHTML(request)
- req_html = ''.join(['%s : %s<br>' % item
- for item in request.items()])
- try:
- strv = str(info[1])
- # A call to str(obj) could raise anything at all.
- # We'll ignore these errors, and print something
- # useful instead, but also log the error.
- except:
- logger.exception(
- 'Error in ErrorReportingUtility while getting a str '
- 'representation of an object')
- strv = '<unprintable %s object>' % (
- str(type(info[1]).__name__)
- )
+ strv = getPrintable(info[1])
log = self._getLog()
entry_id = str(now) + str(random()) # Low chance of collision
@@ -192,7 +236,7 @@
self.keep_entries = int(keep_entries)
self.copy_to_zlog = bool(copy_to_zlog)
self._ignored_exceptions = tuple(
- [str(e) for e in ignored_exceptions if e]
+ [unicode(e) for e in ignored_exceptions if e]
)
def getLogEntries(self):
Modified: Zope3/trunk/src/zope/app/error/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/error/tests.py 2006-02-20 11:28:00 UTC (rev 41711)
+++ Zope3/trunk/src/zope/app/error/tests.py 2006-02-20 13:18:38 UTC (rev 41712)
@@ -22,24 +22,22 @@
from zope.publisher.tests.httprequest import TestRequest
from zope.app.testing.placelesssetup import PlacelessSetup
-from zope.app.error.error import ErrorReportingUtility
+from zope.app.error.error import ErrorReportingUtility, getFormattedException
class Error(Exception):
+ def __init__(self, value):
+ self.value = value
+
def __str__(self):
- return u"Error (\u0410)"
+ return self.value
-class C1(object):
+def getAnErrorInfo(value=""):
+ try:
+ raise Error(value)
+ except:
+ return sys.exc_info()
- def getAnErrorInfo(self):
- exc_info = None
- try:
- raise Error()
- except:
- exc_info = sys.exc_info()
- return exc_info
-
-
class ErrorReportingUtilityTests(PlacelessSetup, unittest.TestCase):
def test_checkForEmpryLog(self):
@@ -64,12 +62,12 @@
# Test for Logging Error. Create one error and check whether its
# logged or not.
errUtility = ErrorReportingUtility()
- exc_info = C1().getAnErrorInfo()
+ exc_info = getAnErrorInfo()
errUtility.raising(exc_info)
getErrLog = errUtility.getLogEntries()
self.assertEquals(1, len(getErrLog))
- tb_text = ''.join(format_exception(*exc_info, **{'as_html': 0}))
+ tb_text = ''.join(format_exception(as_html=0, *exc_info))
err_id = getErrLog[0]['id']
self.assertEquals(tb_text,
@@ -88,12 +86,12 @@
request.setPrincipal(PrincipalStub())
errUtility = ErrorReportingUtility()
- exc_info = C1().getAnErrorInfo()
+ exc_info = getAnErrorInfo(u"Error (\u0441)")
errUtility.raising(exc_info, request=request)
getErrLog = errUtility.getLogEntries()
self.assertEquals(1, len(getErrLog))
- tb_text = ''.join(format_exception(*exc_info, **{'as_html': 0}))
+ tb_text = ''.join(format_exception(as_html=0, *exc_info))
err_id = getErrLog[0]['id']
self.assertEquals(tb_text,
@@ -102,7 +100,35 @@
username = getErrLog[0]['username']
self.assertEquals(username, u'unauthenticated, \u0441, \u0441, \u0441')
+ def test_ErrorLog_nonascii(self):
+ # Emulate a unicode url, it gets encoded to utf-8 before it's passed
+ # to the request. Also add some unicode field to the request's
+ # environment and make the principal's title unicode.
+ request = TestRequest(environ={'PATH_INFO': '/\xd1\x82',
+ 'SOME_NONASCII': '\xe1'})
+ class PrincipalStub(object):
+ id = '\xe1'
+ title = '\xe1'
+ description = '\xe1'
+ request.setPrincipal(PrincipalStub())
+ errUtility = ErrorReportingUtility()
+ exc_info = getAnErrorInfo("Error (\xe1)")
+ errUtility.raising(exc_info, request=request)
+ getErrLog = errUtility.getLogEntries()
+ self.assertEquals(1, len(getErrLog))
+
+ tb_text = getFormattedException(exc_info)
+
+ err_id = getErrLog[0]['id']
+ self.assertEquals(tb_text,
+ errUtility.getLogEntryById(err_id)['tb_text'])
+
+ username = getErrLog[0]['username']
+ self.assertEquals(username, "unauthenticated,"
+ " '\\xe1', '\\xe1', '\\xe1'")
+
+
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(ErrorReportingUtilityTests),
More information about the Zope3-Checkins
mailing list