summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWalter Doekes <walter+github@wjd.nu>2014-08-13 15:32:14 +0200
committerTim Graham <timograham@gmail.com>2014-08-13 12:56:26 -0400
commite0e28bfe715b3f7d4e6cc7ab7bf4000b22c0cf79 (patch)
tree85485d54d5e13a3a4921fad05d647f6de60f87da
parentd441a9d00629bbaf3f1ef0e4f75f3ce08b76c214 (diff)
Fixed #20368 -- Made TECHNICAL_500 more robust against bad input.
This limits large variables and avoids non-utf-8 in the TECHNICAL_500 output.
-rw-r--r--django/views/debug.py12
-rw-r--r--tests/view_tests/tests/test_debug.py46
2 files changed, 57 insertions, 1 deletions
diff --git a/django/views/debug.py b/django/views/debug.py
index 23bf16604d..20fe104399 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -309,7 +309,17 @@ class ExceptionReporter(object):
frames = self.get_traceback_frames()
for i, frame in enumerate(frames):
if 'vars' in frame:
- frame['vars'] = [(k, force_escape(pprint(v))) for k, v in frame['vars']]
+ frame_vars = []
+ for k, v in frame['vars']:
+ v = pprint(v)
+ # The force_escape filter assume unicode, make sure that works
+ if isinstance(v, six.binary_type):
+ v = v.decode('utf-8', 'replace') # don't choke on non-utf-8 input
+ # Trim large blobs of data
+ if len(v) > 4096:
+ v = '%s... <trimmed %d bytes string>' % (v[0:4096], len(v))
+ frame_vars.append((k, force_escape(v)))
+ frame['vars'] = frame_vars
frames[i] = frame
unicode_hint = ''
diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py
index 3d51da9f94..22bd11989f 100644
--- a/tests/view_tests/tests/test_debug.py
+++ b/tests/view_tests/tests/test_debug.py
@@ -302,6 +302,52 @@ class ExceptionReporterTests(TestCase):
self.assertIn('<h2>Request information</h2>', html)
self.assertIn('<p>Request data not supplied</p>', html)
+ def test_non_utf8_values_handling(self):
+ "Non-UTF-8 exceptions/values should not make the output generation choke."
+ try:
+ class NonUtf8Output(Exception):
+ def __repr__(self):
+ return b'EXC\xe9EXC'
+ somevar = b'VAL\xe9VAL' # NOQA
+ raise NonUtf8Output()
+ except Exception:
+ exc_type, exc_value, tb = sys.exc_info()
+ reporter = ExceptionReporter(None, exc_type, exc_value, tb)
+ html = reporter.get_traceback_html()
+ self.assertIn('VAL\\xe9VAL', html)
+ self.assertIn('EXC\\xe9EXC', html)
+
+ def test_unprintable_values_handling(self):
+ "Unprintable values should not make the output generation choke."
+ try:
+ class OomOutput(object):
+ def __repr__(self):
+ raise MemoryError('OOM')
+ oomvalue = OomOutput() # NOQA
+ raise ValueError()
+ except Exception:
+ exc_type, exc_value, tb = sys.exc_info()
+ reporter = ExceptionReporter(None, exc_type, exc_value, tb)
+ html = reporter.get_traceback_html()
+ self.assertIn('<td class="code"><pre>Error in formatting', html)
+
+ def test_too_large_values_handling(self):
+ "Large values should not create a large HTML."
+ large = 32 * 1024 * 1024
+ repr_of_str_adds = len(repr(''))
+ try:
+ class LargeOutput(object):
+ def __repr__(self):
+ return repr('A' * large)
+ largevalue = LargeOutput() # NOQA
+ raise ValueError()
+ except Exception:
+ exc_type, exc_value, tb = sys.exc_info()
+ reporter = ExceptionReporter(None, exc_type, exc_value, tb)
+ html = reporter.get_traceback_html()
+ self.assertEqual(len(html) // 1024 // 1024, 0) # still fit in 1MB
+ self.assertIn('&lt;trimmed %d bytes string&gt;' % (large + repr_of_str_adds,), html)
+
@skipIf(six.PY2, 'Bug manifests on PY3 only')
def test_unfrozen_importlib(self):
"""