mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
bpo-44022: Fix http client infinite line reading (DoS) after a HTTP 100 Continue (GH-25916)
Fixes http.client potential denial of service where it could get stuck reading lines from a malicious server after a 100 Continue response. Co-authored-by: Gregory P. Smith <greg@krypto.org>
This commit is contained in:
parent
da5c808fb5
commit
47895e31b6
3 changed files with 32 additions and 18 deletions
|
@ -202,15 +202,11 @@ class HTTPMessage(email.message.Message):
|
|||
lst.append(line)
|
||||
return lst
|
||||
|
||||
def parse_headers(fp, _class=HTTPMessage):
|
||||
"""Parses only RFC2822 headers from a file pointer.
|
||||
|
||||
email Parser wants to see strings rather than bytes.
|
||||
But a TextIOWrapper around self.rfile would buffer too many bytes
|
||||
from the stream, bytes which we later need to read as bytes.
|
||||
So we read the correct bytes here, as bytes, for email Parser
|
||||
to parse.
|
||||
def _read_headers(fp):
|
||||
"""Reads potential header lines into a list from a file pointer.
|
||||
|
||||
Length of line is limited by _MAXLINE, and number of
|
||||
headers is limited by _MAXHEADERS.
|
||||
"""
|
||||
headers = []
|
||||
while True:
|
||||
|
@ -222,6 +218,19 @@ def parse_headers(fp, _class=HTTPMessage):
|
|||
raise HTTPException("got more than %d headers" % _MAXHEADERS)
|
||||
if line in (b'\r\n', b'\n', b''):
|
||||
break
|
||||
return headers
|
||||
|
||||
def parse_headers(fp, _class=HTTPMessage):
|
||||
"""Parses only RFC2822 headers from a file pointer.
|
||||
|
||||
email Parser wants to see strings rather than bytes.
|
||||
But a TextIOWrapper around self.rfile would buffer too many bytes
|
||||
from the stream, bytes which we later need to read as bytes.
|
||||
So we read the correct bytes here, as bytes, for email Parser
|
||||
to parse.
|
||||
|
||||
"""
|
||||
headers = _read_headers(fp)
|
||||
hstring = b''.join(headers).decode('iso-8859-1')
|
||||
return email.parser.Parser(_class=_class).parsestr(hstring)
|
||||
|
||||
|
@ -309,15 +318,10 @@ class HTTPResponse(io.BufferedIOBase):
|
|||
if status != CONTINUE:
|
||||
break
|
||||
# skip the header from the 100 response
|
||||
while True:
|
||||
skip = self.fp.readline(_MAXLINE + 1)
|
||||
if len(skip) > _MAXLINE:
|
||||
raise LineTooLong("header line")
|
||||
skip = skip.strip()
|
||||
if not skip:
|
||||
break
|
||||
if self.debuglevel > 0:
|
||||
print("header:", skip)
|
||||
skipped_headers = _read_headers(self.fp)
|
||||
if self.debuglevel > 0:
|
||||
print("headers:", skipped_headers)
|
||||
del skipped_headers
|
||||
|
||||
self.code = self.status = status
|
||||
self.reason = reason.strip()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue