Skip to content

Commit

Permalink
Handle invalid/malformed data from clients in HttpParser (#740)
Browse files Browse the repository at this point in the history
* add validation in _process_line in parser.py

add validation in _process_line in proxy/http/parser/parser.py

* quick fail when parsing request

quick fail when parsing request
add test case for parsing invalid http request

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* remove unnecessary checks and empty line

remove unnecessary checks and empty line

* minor fix

minor fix

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* solve exception expression conflict

solve exception expression conflict

* use NotImplementedError temporary measure

use change HttpProtocolException to NotImplementedError for a temporary
measure

* change exception type in test

change exception type in test

* remove unnecessary import

remove unnecessary import

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Abhinav Singh <[email protected]>
Co-authored-by: Abhinav Singh <[email protected]>
  • Loading branch information
4 people authored Nov 18, 2021
1 parent 8052c90 commit 658acd8
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 5 deletions.
20 changes: 15 additions & 5 deletions proxy/http/parser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
from .chunk import ChunkParser, chunkParserStates
from .types import httpParserTypes, httpParserStates


flags.add_argument(
'--enable-proxy-protocol',
action='store_true',
Expand Down Expand Up @@ -305,16 +304,27 @@ def _process_line_and_headers(self, raw: bytes) -> Tuple[bool, bytes]:

def _process_line(self, raw: bytes) -> None:
if self.type == httpParserTypes.REQUEST_PARSER:
# Ref:
# https://datatracker.ietf.org/doc/html/rfc2616#section-5.1
# https://greenbytes.de/tech/webdav/rfc7230.html#request.line
# https://greenbytes.de/tech/webdav/rfc7231.html#methods
# http://www.iana.org/assignments/http-methods/http-methods.xhtml
if self.protocol is not None and self.protocol.version is None:
# We expect to receive entire proxy protocol v1 line
# in one network read and don't expect partial packets
self.protocol.parse(raw)
else:
line = raw.split(WHITESPACE)
self.method = line[0].upper()
self.set_url(line[1])
self.version = line[2]
self.state = httpParserStates.LINE_RCVD
if len(line) == 3:
self.method = line[0].upper()
self.set_url(line[1])
self.version = line[2]
self.state = httpParserStates.LINE_RCVD
else:
# raise exception
# TODO, it would be better to use raise HttpProtocolException,
# but we should solve circular import problem first
raise NotImplementedError('Invalid request line')
else:
line = raw.split(WHITESPACE)
self.version = line[0]
Expand Down
9 changes: 9 additions & 0 deletions tests/http/test_http_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ class TestHttpParser(unittest.TestCase):
def setUp(self) -> None:
self.parser = HttpParser(httpParserTypes.REQUEST_PARSER)

def test_issue_127(self) -> None:
with self.assertRaises(NotImplementedError):
self.parser.parse(CRLF)

with self.assertRaises(NotImplementedError):
raw = b'qwqrqw!@!#@!#ad adfad\r\n'
while True:
self.parser.parse(raw)

def test_issue_398(self) -> None:
p = HttpParser(httpParserTypes.RESPONSE_PARSER)
p.parse(HTTP_1_0 + b' 200 OK' + CRLF)
Expand Down

0 comments on commit 658acd8

Please sign in to comment.