mirror of
https://github.com/python/cpython.git
synced 2025-10-10 00:43:41 +00:00
Issue #25738: Don’t send message body for 205 Reset Content
Patch by Susumu Koshiba.
This commit is contained in:
parent
4e50553823
commit
e42e129ebe
5 changed files with 73 additions and 11 deletions
|
@ -191,7 +191,9 @@ of which this module provides three different variants:
|
||||||
a complete set of headers, as the response body. The :attr:`responses`
|
a complete set of headers, as the response body. The :attr:`responses`
|
||||||
attribute holds the default values for *message* and *explain* that
|
attribute holds the default values for *message* and *explain* that
|
||||||
will be used if no value is provided; for unknown codes the default value
|
will be used if no value is provided; for unknown codes the default value
|
||||||
for both is the string ``???``.
|
for both is the string ``???``. The body will be empty if the method is
|
||||||
|
HEAD or the response code is one of the following: ``1xx``,
|
||||||
|
``204 No Content``, ``205 Reset Content``, ``304 Not Modified``.
|
||||||
|
|
||||||
.. versionchanged:: 3.4
|
.. versionchanged:: 3.4
|
||||||
The error response includes a Content-Length header.
|
The error response includes a Content-Length header.
|
||||||
|
|
|
@ -450,20 +450,30 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
||||||
if explain is None:
|
if explain is None:
|
||||||
explain = longmsg
|
explain = longmsg
|
||||||
self.log_error("code %d, message %s", code, message)
|
self.log_error("code %d, message %s", code, message)
|
||||||
# using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201)
|
|
||||||
content = (self.error_message_format %
|
|
||||||
{'code': code, 'message': _quote_html(message), 'explain': _quote_html(explain)})
|
|
||||||
body = content.encode('UTF-8', 'replace')
|
|
||||||
self.send_response(code, message)
|
self.send_response(code, message)
|
||||||
self.send_header("Content-Type", self.error_content_type)
|
|
||||||
self.send_header('Connection', 'close')
|
self.send_header('Connection', 'close')
|
||||||
self.send_header('Content-Length', int(len(body)))
|
|
||||||
|
# Message body is omitted for cases described in:
|
||||||
|
# - RFC7230: 3.3. 1xx, 204(No Content), 304(Not Modified)
|
||||||
|
# - RFC7231: 6.3.6. 205(Reset Content)
|
||||||
|
body = None
|
||||||
|
if (code >= 200 and
|
||||||
|
code not in (HTTPStatus.NO_CONTENT,
|
||||||
|
HTTPStatus.RESET_CONTENT,
|
||||||
|
HTTPStatus.NOT_MODIFIED)):
|
||||||
|
# HTML encode to prevent Cross Site Scripting attacks
|
||||||
|
# (see bug #1100201)
|
||||||
|
content = (self.error_message_format % {
|
||||||
|
'code': code,
|
||||||
|
'message': _quote_html(message),
|
||||||
|
'explain': _quote_html(explain)
|
||||||
|
})
|
||||||
|
body = content.encode('UTF-8', 'replace')
|
||||||
|
self.send_header("Content-Type", self.error_content_type)
|
||||||
|
self.send_header('Content-Length', int(len(body)))
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
if (self.command != 'HEAD' and
|
if self.command != 'HEAD' and body:
|
||||||
code >= 200 and
|
|
||||||
code not in (
|
|
||||||
HTTPStatus.NO_CONTENT, HTTPStatus.NOT_MODIFIED)):
|
|
||||||
self.wfile.write(body)
|
self.wfile.write(body)
|
||||||
|
|
||||||
def send_response(self, code, message=None):
|
def send_response(self, code, message=None):
|
||||||
|
|
|
@ -115,6 +115,12 @@ class BaseHTTPServerTestCase(BaseTestCase):
|
||||||
body = self.headers['x-special-incoming'].encode('utf-8')
|
body = self.headers['x-special-incoming'].encode('utf-8')
|
||||||
self.wfile.write(body)
|
self.wfile.write(body)
|
||||||
|
|
||||||
|
def do_SEND_ERROR(self):
|
||||||
|
self.send_error(int(self.path[1:]))
|
||||||
|
|
||||||
|
def do_HEAD(self):
|
||||||
|
self.send_error(int(self.path[1:]))
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
BaseTestCase.setUp(self)
|
BaseTestCase.setUp(self)
|
||||||
self.con = http.client.HTTPConnection(self.HOST, self.PORT)
|
self.con = http.client.HTTPConnection(self.HOST, self.PORT)
|
||||||
|
@ -236,6 +242,44 @@ class BaseHTTPServerTestCase(BaseTestCase):
|
||||||
data = res.read()
|
data = res.read()
|
||||||
self.assertEqual(int(res.getheader('Content-Length')), len(data))
|
self.assertEqual(int(res.getheader('Content-Length')), len(data))
|
||||||
|
|
||||||
|
def test_send_error(self):
|
||||||
|
allow_transfer_encoding_codes = (HTTPStatus.NOT_MODIFIED,
|
||||||
|
HTTPStatus.RESET_CONTENT)
|
||||||
|
for code in (HTTPStatus.NO_CONTENT, HTTPStatus.NOT_MODIFIED,
|
||||||
|
HTTPStatus.PROCESSING, HTTPStatus.RESET_CONTENT,
|
||||||
|
HTTPStatus.SWITCHING_PROTOCOLS):
|
||||||
|
self.con.request('SEND_ERROR', '/{}'.format(code))
|
||||||
|
res = self.con.getresponse()
|
||||||
|
self.assertEqual(code, res.status)
|
||||||
|
self.assertEqual(None, res.getheader('Content-Length'))
|
||||||
|
self.assertEqual(None, res.getheader('Content-Type'))
|
||||||
|
if code not in allow_transfer_encoding_codes:
|
||||||
|
self.assertEqual(None, res.getheader('Transfer-Encoding'))
|
||||||
|
|
||||||
|
data = res.read()
|
||||||
|
self.assertEqual(b'', data)
|
||||||
|
|
||||||
|
def test_head_via_send_error(self):
|
||||||
|
allow_transfer_encoding_codes = (HTTPStatus.NOT_MODIFIED,
|
||||||
|
HTTPStatus.RESET_CONTENT)
|
||||||
|
for code in (HTTPStatus.OK, HTTPStatus.NO_CONTENT,
|
||||||
|
HTTPStatus.NOT_MODIFIED, HTTPStatus.RESET_CONTENT,
|
||||||
|
HTTPStatus.SWITCHING_PROTOCOLS):
|
||||||
|
self.con.request('HEAD', '/{}'.format(code))
|
||||||
|
res = self.con.getresponse()
|
||||||
|
self.assertEqual(code, res.status)
|
||||||
|
if code == HTTPStatus.OK:
|
||||||
|
self.assertTrue(int(res.getheader('Content-Length')) > 0)
|
||||||
|
self.assertIn('text/html', res.getheader('Content-Type'))
|
||||||
|
else:
|
||||||
|
self.assertEqual(None, res.getheader('Content-Length'))
|
||||||
|
self.assertEqual(None, res.getheader('Content-Type'))
|
||||||
|
if code not in allow_transfer_encoding_codes:
|
||||||
|
self.assertEqual(None, res.getheader('Transfer-Encoding'))
|
||||||
|
|
||||||
|
data = res.read()
|
||||||
|
self.assertEqual(b'', data)
|
||||||
|
|
||||||
|
|
||||||
class RequestHandlerLoggingTestCase(BaseTestCase):
|
class RequestHandlerLoggingTestCase(BaseTestCase):
|
||||||
class request_handler(BaseHTTPRequestHandler):
|
class request_handler(BaseHTTPRequestHandler):
|
||||||
|
|
|
@ -781,6 +781,7 @@ Arkady Koplyarov
|
||||||
Peter A. Koren
|
Peter A. Koren
|
||||||
Марк Коренберг
|
Марк Коренберг
|
||||||
Vlad Korolev
|
Vlad Korolev
|
||||||
|
Susumu Koshiba
|
||||||
Joseph Koshy
|
Joseph Koshy
|
||||||
Daniel Kozan
|
Daniel Kozan
|
||||||
Jerzy Kozera
|
Jerzy Kozera
|
||||||
|
|
|
@ -131,6 +131,11 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #25738: Stop http.server.BaseHTTPRequestHandler.send_error() from
|
||||||
|
sending a message body for 205 Reset Content. Also, don't send Content
|
||||||
|
header fields in responses that don't have a body. Patch by Susumu
|
||||||
|
Koshiba.
|
||||||
|
|
||||||
- Issue #21313: Fix the "platform" module to tolerate when sys.version
|
- Issue #21313: Fix the "platform" module to tolerate when sys.version
|
||||||
contains truncated build information.
|
contains truncated build information.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue