diff --git a/Lib/http/client.py b/Lib/http/client.py index 5aa178d7b1..1859fa299d 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -72,6 +72,7 @@ import email.parser import email.message import http import io +import logging import re import socket import collections.abc @@ -145,6 +146,9 @@ _is_illegal_header_value = re.compile(rb'\n(?![ \t])|\r(?![ \t\n])').search _METHODS_EXPECTING_BODY = {'PATCH', 'POST', 'PUT'} +LOGGER = logging.getLogger(__name__) + + def _encode(data, name='data'): """Call data.encode("latin-1") but show a better error message.""" try: @@ -257,8 +261,7 @@ class HTTPResponse(io.BufferedIOBase): line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") if len(line) > _MAXLINE: raise LineTooLong("status line") - if self.debuglevel > 0: - print("reply:", repr(line)) + LOGGER.debug(f"reply: {line!r}") if not line: # Presumably, the server closed the connection before # sending a valid response. @@ -304,8 +307,7 @@ class HTTPResponse(io.BufferedIOBase): skip = skip.strip() if not skip: break - if self.debuglevel > 0: - print("header:", skip) + LOGGER.debug(f"header: {skip}") self.code = self.status = status self.reason = reason.strip() @@ -319,9 +321,8 @@ class HTTPResponse(io.BufferedIOBase): self.headers = self.msg = parse_headers(self.fp) - if self.debuglevel > 0: - for hdr in self.headers: - print("header:", hdr + ":", self.headers.get(hdr)) + for hdr in self.headers: + LOGGER.debug(f"header: {hdr}: {self.headers.get(hdr)}") # are we using the chunked-style of transfer encoding? tr_enc = self.headers.get("transfer-encoding") @@ -339,7 +340,7 @@ class HTTPResponse(io.BufferedIOBase): self.length = None length = self.headers.get("content-length") - # are we using the chunked-style of transfer encoding? + # are we using the chunked-style of transfer encoding? tr_enc = self.headers.get("transfer-encoding") if length and not self.chunked: try: @@ -919,8 +920,7 @@ class HTTPConnection: if line in (b'\r\n', b'\n', b''): break - if self.debuglevel > 0: - print('header:', line.decode()) + LOGGER.debug("header: " + line.decode()) def connect(self): """Connect to the host and port specified in __init__.""" @@ -957,14 +957,12 @@ class HTTPConnection: else: raise NotConnected() - if self.debuglevel > 0: - print("send:", repr(data)) + LOGGER.debug(f"send: {data!r}") if hasattr(data, "read") : - if self.debuglevel > 0: - print("sendIng a read()able") + LOGGER.debug("sendIng a read()able") encode = self._is_textIO(data) - if encode and self.debuglevel > 0: - print("encoding file using iso-8859-1") + if encode: + LOGGER.debug("encoding file using iso-8859-1") while 1: datablock = data.read(self.blocksize) if not datablock: @@ -991,11 +989,10 @@ class HTTPConnection: self._buffer.append(s) def _read_readable(self, readable): - if self.debuglevel > 0: - print("sendIng a read()able") + LOGGER.debug("sendIng a read()able") encode = self._is_textIO(readable) - if encode and self.debuglevel > 0: - print("encoding file using iso-8859-1") + if encode: + LOGGER.debug("encoding file using iso-8859-1") while True: datablock = readable.read(self.blocksize) if not datablock: @@ -1044,8 +1041,7 @@ class HTTPConnection: for chunk in chunks: if not chunk: - if self.debuglevel > 0: - print('Zero length chunk ignored') + # LOGGER.debug("Zero length chunk ignored") continue if encode_chunked and self._http_vsn == 11: @@ -1257,8 +1253,7 @@ class HTTPConnection: content_length = self._get_content_length(body, method) if content_length is None: if body is not None: - if self.debuglevel > 0: - print('Unable to determine size of %r' % body) + LOGGER.debug(f"Unable to determine size of {body!r}") encode_chunked = True self.putheader('Transfer-Encoding', 'chunked') else: diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index f816eac83b..7cfba12142 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -8,7 +8,7 @@ import socket import threading import unittest -TestCase = unittest.TestCase +from unittest import mock, TestCase from test import support @@ -344,7 +344,8 @@ class HeaderTests(TestCase): with self.assertRaisesRegex(ValueError, 'Invalid header'): conn.putheader(name, value) - def test_headers_debuglevel(self): + @mock.patch('http.client.LOGGER') + def test_headers_debuglevel(self, m_log): body = ( b'HTTP/1.1 200 OK\r\n' b'First: val\r\n' @@ -352,12 +353,15 @@ class HeaderTests(TestCase): ) sock = FakeSocket(body) resp = client.HTTPResponse(sock, debuglevel=1) - with support.captured_stdout() as output: - resp.begin() - lines = output.getvalue().splitlines() - self.assertEqual(lines[0], "reply: 'HTTP/1.1 200 OK\\r\\n'") - self.assertEqual(lines[1], "header: First: val") - self.assertEqual(lines[2], "header: Second: val") + resp.begin() + self.assertEqual( + m_log.debug.call_args_list, + [ + mock.call("reply: 'HTTP/1.1 200 OK\\r\\n'"), + mock.call("header: First: val"), + mock.call("header: Second: val") + ] + ) class TransferEncodingTest(TestCase): @@ -1920,7 +1924,8 @@ class TunnelTests(TestCase): self.assertIn(b'CONNECT destination.com', self.conn.sock.data) self.assertIn(b'Host: destination.com', self.conn.sock.data) - def test_tunnel_debuglog(self): + @mock.patch('http.client.LOGGER') + def test_tunnel_debuglog(self, m_log): expected_header = 'X-Dummy: 1' response_text = 'HTTP/1.0 200 OK\r\n{}\r\n\r\n'.format(expected_header) @@ -1928,10 +1933,11 @@ class TunnelTests(TestCase): self.conn._create_connection = self._create_connection(response_text) self.conn.set_tunnel('destination.com') - with support.captured_stdout() as output: - self.conn.request('PUT', '/', '') - lines = output.getvalue().splitlines() - self.assertIn('header: {}'.format(expected_header), lines) + self.conn.request('PUT', '/', '') + self.assertIn( + mock.call('header: {}\r\n'.format(expected_header)), + m_log.debug.call_args_list + ) if __name__ == '__main__': diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index f7232f67ee..90ffa7fcfb 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1861,9 +1861,7 @@ class HTTPHandlerTest(BaseTest): def test_output(self): # The log message sent to the HTTPHandler is properly received. - logger = logging.getLogger("http") - root_logger = self.root_logger - root_logger.removeHandler(self.root_logger.handlers[0]) + logger = logging.getLogger("httplogger") for secure in (False, True): addr = ('localhost', 0) if secure: @@ -1892,7 +1890,7 @@ class HTTPHandlerTest(BaseTest): context=context, credentials=('foo', 'bar')) self.log_data = None - root_logger.addHandler(self.h_hdlr) + logger.addHandler(self.h_hdlr) for method in ('GET', 'POST'): self.h_hdlr.method = method @@ -1906,12 +1904,12 @@ class HTTPHandlerTest(BaseTest): d = parse_qs(self.log_data.query) else: d = parse_qs(self.post_data.decode('utf-8')) - self.assertEqual(d['name'], ['http']) + self.assertEqual(d['name'], ['httplogger']) self.assertEqual(d['funcName'], ['test_output']) self.assertEqual(d['msg'], [msg]) self.server.stop(2.0) - self.root_logger.removeHandler(self.h_hdlr) + logger.removeHandler(self.h_hdlr) self.h_hdlr.close() class MemoryTest(BaseTest):