diff -r bf551ee0781a Doc/library/basehttpserver.rst --- a/Doc/library/basehttpserver.rst Sat Jun 04 23:30:24 2016 +0300 +++ b/Doc/library/basehttpserver.rst Sat Jun 04 19:18:36 2016 -0700 @@ -197,7 +197,9 @@ Sends and logs a complete error reply to the client. The numeric *code* specifies the HTTP error code, with *message* as optional, more specific text. A complete set of headers is sent, followed by text composed using the - :attr:`error_message_format` class variable. + :attr:`error_message_format` class variable. 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``. .. method:: send_response(code[, message]) diff -r bf551ee0781a Lib/BaseHTTPServer.py --- a/Lib/BaseHTTPServer.py Sat Jun 04 23:30:24 2016 +0300 +++ b/Lib/BaseHTTPServer.py Sat Jun 04 19:18:36 2016 -0700 @@ -362,14 +362,20 @@ message = short explain = long 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': explain}) + # HTML encode to prevent Cross Site Scripting attacks (see bug #1100201) + content = (self.error_message_format % { + 'code': code, + 'message': _quote_html(message), + 'explain': explain + }) self.send_response(code, message) self.send_header("Content-Type", self.error_content_type) self.send_header('Connection', 'close') self.end_headers() - if self.command != 'HEAD' and code >= 200 and code not in (204, 304): + + if (self.command != 'HEAD'and + code >= 200 and + code not in (204, 205, 304)): self.wfile.write(content) error_message_format = DEFAULT_ERROR_MESSAGE diff -r bf551ee0781a Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py Sat Jun 04 23:30:24 2016 +0300 +++ b/Lib/test/test_httpservers.py Sat Jun 04 19:18:36 2016 -0700 @@ -178,6 +178,24 @@ self.send_header('Connection', 'close') self.end_headers() + def do_NOCONTENT_VIA_SEND_ERROR(self): + self.send_error(204) + + def do_RESETCONTENT_VIA_SEND_ERROR(self): + self.send_error(205) + + def do_NOTMODIFIED_VIA_SEND_ERROR(self): + self.send_error(304) + + def do_SWITCHING_PROTOCOLS_VIA_SEND_ERROR(self): + self.send_error(101) + + def do_PROCESSING_VIA_SEND_ERROR(self): + self.send_error(102) + + def do_HEAD(self): + self.send_error(200) + def setUp(self): BaseTestCase.setUp(self) self.con = httplib.HTTPConnection('localhost', self.PORT) @@ -276,6 +294,63 @@ res = self.con.getresponse() self.assertEqual(res.status, 999) + def test_no_content_via_send_error(self): + self.con.request('NOCONTENT_VIA_SEND_ERROR', '/') + res = self.con.getresponse() + self.assertEqual(204, res.status) + self.assertEqual(None, res.getheader('Content-Length')) + + data = res.read() + self.assertEqual(b'', data) + + def test_reset_content_via_send_error(self): + self.con.request('RESETCONTENT_VIA_SEND_ERROR', '/') + res = self.con.getresponse() + self.assertEqual(205, res.status) + self.assertEqual(None, res.getheader('Content-Length')) + + data = res.read() + self.assertEqual(b'', data) + + def test_not_modified_via_send_error(self): + self.con.request('NOTMODIFIED_VIA_SEND_ERROR', '/') + res = self.con.getresponse() + self.assertEqual(304, res.status) + self.assertEqual(None, res.getheader('Content-Length')) + self.assertEqual(None, res.getheader('Transfer-Encoding')) + + data = res.read() + self.assertEqual(b'', data) + + def test_switching_protocols_via_send_error(self): + self.con.request('SWITCHING_PROTOCOLS_VIA_SEND_ERROR', '/') + res = self.con.getresponse() + self.assertEqual(101, res.status) + self.assertEqual(None, res.getheader('Content-Length')) + self.assertEqual(None, res.getheader('Transfer-Encoding')) + + data = res.read() + self.assertEqual(b'', data) + + def test_processing_via_send_error(self): + self.con.request('PROCESSING_VIA_SEND_ERROR', '/') + res = self.con.getresponse() + self.assertEqual(102, res.status) + self.assertEqual(None, res.getheader('Content-Length')) + self.assertEqual(None, res.getheader('Transfer-Encoding')) + + data = res.read() + self.assertEqual(b'', data) + + def test_head_via_send_error(self): + self.con.request('HEAD', '/') + res = self.con.getresponse() + self.assertEqual(200, res.status) + self.assertEqual(None, res.getheader('Content-Length')) + + data = res.read() + self.assertEqual(b'', data) + class SimpleHTTPServerTestCase(BaseTestCase): class request_handler(NoLogRequestHandler, SimpleHTTPRequestHandler):