Skip to content

Commit 29501d8

Browse files
committed
Strictly require ASCII headers to have ASCII names
Header value still can have unicode values. Also raise proper exception for invalid type or value with a friendly error message. See http://tools.ietf.org/html/rfc7230#section-3.2.4 for more info.
1 parent d418ca5 commit 29501d8

File tree

2 files changed

+19
-3
lines changed

2 files changed

+19
-3
lines changed

aiohttp/protocol.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import http.server
1212
import itertools
1313
import re
14+
import string
1415
import sys
1516
import zlib
1617
from wsgiref.handlers import format_date_time
@@ -20,6 +21,7 @@
2021
from aiohttp import multidict
2122
from aiohttp.log import internal_log
2223

24+
ASCIISET = set(string.printable)
2325
METHRE = re.compile('[A-Z0-9$-_.]+')
2426
VERSRE = re.compile('HTTP/(\d+).(\d+)')
2527
HDRRE = re.compile('[\x00-\x1F\x7F()<>@,;:\[\]={} \t\\\\\"]')
@@ -572,8 +574,12 @@ def add_header(self, name, value):
572574
"""Analyze headers. Calculate content length,
573575
removes hop headers, etc."""
574576
assert not self.headers_sent, 'headers have been sent already'
575-
assert isinstance(name, str), '{!r} is not a string'.format(name)
576-
assert isinstance(value, str), '{!r} is not a string'.format(value)
577+
assert isinstance(name, str), \
578+
'Header name should be a string, got {!r}'.format(name)
579+
assert set(name).issubset(ASCIISET), \
580+
'Header name should contain ASCII chars, got {!r}'.format(name)
581+
assert isinstance(value, str), \
582+
'Header {!r} should have string value, got {!r}'.format(name, value)
577583

578584
name = name.strip().upper()
579585
value = value.strip()

tests/test_http_protocol.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,22 @@ def test_add_header_with_spaces(self):
7676
self.assertEqual(
7777
[('CONTENT-TYPE', 'plain/html')], list(msg.headers.items()))
7878

79+
def test_add_header_non_ascii(self):
80+
msg = protocol.Response(self.transport, 200)
81+
self.assertEqual([], list(msg.headers))
82+
83+
with self.assertRaises(AssertionError):
84+
msg.add_header('тип-контента', 'текст/плейн')
85+
7986
def test_add_header_invalid_value_type(self):
8087
msg = protocol.Response(self.transport, 200)
8188
self.assertEqual([], list(msg.headers))
8289

8390
with self.assertRaises(AssertionError):
84-
msg.add_header('content-type', b'value')
91+
msg.add_header('content-type', {'test': 'plain'})
92+
93+
with self.assertRaises(AssertionError):
94+
msg.add_header(list('content-type'), 'text/plain')
8595

8696
def test_add_headers(self):
8797
msg = protocol.Response(self.transport, 200)

0 commit comments

Comments
 (0)