Limit the size of each request line
This commit is contained in:
@@ -198,6 +198,15 @@ class Request():
|
|||||||
#: Request.max_content_length = 1 * 1024 * 1024 # 1MB requests allowed
|
#: Request.max_content_length = 1 * 1024 * 1024 # 1MB requests allowed
|
||||||
max_content_length = 16 * 1024
|
max_content_length = 16 * 1024
|
||||||
|
|
||||||
|
#: Specify the maximum length allowed for a line in the request. Requests
|
||||||
|
#: with longer lines will not be correctly interpreted. Applications can
|
||||||
|
#: change this maximum as necessary.
|
||||||
|
#:
|
||||||
|
#: Example::
|
||||||
|
#:
|
||||||
|
#: Request.max_readline = 16 * 1024 # 16KB lines allowed
|
||||||
|
max_readline = 2 * 1024
|
||||||
|
|
||||||
class G:
|
class G:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -244,7 +253,7 @@ class Request():
|
|||||||
This method returns a newly created ``Request`` object.
|
This method returns a newly created ``Request`` object.
|
||||||
"""
|
"""
|
||||||
# request line
|
# request line
|
||||||
line = client_stream.readline().strip().decode()
|
line = Request._safe_readline(client_stream).strip().decode()
|
||||||
if not line:
|
if not line:
|
||||||
return None
|
return None
|
||||||
method, url, http_version = line.split()
|
method, url, http_version = line.split()
|
||||||
@@ -254,7 +263,7 @@ class Request():
|
|||||||
headers = {}
|
headers = {}
|
||||||
content_length = 0
|
content_length = 0
|
||||||
while True:
|
while True:
|
||||||
line = client_stream.readline().strip().decode()
|
line = Request._safe_readline(client_stream).strip().decode()
|
||||||
if line == '':
|
if line == '':
|
||||||
break
|
break
|
||||||
header, value = line.split(':', 1)
|
header, value = line.split(':', 1)
|
||||||
@@ -298,6 +307,14 @@ class Request():
|
|||||||
self._form = self._parse_urlencoded(self.body.decode())
|
self._form = self._parse_urlencoded(self.body.decode())
|
||||||
return self._form
|
return self._form
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _safe_readline(stream):
|
||||||
|
line = stream.readline(Request.max_readline + 1)
|
||||||
|
print(line, Request.max_readline)
|
||||||
|
if len(line) > Request.max_readline:
|
||||||
|
raise ValueError('line too long')
|
||||||
|
return line
|
||||||
|
|
||||||
|
|
||||||
class Response():
|
class Response():
|
||||||
"""An HTTP response class.
|
"""An HTTP response class.
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class Request(BaseRequest):
|
|||||||
object.
|
object.
|
||||||
"""
|
"""
|
||||||
# request line
|
# request line
|
||||||
line = (await client_stream.readline()).strip().decode()
|
line = (await Request._safe_readline(client_stream)).strip().decode()
|
||||||
if not line: # pragma: no cover
|
if not line: # pragma: no cover
|
||||||
return None
|
return None
|
||||||
method, url, http_version = line.split()
|
method, url, http_version = line.split()
|
||||||
@@ -44,7 +44,8 @@ class Request(BaseRequest):
|
|||||||
headers = {}
|
headers = {}
|
||||||
content_length = 0
|
content_length = 0
|
||||||
while True:
|
while True:
|
||||||
line = (await client_stream.readline()).strip().decode()
|
line = (await Request._safe_readline(
|
||||||
|
client_stream)).strip().decode()
|
||||||
if line == '':
|
if line == '':
|
||||||
break
|
break
|
||||||
header, value = line.split(':', 1)
|
header, value = line.split(':', 1)
|
||||||
@@ -60,6 +61,13 @@ class Request(BaseRequest):
|
|||||||
return Request(app, client_addr, method, url, http_version, headers,
|
return Request(app, client_addr, method, url, http_version, headers,
|
||||||
body)
|
body)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def _safe_readline(stream):
|
||||||
|
line = (await stream.readline())
|
||||||
|
if len(line) > Request.max_readline:
|
||||||
|
raise ValueError('line too long')
|
||||||
|
return line
|
||||||
|
|
||||||
|
|
||||||
class Response(BaseResponse):
|
class Response(BaseResponse):
|
||||||
"""An HTTP response class.
|
"""An HTTP response class.
|
||||||
|
|||||||
@@ -79,6 +79,18 @@ class TestRequest(unittest.TestCase):
|
|||||||
req = Request.create('app', fd, 'addr')
|
req = Request.create('app', fd, 'addr')
|
||||||
self.assertIsNone(req.form)
|
self.assertIsNone(req.form)
|
||||||
|
|
||||||
|
def test_large_line(self):
|
||||||
|
saved_max_readline = Request.max_readline
|
||||||
|
Request.max_readline = 16
|
||||||
|
|
||||||
|
fd = get_request_fd('GET', '/foo', headers={
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'},
|
||||||
|
body='foo=bar&abc=def&x=y')
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
Request.create('app', fd, 'addr')
|
||||||
|
|
||||||
|
Request.max_readline = saved_max_readline
|
||||||
|
|
||||||
def test_large_payload(self):
|
def test_large_payload(self):
|
||||||
saved_max_content_length = Request.max_content_length
|
saved_max_content_length = Request.max_content_length
|
||||||
Request.max_content_length = 16
|
Request.max_content_length = 16
|
||||||
@@ -87,6 +99,6 @@ class TestRequest(unittest.TestCase):
|
|||||||
'Content-Type': 'application/x-www-form-urlencoded'},
|
'Content-Type': 'application/x-www-form-urlencoded'},
|
||||||
body='foo=bar&abc=def&x=y')
|
body='foo=bar&abc=def&x=y')
|
||||||
req = Request.create('app', fd, 'addr')
|
req = Request.create('app', fd, 'addr')
|
||||||
assert req.body == b''
|
self.assertEqual(req.body, b'')
|
||||||
|
|
||||||
Request.max_content_length = saved_max_content_length
|
Request.max_content_length = saved_max_content_length
|
||||||
|
|||||||
@@ -89,6 +89,18 @@ class TestRequestAsync(unittest.TestCase):
|
|||||||
req = _run(Request.create('app', fd, 'addr'))
|
req = _run(Request.create('app', fd, 'addr'))
|
||||||
self.assertIsNone(req.form)
|
self.assertIsNone(req.form)
|
||||||
|
|
||||||
|
def test_large_line(self):
|
||||||
|
saved_max_readline = Request.max_readline
|
||||||
|
Request.max_readline = 16
|
||||||
|
|
||||||
|
fd = get_async_request_fd('GET', '/foo', headers={
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'},
|
||||||
|
body='foo=bar&abc=def&x=y')
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
_run(Request.create('app', fd, 'addr'))
|
||||||
|
|
||||||
|
Request.max_readline = saved_max_readline
|
||||||
|
|
||||||
def test_large_payload(self):
|
def test_large_payload(self):
|
||||||
saved_max_content_length = Request.max_content_length
|
saved_max_content_length = Request.max_content_length
|
||||||
Request.max_content_length = 16
|
Request.max_content_length = 16
|
||||||
@@ -97,6 +109,6 @@ class TestRequestAsync(unittest.TestCase):
|
|||||||
'Content-Type': 'application/x-www-form-urlencoded'},
|
'Content-Type': 'application/x-www-form-urlencoded'},
|
||||||
body='foo=bar&abc=def&x=y')
|
body='foo=bar&abc=def&x=y')
|
||||||
req = _run(Request.create('app', fd, 'addr'))
|
req = _run(Request.create('app', fd, 'addr'))
|
||||||
assert req.body == b''
|
self.assertEqual(req.body, b'')
|
||||||
|
|
||||||
Request.max_content_length = saved_max_content_length
|
Request.max_content_length = saved_max_content_length
|
||||||
|
|||||||
Reference in New Issue
Block a user