]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Add backports.ssl_match_hostname dependency in place of our copy.
authorBen Darnell <ben@bendarnell.com>
Tue, 5 Nov 2013 20:53:51 +0000 (15:53 -0500)
committerBen Darnell <ben@bendarnell.com>
Tue, 5 Nov 2013 21:00:42 +0000 (16:00 -0500)
This function has changed recently and it makes more sense to stop
maintaining a separate copy, even though it does introduce our first
required dependency.

docs/index.rst
maint/requirements.txt
setup.py
tornado/netutil.py

index 61aca470ea4571e8b13c2b183d7c6761c860fe48..9a618af1cb424efd38e3db6cad519b56e6b462ad 100644 (file)
@@ -17,6 +17,13 @@ can scale to tens of thousands of open connections, making it ideal for
 `WebSockets <http://en.wikipedia.org/wiki/WebSocket>`_, and other
 applications that require a long-lived connection to each user.
 
+Upgrade notes
+-------------
+
+As of Tornado 3.2, the `backports.ssl_match_hostname
+<https://pypi.python.org/pypi/backports.ssl_match_hostname>`_ package
+must be installed when running Tornado on Python 2.  This will be
+installed automatically when using ``pip`` or ``easy_install``.
 
 Quick links
 -----------
@@ -78,9 +85,13 @@ copy of the source tarball as well.
 The Tornado source code is `hosted on GitHub
 <https://github.com/facebook/tornado>`_.
 
-**Prerequisites**: Tornado runs on Python 2.6, 2.7, 3.2, and 3.3.  It has
-no strict dependencies outside the Python standard library, although some
-features may require one of the following libraries:
+**Prerequisites**: Tornado runs on Python 2.6, 2.7, 3.2, and 3.3.  On
+Python 2, the `backports.ssl_match_hostname
+<https://pypi.python.org/pypi/backports.ssl_match_hostname>`_ package
+must be installed (This will be installed automatically when using
+``pip`` or ``easy_install``); on Python 3 there are no strict
+dependencies outside the standard library.  Some Tornado features may
+require one of the following optional libraries:
 
 * `unittest2 <https://pypi.python.org/pypi/unittest2>`_ is needed to run
   Tornado's test suite on Python 2.6 (it is unnecessary on more recent
index be94459bb5c9cac5f0b4ce79c9c6d39289274987..18d99731995995182f1bd21ade2630335ceb96d1 100644 (file)
@@ -1,5 +1,8 @@
 # Frozen pip requirements for tools used in the development of tornado
 
+# Tornado's required dependencies
+backports.ssl-match-hostname==3.4.0.2
+
 # Tornado's optional dependencies
 Twisted==13.0.0
 futures==2.1.3
index 1d019fc7cc57c51d897b039ee46c263ef75ef132..5d6032277854b9df6248e8b1dfb375acbed61e21 100644 (file)
--- a/setup.py
+++ b/setup.py
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import distutils.core
 import sys
-# Importing setuptools adds some features like "setup.py develop", but
-# it's optional so swallow the error if it's not there.
+
 try:
+    # Use setuptools if available, for install_requires (among other things).
     import setuptools
+    from setuptools import setup
 except ImportError:
-    pass
+    setuptools = None
+    from distutils.core import setup
 
 try:
     from Cython.Build import cythonize
@@ -33,18 +34,20 @@ kwargs = {}
 version = "3.2.dev2"
 
 with open('README.rst') as f:
-    long_description = f.read()
+    kwargs['long_description'] = f.read()
 
 if cythonize is not None:
-    extensions = cythonize('tornado/speedups.pyx')
-else:
-    extensions = []
+    kwargs['ext_modules'] = cythonize('tornado/speedups.pyx')
+
+if setuptools is not None:
+    # If setuptools is not available, you're on your own for dependencies.
+    if sys.version_info < (3, 2):
+        kwargs['install_requires'] = ['backports.ssl_match_hostname']
 
-distutils.core.setup(
+setuptools.setup(
     name="tornado",
     version=version,
     packages = ["tornado", "tornado.test", "tornado.platform"],
-    ext_modules = extensions,
     package_data = {
         "tornado": ["ca-certificates.crt"],
         # data files need to be listed both here (which determines what gets
@@ -79,6 +82,5 @@ distutils.core.setup(
         'Programming Language :: Python :: Implementation :: CPython',
         'Programming Language :: Python :: Implementation :: PyPy',
         ],
-    long_description=long_description,
     **kwargs
 )
index 9dc8506ebf06a45194e471500992e7e513c3ffb4..21db47557940726effc1bd1f89f91bf658c2d2a2 100644 (file)
@@ -20,7 +20,6 @@ from __future__ import absolute_import, division, print_function, with_statement
 
 import errno
 import os
-import re
 import socket
 import ssl
 import stat
@@ -30,6 +29,13 @@ from tornado.ioloop import IOLoop
 from tornado.platform.auto import set_close_exec
 from tornado.util import Configurable
 
+if hasattr(ssl, 'match_hostname') and hasattr(ssl, 'CertificateError'):  # python 3.2+
+    ssl_match_hostname = ssl.match_hostname
+    SSLCertificateError = ssl.CertificateError
+else:
+    import backports.ssl_match_hostname
+    ssl_match_hostname = backports.ssl_match_hostname.match_hostname
+    SSLCertificateError = backports.ssl_match_hostname.CertificateError
 
 def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128, flags=None):
     """Creates listening sockets bound to the given port and address.
@@ -391,73 +397,3 @@ def ssl_wrap_socket(socket, ssl_options, server_hostname=None, **kwargs):
             return context.wrap_socket(socket, **kwargs)
     else:
         return ssl.wrap_socket(socket, **dict(context, **kwargs))
-
-if hasattr(ssl, 'match_hostname') and hasattr(ssl, 'CertificateError'):  # python 3.2+
-    ssl_match_hostname = ssl.match_hostname
-    SSLCertificateError = ssl.CertificateError
-else:
-    # match_hostname was added to the standard library ssl module in python 3.2.
-    # The following code was backported for older releases and copied from
-    # https://bitbucket.org/brandon/backports.ssl_match_hostname
-    class SSLCertificateError(ValueError):
-        pass
-
-    def _dnsname_to_pat(dn, max_wildcards=1):
-        pats = []
-        for frag in dn.split(r'.'):
-            if frag.count('*') > max_wildcards:
-                # Issue #17980: avoid denials of service by refusing more
-                # than one wildcard per fragment.  A survery of established
-                # policy among SSL implementations showed it to be a
-                # reasonable choice.
-                raise SSLCertificateError(
-                    "too many wildcards in certificate DNS name: " + repr(dn))
-            if frag == '*':
-                # When '*' is a fragment by itself, it matches a non-empty dotless
-                # fragment.
-                pats.append('[^.]+')
-            else:
-                # Otherwise, '*' matches any dotless fragment.
-                frag = re.escape(frag)
-                pats.append(frag.replace(r'\*', '[^.]*'))
-        return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
-
-    def ssl_match_hostname(cert, hostname):
-        """Verify that *cert* (in decoded format as returned by
-        SSLSocket.getpeercert()) matches the *hostname*.  RFC 2818 rules
-        are mostly followed, but IP addresses are not accepted for *hostname*.
-
-        CertificateError is raised on failure. On success, the function
-        returns nothing.
-        """
-        if not cert:
-            raise ValueError("empty or no certificate")
-        dnsnames = []
-        san = cert.get('subjectAltName', ())
-        for key, value in san:
-            if key == 'DNS':
-                if _dnsname_to_pat(value).match(hostname):
-                    return
-                dnsnames.append(value)
-        if not dnsnames:
-            # The subject is only checked when there is no dNSName entry
-            # in subjectAltName
-            for sub in cert.get('subject', ()):
-                for key, value in sub:
-                    # XXX according to RFC 2818, the most specific Common Name
-                    # must be used.
-                    if key == 'commonName':
-                        if _dnsname_to_pat(value).match(hostname):
-                            return
-                        dnsnames.append(value)
-        if len(dnsnames) > 1:
-            raise SSLCertificateError("hostname %r "
-                                      "doesn't match either of %s"
-                                      % (hostname, ', '.join(map(repr, dnsnames))))
-        elif len(dnsnames) == 1:
-            raise SSLCertificateError("hostname %r "
-                                      "doesn't match %r"
-                                      % (hostname, dnsnames[0]))
-        else:
-            raise SSLCertificateError("no appropriate commonName or "
-                                      "subjectAltName fields were found")