Check Content-Length header.

For not chunked request do validation Content-Length header and return 400 if invalid.
This commit is contained in:
Konstantin Kapustin 2012-09-07 17:04:16 +04:00 committed by benoitc
parent 238f252a3a
commit 4be3282440
9 changed files with 76 additions and 15 deletions

View File

@ -35,18 +35,19 @@ class InvalidHTTPVersion(ParseException):
return "Invalid HTTP Version: %s" % self.version
class InvalidHeader(ParseException):
def __init__(self, hdr):
def __init__(self, hdr, req=None):
self.hdr = hdr
self.req = req
def __str__(self):
return "Invalid HTTP Header: %r" % self.hdr
return "Invalid HTTP Header: %s" % self.hdr
class InvalidHeaderName(ParseException):
def __init__(self, hdr):
self.hdr = hdr
def __str__(self):
return "Invalid HTTP header name: %r" % self.hdr
return "Invalid HTTP header name: %s" % self.hdr
class InvalidChunkSize(ParseException):
def __init__(self, data):

View File

@ -94,25 +94,27 @@ class Message(object):
def set_body_reader(self):
chunked = False
response_length = None
content_length = None
for (name, value) in self.headers:
if name == "CONTENT-LENGTH":
try:
response_length = int(value)
except ValueError:
response_length = None
content_length = value
elif name == "TRANSFER-ENCODING":
chunked = value.lower() == "chunked"
elif name == "SEC-WEBSOCKET-KEY1":
response_length = 8
if response_length is not None or chunked:
break
content_length = 8
if chunked:
self.body = Body(ChunkedReader(self, self.unreader))
elif response_length is not None:
self.body = Body(LengthReader(self.unreader, response_length))
elif content_length is not None:
try:
content_length = int(content_length)
except ValueError:
raise InvalidHeader("CONTENT-LENGTH", req=self)
if content_length < 0:
raise InvalidHeader("CONTENT-LENGTH", req=self)
self.body = Body(LengthReader(self.unreader, content_length))
else:
self.body = Body(EOFReader(self.unreader))

View File

@ -142,7 +142,9 @@ class Worker(object):
elif isinstance(exc, InvalidHTTPVersion):
mesg = "<p>Invalid HTTP Version '%s'</p>" % str(exc)
elif isinstance(exc, (InvalidHeaderName, InvalidHeader,)):
mesg = "<p>Invalid Header '%s'</p>" % str(exc)
mesg = "<p>%s</p>" % str(exc)
if not req and hasattr(exc, "req"):
req = exc.req # for access log
elif isinstance(exc, LimitRequestLine):
mesg = "<p>%s</p>" % str(exc)
elif isinstance(exc, LimitRequestHeaders):

View File

@ -0,0 +1,4 @@
PUT /stuff/here?foo=bar HTTP/1.0\r\n
CONTENT-LENGTH: -1\r\n
\r\n
{"test": "-1}

View File

@ -0,0 +1,3 @@
from gunicorn.http.errors import InvalidHeader
request = InvalidHeader

View File

@ -0,0 +1,4 @@
POST /stuff/here?foo=bar HTTP/1.0\r\n
CONTENT-LENGTH: bla-bla-bla\r\n
\r\n
{"test": "-1}

View File

@ -0,0 +1,3 @@
from gunicorn.http.errors import InvalidHeader
request = InvalidHeader

View File

@ -0,0 +1,19 @@
POST /chunked_cont_h_at_first HTTP/1.1\r\n
Content-Length: -1\r\n
Transfer-Encoding: chunked\r\n
\r\n
5; some; parameters=stuff\r\n
hello\r\n
6; blahblah; blah\r\n
world\r\n
0\r\n
\r\n
PUT /chunked_cont_h_at_last HTTP/1.1\r\n
Transfer-Encoding: chunked\r\n
Content-Length: -1\r\n
\r\n
5; some; parameters=stuff\r\n
hello\r\n
6; blahblah; blah\r\n
world\r\n
0\r\n

View File

@ -0,0 +1,23 @@
req1 = {
"method": "POST",
"uri": uri("/chunked_cont_h_at_first"),
"version": (1, 1),
"headers": [
("CONTENT-LENGTH", "-1"),
("TRANSFER-ENCODING", "chunked")
],
"body": "hello world"
}
req2 = {
"method": "PUT",
"uri": uri("/chunked_cont_h_at_last"),
"version": (1, 1),
"headers": [
("TRANSFER-ENCODING", "chunked"),
("CONTENT-LENGTH", "-1"),
],
"body": "hello world"
}
request = [req1, req2]