diff --git a/django/utils/log.py b/django/utils/log.py index f2813f41759..a2296a32811 100644 --- a/django/utils/log.py +++ b/django/utils/log.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import logging import sys import warnings @@ -6,6 +8,7 @@ from django.conf import settings from django.core import mail from django.core.mail import get_connection from django.utils.deprecation import RemovedInNextVersionWarning +from django.utils.encoding import force_text from django.utils.module_loading import import_string from django.views.debug import ExceptionReporter, get_exception_reporter_filter @@ -106,7 +109,7 @@ class AdminEmailHandler(logging.Handler): record.getMessage() ) filter = get_exception_reporter_filter(request) - request_repr = '\n{0}'.format(filter.get_request_repr(request)) + request_repr = '\n{0}'.format(force_text(filter.get_request_repr(request))) except Exception: subject = '%s: %s' % ( record.levelname, diff --git a/docs/releases/1.7.1.txt b/docs/releases/1.7.1.txt index 0a5a0163b83..1604e75da86 100644 --- a/docs/releases/1.7.1.txt +++ b/docs/releases/1.7.1.txt @@ -97,3 +97,6 @@ Bugfixes possible to import arbitrary packages from the Python path. This was not considered a security issue because ``admindocs`` is only accessible to staff users (:ticket:`23601`). + +* Fixed ``UnicodeDecodeError`` crash in ``AdminEmailHandler`` with non-ASCII + characters in the request (:ticket:`23593`). diff --git a/tests/logging_tests/tests.py b/tests/logging_tests/tests.py index fb10ef5ac1c..da5ef453b14 100644 --- a/tests/logging_tests/tests.py +++ b/tests/logging_tests/tests.py @@ -1,3 +1,4 @@ +# -*- coding:utf-8 -*- from __future__ import unicode_literals import logging @@ -320,6 +321,26 @@ class AdminEmailHandlerTest(TestCase): mail.mail_admins = orig_mail_admins admin_email_handler.email_backend = orig_email_backend + @override_settings( + ADMINS=(('whatever admin', 'admin@example.com'),), + ) + def test_emit_non_ascii(self): + """ + #23593 - AdminEmailHandler should allow Unicode characters in the + request. + """ + handler = self.get_admin_email_handler(self.logger) + record = self.logger.makeRecord('name', logging.ERROR, 'function', 'lno', 'message', None, None) + rf = RequestFactory() + url_path = '/ยบ' + record.request = rf.get(url_path) + handler.emit(record) + self.assertEqual(len(mail.outbox), 1) + msg = mail.outbox[0] + self.assertEqual(msg.to, ['admin@example.com']) + self.assertEqual(msg.subject, "[Django] ERROR (EXTERNAL IP): message") + self.assertIn("path:%s" % url_path, msg.body) + class SettingsConfigTest(AdminScriptTestCase): """