diff -r 2a14385710dc Doc/library/http.server.rst --- a/Doc/library/http.server.rst Tue Nov 22 01:25:55 2016 -0500 +++ b/Doc/library/http.server.rst Tue Nov 22 16:06:10 2016 +0800 @@ -221,8 +221,9 @@ Adds the HTTP header to an internal buffer which will be written to the output stream when either :meth:`end_headers` or :meth:`flush_headers` is invoked. *keyword* should specify the header keyword, with *value* - specifying its value. Note that, after the send_header calls are done, - :meth:`end_headers` MUST BE called in order to complete the operation. + specifying its value. *keyword* and *value* should both be :class:`str`. + Note that, after the send_header calls are done, :meth:`end_headers` + MUST BE called in order to complete the operation. .. versionchanged:: 3.2 Headers are stored in an internal buffer. diff -r 2a14385710dc Lib/http/server.py --- a/Lib/http/server.py Tue Nov 22 01:25:55 2016 -0500 +++ b/Lib/http/server.py Tue Nov 22 16:06:10 2016 +0800 @@ -469,7 +469,7 @@ }) body = content.encode('UTF-8', 'replace') self.send_header("Content-Type", self.error_content_type) - self.send_header('Content-Length', int(len(body))) + self.send_header('Content-Length', str(len(body))) self.end_headers() if self.command != 'HEAD' and body: diff -r 2a14385710dc Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py Tue Nov 22 01:25:55 2016 -0500 +++ b/Lib/test/test_httpservers.py Tue Nov 22 16:06:10 2016 +0800 @@ -235,6 +235,7 @@ self.assertEqual(res.read(), 'Ärger mit Unicode'.encode('utf-8')) def test_error_content_length(self): + from unittest import mock # Issue #16088: standard error responses should have a content-length self.con.request('NOTFOUND', '/') res = self.con.getresponse() @@ -243,6 +244,22 @@ data = res.read() self.assertEqual(int(res.getheader('Content-Length')), len(data)) + # Issue #27414: Content-Length value should be of type str instead of int + with mock.patch.object( + self.request_handler, 'send_header') as mock_send_header: + self.con.request('NOTFOUND', '/', headers={'Connection': 'close'}) + res = self.con.getresponse() + self.assertEqual(res.status, HTTPStatus.NOT_FOUND) + + for args in mock_send_header.call_args_list: + # there must be a Content-Length or the test above will fail + if args[0][0] == 'Content-Length': + value = args[0][1] + self.assertIsInstance(value, str) + + data = res.read() + self.assertEqual(int(value), len(data)) + def test_send_error(self): allow_transfer_encoding_codes = (HTTPStatus.NOT_MODIFIED, HTTPStatus.RESET_CONTENT)