Skip to content

Commit 6fe5057

Browse files
committed
Update docs and tests for ff4869b.
Callers don't need to be updated: all of them catch Exception.
1 parent 4809c7f commit 6fe5057

2 files changed

Lines changed: 24 additions & 3 deletions

File tree

src/websockets/http11.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ def parse(
115115
116116
The request method, path, and headers are expected to contain only ASCII
117117
characters. The request path isn't URL-decoded or validated in any way.
118+
Non-ASCII header values are decoded as ISO-8859-1, which has been
119+
historically allowed, but is now deprecated.
118120
119121
:meth:`parse` doesn't read the request body because WebSocket handshake
120122
requests don't have one. If the request contains a body, it may be read
@@ -127,6 +129,7 @@ def parse(
127129
Raises:
128130
EOFError: If the connection is closed without a full HTTP request.
129131
SecurityError: If the request exceeds a security limit.
132+
UnicodeDecodeError: If the request method or path isn't ASCII.
130133
ValueError: If the request isn't well formatted.
131134
132135
"""
@@ -224,8 +227,9 @@ def parse(
224227
225228
This is a generator-based coroutine.
226229
227-
The reason phrase and headers are expected to contain only ASCII
228-
characters. Other characters are represented with surrogate escapes.
230+
The reason phrase and header values are expected to contain only ASCII
231+
characters. Non-ASCII values are decoded as ISO-8859-1, which has been
232+
historically allowed, but is now deprecated.
229233
230234
Args:
231235
read_line: Generator-based coroutine that reads a LF-terminated
@@ -339,7 +343,9 @@ def parse_headers(
339343
"""
340344
Parse HTTP headers.
341345
342-
Non-ASCII characters are represented with surrogate escapes.
346+
Header values are expected to contain only ASCII characters. Non-ASCII
347+
values are decoded as ISO-8859-1, which has been historically allowed,
348+
but is now deprecated.
343349
344350
Args:
345351
read_line: Generator-based coroutine that reads a LF-terminated line

tests/test_http11.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ def test_parse_non_get_method(self):
3939
self.assertEqual(request.method, "OPTIONS")
4040
self.assertEqual(request.path, "*")
4141

42+
def test_parse_non_ascii_method(self):
43+
self.reader.feed_data(b"G\xc9T /chat HTTP/1.1\r\n\r\n")
44+
with self.assertRaises(UnicodeDecodeError):
45+
next(self.parse())
46+
47+
def test_parse_non_ascii_path(self):
48+
self.reader.feed_data(b"GET /caf\xe9 HTTP/1.1\r\n\r\n")
49+
with self.assertRaises(UnicodeDecodeError):
50+
next(self.parse())
51+
4252
def test_parse_empty(self):
4353
self.reader.feed_eof()
4454
with self.assertRaises(EOFError) as raised:
@@ -201,6 +211,11 @@ def test_parse_non_three_digit_status(self):
201211
str(raised.exception), "invalid status code; expected 100–599; got 007"
202212
)
203213

214+
def test_parse_iso_8859_1_reason(self):
215+
self.reader.feed_data(b"HTTP/1.1 200 \xd8K\r\nContent-Length: 0\r\n\r\n")
216+
response = self.assertGeneratorReturns(self.parse())
217+
self.assertEqual(response.reason_phrase, "ØK")
218+
204219
def test_parse_invalid_reason(self):
205220
self.reader.feed_data(b"HTTP/1.1 200 \x7f\r\n\r\n")
206221
with self.assertRaises(ValueError) as raised:

0 commit comments

Comments
 (0)