[Python-checkins] cpython (3.5): Issue #25738: Don’t send message body for 205 Reset Content

martin.panter python-checkins at python.org
Wed Jun 8 05:50:56 EDT 2016


https://hg.python.org/cpython/rev/1dc495007b8f
changeset: 101786:1dc495007b8f
branch: 3.5
user: Martin Panter <vadmium+py at gmail.com>
date: Wed Jun 08 08:29:13 2016 +0000
summary:
 Issue #25738: Don’t send message body for 205 Reset Content
Patch by Susumu Koshiba.
files:
 Doc/library/http.server.rst | 4 +-
 Lib/http/server.py | 30 ++++++++++-----
 Lib/test/test_httpservers.py | 44 ++++++++++++++++++++++++
 Misc/ACKS | 1 +
 Misc/NEWS | 5 ++
 5 files changed, 73 insertions(+), 11 deletions(-)
diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst
--- a/Doc/library/http.server.rst
+++ b/Doc/library/http.server.rst
@@ -191,7 +191,9 @@
 a complete set of headers, as the response body. The :attr:`responses`
 attribute holds the default values for *message* and *explain* that
 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
 The error response includes a Content-Length header.
diff --git a/Lib/http/server.py b/Lib/http/server.py
--- a/Lib/http/server.py
+++ b/Lib/http/server.py
@@ -450,20 +450,30 @@
 if explain is None:
 explain = longmsg
 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_header("Content-Type", self.error_content_type)
 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()
 
- if (self.command != 'HEAD' and
- code >= 200 and
- code not in (
- HTTPStatus.NO_CONTENT, HTTPStatus.NOT_MODIFIED)):
+ if self.command != 'HEAD' and body:
 self.wfile.write(body)
 
 def send_response(self, code, message=None):
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -115,6 +115,12 @@
 body = self.headers['x-special-incoming'].encode('utf-8')
 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):
 BaseTestCase.setUp(self)
 self.con = http.client.HTTPConnection(self.HOST, self.PORT)
@@ -236,6 +242,44 @@
 data = res.read()
 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 request_handler(BaseHTTPRequestHandler):
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -781,6 +781,7 @@
 Peter A. Koren
 Марк Коренберг
 Vlad Korolev
+Susumu Koshiba
 Joseph Koshy
 Daniel Kozan
 Jerzy Kozera
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -131,6 +131,11 @@
 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
 contains truncated build information.
 
-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /