Commit 0996f427 authored by Jason Madden's avatar Jason Madden Committed by GitHub

Merge pull request #1132 from gevent/update-3.7.0b2

Update to 3.7.0b2
parents e97ed2aa 88e772ca
...@@ -17,10 +17,10 @@ env: ...@@ -17,10 +17,10 @@ env:
matrix: matrix:
# These are ordered to get as much diversity in the # These are ordered to get as much diversity in the
# first group of parallel runs (4) as posible # first group of parallel runs (4) as posible
- TASK=test-py37
- TASK=test-py27 - TASK=test-py27
- TASK=test-pypy - TASK=test-pypy
- TASK=test-py36 - TASK=test-py36
- TASK=test-py37
- TASK=test-py27-noembed - TASK=test-py27-noembed
- TASK=test-pypy3 - TASK=test-pypy3
- TASK=test-py35 - TASK=test-py35
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
- The internal, undocumented class ``gevent._socket3._fileobject`` has - The internal, undocumented class ``gevent._socket3._fileobject`` has
been removed. See :issue:`1084`. been removed. See :issue:`1084`.
- Travis CI tests on Python 3.7.0b1 and PyPy 2.7 5.10.0 and PyPy 3.5 - Travis CI tests on Python 3.7.0b2 and PyPy 2.7 5.10.0 and PyPy 3.5
5.10.1. 5.10.1.
- Support the ``capture_output`` argument added to Python 3.7 in - Support the ``capture_output`` argument added to Python 3.7 in
......
...@@ -108,7 +108,7 @@ leaktest: test_prelim ...@@ -108,7 +108,7 @@ leaktest: test_prelim
@${PYTHON} scripts/travis.py fold_end default @${PYTHON} scripts/travis.py fold_end default
bench: bench:
${PYTHON} benchmarks/bench_sendall.py --loops 3 --processes 2 --values 2 --warmups 2 ${PYTHON} benchmarks/bench_sendall.py --loops 3 --processes 2 --values 2 --warmups 2 --quiet
travis_test_linters: travis_test_linters:
make lint make lint
...@@ -131,7 +131,7 @@ PY27=$(BUILD_RUNTIMES)/snakepit/python2.7.14 ...@@ -131,7 +131,7 @@ PY27=$(BUILD_RUNTIMES)/snakepit/python2.7.14
PY34=$(BUILD_RUNTIMES)/snakepit/python3.4.7 PY34=$(BUILD_RUNTIMES)/snakepit/python3.4.7
PY35=$(BUILD_RUNTIMES)/snakepit/python3.5.4 PY35=$(BUILD_RUNTIMES)/snakepit/python3.5.4
PY36=$(BUILD_RUNTIMES)/snakepit/python3.6.4 PY36=$(BUILD_RUNTIMES)/snakepit/python3.6.4
PY37=$(BUILD_RUNTIMES)/snakepit/python3.7.0b1 PY37=$(BUILD_RUNTIMES)/snakepit/python3.7.0b2
PYPY=$(BUILD_RUNTIMES)/snakepit/pypy5100 PYPY=$(BUILD_RUNTIMES)/snakepit/pypy5100
PYPY3=$(BUILD_RUNTIMES)/snakepit/pypy3.5_5101 PYPY3=$(BUILD_RUNTIMES)/snakepit/pypy3.5_5101
...@@ -180,6 +180,7 @@ develop: ...@@ -180,6 +180,7 @@ develop:
# We need wheel>=0.26 on Python 3.5. See previous revisions. # We need wheel>=0.26 on Python 3.5. See previous revisions.
time ${PYTHON} -m pip install -U -r ci-requirements.txt time ${PYTHON} -m pip install -U -r ci-requirements.txt
GEVENTSETUP_EV_VERIFY=3 time ${PYTHON} -m pip install -U -e . GEVENTSETUP_EV_VERIFY=3 time ${PYTHON} -m pip install -U -e .
${PYTHON} -m pip freeze
ccache -s ccache -s
@${PYTHON} scripts/travis.py fold_end install @${PYTHON} scripts/travis.py fold_end install
...@@ -196,7 +197,7 @@ test-py36: $(PY36) ...@@ -196,7 +197,7 @@ test-py36: $(PY36)
PYTHON=python3.6.4 PATH=$(BUILD_RUNTIMES)/versions/python3.6.4/bin:$(PATH) make develop allbackendtest PYTHON=python3.6.4 PATH=$(BUILD_RUNTIMES)/versions/python3.6.4/bin:$(PATH) make develop allbackendtest
test-py37: $(PY37) test-py37: $(PY37)
LD_LIBRARY_PATH=$(BUILD_RUNTIMES)/versions/python3.7.0b1/openssl/lib PYTHON=python3.7.0b1 PATH=$(BUILD_RUNTIMES)/versions/python3.7.0b1/bin:$(PATH) make develop allbackendtest LD_LIBRARY_PATH=$(BUILD_RUNTIMES)/versions/python3.7.0b2/openssl/lib PYTHON=python3.7.0b2 PATH=$(BUILD_RUNTIMES)/versions/python3.7.0b2/bin:$(PATH) make develop allbackendtest
test-pypy: $(PYPY) test-pypy: $(PYPY)
PYTHON=$(PYPY) PATH=$(BUILD_RUNTIMES)/versions/pypy5100/bin:$(PATH) make develop cffibackendtest PYTHON=$(PYPY) PATH=$(BUILD_RUNTIMES)/versions/pypy5100/bin:$(PATH) make develop cffibackendtest
......
...@@ -16,7 +16,7 @@ prospector[with_pyroma] ; python_version < '3.7' ...@@ -16,7 +16,7 @@ prospector[with_pyroma] ; python_version < '3.7'
coverage>=4.0 coverage>=4.0
coveralls>=1.0 coveralls>=1.0
# See version requirements in setup.py # See version requirements in setup.py
cffi ; platform_python_implementation == "CPython" cffi >= 1.11.5 ; platform_python_implementation == "CPython"
futures futures
dnspython dnspython
idna idna
......
...@@ -49,7 +49,7 @@ PYENV=$BASE/pyenv ...@@ -49,7 +49,7 @@ PYENV=$BASE/pyenv
# The file for 3.7b1 shipped with pyenv on Feb 6 2018 # The file for 3.7b1 shipped with pyenv on Feb 6 2018
# won't compile on Travis. So we use a forked version that # won't compile on Travis. So we use a forked version that
# compiles openssl for us. # compiles openssl for us. We also beat them to the punch for 3.7b2
# https://github.com/travis-ci/travis-ci/issues/9069 # https://github.com/travis-ci/travis-ci/issues/9069
if [ ! -d "$PYENV/.git" ]; then if [ ! -d "$PYENV/.git" ]; then
...@@ -104,7 +104,7 @@ for var in "$@"; do ...@@ -104,7 +104,7 @@ for var in "$@"; do
install 3.6.4 python3.6.4 install 3.6.4 python3.6.4
;; ;;
3.7) 3.7)
install 3.7.0b1 python3.7.0b1 install 3.7.0b2 python3.7.0b2
;; ;;
pypy) pypy)
install pypy2.7-5.10.0 pypy5100 install pypy2.7-5.10.0 pypy5100
......
...@@ -208,7 +208,10 @@ class AbstractCallbacks(object): ...@@ -208,7 +208,10 @@ class AbstractCallbacks(object):
watcher.loop.handle_error(None, t, v, tb) watcher.loop.handle_error(None, t, v, tb)
return 1 return 1
else: else:
raise v # Raising it causes a lot of noise from CFFI
print("WARNING: gevent: Unhandled error with no watcher",
file=sys.stderr)
traceback.print_exception(t, v, tb)
def python_stop(self, handle): def python_stop(self, handle):
if not handle: # pragma: no cover if not handle: # pragma: no cover
...@@ -220,8 +223,7 @@ class AbstractCallbacks(object): ...@@ -220,8 +223,7 @@ class AbstractCallbacks(object):
# NOTE: Raising exceptions here does nothing, they're swallowed by CFFI. # NOTE: Raising exceptions here does nothing, they're swallowed by CFFI.
# Since the C level passed in a null pointer, even dereferencing the handle # Since the C level passed in a null pointer, even dereferencing the handle
# will just produce some exceptions. # will just produce some exceptions.
if GEVENT_DEBUG_LEVEL < CRITICAL: return
return
_dbg("python_stop: stopping watcher with handle", handle) _dbg("python_stop: stopping watcher with handle", handle)
watcher = self.from_handle(handle) watcher = self.from_handle(handle)
watcher.stop() watcher.stop()
......
...@@ -10,17 +10,26 @@ from __future__ import absolute_import ...@@ -10,17 +10,26 @@ from __future__ import absolute_import
import io import io
import os import os
import sys import sys
import time
from gevent import _socketcommon from gevent import _socketcommon
from gevent._util import copy_globals from gevent._util import copy_globals
from gevent._compat import PYPY from gevent._compat import PYPY
import _socket import _socket
from os import dup from os import dup
copy_globals(_socketcommon, globals(), copy_globals(_socketcommon, globals(),
names_to_ignore=_socketcommon.__extensions__, names_to_ignore=_socketcommon.__extensions__,
dunder_names_to_keep=()) dunder_names_to_keep=())
try:
from errno import EHOSTUNREACH
from errno import ECONNREFUSED
except ImportError:
EHOSTUNREACH = -1
ECONNREFUSED = -1
__socket__ = _socketcommon.__socket__ __socket__ = _socketcommon.__socket__
__implements__ = _socketcommon._implements __implements__ = _socketcommon._implements
__extensions__ = _socketcommon.__extensions__ __extensions__ = _socketcommon.__extensions__
...@@ -337,11 +346,25 @@ class socket(object): ...@@ -337,11 +346,25 @@ class socket(object):
if err: if err:
raise error(err, strerror(err)) raise error(err, strerror(err))
result = _socket.socket.connect_ex(self._sock, address) result = _socket.socket.connect_ex(self._sock, address)
if not result or result == EISCONN: if not result or result == EISCONN:
break break
elif (result in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or (result == EINVAL and is_windows): elif (result in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or (result == EINVAL and is_windows):
self._wait(self._write_event) self._wait(self._write_event)
else: else:
if (isinstance(address, tuple)
and address[0] == 'fe80::1'
and result == EHOSTUNREACH):
# On Python 3.7 on mac, we see EHOSTUNREACH
# returned for this link-local address, but it really is
# supposed to be ECONNREFUSED according to the standard library
# tests (test_socket.NetworkConnectionNoServer.test_create_connection)
# (On previous versions, that code passed the '127.0.0.1' IPv4 address, so
# ipv6 link locals were never a factor; 3.7 passes 'localhost'.)
# It is something of a mystery how the stdlib socket code doesn't
# produce EHOSTUNREACH---I (JAM) can't see how socketmodule.c would avoid
# that. The normal connect just calls connect_ex much like we do.
result = ECONNREFUSED
raise error(result, strerror(result)) raise error(result, strerror(result))
def connect_ex(self, address): def connect_ex(self, address):
......
...@@ -157,15 +157,15 @@ def wait(io, timeout=None, timeout_exc=_NONE): ...@@ -157,15 +157,15 @@ def wait(io, timeout=None, timeout_exc=_NONE):
""" """
if io.callback is not None: if io.callback is not None:
raise ConcurrentObjectUseError('This socket is already used by another greenlet: %r' % (io.callback, )) raise ConcurrentObjectUseError('This socket is already used by another greenlet: %r' % (io.callback, ))
if timeout is not None: timeout = Timeout._start_new_or_dummy(
timeout_exc = timeout_exc if timeout_exc is not _NONE else _timeout_error('timed out') timeout,
timeout = Timeout.start_new(timeout, timeout_exc) (timeout_exc
if timeout_exc is not _NONE or timeout is None
else _timeout_error('timed out')))
try:
with timeout:
return get_hub().wait(io) return get_hub().wait(io)
finally:
if timeout is not None:
timeout.cancel()
# rename "io" to "watcher" because wait() works with any watcher # rename "io" to "watcher" because wait() works with any watcher
......
...@@ -87,6 +87,16 @@ class SSLContext(orig_SSLContext): ...@@ -87,6 +87,16 @@ class SSLContext(orig_SSLContext):
def verify_mode(self, value): def verify_mode(self, value):
super(orig_SSLContext, orig_SSLContext).verify_mode.__set__(self, value) super(orig_SSLContext, orig_SSLContext).verify_mode.__set__(self, value)
if hasattr(orig_SSLContext, 'minimum_version'):
# Like the above, added in 3.7
@orig_SSLContext.minimum_version.setter
def minimum_version(self, value):
super(orig_SSLContext, orig_SSLContext).minimum_version.__set__(self, value)
@orig_SSLContext.maximum_version.setter
def maximum_version(self, value):
super(orig_SSLContext, orig_SSLContext).maximum_version.__set__(self, value)
class _contextawaresock(socket._gevent_sock_class): # Python 2: pylint:disable=slots-on-old-class class _contextawaresock(socket._gevent_sock_class): # Python 2: pylint:disable=slots-on-old-class
# We have to pass the raw stdlib socket to SSLContext.wrap_socket. # We have to pass the raw stdlib socket to SSLContext.wrap_socket.
...@@ -127,6 +137,23 @@ class _contextawaresock(socket._gevent_sock_class): # Python 2: pylint:disable=s ...@@ -127,6 +137,23 @@ class _contextawaresock(socket._gevent_sock_class): # Python 2: pylint:disable=s
pass pass
raise AttributeError(name) raise AttributeError(name)
try:
_SSLObject_factory = SSLObject
except NameError:
# 3.4 and below do not have SSLObject, something
# we magically import through copy_globals
pass
else:
if hasattr(SSLObject, '_create'):
# 3.7 is making thing difficult and won't let you
# actually construct an object
def _SSLObject_factory(sslobj, owner=None, session=None):
s = SSLObject.__new__(SSLObject)
s._sslobj = sslobj
s._sslobj.owner = owner or s
if session is not None:
s._sslobj.session = session
return s
class SSLSocket(socket): class SSLSocket(socket):
""" """
...@@ -224,8 +251,9 @@ class SSLSocket(socket): ...@@ -224,8 +251,9 @@ class SSLSocket(socket):
try: try:
self._sslobj = self._context._wrap_socket(self._sock, server_side, self._sslobj = self._context._wrap_socket(self._sock, server_side,
server_hostname) server_hostname)
if _session is not None: # 3.6 if _session is not None: # 3.6+
self._sslobj = SSLObject(self._sslobj, owner=self, session=self._session) self._sslobj = _SSLObject_factory(self._sslobj, owner=self,
session=self._session)
if do_handshake_on_connect: if do_handshake_on_connect:
timeout = self.gettimeout() timeout = self.gettimeout()
if timeout == 0.0: if timeout == 0.0:
...@@ -585,8 +613,8 @@ class SSLSocket(socket): ...@@ -585,8 +613,8 @@ class SSLSocket(socket):
if self._connected: if self._connected:
raise ValueError("attempt to connect already-connected SSLSocket!") raise ValueError("attempt to connect already-connected SSLSocket!")
self._sslobj = self._context._wrap_socket(self._sock, False, self.server_hostname) self._sslobj = self._context._wrap_socket(self._sock, False, self.server_hostname)
if self._session is not None: # 3.6 if self._session is not None: # 3.6+
self._sslobj = SSLObject(self._sslobj, owner=self, session=self._session) self._sslobj = _SSLObject_factory(self._sslobj, owner=self, session=self._session)
try: try:
if connect_ex: if connect_ex:
rc = socket.connect_ex(self, addr) rc = socket.connect_ex(self, addr)
...@@ -629,6 +657,9 @@ class SSLSocket(socket): ...@@ -629,6 +657,9 @@ class SSLSocket(socket):
if the requested `cb_type` is not supported. Return bytes of the data if the requested `cb_type` is not supported. Return bytes of the data
or None if the data is not available (e.g. before the handshake). or None if the data is not available (e.g. before the handshake).
""" """
if hasattr(self._sslobj, 'get_channel_binding'):
# 3.7+, and sslobj is not None
return self._sslobj.get_channel_binding(cb_type)
if cb_type not in CHANNEL_BINDING_TYPES: if cb_type not in CHANNEL_BINDING_TYPES:
raise ValueError("Unsupported channel binding type") raise ValueError("Unsupported channel binding type")
if cb_type != "tls-unique": if cb_type != "tls-unique":
......
...@@ -100,8 +100,7 @@ class _AbstractLinkable(object): ...@@ -100,8 +100,7 @@ class _AbstractLinkable(object):
switch = getcurrent().switch switch = getcurrent().switch
self.rawlink(switch) self.rawlink(switch)
try: try:
timer = Timeout._start_new_or_dummy(timeout) with Timeout._start_new_or_dummy(timeout) as timer:
try:
try: try:
result = self.hub.switch() result = self.hub.switch()
if result is not self: # pragma: no cover if result is not self: # pragma: no cover
...@@ -113,8 +112,6 @@ class _AbstractLinkable(object): ...@@ -113,8 +112,6 @@ class _AbstractLinkable(object):
# test_set_and_clear and test_timeout in test_threading # test_set_and_clear and test_timeout in test_threading
# rely on the exact return values, not just truthish-ness # rely on the exact return values, not just truthish-ness
return False return False
finally:
timer.close()
finally: finally:
self.unlink(switch) self.unlink(switch)
......
...@@ -164,6 +164,8 @@ typedef struct uv_fs_event_s uv_fs_event_t; ...@@ -164,6 +164,8 @@ typedef struct uv_fs_event_s uv_fs_event_t;
typedef struct uv_fs_poll_s uv_fs_poll_t; typedef struct uv_fs_poll_s uv_fs_poll_t;
size_t uv_handle_size(uv_handle_type);
// callbacks with the same signature // callbacks with the same signature
// XXX: Note that these, and all callbacks, are defined to take // XXX: Note that these, and all callbacks, are defined to take
// a void* or handle* instead of the more specific, correct, // a void* or handle* instead of the more specific, correct,
...@@ -338,6 +340,8 @@ int uv_fs_poll_start(void*, uv_fs_poll_cb, const char* path, unsigned int); ...@@ -338,6 +340,8 @@ int uv_fs_poll_start(void*, uv_fs_poll_cb, const char* path, unsigned int);
int uv_fs_poll_stop(void*); int uv_fs_poll_stop(void*);
/* Standard library */
void* memset(void *b, int c, size_t len);
/* gevent callbacks */ /* gevent callbacks */
......
#include <string.h>
#include "uv.h" #include "uv.h"
static int python_callback(void* handle, int revents); static int python_callback(void* handle, int revents);
......
...@@ -120,7 +120,7 @@ class watcher(_base.watcher): ...@@ -120,7 +120,7 @@ class watcher(_base.watcher):
# Instead, this is arranged as a callback to GC when the # Instead, this is arranged as a callback to GC when the
# watcher class dies. Obviously it's important to keep the ffi # watcher class dies. Obviously it's important to keep the ffi
# watcher alive. # watcher alive.
_dbg("Request to close handle", ffi_watcher) _dbg("Request to close handle", ffi.cast('void*', ffi_watcher), ffi_watcher)
# We can pass in "subclasses" if uv_handle_t that line up at the C level, # We can pass in "subclasses" if uv_handle_t that line up at the C level,
# but that don't in CFFI without a cast. But be careful what we use the cast # but that don't in CFFI without a cast. But be careful what we use the cast
# for, don't pass it back to C. # for, don't pass it back to C.
...@@ -729,12 +729,16 @@ class OneShotCheck(check): ...@@ -729,12 +729,16 @@ class OneShotCheck(check):
_watcher_skip_ffi = True _watcher_skip_ffi = True
def __make_cb(self, func):
stop = self.stop
@functools.wraps(func)
def cb(*args):
stop()
return func(*args)
return cb
def start(self, callback, *args): def start(self, callback, *args):
@functools.wraps(callback) return check.start(self, self.__make_cb(callback), *args)
def _callback(*args):
self.stop()
return callback(*args)
return check.start(self, _callback, *args)
class prepare(_base.PrepareMixin, watcher): class prepare(_base.PrepareMixin, watcher):
pass pass
...@@ -75,7 +75,7 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N ...@@ -75,7 +75,7 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N
host, port = address host, port = address
# getaddrinfo is documented as returning a list, but our interface # getaddrinfo is documented as returning a list, but our interface
# is pluggable, so be sure it does. # is pluggable, so be sure it does.
addrs = list(getaddrinfo(host, port, 0 if has_ipv6 else AF_INET, SOCK_STREAM)) addrs = list(getaddrinfo(host, port, 0, SOCK_STREAM))
if not addrs: if not addrs:
raise error("getaddrinfo returns an empty list") raise error("getaddrinfo returns an empty list")
......
...@@ -312,6 +312,8 @@ if ssl is not None: ...@@ -312,6 +312,8 @@ if ssl is not None:
def secure_connection(self): def secure_connection(self):
context = ssl.SSLContext() context = ssl.SSLContext()
# TODO: fix TLSv1.3 support
context.options |= ssl.OP_NO_TLSv1_3
context.load_cert_chain(CERTFILE) context.load_cert_chain(CERTFILE)
socket = context.wrap_socket(self.socket, socket = context.wrap_socket(self.socket,
suppress_ragged_eofs=False, suppress_ragged_eofs=False,
...@@ -908,6 +910,8 @@ class TestTLS_FTPClass(TestCase): ...@@ -908,6 +910,8 @@ class TestTLS_FTPClass(TestCase):
def test_context(self): def test_context(self):
self.client.quit() self.client.quit()
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# TODO: fix TLSv1.3 support
ctx.options |= ssl.OP_NO_TLSv1_3
ctx.check_hostname = False ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE ctx.verify_mode = ssl.CERT_NONE
self.assertRaises(ValueError, ftplib.FTP_TLS, keyfile=CERTFILE, self.assertRaises(ValueError, ftplib.FTP_TLS, keyfile=CERTFILE,
...@@ -940,6 +944,8 @@ class TestTLS_FTPClass(TestCase): ...@@ -940,6 +944,8 @@ class TestTLS_FTPClass(TestCase):
def test_check_hostname(self): def test_check_hostname(self):
self.client.quit() self.client.quit()
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# TODO: fix TLSv1.3 support
ctx.options |= ssl.OP_NO_TLSv1_3
self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
self.assertEqual(ctx.check_hostname, True) self.assertEqual(ctx.check_hostname, True)
ctx.load_verify_locations(CAFILE) ctx.load_verify_locations(CAFILE)
......
...@@ -1594,6 +1594,72 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -1594,6 +1594,72 @@ class GeneralModuleTests(unittest.TestCase):
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s: with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s:
self.assertRaises(OverflowError, s.bind, (support.HOSTv6, 0, -10)) self.assertRaises(OverflowError, s.bind, (support.HOSTv6, 0, -10))
@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
def test_getaddrinfo_ipv6_basic(self):
((*_, sockaddr),) = socket.getaddrinfo(
'ff02::1de:c0:face:8D', # Note capital letter `D`.
1234, socket.AF_INET6,
socket.SOCK_DGRAM,
socket.IPPROTO_UDP
)
self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, 0))
@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
@unittest.skipUnless(
hasattr(socket, 'if_nameindex'),
'if_nameindex is not supported')
def test_getaddrinfo_ipv6_scopeid_symbolic(self):
# Just pick up any network interface (Linux, Mac OS X)
(ifindex, test_interface) = socket.if_nameindex()[0]
((*_, sockaddr),) = socket.getaddrinfo(
'ff02::1de:c0:face:8D%' + test_interface,
1234, socket.AF_INET6,
socket.SOCK_DGRAM,
socket.IPPROTO_UDP
)
# Note missing interface name part in IPv6 address
self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, ifindex))
@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
@unittest.skipUnless(
sys.platform == 'win32',
'Numeric scope id does not work or undocumented')
def test_getaddrinfo_ipv6_scopeid_numeric(self):
# Also works on Linux and Mac OS X, but is not documented (?)
# Windows, Linux and Max OS X allow nonexistent interface numbers here.
ifindex = 42
((*_, sockaddr),) = socket.getaddrinfo(
'ff02::1de:c0:face:8D%' + str(ifindex),
1234, socket.AF_INET6,
socket.SOCK_DGRAM,
socket.IPPROTO_UDP
)
# Note missing interface name part in IPv6 address
self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, ifindex))
@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
@unittest.skipUnless(
hasattr(socket, 'if_nameindex'),
'if_nameindex is not supported')
def test_getnameinfo_ipv6_scopeid_symbolic(self):
# Just pick up any network interface.
(ifindex, test_interface) = socket.if_nameindex()[0]
sockaddr = ('ff02::1de:c0:face:8D', 1234, 0, ifindex) # Note capital letter `D`.
nameinfo = socket.getnameinfo(sockaddr, socket.NI_NUMERICHOST | socket.NI_NUMERICSERV)
self.assertEqual(nameinfo, ('ff02::1de:c0:face:8d%' + test_interface, '1234'))
@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
@unittest.skipUnless(
sys.platform == 'win32',
'Numeric scope id does not work or undocumented')
def test_getnameinfo_ipv6_scopeid_numeric(self):
# Also works on Linux (undocumented), but does not work on Mac OS X
# Windows and Linux allow nonexistent interface numbers here.
ifindex = 42
sockaddr = ('ff02::1de:c0:face:8D', 1234, 0, ifindex) # Note capital letter `D`.
nameinfo = socket.getnameinfo(sockaddr, socket.NI_NUMERICHOST | socket.NI_NUMERICSERV)
self.assertEqual(nameinfo, ('ff02::1de:c0:face:8d%' + str(ifindex), '1234'))
def test_str_for_enums(self): def test_str_for_enums(self):
# Make sure that the AF_* and SOCK_* constants have enum-like string # Make sure that the AF_* and SOCK_* constants have enum-like string
# reprs. # reprs.
...@@ -5879,6 +5945,27 @@ class LinuxKernelCryptoAPI(unittest.TestCase): ...@@ -5879,6 +5945,27 @@ class LinuxKernelCryptoAPI(unittest.TestCase):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
sock.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, assoclen=-1) sock.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, assoclen=-1)
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
class TestMSWindowsTCPFlags(unittest.TestCase):
knownTCPFlags = {
# avaliable since long time ago
'TCP_MAXSEG',
'TCP_NODELAY',
# available starting with Windows 10 1607
'TCP_FASTOPEN',
# available starting with Windows 10 1703
'TCP_KEEPCNT',
# available starting with Windows 10 1709
'TCP_KEEPIDLE',
'TCP_KEEPINTVL'
}
def test_new_tcp_flags(self):
provided = [s for s in dir(socket) if s.startswith('TCP')]
unknown = [s for s in provided if s not in self.knownTCPFlags]
self.assertEqual([], unknown,
"New TCP flags were discovered. See bpo-32394 for more information")
def test_main(): def test_main():
tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest, tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest,
...@@ -5939,6 +6026,7 @@ def test_main(): ...@@ -5939,6 +6026,7 @@ def test_main():
SendfileUsingSendTest, SendfileUsingSendTest,
SendfileUsingSendfileTest, SendfileUsingSendfileTest,
]) ])
tests.append(TestMSWindowsTCPFlags)
thread_info = support.threading_setup() thread_info = support.threading_setup()
support.run_unittest(*tests) support.run_unittest(*tests)
......
...@@ -30,7 +30,8 @@ ssl = support.import_module("ssl") ...@@ -30,7 +30,8 @@ ssl = support.import_module("ssl")
PROTOCOLS = sorted(ssl._PROTOCOL_NAMES) PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
HOST = support.HOST HOST = support.HOST
IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL') IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL')
IS_OPENSSL_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0) IS_OPENSSL_1_1_0 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0)
IS_OPENSSL_1_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 1)
PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS') PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS')
def data_file(*name): def data_file(*name):
...@@ -54,6 +55,7 @@ CAPATH = data_file("capath") ...@@ -54,6 +55,7 @@ CAPATH = data_file("capath")
BYTES_CAPATH = os.fsencode(CAPATH) BYTES_CAPATH = os.fsencode(CAPATH)
CAFILE_NEURONIO = data_file("capath", "4e1295a3.0") CAFILE_NEURONIO = data_file("capath", "4e1295a3.0")
CAFILE_CACERT = data_file("capath", "5ed36f99.0") CAFILE_CACERT = data_file("capath", "5ed36f99.0")
WRONG_CERT = data_file("wrongcert.pem")
CERTFILE_INFO = { CERTFILE_INFO = {
'issuer': ((('countryName', 'XY'),), 'issuer': ((('countryName', 'XY'),),
...@@ -124,6 +126,7 @@ OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0) ...@@ -124,6 +126,7 @@ OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0) OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0) OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
def handle_error(prefix): def handle_error(prefix):
...@@ -143,6 +146,21 @@ def have_verify_flags(): ...@@ -143,6 +146,21 @@ def have_verify_flags():
# 0.9.8 or higher # 0.9.8 or higher
return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 0, 15) return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 0, 15)
def _have_secp_curves():
if not ssl.HAS_ECDH:
return False
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
try:
ctx.set_ecdh_curve("secp384r1")
except ValueError:
return False
else:
return True
HAVE_SECP_CURVES = _have_secp_curves()
def utc_offset(): #NOTE: ignore issues like #1647654 def utc_offset(): #NOTE: ignore issues like #1647654
# local time = utc time + utc offset # local time = utc time + utc offset
if time.daylight and time.localtime().tm_isdst > 0: if time.daylight and time.localtime().tm_isdst > 0:
...@@ -217,6 +235,7 @@ def testing_context(server_cert=SIGNED_CERTFILE): ...@@ -217,6 +235,7 @@ def testing_context(server_cert=SIGNED_CERTFILE):
server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
server_context.load_cert_chain(server_cert) server_context.load_cert_chain(server_cert)
client_context.load_verify_locations(SIGNING_CA)
return client_context, server_context, hostname return client_context, server_context, hostname
...@@ -244,6 +263,11 @@ class BasicSocketTests(unittest.TestCase): ...@@ -244,6 +263,11 @@ class BasicSocketTests(unittest.TestCase):
ssl.OP_NO_TLSv1_2 ssl.OP_NO_TLSv1_2
self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23) self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23)
def test_private_init(self):
with self.assertRaisesRegex(TypeError, "public constructor"):
with socket.socket() as s:
ssl.SSLSocket(s)
def test_str_for_enums(self): def test_str_for_enums(self):
# Make sure that the PROTOCOL_* constants have enum-like string # Make sure that the PROTOCOL_* constants have enum-like string
# reprs. # reprs.
...@@ -455,6 +479,8 @@ class BasicSocketTests(unittest.TestCase): ...@@ -455,6 +479,8 @@ class BasicSocketTests(unittest.TestCase):
self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1) self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
self.assertRaises(OSError, ss.send, b'x') self.assertRaises(OSError, ss.send, b'x')
self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0)) self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
self.assertRaises(NotImplementedError, ss.sendmsg,
[b'x'], (), 0, ('0.0.0.0', 0))
def test_timeout(self): def test_timeout(self):
# Issue #8524: when creating an SSL socket, the timeout of the # Issue #8524: when creating an SSL socket, the timeout of the
...@@ -622,14 +648,16 @@ class BasicSocketTests(unittest.TestCase): ...@@ -622,14 +648,16 @@ class BasicSocketTests(unittest.TestCase):
fail(cert, 'example.net') fail(cert, 'example.net')
# -- IPv6 matching -- # -- IPv6 matching --
cert = {'subject': ((('commonName', 'example.com'),),), if hasattr(socket, 'AF_INET6'):
'subjectAltName': (('DNS', 'example.com'), cert = {'subject': ((('commonName', 'example.com'),),),
('IP Address', '2001:0:0:0:0:0:0:CAFE\n'), 'subjectAltName': (
('IP Address', '2003:0:0:0:0:0:0:BABA\n'))} ('DNS', 'example.com'),
ok(cert, '2001::cafe') ('IP Address', '2001:0:0:0:0:0:0:CAFE\n'),
ok(cert, '2003::baba') ('IP Address', '2003:0:0:0:0:0:0:BABA\n'))}
fail(cert, '2003::bebe') ok(cert, '2001::cafe')
fail(cert, 'example.net') ok(cert, '2003::baba')
fail(cert, '2003::bebe')
fail(cert, 'example.net')
# -- Miscellaneous -- # -- Miscellaneous --
...@@ -665,14 +693,45 @@ class BasicSocketTests(unittest.TestCase): ...@@ -665,14 +693,45 @@ class BasicSocketTests(unittest.TestCase):
# Issue #17980: avoid denials of service by refusing more than one # Issue #17980: avoid denials of service by refusing more than one
# wildcard per fragment. # wildcard per fragment.
cert = {'subject': ((('commonName', 'a*b.com'),),)} cert = {'subject': ((('commonName', 'a*b.example.com'),),)}
fail(cert, 'axxb.com') with self.assertRaisesRegex(
cert = {'subject': ((('commonName', 'a*b.co*'),),)} ssl.CertificateError,
fail(cert, 'axxb.com') "partial wildcards in leftmost label are not supported"):
cert = {'subject': ((('commonName', 'a*b*.com'),),)} ssl.match_hostname(cert, 'axxb.example.com')
with self.assertRaises(ssl.CertificateError) as cm:
ssl.match_hostname(cert, 'axxbxxc.com') cert = {'subject': ((('commonName', 'www.*.example.com'),),)}
self.assertIn("too many wildcards", str(cm.exception)) with self.assertRaisesRegex(
ssl.CertificateError,
"wildcard can only be present in the leftmost label"):
ssl.match_hostname(cert, 'www.sub.example.com')
cert = {'subject': ((('commonName', 'a*b*.example.com'),),)}
with self.assertRaisesRegex(
ssl.CertificateError,
"too many wildcards"):
ssl.match_hostname(cert, 'axxbxxc.example.com')
cert = {'subject': ((('commonName', '*'),),)}
with self.assertRaisesRegex(
ssl.CertificateError,
"sole wildcard without additional labels are not support"):
ssl.match_hostname(cert, 'host')
cert = {'subject': ((('commonName', '*.com'),),)}
with self.assertRaisesRegex(
ssl.CertificateError,
r"hostname 'com' doesn't match '\*.com'"):
ssl.match_hostname(cert, 'com')
# extra checks for _inet_paton()
for invalid in ['1', '', '1.2.3', '256.0.0.1', '127.0.0.1/24']:
with self.assertRaises(ValueError):
ssl._inet_paton(invalid)
for ipaddr in ['127.0.0.1', '192.168.0.1']:
self.assertTrue(ssl._inet_paton(ipaddr))
if hasattr(socket, 'AF_INET6'):
for ipaddr in ['::1', '2001:db8:85a3::8a2e:370:7334']:
self.assertTrue(ssl._inet_paton(ipaddr))
def test_server_side(self): def test_server_side(self):
# server_hostname doesn't work for server sockets # server_hostname doesn't work for server sockets
...@@ -966,7 +1025,8 @@ class ContextTests(unittest.TestCase): ...@@ -966,7 +1025,8 @@ class ContextTests(unittest.TestCase):
default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3) default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
# SSLContext also enables these by default # SSLContext also enables these by default
default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE | default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE) OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
OP_ENABLE_MIDDLEBOX_COMPAT)
self.assertEqual(default, ctx.options) self.assertEqual(default, ctx.options)
ctx.options |= ssl.OP_NO_TLSv1 ctx.options |= ssl.OP_NO_TLSv1
self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options) self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
...@@ -1017,6 +1077,69 @@ class ContextTests(unittest.TestCase): ...@@ -1017,6 +1077,69 @@ class ContextTests(unittest.TestCase):
with self.assertRaises(AttributeError): with self.assertRaises(AttributeError):
ctx.hostname_checks_common_name = True ctx.hostname_checks_common_name = True
@unittest.skipUnless(hasattr(ssl.SSLContext, 'minimum_version'),
"required OpenSSL 1.1.0g")
def test_min_max_version(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
self.assertEqual(
ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTED
)
self.assertEqual(
ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
)
ctx.minimum_version = ssl.TLSVersion.TLSv1_1
ctx.maximum_version = ssl.TLSVersion.TLSv1_2
self.assertEqual(
ctx.minimum_version, ssl.TLSVersion.TLSv1_1
)
self.assertEqual(
ctx.maximum_version, ssl.TLSVersion.TLSv1_2
)
ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
ctx.maximum_version = ssl.TLSVersion.TLSv1
self.assertEqual(
ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTED
)
self.assertEqual(
ctx.maximum_version, ssl.TLSVersion.TLSv1
)
ctx.maximum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
self.assertEqual(
ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
)
ctx.maximum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
self.assertIn(
ctx.maximum_version,
{ssl.TLSVersion.TLSv1, ssl.TLSVersion.SSLv3}
)
ctx.minimum_version = ssl.TLSVersion.MAXIMUM_SUPPORTED
self.assertIn(
ctx.minimum_version,
{ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_3}
)
with self.assertRaises(ValueError):
ctx.minimum_version = 42
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1)
self.assertEqual(
ctx.minimum_version, ssl.TLSVersion.MINIMUM_SUPPORTED
)
self.assertEqual(
ctx.maximum_version, ssl.TLSVersion.MAXIMUM_SUPPORTED
)
with self.assertRaises(ValueError):
ctx.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED
with self.assertRaises(ValueError):
ctx.maximum_version = ssl.TLSVersion.TLSv1
@unittest.skipUnless(have_verify_flags(), @unittest.skipUnless(have_verify_flags(),
"verify_flags need OpenSSL > 0.9.8") "verify_flags need OpenSSL > 0.9.8")
def test_verify_flags(self): def test_verify_flags(self):
...@@ -1528,16 +1651,6 @@ class SSLErrorTests(unittest.TestCase): ...@@ -1528,16 +1651,6 @@ class SSLErrorTests(unittest.TestCase):
# For compatibility # For compatibility
self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ) self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
def test_bad_idna_in_server_hostname(self):
# Note: this test is testing some code that probably shouldn't exist
# in the first place, so if it starts failing at some point because
# you made the ssl module stop doing IDNA decoding then please feel
# free to remove it. The test was mainly added because this case used
# to cause memory corruption (see bpo-30594).
ctx = ssl.create_default_context()
with self.assertRaises(UnicodeError):
ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
server_hostname="xn--.com")
def test_bad_server_hostname(self): def test_bad_server_hostname(self):
ctx = ssl.create_default_context() ctx = ssl.create_default_context()
...@@ -1612,6 +1725,13 @@ class MemoryBIOTests(unittest.TestCase): ...@@ -1612,6 +1725,13 @@ class MemoryBIOTests(unittest.TestCase):
self.assertRaises(TypeError, bio.write, 1) self.assertRaises(TypeError, bio.write, 1)
class SSLObjectTests(unittest.TestCase):
def test_private_init(self):
bio = ssl.MemoryBIO()
with self.assertRaisesRegex(TypeError, "public constructor"):
ssl.SSLObject(bio, bio)
class SimpleBackgroundTests(unittest.TestCase): class SimpleBackgroundTests(unittest.TestCase):
"""Tests that connect to a simple server running in the background""" """Tests that connect to a simple server running in the background"""
...@@ -1738,6 +1858,8 @@ class SimpleBackgroundTests(unittest.TestCase): ...@@ -1738,6 +1858,8 @@ class SimpleBackgroundTests(unittest.TestCase):
der = ssl.PEM_cert_to_DER_cert(pem) der = ssl.PEM_cert_to_DER_cert(pem)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS) ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
ctx.verify_mode = ssl.CERT_REQUIRED ctx.verify_mode = ssl.CERT_REQUIRED
# TODO: fix TLSv1.3 support
ctx.options |= ssl.OP_NO_TLSv1_3
ctx.load_verify_locations(cadata=pem) ctx.load_verify_locations(cadata=pem)
with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s: with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
s.connect(self.server_addr) s.connect(self.server_addr)
...@@ -1747,6 +1869,8 @@ class SimpleBackgroundTests(unittest.TestCase): ...@@ -1747,6 +1869,8 @@ class SimpleBackgroundTests(unittest.TestCase):
# same with DER # same with DER
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS) ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
ctx.verify_mode = ssl.CERT_REQUIRED ctx.verify_mode = ssl.CERT_REQUIRED
# TODO: fix TLSv1.3 support
ctx.options |= ssl.OP_NO_TLSv1_3
ctx.load_verify_locations(cadata=der) ctx.load_verify_locations(cadata=der)
with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s: with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
s.connect(self.server_addr) s.connect(self.server_addr)
...@@ -2589,7 +2713,10 @@ class ThreadedTests(unittest.TestCase): ...@@ -2589,7 +2713,10 @@ class ThreadedTests(unittest.TestCase):
def test_ecc_cert(self): def test_ecc_cert(self):
client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
client_context.load_verify_locations(SIGNING_CA) client_context.load_verify_locations(SIGNING_CA)
client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA') client_context.set_ciphers(
'TLS13-AES-128-GCM-SHA256:TLS13-CHACHA20-POLY1305-SHA256:'
'ECDHE:ECDSA:!NULL:!aRSA'
)
hostname = SIGNED_CERTFILE_ECC_HOSTNAME hostname = SIGNED_CERTFILE_ECC_HOSTNAME
server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
...@@ -2610,6 +2737,9 @@ class ThreadedTests(unittest.TestCase): ...@@ -2610,6 +2737,9 @@ class ThreadedTests(unittest.TestCase):
def test_dual_rsa_ecc(self): def test_dual_rsa_ecc(self):
client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
client_context.load_verify_locations(SIGNING_CA) client_context.load_verify_locations(SIGNING_CA)
# TODO: fix TLSv1.3 once SSLContext can restrict signature
# algorithms.
client_context.options |= ssl.OP_NO_TLSv1_3
# only ECDSA certs # only ECDSA certs
client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA') client_context.set_ciphers('ECDHE:ECDSA:!NULL:!aRSA')
hostname = SIGNED_CERTFILE_ECC_HOSTNAME hostname = SIGNED_CERTFILE_ECC_HOSTNAME
...@@ -2634,10 +2764,12 @@ class ThreadedTests(unittest.TestCase): ...@@ -2634,10 +2764,12 @@ class ThreadedTests(unittest.TestCase):
if support.verbose: if support.verbose:
sys.stdout.write("\n") sys.stdout.write("\n")
server_context = ssl.SSLContext(ssl.PROTOCOL_TLS) server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
server_context.load_cert_chain(IDNSANSFILE) server_context.load_cert_chain(IDNSANSFILE)
# TODO: fix TLSv1.3 support
server_context.options |= ssl.OP_NO_TLSv1_3
context = ssl.SSLContext(ssl.PROTOCOL_TLS) context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.verify_mode = ssl.CERT_REQUIRED context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True context.check_hostname = True
context.load_verify_locations(SIGNING_CA) context.load_verify_locations(SIGNING_CA)
...@@ -2646,18 +2778,26 @@ class ThreadedTests(unittest.TestCase): ...@@ -2646,18 +2778,26 @@ class ThreadedTests(unittest.TestCase):
# different ways # different ways
idn_hostnames = [ idn_hostnames = [
('könig.idn.pythontest.net', ('könig.idn.pythontest.net',
'könig.idn.pythontest.net',), 'xn--knig-5qa.idn.pythontest.net'),
('xn--knig-5qa.idn.pythontest.net', ('xn--knig-5qa.idn.pythontest.net',
'xn--knig-5qa.idn.pythontest.net'), 'xn--knig-5qa.idn.pythontest.net'),
(b'xn--knig-5qa.idn.pythontest.net', (b'xn--knig-5qa.idn.pythontest.net',
b'xn--knig-5qa.idn.pythontest.net'), 'xn--knig-5qa.idn.pythontest.net'),
('königsgäßchen.idna2003.pythontest.net', ('königsgäßchen.idna2003.pythontest.net',
'königsgäßchen.idna2003.pythontest.net'), 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
('xn--knigsgsschen-lcb0w.idna2003.pythontest.net', ('xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'), 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
(b'xn--knigsgsschen-lcb0w.idna2003.pythontest.net', (b'xn--knigsgsschen-lcb0w.idna2003.pythontest.net',
b'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'), 'xn--knigsgsschen-lcb0w.idna2003.pythontest.net'),
# ('königsgäßchen.idna2008.pythontest.net',
# 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
('xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
(b'xn--knigsgchen-b4a3dun.idna2008.pythontest.net',
'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'),
] ]
for server_hostname, expected_hostname in idn_hostnames: for server_hostname, expected_hostname in idn_hostnames:
server = ThreadedEchoServer(context=server_context, chatty=True) server = ThreadedEchoServer(context=server_context, chatty=True)
...@@ -2670,22 +2810,6 @@ class ThreadedTests(unittest.TestCase): ...@@ -2670,22 +2810,6 @@ class ThreadedTests(unittest.TestCase):
self.assertEqual(s.server_hostname, expected_hostname) self.assertEqual(s.server_hostname, expected_hostname)
self.assertTrue(cert, "Can't get peer certificate.") self.assertTrue(cert, "Can't get peer certificate.")
with ssl.SSLSocket(socket.socket(),
server_hostname=server_hostname) as s:
s.connect((HOST, server.port))
s.getpeercert()
self.assertEqual(s.server_hostname, expected_hostname)
# bug https://bugs.python.org/issue28414
# IDNA 2008 deviations are broken
idna2008 = 'xn--knigsgchen-b4a3dun.idna2008.pythontest.net'
server = ThreadedEchoServer(context=server_context, chatty=True)
with server:
with self.assertRaises(UnicodeError):
with context.wrap_socket(socket.socket(),
server_hostname=idna2008) as s:
s.connect((HOST, server.port))
# incorrect hostname should raise an exception # incorrect hostname should raise an exception
server = ThreadedEchoServer(context=server_context, chatty=True) server = ThreadedEchoServer(context=server_context, chatty=True)
with server: with server:
...@@ -2700,15 +2824,22 @@ class ThreadedTests(unittest.TestCase): ...@@ -2700,15 +2824,22 @@ class ThreadedTests(unittest.TestCase):
Launch a server with CERT_REQUIRED, and check that trying to Launch a server with CERT_REQUIRED, and check that trying to
connect to it with a wrong client certificate fails. connect to it with a wrong client certificate fails.
""" """
certfile = os.path.join(os.path.dirname(__file__) or os.curdir, client_context, server_context, hostname = testing_context()
"wrongcert.pem") # load client cert
server = ThreadedEchoServer(CERTFILE, client_context.load_cert_chain(WRONG_CERT)
certreqs=ssl.CERT_REQUIRED, # require TLS client authentication
cacerts=CERTFILE, chatty=False, server_context.verify_mode = ssl.CERT_REQUIRED
connectionchatty=False) # TODO: fix TLSv1.3 support
# With TLS 1.3, test fails with exception in server thread
server_context.options |= ssl.OP_NO_TLSv1_3
server = ThreadedEchoServer(
context=server_context, chatty=True, connectionchatty=True,
)
with server, \ with server, \
socket.socket() as sock, \ client_context.wrap_socket(socket.socket(),
test_wrap_socket(sock, certfile=certfile) as s: server_hostname=hostname) as s:
try: try:
# Expect either an SSL error about the server rejecting # Expect either an SSL error about the server rejecting
# the connection, or a low-level connection reset (which # the connection, or a low-level connection reset (which
...@@ -3360,11 +3491,15 @@ class ThreadedTests(unittest.TestCase): ...@@ -3360,11 +3491,15 @@ class ThreadedTests(unittest.TestCase):
chatty=False) as server: chatty=False) as server:
with context.wrap_socket(socket.socket()) as s: with context.wrap_socket(socket.socket()) as s:
self.assertIs(s.version(), None) self.assertIs(s.version(), None)
self.assertIs(s._sslobj, None)
s.connect((HOST, server.port)) s.connect((HOST, server.port))
if ssl.OPENSSL_VERSION_INFO >= (1, 0, 2): if ssl.OPENSSL_VERSION_INFO >= (1, 1, 1):
self.assertEqual(s.version(), 'TLSv1.3')
elif ssl.OPENSSL_VERSION_INFO >= (1, 0, 2):
self.assertEqual(s.version(), 'TLSv1.2') self.assertEqual(s.version(), 'TLSv1.2')
else: # 0.9.8 to 1.0.1 else: # 0.9.8 to 1.0.1
self.assertIn(s.version(), ('TLSv1', 'TLSv1.2')) self.assertIn(s.version(), ('TLSv1', 'TLSv1.2'))
self.assertIs(s._sslobj, None)
self.assertIs(s.version(), None) self.assertIs(s.version(), None)
@unittest.skipUnless(ssl.HAS_TLSv1_3, @unittest.skipUnless(ssl.HAS_TLSv1_3,
...@@ -3372,18 +3507,72 @@ class ThreadedTests(unittest.TestCase): ...@@ -3372,18 +3507,72 @@ class ThreadedTests(unittest.TestCase):
def test_tls1_3(self): def test_tls1_3(self):
context = ssl.SSLContext(ssl.PROTOCOL_TLS) context = ssl.SSLContext(ssl.PROTOCOL_TLS)
context.load_cert_chain(CERTFILE) context.load_cert_chain(CERTFILE)
# disable all but TLS 1.3
context.options |= ( context.options |= (
ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2 ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2
) )
with ThreadedEchoServer(context=context) as server: with ThreadedEchoServer(context=context) as server:
with context.wrap_socket(socket.socket()) as s: with context.wrap_socket(socket.socket()) as s:
s.connect((HOST, server.port)) s.connect((HOST, server.port))
self.assertIn(s.cipher()[0], [ self.assertIn(s.cipher()[0], {
'TLS13-AES-256-GCM-SHA384', 'TLS13-AES-256-GCM-SHA384',
'TLS13-CHACHA20-POLY1305-SHA256', 'TLS13-CHACHA20-POLY1305-SHA256',
'TLS13-AES-128-GCM-SHA256', 'TLS13-AES-128-GCM-SHA256',
]) })
self.assertEqual(s.version(), 'TLSv1.3')
@unittest.skipUnless(hasattr(ssl.SSLContext, 'minimum_version'),
"required OpenSSL 1.1.0g")
def test_min_max_version(self):
client_context, server_context, hostname = testing_context()
# client TLSv1.0 to 1.2
client_context.minimum_version = ssl.TLSVersion.TLSv1
client_context.maximum_version = ssl.TLSVersion.TLSv1_2
# server only TLSv1.2
server_context.minimum_version = ssl.TLSVersion.TLSv1_2
server_context.maximum_version = ssl.TLSVersion.TLSv1_2
with ThreadedEchoServer(context=server_context) as server:
with client_context.wrap_socket(socket.socket(),
server_hostname=hostname) as s:
s.connect((HOST, server.port))
self.assertEqual(s.version(), 'TLSv1.2')
# client 1.0 to 1.2, server 1.0 to 1.1
server_context.minimum_version = ssl.TLSVersion.TLSv1
server_context.maximum_version = ssl.TLSVersion.TLSv1_1
with ThreadedEchoServer(context=server_context) as server:
with client_context.wrap_socket(socket.socket(),
server_hostname=hostname) as s:
s.connect((HOST, server.port))
self.assertEqual(s.version(), 'TLSv1.1')
# client 1.0, server 1.2 (mismatch)
server_context.minimum_version = ssl.TLSVersion.TLSv1_2
server_context.maximum_version = ssl.TLSVersion.TLSv1_2
client_context.minimum_version = ssl.TLSVersion.TLSv1
client_context.maximum_version = ssl.TLSVersion.TLSv1
with ThreadedEchoServer(context=server_context) as server:
with client_context.wrap_socket(socket.socket(),
server_hostname=hostname) as s:
with self.assertRaises(ssl.SSLError) as e:
s.connect((HOST, server.port))
self.assertIn("alert", str(e.exception))
@unittest.skipUnless(hasattr(ssl.SSLContext, 'minimum_version'),
"required OpenSSL 1.1.0g")
@unittest.skipUnless(ssl.HAS_SSLv3, "requires SSLv3 support")
def test_min_max_version_sslv3(self):
client_context, server_context, hostname = testing_context()
server_context.minimum_version = ssl.TLSVersion.SSLv3
client_context.minimum_version = ssl.TLSVersion.SSLv3
client_context.maximum_version = ssl.TLSVersion.SSLv3
with ThreadedEchoServer(context=server_context) as server:
with client_context.wrap_socket(socket.socket(),
server_hostname=hostname) as s:
s.connect((HOST, server.port))
self.assertEqual(s.version(), 'SSLv3')
@unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL") @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL")
def test_default_ecdh_curve(self): def test_default_ecdh_curve(self):
...@@ -3412,58 +3601,54 @@ class ThreadedTests(unittest.TestCase): ...@@ -3412,58 +3601,54 @@ class ThreadedTests(unittest.TestCase):
if support.verbose: if support.verbose:
sys.stdout.write("\n") sys.stdout.write("\n")
server = ThreadedEchoServer(CERTFILE, client_context, server_context, hostname = testing_context()
certreqs=ssl.CERT_NONE, # TODO: fix TLSv1.3 support
ssl_version=ssl.PROTOCOL_TLS_SERVER, client_context.options |= ssl.OP_NO_TLSv1_3
cacerts=CERTFILE,
server = ThreadedEchoServer(context=server_context,
chatty=True, chatty=True,
connectionchatty=False) connectionchatty=False)
with server: with server:
s = test_wrap_socket(socket.socket(), with client_context.wrap_socket(
server_side=False, socket.socket(),
certfile=CERTFILE, server_hostname=hostname) as s:
ca_certs=CERTFILE, s.connect((HOST, server.port))
cert_reqs=ssl.CERT_NONE, # get the data
ssl_version=ssl.PROTOCOL_TLS_CLIENT) cb_data = s.get_channel_binding("tls-unique")
s.connect((HOST, server.port)) if support.verbose:
# get the data sys.stdout.write(
cb_data = s.get_channel_binding("tls-unique") " got channel binding data: {0!r}\n".format(cb_data))
if support.verbose:
sys.stdout.write(" got channel binding data: {0!r}\n" # check if it is sane
.format(cb_data)) self.assertIsNotNone(cb_data)
self.assertEqual(len(cb_data), 12) # True for TLSv1
# check if it is sane
self.assertIsNotNone(cb_data) # and compare with the peers version
self.assertEqual(len(cb_data), 12) # True for TLSv1 s.write(b"CB tls-unique\n")
peer_data_repr = s.read().strip()
# and compare with the peers version self.assertEqual(peer_data_repr,
s.write(b"CB tls-unique\n") repr(cb_data).encode("us-ascii"))
peer_data_repr = s.read().strip()
self.assertEqual(peer_data_repr,
repr(cb_data).encode("us-ascii"))
s.close()
# now, again # now, again
s = test_wrap_socket(socket.socket(), with client_context.wrap_socket(
server_side=False, socket.socket(),
certfile=CERTFILE, server_hostname=hostname) as s:
ca_certs=CERTFILE, s.connect((HOST, server.port))
cert_reqs=ssl.CERT_NONE, new_cb_data = s.get_channel_binding("tls-unique")
ssl_version=ssl.PROTOCOL_TLS_CLIENT) if support.verbose:
s.connect((HOST, server.port)) sys.stdout.write(
new_cb_data = s.get_channel_binding("tls-unique") "got another channel binding data: {0!r}\n".format(
if support.verbose: new_cb_data)
sys.stdout.write(" got another channel binding data: {0!r}\n" )
.format(new_cb_data)) # is it really unique
# is it really unique self.assertNotEqual(cb_data, new_cb_data)
self.assertNotEqual(cb_data, new_cb_data) self.assertIsNotNone(cb_data)
self.assertIsNotNone(cb_data) self.assertEqual(len(cb_data), 12) # True for TLSv1
self.assertEqual(len(cb_data), 12) # True for TLSv1 s.write(b"CB tls-unique\n")
s.write(b"CB tls-unique\n") peer_data_repr = s.read().strip()
peer_data_repr = s.read().strip() self.assertEqual(peer_data_repr,
self.assertEqual(peer_data_repr, repr(new_cb_data).encode("us-ascii"))
repr(new_cb_data).encode("us-ascii"))
s.close()
def test_compression(self): def test_compression(self):
client_context, server_context, hostname = testing_context() client_context, server_context, hostname = testing_context()
...@@ -3488,8 +3673,11 @@ class ThreadedTests(unittest.TestCase): ...@@ -3488,8 +3673,11 @@ class ThreadedTests(unittest.TestCase):
def test_dh_params(self): def test_dh_params(self):
# Check we can get a connection with ephemeral Diffie-Hellman # Check we can get a connection with ephemeral Diffie-Hellman
client_context, server_context, hostname = testing_context() client_context, server_context, hostname = testing_context()
# test scenario needs TLS <= 1.2
client_context.options |= ssl.OP_NO_TLSv1_3
server_context.load_dh_params(DHFILE) server_context.load_dh_params(DHFILE)
server_context.set_ciphers("kEDH") server_context.set_ciphers("kEDH")
server_context.options |= ssl.OP_NO_TLSv1_3
stats = server_params_test(client_context, server_context, stats = server_params_test(client_context, server_context,
chatty=True, connectionchatty=True, chatty=True, connectionchatty=True,
sni_name=hostname) sni_name=hostname)
...@@ -3498,6 +3686,45 @@ class ThreadedTests(unittest.TestCase): ...@@ -3498,6 +3686,45 @@ class ThreadedTests(unittest.TestCase):
if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts: if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts:
self.fail("Non-DH cipher: " + cipher[0]) self.fail("Non-DH cipher: " + cipher[0])
@unittest.skipUnless(HAVE_SECP_CURVES, "needs secp384r1 curve support")
@unittest.skipIf(IS_OPENSSL_1_1_1, "TODO: Test doesn't work on 1.1.1")
def test_ecdh_curve(self):
# server secp384r1, client auto
client_context, server_context, hostname = testing_context()
server_context.set_ecdh_curve("secp384r1")
server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
server_context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
stats = server_params_test(client_context, server_context,
chatty=True, connectionchatty=True,
sni_name=hostname)
# server auto, client secp384r1
client_context, server_context, hostname = testing_context()
client_context.set_ecdh_curve("secp384r1")
server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
server_context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
stats = server_params_test(client_context, server_context,
chatty=True, connectionchatty=True,
sni_name=hostname)
# server / client curve mismatch
client_context, server_context, hostname = testing_context()
client_context.set_ecdh_curve("prime256v1")
server_context.set_ecdh_curve("secp384r1")
server_context.set_ciphers("ECDHE:!eNULL:!aNULL")
server_context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
try:
stats = server_params_test(client_context, server_context,
chatty=True, connectionchatty=True,
sni_name=hostname)
except ssl.SSLError:
pass
else:
# OpenSSL 1.0.2 does not fail although it should.
if IS_OPENSSL_1_1_0:
self.fail("mismatch curve did not fail")
def test_selected_alpn_protocol(self): def test_selected_alpn_protocol(self):
# selected_alpn_protocol() is None unless ALPN is used. # selected_alpn_protocol() is None unless ALPN is used.
client_context, server_context, hostname = testing_context() client_context, server_context, hostname = testing_context()
...@@ -3539,7 +3766,7 @@ class ThreadedTests(unittest.TestCase): ...@@ -3539,7 +3766,7 @@ class ThreadedTests(unittest.TestCase):
except ssl.SSLError as e: except ssl.SSLError as e:
stats = e stats = e
if (expected is None and IS_OPENSSL_1_1 if (expected is None and IS_OPENSSL_1_1_0
and ssl.OPENSSL_VERSION_INFO < (1, 1, 0, 6)): and ssl.OPENSSL_VERSION_INFO < (1, 1, 0, 6)):
# OpenSSL 1.1.0 to 1.1.0e raises handshake error # OpenSSL 1.1.0 to 1.1.0e raises handshake error
self.assertIsInstance(stats, ssl.SSLError) self.assertIsInstance(stats, ssl.SSLError)
...@@ -3746,6 +3973,8 @@ class ThreadedTests(unittest.TestCase): ...@@ -3746,6 +3973,8 @@ class ThreadedTests(unittest.TestCase):
def test_session(self): def test_session(self):
client_context, server_context, hostname = testing_context() client_context, server_context, hostname = testing_context()
# TODO: sessions aren't compatible with TLSv1.3 yet
client_context.options |= ssl.OP_NO_TLSv1_3
# first connection without session # first connection without session
stats = server_params_test(client_context, server_context, stats = server_params_test(client_context, server_context,
...@@ -3804,7 +4033,7 @@ class ThreadedTests(unittest.TestCase): ...@@ -3804,7 +4033,7 @@ class ThreadedTests(unittest.TestCase):
client_context, server_context, hostname = testing_context() client_context, server_context, hostname = testing_context()
client_context2, _, _ = testing_context() client_context2, _, _ = testing_context()
# TODO: session reuse does not work with TLS 1.3 # TODO: session reuse does not work with TLSv1.3
client_context.options |= ssl.OP_NO_TLSv1_3 client_context.options |= ssl.OP_NO_TLSv1_3
client_context2.options |= ssl.OP_NO_TLSv1_3 client_context2.options |= ssl.OP_NO_TLSv1_3
...@@ -3893,7 +4122,7 @@ def test_main(verbose=False): ...@@ -3893,7 +4122,7 @@ def test_main(verbose=False):
tests = [ tests = [
ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests, ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests,
SimpleBackgroundTests, ThreadedTests, SSLObjectTests, SimpleBackgroundTests, ThreadedTests,
] ]
if support.is_resource_enabled('network'): if support.is_resource_enabled('network'):
......
...@@ -1179,7 +1179,7 @@ class ProcessTestCase(BaseTestCase): ...@@ -1179,7 +1179,7 @@ class ProcessTestCase(BaseTestCase):
msvcrt.CrtSetReportFile(report_type, msvcrt.CRTDBG_FILE_STDERR) msvcrt.CrtSetReportFile(report_type, msvcrt.CRTDBG_FILE_STDERR)
try: try:
subprocess.Popen([cmd], subprocess.Popen(cmd,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
except OSError: except OSError:
...@@ -1475,37 +1475,6 @@ class RunFuncTestCase(BaseTestCase): ...@@ -1475,37 +1475,6 @@ class RunFuncTestCase(BaseTestCase):
env=newenv) env=newenv)
self.assertEqual(cp.returncode, 33) self.assertEqual(cp.returncode, 33)
def test_run_with_pathlike_path(self):
# bpo-31961: test run(pathlike_object)
class Path:
def __fspath__(self):
# the name of a command that can be run without
# any argumenets that exit fast
return 'dir' if mswindows else 'ls'
path = Path()
if mswindows:
res = subprocess.run(path, stdout=subprocess.DEVNULL, shell=True)
else:
res = subprocess.run(path, stdout=subprocess.DEVNULL)
self.assertEqual(res.returncode, 0)
def test_run_with_pathlike_path_and_arguments(self):
# bpo-31961: test run([pathlike_object, 'additional arguments'])
class Path:
def __fspath__(self):
# the name of a command that can be run without
# any argumenets that exits fast
return sys.executable
path = Path()
args = [path, '-c', 'import sys; sys.exit(57)']
res = subprocess.run(args)
self.assertEqual(res.returncode, 57)
def test_capture_output(self): def test_capture_output(self):
cp = self.run_python(("import sys;" cp = self.run_python(("import sys;"
"sys.stdout.write('BDFL'); " "sys.stdout.write('BDFL'); "
......
...@@ -243,7 +243,12 @@ if LIBUV: ...@@ -243,7 +243,12 @@ if LIBUV:
] ]
if PYPY: if PYPY:
disabled_tests += [
# This seems to crash the interpreter. I cannot reproduce
# on macOS or local Linux VM.
# See https://travis-ci.org/gevent/gevent/jobs/348661604#L709
'test_smtplib.TooLongLineTests.testLineTooLong',
]
if ARES: if ARES:
disabled_tests += [ disabled_tests += [
...@@ -913,6 +918,15 @@ if PY37: ...@@ -913,6 +918,15 @@ if PY37:
# This wants to check that the underlying fileno is blocking, # This wants to check that the underlying fileno is blocking,
# but it isn't. # but it isn't.
'test_socket.NonBlockingTCPTests.testSetBlocking', 'test_socket.NonBlockingTCPTests.testSetBlocking',
# 3.7b2 made it impossible to instantiate SSLSocket objects
# directly, and this tests for that, but we don't follow that change.
'test_ssl.BasicSocketTests.test_private_init',
# 3.7b2 made a change to this test that on the surface looks incorrect,
# but it passes when they run it and fails when we do. It's not
# clear why.
'test_ssl.ThreadedTests.test_check_hostname_idn',
] ]
# if 'signalfd' in os.environ.get('GEVENT_BACKEND', ''): # if 'signalfd' in os.environ.get('GEVENT_BACKEND', ''):
......
...@@ -15,6 +15,7 @@ from greentest.util import log ...@@ -15,6 +15,7 @@ from greentest.util import log
from greentest.sysinfo import RUNNING_ON_CI from greentest.sysinfo import RUNNING_ON_CI
from greentest.sysinfo import PYPY from greentest.sysinfo import PYPY
from greentest.sysinfo import RESOLVER_ARES from greentest.sysinfo import RESOLVER_ARES
from greentest.sysinfo import LIBUV
from greentest import six from greentest import six
...@@ -35,6 +36,12 @@ RUN_ALONE = [ ...@@ -35,6 +36,12 @@ RUN_ALONE = [
'test__examples.py', 'test__examples.py',
] ]
if RUNNING_ON_CI and PYPY and LIBUV:
RUN_ALONE += [
# https://bitbucket.org/pypy/pypy/issues/2769/systemerror-unexpected-internal-exception
'test__pywsgi.py',
]
# tests that can't be run when coverage is enabled # tests that can't be run when coverage is enabled
IGNORE_COVERAGE = [ IGNORE_COVERAGE = [
# Hangs forever # Hangs forever
......
...@@ -169,6 +169,16 @@ if PYPY: ...@@ -169,6 +169,16 @@ if PYPY:
'FLAKY test__example_udp_client.py', 'FLAKY test__example_udp_client.py',
] ]
if LIBUV:
IGNORED_TESTS += [
# This has started crashing with a SystemError.
# I cannot reproduce with the same version on macOS
# and I cannot reproduce with the same version in a Linux vm.
# Commenting out individual tests just moves the crash around.
# https://bitbucket.org/pypy/pypy/issues/2769/systemerror-unexpected-internal-exception
'test__pywsgi.py',
]
if PY3 and TRAVIS: if PY3 and TRAVIS:
FAILING_TESTS += [ FAILING_TESTS += [
## --- ## ---
......
...@@ -274,7 +274,10 @@ class TestGeventLocal(greentest.TestCase): ...@@ -274,7 +274,10 @@ class TestGeventLocal(greentest.TestCase):
# The sentinels should be gone too # The sentinels should be gone too
self.assertEqual(len(deleted_sentinels), len(greenlets)) self.assertEqual(len(deleted_sentinels), len(greenlets))
@greentest.skipOnLibuvOnPyPyOnWin("GC makes this non-deterministic, especially on Windows")
def test_locals_collected_when_unreferenced_even_in_running_greenlet(self): def test_locals_collected_when_unreferenced_even_in_running_greenlet(self):
# In fact only on Windows do we see GC being an issue;
# pypy2 5.0 on macos and travis don't have a problem.
# https://github.com/gevent/gevent/issues/981 # https://github.com/gevent/gevent/issues/981
import gevent import gevent
import gc import gc
...@@ -308,17 +311,16 @@ class TestGeventLocal(greentest.TestCase): ...@@ -308,17 +311,16 @@ class TestGeventLocal(greentest.TestCase):
self.assertEqual(count, len(deleted_sentinels)) self.assertEqual(count, len(deleted_sentinels))
@greentest.skipOnPyPy("GC makes this non-deterministic, especially on Windows")
def test_local_dicts_for_greenlet(self): def test_local_dicts_for_greenlet(self):
# In fact, only on Windows do we see gc being an issue;
# pypy2 5.10 on macOS and Travis don't have a problem.
import gevent import gevent
from gevent.local import all_local_dicts_for_greenlet from gevent.local import all_local_dicts_for_greenlet
x = MyLocal() x = MyLocal()
x.foo = 42 x.foo = 42
del x.sentinel del x.sentinel
if greentest.PYPY:
import gc
gc.collect()
results = all_local_dicts_for_greenlet(gevent.getcurrent()) results = all_local_dicts_for_greenlet(gevent.getcurrent())
self.assertEqual(results, self.assertEqual(results,
[((MyLocal, id(x)), {'foo': 42})]) [((MyLocal, id(x)), {'foo': 42})])
......
...@@ -1562,16 +1562,17 @@ class TestInputRaw(greentest.BaseTestCase): ...@@ -1562,16 +1562,17 @@ class TestInputRaw(greentest.BaseTestCase):
i = self.make_input("2\r\n1", chunked_input=True) i = self.make_input("2\r\n1", chunked_input=True)
self.assertRaises(IOError, i.readline) self.assertRaises(IOError, i.readline)
@greentest.skipOnLibuvOnCIOnPyPy("Crashes. See https://github.com/gevent/gevent/issues/1130")
def test_32bit_overflow(self): def test_32bit_overflow(self):
# https://github.com/gevent/gevent/issues/289 # https://github.com/gevent/gevent/issues/289
# Should not raise an OverflowError on Python 2 # Should not raise an OverflowError on Python 2
print("BEGIN 32bit")
data = b'asdf\nghij\n' data = b'asdf\nghij\n'
long_data = b'a' * (pywsgi.MAX_REQUEST_LINE + 10) long_data = b'a' * (pywsgi.MAX_REQUEST_LINE + 10)
long_data += b'\n' long_data += b'\n'
data = data + long_data data = data + long_data
partial_data = b'qjk\n' # Note terminating \n partial_data = b'qjk\n' # Note terminating \n
n = 25 * 1000000000 n = 25 * 1000000000
print("N", n, "Data len", len(data))
if hasattr(n, 'bit_length'): if hasattr(n, 'bit_length'):
self.assertEqual(n.bit_length(), 35) self.assertEqual(n.bit_length(), 35)
if not PY3 and not PYPY: if not PY3 and not PYPY:
......
...@@ -128,3 +128,7 @@ test___config.py ...@@ -128,3 +128,7 @@ test___config.py
test__destroy_default_loop.py test__destroy_default_loop.py
test__util.py test__util.py
test___ident.py test___ident.py
test__issue639.py
test__issue_728.py
test__refcount_core.py
test__api.py
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment