Skip to content

Commit 78a046f

Browse files
committed
httputil: Add CRLF to _FORBIDDEN_HEADER_CHARS_RE
I think these were omitted due to quirks of an older version of the parsing code. Linefeeds are already effectively prohibited within header values since they are interpreted as delimiters, so the net effect of this change is to prohibit bare carriage returns within header values. This RE is used only when parsing headers inside multipart/form-data bodies; for HTTP headers CR was already prohibited.
1 parent 24a2d96 commit 78a046f

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

tornado/httputil.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373

7474
# Roughly the inverse of RequestHandler._VALID_HEADER_CHARS, but permits
7575
# chars greater than \xFF (which may appear after decoding utf8).
76-
_FORBIDDEN_HEADER_CHARS_RE = re.compile(r"[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]")
76+
_FORBIDDEN_HEADER_CHARS_RE = re.compile(r"[\x00-\x08\x0A-\x1F\x7F]")
7777

7878

7979
class _ABNF:

tornado/test/httputil_test.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ def test_special_filenames(self):
136136
'a";";.txt',
137137
'a\\"b.txt',
138138
"a\\b.txt",
139+
"a b.txt",
140+
"a\tb.txt",
139141
]
140142
for filename in filenames:
141143
logging.debug("trying filename %r", filename)
@@ -156,6 +158,29 @@ def test_special_filenames(self):
156158
self.assertEqual(file["filename"], filename)
157159
self.assertEqual(file["body"], b"Foo")
158160

161+
def test_invalid_chars(self):
162+
filenames = [
163+
"a\rb.txt",
164+
"a\0b.txt",
165+
"a\x08b.txt",
166+
]
167+
for filename in filenames:
168+
str_data = """\
169+
--1234
170+
Content-Disposition: form-data; name="files"; filename="%s"
171+
172+
Foo
173+
--1234--""" % filename.replace(
174+
"\\", "\\\\"
175+
).replace(
176+
'"', '\\"'
177+
)
178+
data = utf8(str_data.replace("\n", "\r\n"))
179+
args, files = form_data_args()
180+
with self.assertRaises(HTTPInputError) as cm:
181+
parse_multipart_form_data(b"1234", data, args, files)
182+
self.assertIn("Invalid header value", str(cm.exception))
183+
159184
def test_non_ascii_filename_rfc5987(self):
160185
data = b"""\
161186
--1234

0 commit comments

Comments
 (0)