A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/python/cpython/commit/5466bf1c94d38e75bc053b0cfc163e2f948fe345 below:

Fix Issue6791 - Limit the HTTP header readline with _MAXLENGTH. Patch… · python/cpython@5466bf1 · GitHub

File tree Expand file treeCollapse file tree 4 files changed

+67

-8

lines changed

Filter options

Expand file treeCollapse file tree 4 files changed

+67

-8

lines changed Original file line number Diff line number Diff line change

@@ -203,6 +203,9 @@

203 203

# maximal amount of data to read at one time in _safe_read

204 204

MAXAMOUNT = 1048576

205 205 206 +

# maximal line length when calling readline().

207 +

_MAXLINE = 65536

208 + 206 209

class HTTPMessage(email.message.Message):

207 210

# XXX The only usage of this method is in

208 211

# http.server.CGIHTTPRequestHandler. Maybe move the code there so

@@ -245,7 +248,9 @@ def parse_headers(fp, _class=HTTPMessage):

245 248

"""

246 249

headers = []

247 250

while True:

248 -

line = fp.readline()

251 +

line = fp.readline(_MAXLINE + 1)

252 +

if len(line) > _MAXLINE:

253 +

raise LineTooLong("header line")

249 254

headers.append(line)

250 255

if line in (b'\r\n', b'\n', b''):

251 256

break

@@ -299,7 +304,9 @@ def __init__(self, sock, debuglevel=0, strict=_strict_sentinel, method=None, url

299 304

self.will_close = _UNKNOWN # conn will close at end of response

300 305 301 306

def _read_status(self):

302 -

line = str(self.fp.readline(), "iso-8859-1")

307 +

line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")

308 +

if len(line) > _MAXLINE:

309 +

raise LineTooLong("status line")

303 310

if self.debuglevel > 0:

304 311

print("reply:", repr(line))

305 312

if not line:

@@ -340,7 +347,10 @@ def begin(self):

340 347

break

341 348

# skip the header from the 100 response

342 349

while True:

343 -

skip = self.fp.readline().strip()

350 +

skip = self.fp.readline(_MAXLINE + 1)

351 +

if len(skip) > _MAXLINE:

352 +

raise LineTooLong("header line")

353 +

skip = skip.strip()

344 354

if not skip:

345 355

break

346 356

if self.debuglevel > 0:

@@ -508,7 +518,9 @@ def _read_chunked(self, amt):

508 518

value = []

509 519

while True:

510 520

if chunk_left is None:

511 -

line = self.fp.readline()

521 +

line = self.fp.readline(_MAXLINE + 1)

522 +

if len(line) > _MAXLINE:

523 +

raise LineTooLong("chunk size")

512 524

i = line.find(b";")

513 525

if i >= 0:

514 526

line = line[:i] # strip chunk-extensions

@@ -543,7 +555,9 @@ def _read_chunked(self, amt):

543 555

# read and discard trailer up to the CRLF terminator

544 556

### note: we shouldn't have any trailers!

545 557

while True:

546 -

line = self.fp.readline()

558 +

line = self.fp.readline(_MAXLINE + 1)

559 +

if len(line) > _MAXLINE:

560 +

raise LineTooLong("trailer line")

547 561

if not line:

548 562

# a vanishingly small number of sites EOF without

549 563

# sending the trailer

@@ -692,7 +706,9 @@ def _tunnel(self):

692 706

raise socket.error("Tunnel connection failed: %d %s" % (code,

693 707

message.strip()))

694 708

while True:

695 -

line = response.fp.readline()

709 +

line = response.fp.readline(_MAXLINE + 1)

710 +

if len(line) > _MAXLINE:

711 +

raise LineTooLong("header line")

696 712

if line == b'\r\n':

697 713

break

698 714

@@ -1137,5 +1153,10 @@ def __init__(self, line):

1137 1153

self.args = line,

1138 1154

self.line = line

1139 1155 1156 +

class LineTooLong(HTTPException):

1157 +

def __init__(self, line_type):

1158 +

HTTPException.__init__(self, "got more than %d bytes when reading %s"

1159 +

% (_MAXLINE, line_type))

1160 + 1140 1161

# for backwards compatibility

1141 1162

error = HTTPException

Original file line number Diff line number Diff line change

@@ -314,8 +314,12 @@ def parse_request(self):

314 314

self.command, self.path, self.request_version = command, path, version

315 315 316 316

# Examine the headers and look for a Connection directive.

317 -

self.headers = http.client.parse_headers(self.rfile,

318 -

_class=self.MessageClass)

317 +

try:

318 +

self.headers = http.client.parse_headers(self.rfile,

319 +

_class=self.MessageClass)

320 +

except http.client.LineTooLong:

321 +

self.send_error(400, "Line too long")

322 +

return False

319 323 320 324

conntype = self.headers.get('Connection', "")

321 325

if conntype.lower() == 'close':

Original file line number Diff line number Diff line change

@@ -317,6 +317,33 @@ def test_epipe(self):

317 317

self.assertEqual("Basic realm=\"example\"",

318 318

resp.getheader("www-authenticate"))

319 319 320 +

# Test lines overflowing the max line size (_MAXLINE in http.client)

321 + 322 +

def test_overflowing_status_line(self):

323 +

body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n"

324 +

resp = client.HTTPResponse(FakeSocket(body))

325 +

self.assertRaises((client.LineTooLong, client.BadStatusLine), resp.begin)

326 + 327 +

def test_overflowing_header_line(self):

328 +

body = (

329 +

'HTTP/1.1 200 OK\r\n'

330 +

'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n'

331 +

)

332 +

resp = client.HTTPResponse(FakeSocket(body))

333 +

self.assertRaises(client.LineTooLong, resp.begin)

334 + 335 +

def test_overflowing_chunked_line(self):

336 +

body = (

337 +

'HTTP/1.1 200 OK\r\n'

338 +

'Transfer-Encoding: chunked\r\n\r\n'

339 +

+ '0' * 65536 + 'a\r\n'

340 +

'hello world\r\n'

341 +

'0\r\n'

342 +

)

343 +

resp = client.HTTPResponse(FakeSocket(body))

344 +

resp.begin()

345 +

self.assertRaises(client.LineTooLong, resp.read)

346 + 320 347

class OfflineTest(TestCase):

321 348

def test_responses(self):

322 349

self.assertEqual(client.responses[client.NOT_FOUND], "Not Found")

Original file line number Diff line number Diff line change

@@ -573,6 +573,13 @@ def test_request_length(self):

573 573

self.assertEqual(result[0], b'HTTP/1.1 414 Request-URI Too Long\r\n')

574 574

self.assertFalse(self.handler.get_called)

575 575 576 +

def test_header_length(self):

577 +

# Issue #6791: same for headers

578 +

result = self.send_typical_request(

579 +

b'GET / HTTP/1.1\r\nX-Foo: bar' + b'r' * 65537 + b'\r\n\r\n')

580 +

self.assertEqual(result[0], b'HTTP/1.1 400 Line too long\r\n')

581 +

self.assertFalse(self.handler.get_called)

582 + 576 583

class SimpleHTTPRequestHandlerTestCase(unittest.TestCase):

577 584

""" Test url parsing """

578 585

def setUp(self):

You can’t perform that action at this time.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4