Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3216,3 +3216,10 @@ def linked_to_musl():
return _linked_to_musl
_linked_to_musl = tuple(map(int, version.split('.')))
return _linked_to_musl


def control_characters_c0() -> list[str]:
"""Returns a list of C0 control characters as strings.
C0 control characters defined as the byte range 0x00-0x1F, and 0x7F.
"""
return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"]
12 changes: 11 additions & 1 deletion Lib/test/test_wsgiref.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from unittest import mock
from test import support
from test.support import socket_helper
from test.support import socket_helper, control_characters_c0
from test.test_httpservers import NoLogRequestHandler
from unittest import TestCase
from wsgiref.util import setup_testing_defaults
Expand Down Expand Up @@ -503,6 +503,16 @@ def testExtras(self):
'\r\n'
)

def testRaisesControlCharacters(self):
headers = Headers()
for c0 in control_characters_c0():
self.assertRaises(ValueError, headers.__setitem__, f"key{c0}", "val")
self.assertRaises(ValueError, headers.__setitem__, "key", f"val{c0}")
self.assertRaises(ValueError, headers.add_header, f"key{c0}", "val", param="param")
self.assertRaises(ValueError, headers.add_header, "key", f"val{c0}", param="param")
self.assertRaises(ValueError, headers.add_header, "key", "val", param=f"param{c0}")


class ErrorHandler(BaseCGIHandler):
"""Simple handler subclass for testing BaseHandler"""

Expand Down
3 changes: 3 additions & 0 deletions Lib/wsgiref/headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# existence of which force quoting of the parameter value.
import re
tspecials = re.compile(r'[ \(\)<>@,;:\\"/\[\]\?=]')
_control_chars_re = re.compile(r'[\x00-\x1F\x7F]')

def _formatparam(param, value=None, quote=1):
"""Convenience function to format and return a key=value pair.
Expand Down Expand Up @@ -41,6 +42,8 @@ def __init__(self, headers=None):
def _convert_string_type(self, value):
"""Convert/check value type."""
if type(value) is str:
if _control_chars_re.search(value):
raise ValueError("Control characters not allowed in headers")
return value
raise AssertionError("Header names/values must be"
" of type str (got {0})".format(repr(value)))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Reject C0 control characters within wsgiref.headers.Headers fields, values,
and parameters.
Loading