From 438b976b8da7cfc4b74b4e7a14274ecd720b4f3d Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sun, 15 Feb 2015 18:23:19 -0500 Subject: [PATCH] Reuse a global SSLContext by default in simple_httpclient --- tornado/iostream.py | 24 +----------------------- tornado/netutil.py | 22 ++++++++++++++++++++++ tornado/simple_httpclient.py | 9 ++++++++- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/tornado/iostream.py b/tornado/iostream.py index 2a6e455f5..b97131829 100644 --- a/tornado/iostream.py +++ b/tornado/iostream.py @@ -26,7 +26,6 @@ Contents: from __future__ import absolute_import, division, print_function, with_statement -import certifi import collections import errno import numbers @@ -38,7 +37,7 @@ import re from tornado.concurrent import TracebackFuture from tornado import ioloop from tornado.log import gen_log, app_log -from tornado.netutil import ssl_wrap_socket, ssl_match_hostname, SSLCertificateError +from tornado.netutil import ssl_wrap_socket, ssl_match_hostname, SSLCertificateError, _client_ssl_defaults, _server_ssl_defaults from tornado import stack_context from tornado.util import errno_from_exception @@ -83,27 +82,6 @@ _ERRNO_INPROGRESS = (errno.EINPROGRESS,) if hasattr(errno, "WSAEINPROGRESS"): _ERRNO_INPROGRESS += (errno.WSAEINPROGRESS,) -if hasattr(ssl, 'SSLContext'): - if hasattr(ssl, 'create_default_context'): - # Python 2.7.9+, 3.4+ - # Note that the naming of ssl.Purpose is confusing; the purpose - # of a context is to authentiate the opposite side of the connection. - _client_ssl_defaults = ssl.create_default_context( - ssl.Purpose.SERVER_AUTH) - _server_ssl_defaults = ssl.create_default_context( - ssl.Purpose.CLIENT_AUTH) - else: - # Python 3.2-3.3 - _client_ssl_defaults = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - _client_ssl_defaults.verify_mode = ssl.CERT_REQUIRED - _client_ssl_defaults.load_verify_locations(certifi.where()) - _server_ssl_defaults = ssl.SSLContext(ssl.PROTOCOL_SSLv23) -else: - # Python 2.6-2.7.8 - _client_ssl_defaults = dict(cert_reqs=ssl.CERT_REQUIRED, - ca_certs=certifi.where()) - _ssl_server_defaults = {} - class StreamClosedError(IOError): """Exception raised by `IOStream` methods when the stream is closed. diff --git a/tornado/netutil.py b/tornado/netutil.py index 426b85950..1a07e942a 100644 --- a/tornado/netutil.py +++ b/tornado/netutil.py @@ -18,6 +18,7 @@ from __future__ import absolute_import, division, print_function, with_statement +import certifi import errno import os import sys @@ -50,6 +51,27 @@ else: ssl_match_hostname = backports.ssl_match_hostname.match_hostname SSLCertificateError = backports.ssl_match_hostname.CertificateError +if hasattr(ssl, 'SSLContext'): + if hasattr(ssl, 'create_default_context'): + # Python 2.7.9+, 3.4+ + # Note that the naming of ssl.Purpose is confusing; the purpose + # of a context is to authentiate the opposite side of the connection. + _client_ssl_defaults = ssl.create_default_context( + ssl.Purpose.SERVER_AUTH) + _server_ssl_defaults = ssl.create_default_context( + ssl.Purpose.CLIENT_AUTH) + else: + # Python 3.2-3.3 + _client_ssl_defaults = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + _client_ssl_defaults.verify_mode = ssl.CERT_REQUIRED + _client_ssl_defaults.load_verify_locations(certifi.where()) + _server_ssl_defaults = ssl.SSLContext(ssl.PROTOCOL_SSLv23) +else: + # Python 2.6-2.7.8 + _client_ssl_defaults = dict(cert_reqs=ssl.CERT_REQUIRED, + ca_certs=certifi.where()) + _server_ssl_defaults = {} + # ThreadedResolver runs getaddrinfo on a thread. If the hostname is unicode, # getaddrinfo attempts to import encodings.idna. If this is done at # module-import time, the import lock is already held by the main thread, diff --git a/tornado/simple_httpclient.py b/tornado/simple_httpclient.py index ed9f7387e..bb080af97 100644 --- a/tornado/simple_httpclient.py +++ b/tornado/simple_httpclient.py @@ -7,7 +7,7 @@ from tornado.httpclient import HTTPResponse, HTTPError, AsyncHTTPClient, main, _ from tornado import httputil from tornado.http1connection import HTTP1Connection, HTTP1ConnectionParameters from tornado.iostream import StreamClosedError -from tornado.netutil import Resolver, OverrideResolver +from tornado.netutil import Resolver, OverrideResolver, _client_ssl_defaults from tornado.log import gen_log from tornado import stack_context from tornado.tcpclient import TCPClient @@ -222,6 +222,13 @@ class _HTTPConnection(httputil.HTTPMessageDelegate): if scheme == "https": if self.request.ssl_options is not None: return self.request.ssl_options + # If we are using the defaults, don't construct a + # new SSLContext. + if (self.request.validate_cert and + self.request.ca_certs is None and + self.request.client_cert is None and + self.request.client_key is None): + return _client_ssl_defaults ssl_options = {} if self.request.validate_cert: ssl_options["cert_reqs"] = ssl.CERT_REQUIRED -- 2.47.2