@@ -147,6 +147,14 @@ def test_page_not_found_warning(self):
147
147
msg="Not Found: /does_not_exist/",
148
148
)
149
149
150
+
def test_control_chars_escaped(self):
151
+
self.assertLogsRequest(
152
+
url="/%1B[1;31mNOW IN RED!!!1B[0m/",
153
+
level="WARNING",
154
+
status_code=404,
155
+
msg=r"Not Found: /\x1b[1;31mNOW IN RED!!!1B[0m/",
156
+
)
157
+
150
158
async def test_async_page_not_found_warning(self):
151
159
logger = "django.request"
152
160
level = "WARNING"
@@ -155,6 +163,16 @@ async def test_async_page_not_found_warning(self):
155
163
156
164
self.assertLogRecord(cm, level, "Not Found: /does_not_exist/", 404)
157
165
166
+
async def test_async_control_chars_escaped(self):
167
+
logger = "django.request"
168
+
level = "WARNING"
169
+
with self.assertLogs(logger, level) as cm:
170
+
await self.async_client.get(r"/%1B[1;31mNOW IN RED!!!1B[0m/")
171
+
172
+
self.assertLogRecord(
173
+
cm, level, r"Not Found: /\x1b[1;31mNOW IN RED!!!1B[0m/", 404
174
+
)
175
+
158
176
def test_page_not_found_raised(self):
159
177
self.assertLogsRequest(
160
178
url="/does_not_exist_raised/",
@@ -705,6 +723,7 @@ def assertResponseLogged(self, logger_cm, msg, levelno, status_code, request):
705
723
self.assertEqual(record.levelno, levelno)
706
724
self.assertEqual(record.status_code, status_code)
707
725
self.assertEqual(record.request, request)
726
+
return record
708
727
709
728
def test_missing_response_raises_attribute_error(self):
710
729
with self.assertRaises(AttributeError):
@@ -806,3 +825,64 @@ def test_logs_with_custom_logger(self):
806
825
self.assertEqual(
807
826
f"WARNING:my.custom.logger:{msg}", log_stream.getvalue().strip()
808
827
)
828
+
829
+
def test_unicode_escape_escaping(self):
830
+
test_cases = [
831
+
# Control characters.
832
+
("line\nbreak", "line\\nbreak"),
833
+
("carriage\rreturn", "carriage\\rreturn"),
834
+
("tab\tseparated", "tab\\tseparated"),
835
+
("formfeed\f", "formfeed\\x0c"),
836
+
("bell\a", "bell\\x07"),
837
+
("multi\nline\ntext", "multi\\nline\\ntext"),
838
+
# Slashes.
839
+
("slash\\test", "slash\\\\test"),
840
+
("back\\slash", "back\\\\slash"),
841
+
# Quotes.
842
+
('quote"test"', 'quote"test"'),
843
+
("quote'test'", "quote'test'"),
844
+
# Accented, composed characters, emojis and symbols.
845
+
("café", "caf\\xe9"),
846
+
("e\u0301", "e\\u0301"), # e + combining acute
847
+
("smile🙂", "smile\\U0001f642"),
848
+
("weird ☃️", "weird \\u2603\\ufe0f"),
849
+
# Non-Latin alphabets.
850
+
("Привет", "\\u041f\\u0440\\u0438\\u0432\\u0435\\u0442"),
851
+
("你好", "\\u4f60\\u597d"),
852
+
# ANSI escape sequences.
853
+
("escape\x1b[31mred\x1b[0m", "escape\\x1b[31mred\\x1b[0m"),
854
+
(
855
+
"/\x1b[1;31mCAUTION!!YOU ARE PWNED\x1b[0m/",
856
+
"/\\x1b[1;31mCAUTION!!YOU ARE PWNED\\x1b[0m/",
857
+
),
858
+
(
859
+
"/\r\n\r\n1984-04-22 INFO Listening on 0.0.0.0:8080\r\n\r\n",
860
+
"/\\r\\n\\r\\n1984-04-22 INFO Listening on 0.0.0.0:8080\\r\\n\\r\\n",
861
+
),
862
+
# Plain safe input.
863
+
("normal-path", "normal-path"),
864
+
("slash/colon:", "slash/colon:"),
865
+
# Non strings.
866
+
(0, "0"),
867
+
([1, 2, 3], "[1, 2, 3]"),
868
+
({"test": "🙂"}, "{'test': '🙂'}"),
869
+
]
870
+
871
+
msg = "Test message: %s"
872
+
for case, expected in test_cases:
873
+
with (
874
+
self.assertLogs("django.request", level="ERROR") as cm,
875
+
self.subTest(case=case),
876
+
):
877
+
response = HttpResponse(status=318)
878
+
log_response(msg, case, response=response, level="error")
879
+
880
+
record = self.assertResponseLogged(
881
+
cm,
882
+
msg % expected,
883
+
levelno=logging.ERROR,
884
+
status_code=318,
885
+
request=None,
886
+
)
887
+
# Log record is always a single line.
888
+
self.assertEqual(len(record.getMessage().splitlines()), 1)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4