This commit is contained in:
Benjamin Peterson 2014-11-23 20:38:13 -06:00
commit 6c22e65773
4 changed files with 24 additions and 21 deletions

View File

@ -839,17 +839,22 @@ supports sending logging messages to a Web server, using either ``GET`` or
``POST`` semantics. ``POST`` semantics.
.. class:: HTTPHandler(host, url, method='GET', secure=False, credentials=None) .. class:: HTTPHandler(host, url, method='GET', secure=False, credentials=None, context=None)
Returns a new instance of the :class:`HTTPHandler` class. The *host* can be Returns a new instance of the :class:`HTTPHandler` class. The *host* can be
of the form ``host:port``, should you need to use a specific port number. of the form ``host:port``, should you need to use a specific port number. If
If no *method* is specified, ``GET`` is used. If *secure* is true, an HTTPS no *method* is specified, ``GET`` is used. If *secure* is true, a HTTPS
connection will be used. If *credentials* is specified, it should be a connection will be used. The *context* parameter may be set to a
2-tuple consisting of userid and password, which will be placed in an HTTP :class:`ssl.SSLContext` instance to configure the SSL settings used for the
HTTPS connection. If *credentials* is specified, it should be a 2-tuple
consisting of userid and password, which will be placed in a HTTP
'Authorization' header using Basic authentication. If you specify 'Authorization' header using Basic authentication. If you specify
credentials, you should also specify secure=True so that your userid and credentials, you should also specify secure=True so that your userid and
password are not passed in cleartext across the wire. password are not passed in cleartext across the wire.
.. versionchanged:: 3.4.3
The *context* parameter was added.
.. method:: mapLogRecord(record) .. method:: mapLogRecord(record)
Provides a dictionary, based on ``record``, which is to be URL-encoded Provides a dictionary, based on ``record``, which is to be URL-encoded

View File

@ -1089,7 +1089,8 @@ class HTTPHandler(logging.Handler):
A class which sends records to a Web server, using either GET or A class which sends records to a Web server, using either GET or
POST semantics. POST semantics.
""" """
def __init__(self, host, url, method="GET", secure=False, credentials=None): def __init__(self, host, url, method="GET", secure=False, credentials=None,
context=None):
""" """
Initialize the instance with the host, the request URL, and the method Initialize the instance with the host, the request URL, and the method
("GET" or "POST") ("GET" or "POST")
@ -1098,11 +1099,15 @@ class HTTPHandler(logging.Handler):
method = method.upper() method = method.upper()
if method not in ["GET", "POST"]: if method not in ["GET", "POST"]:
raise ValueError("method must be GET or POST") raise ValueError("method must be GET or POST")
if not secure and context is not None:
raise ValueError("context parameter only makes sense "
"with secure=True")
self.host = host self.host = host
self.url = url self.url = url
self.method = method self.method = method
self.secure = secure self.secure = secure
self.credentials = credentials self.credentials = credentials
self.context = context
def mapLogRecord(self, record): def mapLogRecord(self, record):
""" """
@ -1122,7 +1127,7 @@ class HTTPHandler(logging.Handler):
import http.client, urllib.parse import http.client, urllib.parse
host = self.host host = self.host
if self.secure: if self.secure:
h = http.client.HTTPSConnection(host) h = http.client.HTTPSConnection(host, context=self.context)
else: else:
h = http.client.HTTPConnection(host) h = http.client.HTTPConnection(host)
url = self.url url = self.url

View File

@ -1663,21 +1663,11 @@ class HTTPHandlerTest(BaseTest):
localhost_cert = os.path.join(here, "keycert.pem") localhost_cert = os.path.join(here, "keycert.pem")
sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
sslctx.load_cert_chain(localhost_cert) sslctx.load_cert_chain(localhost_cert)
# Unfortunately, HTTPHandler doesn't allow us to change the
# SSLContext used by HTTPSConnection, so we have to context = ssl.create_default_context(cafile=localhost_cert)
# monkeypatch. This can be cleaned up if issue 22788 is
# fixed.
old = ssl._create_default_https_context
def restore_handler():
ssl._create_default_https_context = old
self.addCleanup(restore_handler)
def hack_create_ctx():
ctx = old()
ctx.load_verify_locations(localhost_cert)
return ctx
ssl._create_default_https_context = hack_create_ctx
else: else:
sslctx = None sslctx = None
context = None
self.server = server = TestHTTPServer(addr, self.handle_request, self.server = server = TestHTTPServer(addr, self.handle_request,
0.01, sslctx=sslctx) 0.01, sslctx=sslctx)
server.start() server.start()
@ -1685,7 +1675,8 @@ class HTTPHandlerTest(BaseTest):
host = 'localhost:%d' % server.server_port host = 'localhost:%d' % server.server_port
secure_client = secure and sslctx secure_client = secure and sslctx
self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob', self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob',
secure=secure_client) secure=secure_client,
context=context)
self.log_data = None self.log_data = None
root_logger.addHandler(self.h_hdlr) root_logger.addHandler(self.h_hdlr)

View File

@ -191,6 +191,8 @@ Core and Builtins
Library Library
------- -------
- Issue #22788: Add *context* parameter to logging.handlers.HTTPHandler.
- Issue #22921: Allow SSLContext to take the *hostname* parameter even if - Issue #22921: Allow SSLContext to take the *hostname* parameter even if
OpenSSL doesn't support SNI. OpenSSL doesn't support SNI.