Commit a67a39f4 authored by Jason Madden's avatar Jason Madden Committed by GitHub

Merge pull request #1503 from gevent/py-ver-updates

Update tested Python versions
parents dcb4a778 cfa645e0
...@@ -7,7 +7,12 @@ ...@@ -7,7 +7,12 @@
1.5a4 (unreleased) 1.5a4 (unreleased)
================== ==================
- Nothing changed yet. Platform and Packaging Updates
------------------------------
- Python version updates: gevent is now tested with CPython 3.6.10,
3.7.6 and 3.8.1. It is also tested with PyPy2 7.3 and PyPy 3.6
7.3.
1.5a3 (2020-01-01) 1.5a3 (2020-01-01)
......
...@@ -17,26 +17,28 @@ PYENV=$BASE/pyenv ...@@ -17,26 +17,28 @@ PYENV=$BASE/pyenv
echo $BASE echo $BASE
mkdir -p $BASE mkdir -p $BASE
update_pyenv () {
if [ ! -d "$PYENV/.git" ]; then VERSION="$1"
rm -rf $PYENV if [ ! -d "$PYENV/.git" ]; then
git clone https://github.com/pyenv/pyenv.git $BASE/pyenv rm -rf $PYENV
else git clone https://github.com/pyenv/pyenv.git $BASE/pyenv
back=$PWD else
cd $PYENV if [ ! -f "$PYENV/plugins/python-build/share/python-build/$VERSION" ]; then
# We don't fetch or reset after the initial creation; echo "Updating $PYENV for $VERSION"
# doing so causes the Travis cache to need re-packed and uploaded, back=$PWD
# and it's pretty large. cd $PYENV
# So if we need to incorporate changes from pyenv, either temporarily
# turn this back on, or remove the Travis caches. git fetch || echo "Fetch failed to complete. Ignoring"
# git fetch || echo "Fetch failed to complete. Ignoring" git reset --hard origin/master
# git reset --hard origin/master cd $back
cd $back fi
fi fi
}
SNAKEPIT=$BASE/snakepit SNAKEPIT=$BASE/snakepit
## ##
# install(exact-version, bin-alias, dir-alias) # install(exact-version, bin-alias, dir-alias)
# #
...@@ -60,6 +62,7 @@ install () { ...@@ -60,6 +62,7 @@ install () {
if [ ! -e "$DESTINATION" ]; then if [ ! -e "$DESTINATION" ]; then
mkdir -p $SNAKEPIT mkdir -p $SNAKEPIT
mkdir -p $BASE/versions mkdir -p $BASE/versions
update_pyenv $VERSION
$BASE/pyenv/plugins/python-build/bin/python-build $VERSION $DESTINATION $BASE/pyenv/plugins/python-build/bin/python-build $VERSION $DESTINATION
fi fi
...@@ -102,19 +105,19 @@ for var in "$@"; do ...@@ -102,19 +105,19 @@ for var in "$@"; do
install 3.5.9 python3.5 3.5.d install 3.5.9 python3.5 3.5.d
;; ;;
3.6) 3.6)
install 3.6.9 python3.6 3.6.d install 3.6.10 python3.6 3.6.d
;; ;;
3.7) 3.7)
install 3.7.5 python3.7 3.7.d install 3.7.6 python3.7 3.7.d
;; ;;
3.8) 3.8)
install 3.8.0 python3.8 3.8.d install 3.8.1 python3.8 3.8.d
;; ;;
pypy2.7) pypy2.7)
install pypy2.7-7.2.0 pypy2.7 pypy2.7.d install pypy2.7-7.3.0 pypy2.7 pypy2.7.d
;; ;;
pypy3.6) pypy3.6)
install pypy3.6-7.2.0 pypy3.6 pypy3.6.d install pypy3.6-7.3.0 pypy3.6 pypy3.6.d
;; ;;
esac esac
done done
...@@ -591,6 +591,19 @@ if PY2: ...@@ -591,6 +591,19 @@ if PY2:
'test_ssl.ContextTests.test_options', 'test_ssl.ContextTests.test_options',
] ]
if PYPY and sys.pypy_version_info[:3] == (7, 3, 0): # pylint:disable=no-member
if OSX:
disabled_tests += [
# This is expected to produce an SSLError, but instead it appears to
# actually work. See above for when it started failing the same on
# Travis.
'test_ssl.ThreadedTests.test_alpn_protocols',
# This fails, presumably due to the OpenSSL it's compiled with.
'test_ssl.ThreadedTests.test_default_ecdh_curve',
]
def _make_run_with_original(mod_name, func_name): def _make_run_with_original(mod_name, func_name):
@contextlib.contextmanager @contextlib.contextmanager
def with_orig(): def with_orig():
...@@ -843,6 +856,9 @@ if PYPY and PY3: ...@@ -843,6 +856,9 @@ if PYPY and PY3:
# (at least on OS X; it's less consistent about that on travis) # (at least on OS X; it's less consistent about that on travis)
'test_ssl.NetworkedBIOTests.test_handshake', 'test_ssl.NetworkedBIOTests.test_handshake',
# This passes various "invalid" strings and expects a ValueError. not sure why
# we don't see errors on CPython.
'test_subprocess.ProcessTestCase.test_invalid_env',
] ]
if OSX: if OSX:
...@@ -854,6 +870,7 @@ if PYPY and PY3: ...@@ -854,6 +870,7 @@ if PYPY and PY3:
'test_subprocess.POSIXProcessTestCase.test_pass_fds_inheritable', 'test_subprocess.POSIXProcessTestCase.test_pass_fds_inheritable',
'test_subprocess.POSIXProcessTestCase.test_pipe_cloexec', 'test_subprocess.POSIXProcessTestCase.test_pipe_cloexec',
# The below are new with 5.10.1 # The below are new with 5.10.1
# These fail with 'OSError: received malformed or improperly truncated ancillary data' # These fail with 'OSError: received malformed or improperly truncated ancillary data'
'test_socket.RecvmsgSCMRightsStreamTest.testCmsgTruncLen0', 'test_socket.RecvmsgSCMRightsStreamTest.testCmsgTruncLen0',
...@@ -872,12 +889,16 @@ if PYPY and PY3: ...@@ -872,12 +889,16 @@ if PYPY and PY3:
'test_ssl.ThreadedTests.test_protocol_sslv3', 'test_ssl.ThreadedTests.test_protocol_sslv3',
'test_ssl.ThreadedTests.test_protocol_tlsv1', 'test_ssl.ThreadedTests.test_protocol_tlsv1',
'test_ssl.ThreadedTests.test_protocol_tlsv1_1', 'test_ssl.ThreadedTests.test_protocol_tlsv1_1',
# Similar, they fail without monkey-patching.
'test_ssl.TestPostHandshakeAuth.test_pha_no_pha_client',
'test_ssl.TestPostHandshakeAuth.test_pha_optional',
'test_ssl.TestPostHandshakeAuth.test_pha_required',
# This gets None instead of http1.1, even without gevent # This gets None instead of http1.1, even without gevent
'test_ssl.ThreadedTests.test_npn_protocols', 'test_ssl.ThreadedTests.test_npn_protocols',
# This fails to decode a filename even without gevent, # This fails to decode a filename even without gevent,
# at least on High Sierarr. # at least on High Sierra. Newer versions of the tests actually skip this.
'test_httpservers.SimpleHTTPServerTestCase.test_undecodable_filename', 'test_httpservers.SimpleHTTPServerTestCase.test_undecodable_filename',
] ]
...@@ -1151,6 +1172,13 @@ if PY37: ...@@ -1151,6 +1172,13 @@ if PY37:
'test_ssl.ThreadedTests.test_wrong_cert_tls13', 'test_ssl.ThreadedTests.test_wrong_cert_tls13',
] ]
if sys.version_info < (3, 7, 6):
disabled_tests += [
# Earlier versions parse differently so the newer test breaks
'test_ssl.BasicSocketTests.test_parse_all_sans',
'test_ssl.BasicSocketTests.test_parse_cert_CVE_2013_4238',
]
if APPVEYOR: if APPVEYOR:
disabled_tests += [ disabled_tests += [
...@@ -1171,6 +1199,14 @@ if PY38: ...@@ -1171,6 +1199,14 @@ if PY38:
'test_threading.ExceptHookTests.test_excepthook_thread_None', 'test_threading.ExceptHookTests.test_excepthook_thread_None',
] ]
if sys.version_info < (3, 8, 1):
disabled_tests += [
# Earlier versions parse differently so the newer test breaks
'test_ssl.BasicSocketTests.test_parse_all_sans',
'test_ssl.BasicSocketTests.test_parse_cert_CVE_2013_4238',
]
# if 'signalfd' in os.environ.get('GEVENT_BACKEND', ''): # if 'signalfd' in os.environ.get('GEVENT_BACKEND', ''):
# # tests that don't interact well with signalfd # # tests that don't interact well with signalfd
# disabled_tests.extend([ # disabled_tests.extend([
......
...@@ -54,11 +54,19 @@ class Test(greentest.TestCase): ...@@ -54,11 +54,19 @@ class Test(greentest.TestCase):
raise raise
raise AssertionError('NOT RAISED EBADF: %r() returned %r' % (func, result)) raise AssertionError('NOT RAISED EBADF: %r() returned %r' % (func, result))
def assert_fd_open(self, fileno): if WIN or (PYPY and PY3 and greentest.LINUX):
assert isinstance(fileno, fd_types) def __assert_fd_open(self, fileno):
open_files = get_open_files() # We can't detect open file descriptors on Windows.
if fileno not in open_files: # On PyPy 3.6-7.3 on Travis CI (linux), for some reason the
raise AssertionError('%r is not open:\n%s' % (fileno, open_files['data'])) # client file descriptors don't always show as open. Don't know why,
# was fine in 7.2.
pass
else:
def __assert_fd_open(self, fileno):
assert isinstance(fileno, fd_types)
open_files = get_open_files()
if fileno not in open_files:
raise AssertionError('%r is not open:\n%s' % (fileno, open_files['data']))
def assert_fd_closed(self, fileno): def assert_fd_closed(self, fileno):
assert isinstance(fileno, fd_types), repr(fileno) assert isinstance(fileno, fd_types), repr(fileno)
...@@ -79,15 +87,14 @@ class Test(greentest.TestCase): ...@@ -79,15 +87,14 @@ class Test(greentest.TestCase):
def assert_open(self, sock, *rest): def assert_open(self, sock, *rest):
if isinstance(sock, fd_types): if isinstance(sock, fd_types):
if not WIN: self.__assert_fd_open(sock)
self.assert_fd_open(sock)
else: else:
fileno = sock.fileno() fileno = sock.fileno()
assert isinstance(fileno, fd_types), fileno assert isinstance(fileno, fd_types), fileno
sockname = sock.getsockname() sockname = sock.getsockname()
assert isinstance(sockname, tuple), sockname assert isinstance(sockname, tuple), sockname
if not WIN: if not WIN:
self.assert_fd_open(fileno) self.__assert_fd_open(fileno)
else: else:
self._assert_sock_open(sock) self._assert_sock_open(sock)
if rest: if rest:
......
...@@ -128,16 +128,13 @@ class TestTCP(greentest.TestCase): ...@@ -128,16 +128,13 @@ class TestTCP(greentest.TestCase):
log("accepting", self.listener) log("accepting", self.listener)
conn, _ = self.listener.accept() conn, _ = self.listener.accept()
try: try:
r = conn.makefile(mode='rb') with conn.makefile(mode='rb') as r:
try:
log("accepted on server", conn) log("accepted on server", conn)
accepted_event.set() accepted_event.set()
log("reading") log("reading")
read_data.append(r.read()) read_data.append(r.read())
log("done reading") log("done reading")
finally: del r
r.close()
del r
finally: finally:
conn.close() conn.close()
del conn del conn
...@@ -155,8 +152,9 @@ class TestTCP(greentest.TestCase): ...@@ -155,8 +152,9 @@ class TestTCP(greentest.TestCase):
# The implicit reference-based nastiness of Python 2 # The implicit reference-based nastiness of Python 2
# sockets interferes, especially when using SSL sockets. # sockets interferes, especially when using SSL sockets.
# The best way to get a decent FIN to the server is to shutdown # The best way to get a decent FIN to the server is to shutdown
# the output. Doing that on Python 3, OTOH, is contraindicated. # the output. Doing that on Python 3, OTOH, is contraindicated
should_shutdown = greentest.PY2 # except on PyPy.
should_shutdown = greentest.PY2 or greentest.PYPY
# It's important to wait for the server to fully accept before # It's important to wait for the server to fully accept before
# we shutdown and close the socket. In SSL mode, the number # we shutdown and close the socket. In SSL mode, the number
...@@ -204,7 +202,7 @@ class TestTCP(greentest.TestCase): ...@@ -204,7 +202,7 @@ class TestTCP(greentest.TestCase):
log("closing") log("closing")
client.close() client.close()
finally: finally:
server.join(4) server.join(10)
assert not server.is_alive() assert not server.is_alive()
if server.terminal_exc: if server.terminal_exc:
......
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQCg/pM6dP7BTFNc MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOoy7/QOtTjQ0niE
qe6wIJIBB7HjwL42bp0vjcCVl4Z3MRWFswYpfxy+o+8+PguMp4K6zndA5fwNkK/H 6uDcTwtkC0R2Tvy1AjVnXohCntZfdzbTGDoYTgXSOLsP8A697jUiJ8VCePGH50xG
3HmtanncUfPqnV0usN0NHQGh/f9xRoNmB1q2L7kTuO99o0KLQgvonRT2snf8rq9n Z4DKnAF3a9O3a9nr2pLXb0iY3XOMv+YEBii7CfI+3oxFYgCl0sMgHzDD2ZTVYAsm
tPRzhHUGYhog7zzNxetYV309PHpPr19BcKepDtM5RMk2aBnoN5vtItorjXiDosFm DWgLUVsE2gHEccRwrM2tPf2EgR+FAgMBAAECgYEA3qyfyYVSeTrTYxO93x6ZaVMu
6o5wQHrcupcVydszba6P75BEbc1XIWvq2Fv8muaw4pCe81QYINyLqgcPNO/nF3Os A2IZp9zSxMQL9bKiI2GRj+cV2ebSCGbg2btFnD6qBor7FWsmYz+8g6FNN/9sY4az
5EI4HKjCNRSCOhOcWqYctXLXN9lBdMBBvQc3zDmYzh1eIZewzZXPVEQT33xPkhxz 61rMqMtQvLBe+7L8w70FeTze4qQ4Y1oQri0qD6tBWhDVlpnbI5Py9bkZKD67yVUk
HNmhcIctpWX4LTRF6FulkcbeuZDga3gkZYJf/M6IpU1WYXr6q8sNxbgmRRX/NuHo elcEA/5x4PrYXkuqsAECQQD80NjT0mDvaY0JOOaQFSEpMv6QiUA8GGX8Xli7IoKb
V9oDwBzLG07rKUiqRHfjGqoCRmmVeVYpryvXUNjHGH0nlVzz/8lTUxAnJorO3Fdc tAolPG8rQBa+qSpcWfDMTrWw/aWHuMEEQoP/bVDH9W4FAkEA7SYQbBAKnojZ5A3G
I+6zKLUPICdAlvz51AH6yopgPFhrdgA0pVzPO6L5G8SRQCxKhAUCAwEAAQKCAYAa kOHdV7aeivRQxQk/JN8Fb8oKB9Csvpv/BsuGxPKXHdhFa6CBTTsNRtHQw/szPo4l
2jtOTcNMFGH3G7TfFZ+kolbuaPCQ/aQkEV2k1dAswzgWw8RsWXI+7fLyi8C7Zhks xMIjgQJAPoMxqibR+0EBM6+TKzteSL6oPXsCnBl4Vk/J5vPgkbmR7KUl4+7j8N8J
9VD4tyNyU8at7D0zSoYm1Fh9sl+fcQp9rG/gSBA6IYu7EdD0gEM7YeY4K2nm9k4s b2554TrxKEN/w7CGYZRE6UrRd7ATNQJAWD7Yz41sli+wfPdPU2xo1BHljyl4wMk/
Lz8W4q+WqsBA6PK47cfjF6vKAH1AyRk28+jEtPiln9egf5zHWtyqOanh9D0V+Wh9 EPZYbI/PCbdyAH/F935WyQTIjNeEhZc1Zkq6FwdOWw8ns3hrv3rKgQJAHXv1BqUa
hgmjqAYI1rWxZ7/4Qxj7Bfg7Px7blhi+kzOZ5kKQnNd2JT46hM+jgzah/G3zVE+R czGPIFxX2TNoqtcl6/En4vrxVB1wzsfzkkDAg98kBl7qsF+S3qujSzKikjeaVbI2
FFW6ksmJgZ+dCuSbE7HEJmKms1CWq/1Cll0A3uy4JTDZOrK4KcZQ9UjjWJWvlXQm /CyWR2P3yLtOmA==
uNXSSAp1k287DLVUm9c22SDeXpb9PyKmzyvJvVmMqqBx6QzHZ/L7WPzpUWAoLcU+
ZHT7vggDymkIO+fcRbUzv8s5R7RnLbcBga51/5OCUvAWDoJXNw0qwYZOIbfTnQgs
8xbCmbMzllyYM/dK3GxQAwfn8Hzk+DbS/NObMjHLCWLfYeUvutXJSNly6Ny+ZcEC
gcEAzo5Y1UFOfBX4MZLIZ69LfgaXj9URobMwqlEwKil8pWQMa951ga3moLt91nOe
SAQz3meFTBX/VAb2ZHLeIf3FoNkiIx48PkxsR/hhLHpvl26zEg3yXs3tv0IFBx2R
EEnLNpQaAQFR9S1yDOaG2rsb17ZDKyp9isDpAENHAmEnT/XJn+Dc0SOH1EVDjUeM
JqToAF/fjIx/RF4oUJCAgOPBMlRy5ywLQk8uDi6ft0NCzzCi0eCuk1Ty3KzWFGwx
7cYRAoHBAMeIPCzHG3No4JGUFunslVwo5TuC7maO6qYKbq0OyvwWfL4b7gjrMBR9
d5WyZlp/Vf40O463dg8x8qPNOFWp49f3hxTvvfnt2/m3+CQuDOLfqBbHufZApP1J
U9MubUNnDFHHeJ9l0tg2nhiLw24GHeMARZhA/BimMQPY0OpZPpLVxAUArM2EB7hI
glQpYCtdXhqwl1pl0u3TZ08y3BXYNg9BycdpGRMWSsAwsApJRgNuI/dfDKu0uMYF
/pUhXVPatQKBwGgLpAun3dT7bA3sli5ESo6s22OEPGFrVbQ1OUHDrBnTj742TJKJ
+oY0a2q+ypgUJdx94NM2sWquJybqBaKxpf8j4OI3tLjc3h5SqwAwnE13YZRSmifP
K1cP9mBjMFM4GLjhWUfwVkxeG/kLlhpP7fJ2yNbRjHN8QOH1AavdLGRGts1mA1UF
xMHUMfbUd3Bv2L13ja/KhcD2fPA4GcLS9tpXV5nCwdkg8V4LdkBmDR04rotx1f44
6Czokt2usmfHQQKBwFkufxbUd2SB/72Rnxw27hse/DY5My0Lu70y9HzNG9TIiEDA
YwgBdp/x5D04W58fQuQ3nFcRkOcBwB2OYBuJr5ibvfiRnyvSMHvQykwBeSj+Jjbo
VinGgvfiimDdY2C48jyrFzLHZBHXd5oo/dRzT3Bicri2cvbhcQ7zHY1hDiK7AL3r
q1DALmMjpXzQcXdwZ9suCrgQwtIhpw8zAEOTO7ZeBT3nr5lkYUy9djFixrRJyjGK
fjNQtzVrAHrPStNr8QKBwQDCC0zhsCnTv4sAJmW7LL6Ayd5rbWhUZ6px1xY0yHMA
hehj+xbaiC6cfVr5Rg0ncvaa8AExu4kXpVsupTyNwvC4NgzLHtfBw6WUdOnd1awE
kSrDtDReBt2wByAcQwttQsrJ1/Pt6zcNJJI4Z9s8G4NTcQWJwUhU20N55JQKR//l
OQJqhq9NVhte/ctDjVwOHs/OhDNvxsAWxdjnf/O2up0os+M2bFkmHuaVW0vQbqTQ
mw7Vbzk2Ff5oT6E3kbC8Ur4=
-----END PRIVATE KEY----- -----END PRIVATE KEY-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIHMDCCBZigAwIBAgIJALVVA6v9zJS5MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV MIIDcjCCAtugAwIBAgIJAN5dc9TOWjB7MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnMwHhcNMTgwODI5 IFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnMwHhcNMTYwODA1
MTQyMzE3WhcNMjgwODI2MTQyMzE3WjBdMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwO MTAyMTExWhcNMjYwODAzMTAyMTExWjBdMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwO
Q2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0 Q2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0
aW9uMRAwDgYDVQQDDAdhbGxzYW5zMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB aW9uMRAwDgYDVQQDDAdhbGxzYW5zMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
igKCAYEAoP6TOnT+wUxTXKnusCCSAQex48C+Nm6dL43AlZeGdzEVhbMGKX8cvqPv gQDqMu/0DrU40NJ4hOrg3E8LZAtEdk78tQI1Z16IQp7WX3c20xg6GE4F0ji7D/AO
Pj4LjKeCus53QOX8DZCvx9x5rWp53FHz6p1dLrDdDR0Bof3/cUaDZgdati+5E7jv ve41IifFQnjxh+dMRmeAypwBd2vTt2vZ69qS129ImN1zjL/mBAYouwnyPt6MRWIA
faNCi0IL6J0U9rJ3/K6vZ7T0c4R1BmIaIO88zcXrWFd9PTx6T69fQXCnqQ7TOUTJ pdLDIB8ww9mU1WALJg1oC1FbBNoBxHHEcKzNrT39hIEfhQIDAQABo4IBODCCATQw
NmgZ6Deb7SLaK414g6LBZuqOcEB63LqXFcnbM22uj++QRG3NVyFr6thb/JrmsOKQ ggEwBgNVHREEggEnMIIBI4IHYWxsc2Fuc6AeBgMqAwSgFwwVc29tZSBvdGhlciBp
nvNUGCDci6oHDzTv5xdzrORCOByowjUUgjoTnFqmHLVy1zfZQXTAQb0HN8w5mM4d ZGVudGlmaWVyoDUGBisGAQUCAqArMCmgEBsOS0VSQkVST1MuUkVBTE2hFTAToAMC
XiGXsM2Vz1REE998T5IccxzZoXCHLaVl+C00RehbpZHG3rmQ4Gt4JGWCX/zOiKVN AQGhDDAKGwh1c2VybmFtZYEQdXNlckBleGFtcGxlLm9yZ4IPd3d3LmV4YW1wbGUu
VmF6+qvLDcW4JkUV/zbh6FfaA8AcyxtO6ylIqkR34xqqAkZplXlWKa8r11DYxxh9 b3JnpGcwZTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMw
J5Vc8//JU1MQJyaKztxXXCPusyi1DyAnQJb8+dQB+sqKYDxYa3YANKVczzui+RvE IQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UEAwwPZGly
kUAsSoQFAgMBAAGjggLxMIIC7TCCATAGA1UdEQSCAScwggEjggdhbGxzYW5zoB4G bmFtZSBleGFtcGxlhhdodHRwczovL3d3dy5weXRob24ub3JnL4cEfwAAAYcQAAAA
AyoDBKAXDBVzb21lIG90aGVyIGlkZW50aWZpZXKgNQYGKwYBBQICoCswKaAQGw5L AAAAAAAAAAAAAAAAAYgEKgMEBTANBgkqhkiG9w0BAQsFAAOBgQAy16h+F+nOmeiT
RVJCRVJPUy5SRUFMTaEVMBOgAwIBAaEMMAobCHVzZXJuYW1lgRB1c2VyQGV4YW1w VWR0fc8F/j6FcadbLseAUaogcC15OGxCl4UYpLV88HBkABOoGCpP155qwWTwOrdG
bGUub3Jngg93d3cuZXhhbXBsZS5vcmekZzBlMQswCQYDVQQGEwJYWTEXMBUGA1UE iYPGJSusf1OnJEbvzFejZf6u078bPd9/ZL4VWLjv+FPGkjd+N+/OaqMvgj8Lu99f
BwwOQ2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3Vu 3Y/C4S7YbHxxwff6C6l2Xli+q6gnuQ==
ZGF0aW9uMRgwFgYDVQQDDA9kaXJuYW1lIGV4YW1wbGWGF2h0dHBzOi8vd3d3LnB5
dGhvbi5vcmcvhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABiAQqAwQFMA4GA1UdDwEB
/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/
BAIwADAdBgNVHQ4EFgQUoLHAHNTWrHkSCUYkhn5NH0S40CAwgY8GA1UdIwSBhzCB
hIAUoLHAHNTWrHkSCUYkhn5NH0S40CChYaRfMF0xCzAJBgNVBAYTAlhZMRcwFQYD
VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv
dW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnOCCQC1VQOr/cyUuTCBgwYIKwYBBQUH
AQEEdzB1MDwGCCsGAQUFBzAChjBodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0
L3Rlc3RjYS9weWNhY2VydC5jZXIwNQYIKwYBBQUHMAGGKWh0dHA6Ly90ZXN0Y2Eu
cHl0aG9udGVzdC5uZXQvdGVzdGNhL29jc3AvMEMGA1UdHwQ8MDowOKA2oDSGMmh0
dHA6Ly90ZXN0Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL3Jldm9jYXRpb24uY3Js
MA0GCSqGSIb3DQEBCwUAA4IBgQAeKJKycO2DES98gyR2e/GzPYEw87cCS0cEpiiP
3CEUgzfEbF0X89GDKEey4H3Irvosbvt2hEcf2RNpahLUL/fUv53bDmHNmL8qJg5E
UJVMOHvOpSOjqoqeRuSyG0GnnAuUwcxdrZY6UzLdslhuq9F8UjgHr6KSMx56G9uK
LmTy5njMab0in2xL/YRX/0nogK3BHqpUHrfCdEYZkciRxtAa+OPpWn4dcZi+Fpf7
ZYSgPLNt+djtFDMIAk5Bo+XDaQdW3dhF0w44enrGAOV0xPE+/jOuenNhKBafjuNb
lkeSr45+QZsi1rd18ny8z3uuaGqIAziFgmllZOH2D8giTn6+5jZcCNZCoGKUkPI9
l/GMWwxg4HQYYlZcsZzTCem9Rb2XcrasAbmhFapMtR+QAwSed5vKE7ZdtQhj74kB
7Q0E7Lkgpp6BaObb2As8/f0K/UlSVSvrYk+i3JT9wK/qqkRGxsTFEF7N9t0rKu8y
4JdQDtZCI552MsFvYW6m+IOYgxg=
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,D134E931C96D9DEC DEK-Info: DES-EDE3-CBC,1A8D9D2A02EC698A
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
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIEWTCCAsGgAwIBAgIJAJinz4jHSjLtMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA4 IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
MjkxNDIzMTVaFw0yODA4MjYxNDIzMTVaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
DA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5k Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
YXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGP YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
ADCCAYoCggGBALKUqUtopT6E68kN+uJNEt34i2EbmG/bwjcD8IaMsgJPSsMO2Bpd gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
3S6qWgkCeOyCfmAwBxK2kNbxGb63ouysEv7l8GCTJTWv3hG/HQcejJpnAEGi6K1U 6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
fDbyE/db6yZ12SoHVTGkadN4vYGCPd1Wj9ZO1F877SHQ8rDWX3xgTWkxN2ojBw44 pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
T8RHSDiG8D/CvG4uEy+VUszL+Uvny5y2poNSqvI3J56sptWSrh8nIIbkPZPBdUne FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
LYMOHTFK3ZjXSmhlXgziTxK71nnzM3Y9K9gxPnRqoXbvu/wFo55hQCkETiRkYgmm BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
jXcBMZ0TClQVnQWuLjMthRnWFZs4Lfmwqjs7FZD/61581R2BYehvpWbLvvuOJhwv lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
DFzexL2sXcAl7SsxbzeQKRHqGbIDfbnQTXfs3/VC6Ye5P82P2ucj+XC32N9piRmO CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
gCBP8L3ub+YzzdxikZN2gZXXE2jsb3QyE/R2LkWdWyshpKe+RsZP1SBRbHShUyOh
yJ90baoiEwj2mwIDAQABoxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZI
hvcNAQELBQADggGBAHRUO/UIHl3jXQENewYayHxkIx8t7nu40iO2DXbicSijz5bo
5//xAB6RxhBAlsDBehgQP1uoZg+WJW+nHu3CIVOU3qZNZRaozxiCl2UFKcNqLOmx
R3NKpo1jYf4REQIeG8Yw9+hSWLRbshNteP6bKUUf+vanhg9+axyOEOH/iOQvgk/m
b8wA8wNa4ujWljPbTQnj7ry8RqhTM0GcAN5LSdSvcKcpzLcs3aYwh+Z8e30sQWna
F40sa5u7izgBTOrwpcDm/w5kC46vpRQ5fnbshVw6pne2by0mdMECASid/p25N103
jMqTFlmO7kpf/jpCSmamp3/JSEE1BJKHwQ6Ql4nzRA2N1mnvWH7Zxcv043gkHeAu
0x8evpvwuhdIyproejNFlBpKmW8OX7yKTCPPMC/VkX8Q1rVkxU0DQ6hmvwZlhoKa
9Wc2uXpw9xF8itV4Uvcdr3dwqByvIqn7iI/gB+4l41e0u8OmH2MKOx4Nxlly5TNW
HcVKQHyOeyvnINuBAQ==
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQCylKlLaKU+hOvJ MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
DfriTRLd+IthG5hv28I3A/CGjLICT0rDDtgaXd0uqloJAnjsgn5gMAcStpDW8Rm+ LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
t6LsrBL+5fBgkyU1r94Rvx0HHoyaZwBBouitVHw28hP3W+smddkqB1UxpGnTeL2B ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
gj3dVo/WTtRfO+0h0PKw1l98YE1pMTdqIwcOOE/ER0g4hvA/wrxuLhMvlVLMy/lL USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
58uctqaDUqryNyeerKbVkq4fJyCG5D2TwXVJ3i2DDh0xSt2Y10poZV4M4k8Su9Z5 CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
8zN2PSvYMT50aqF277v8BaOeYUApBE4kZGIJpo13ATGdEwpUFZ0Fri4zLYUZ1hWb SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
OC35sKo7OxWQ/+tefNUdgWHob6Vmy777jiYcLwxc3sS9rF3AJe0rMW83kCkR6hmy UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
A3250E137N/1QumHuT/Nj9rnI/lwt9jfaYkZjoAgT/C97m/mM83cYpGTdoGV1xNo BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
7G90MhP0di5FnVsrIaSnvkbGT9UgUWx0oVMjocifdG2qIhMI9psCAwEAAQKCAYBT ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
sHmaPmNaZj59jZCqp0YVQlpHWwBYQ5vD3pPE6oCttm0p9nXt/VkfenQRTthOtmT1 oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
POzDp00/feP7zeGLmqSYUjgRekPw4gdnN7Ip2PY5kdW77NWwDSzdLxuOS8Rq1MW9 eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
/Yu+ZPe3RBlDbT8C0IM+Atlh/BqIQ3zIxN4g0pzUlF0M33d6AYfYSzOcUhibOO7H 0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
j84r+YXBNkIRgYKZYbutRXuZYaGuqejRpBj3voVu0d3Ntdb6lCWuClpB9HzfGN0c x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
RTv8g6UYO4sK3qyFn90ibIR/1GB9watvtoWVZqggiWeBzSWVWRsGEf9O+Cx4oJw1 SPIXQuT8RMPDVNQ=
IphglhmhbgNksbj7bD24on/icldSOiVkoUemUOFmHWhCm4PnB1GmbD8YMfEdSbks
qDr1Ps1zg4mGOinVD/4cY7vuPFO/HCH07wfeaUGzRt4g0/yLr+XjVofOA3oowyxv
JAzr+niHA3lg5ecj4r7M68efwzN1OCyjMrVJw2RAzwvGxE+rm5NiT08SWlKQZnkC
gcEA4wvyLpIur/UB84nV3XVJ89UMNBLm++aTFzld047BLJtMaOhvNqx6Cl5c8VuW
l261KHjiVzpfNM3/A2LBQJcYkhX7avkqEXlj57cl+dCWAVwUzKmLJTPjfaTTZnYJ
xeN3dMYjJz2z2WtgvfvDoJLukVwIMmhTY8wtqqYyQBJ/l06pBsfw5TNvmVIOQHds
8ASOiFt+WRLk2bl9xrGGayqt3VV93KVRzF27cpjOgEcG74F3c0ZW9snERN7vIYwB
JfrlAoHBAMlahPwMP2TYylG8OzHe7EiehTekSO26LGh0Cq3wTGXYsK/q8hQCzL14
kWW638vpwXL6L9ntvrd7hjzWRO3vX/VxnYEA6f0bpqHq1tZi6lzix5CTUN5McpDg
QnjenSJNrNjS1zEF8WeY9iLEuDI/M/iUW4y9R6s3WpgQhPDXpSvd2g3gMGRUYhxQ
Xna8auiJeYFq0oNaOxvJj+VeOfJ3ZMJttd+Y7gTOYZcbg3SdRb/kdxYki0RMD2hF
4ZvjJ6CTfwKBwQDiMqiZFTJGQwYqp4vWEmAW+I4r4xkUpWatoI2Fk5eI5T9+1PLX
uYXsho56NxEU1UrOg4Cb/p+TcBc8PErkGqR0BkpxDMOInTOXSrQe6lxIBoECVXc3
HTbrmiay0a5y5GfCgxPKqIJhfcToAceoVjovv0y7S4yoxGZKuUEe7E8JY2iqRNAO
yOvKCCICv/hcN235E44RF+2/rDlOltagNej5tY6rIFkaDdgOF4bD7f9O5eEni1Bg
litfoesDtQP/3rECgcEAkQfvQ7D6tIPmbqsbJBfCr6fmoqZllT4FIJN84b50+OL0
mTGsfjdqC4tdhx3sdu7/VPbaIqm5NmX10bowWgWSY7MbVME4yQPyqSwC5NbIonEC
d6N0mzoLR0kQ+Ai4u+2g82gicgAq2oj1uSNi3WZi48jQjHYFulCbo246o1NgeFFK
77WshYe2R1ioQfQDOU1URKCR0uTaMHClgfu112yiGd12JAD+aF3TM0kxDXz+sXI5
SKy311DFxECZeXRLpcC3AoHBAJkNMJWTyPYbeVu+CTQkec8Uun233EkXa2kUNZc/
5DuXDaK+A3DMgYRufTKSPpDHGaCZ1SYPInX1Uoe2dgVjWssRL2uitR4ENabDoAOA
ICVYXYYNagqQu5wwirF0QeaMXo1fjhuuHQh8GsMdXZvYEaAITZ9/NG5x/oY08+8H
kr78SMBOPy3XQn964uKG+e3JwpOG14GKABdAlrHKFXNWchu/6dgcYXB87mrC/GhO
zNwzC+QhFTZoOomFoqMgFWujng==
-----END PRIVATE KEY----- -----END PRIVATE KEY-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIEWTCCAsGgAwIBAgIJAJinz4jHSjLtMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA4 IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
MjkxNDIzMTVaFw0yODA4MjYxNDIzMTVaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
DA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5k Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
YXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGP YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
ADCCAYoCggGBALKUqUtopT6E68kN+uJNEt34i2EbmG/bwjcD8IaMsgJPSsMO2Bpd gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
3S6qWgkCeOyCfmAwBxK2kNbxGb63ouysEv7l8GCTJTWv3hG/HQcejJpnAEGi6K1U 6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
fDbyE/db6yZ12SoHVTGkadN4vYGCPd1Wj9ZO1F877SHQ8rDWX3xgTWkxN2ojBw44 pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
T8RHSDiG8D/CvG4uEy+VUszL+Uvny5y2poNSqvI3J56sptWSrh8nIIbkPZPBdUne FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
LYMOHTFK3ZjXSmhlXgziTxK71nnzM3Y9K9gxPnRqoXbvu/wFo55hQCkETiRkYgmm BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
jXcBMZ0TClQVnQWuLjMthRnWFZs4Lfmwqjs7FZD/61581R2BYehvpWbLvvuOJhwv lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
DFzexL2sXcAl7SsxbzeQKRHqGbIDfbnQTXfs3/VC6Ye5P82P2ucj+XC32N9piRmO CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
gCBP8L3ub+YzzdxikZN2gZXXE2jsb3QyE/R2LkWdWyshpKe+RsZP1SBRbHShUyOh
yJ90baoiEwj2mwIDAQABoxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZI
hvcNAQELBQADggGBAHRUO/UIHl3jXQENewYayHxkIx8t7nu40iO2DXbicSijz5bo
5//xAB6RxhBAlsDBehgQP1uoZg+WJW+nHu3CIVOU3qZNZRaozxiCl2UFKcNqLOmx
R3NKpo1jYf4REQIeG8Yw9+hSWLRbshNteP6bKUUf+vanhg9+axyOEOH/iOQvgk/m
b8wA8wNa4ujWljPbTQnj7ry8RqhTM0GcAN5LSdSvcKcpzLcs3aYwh+Z8e30sQWna
F40sa5u7izgBTOrwpcDm/w5kC46vpRQ5fnbshVw6pne2by0mdMECASid/p25N103
jMqTFlmO7kpf/jpCSmamp3/JSEE1BJKHwQ6Ql4nzRA2N1mnvWH7Zxcv043gkHeAu
0x8evpvwuhdIyproejNFlBpKmW8OX7yKTCPPMC/VkX8Q1rVkxU0DQ6hmvwZlhoKa
9Wc2uXpw9xF8itV4Uvcdr3dwqByvIqn7iI/gB+4l41e0u8OmH2MKOx4Nxlly5TNW
HcVKQHyOeyvnINuBAQ==
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQDKjrjWZlfOs1Ch MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANcLaMB7T/Wi9DBc
qt1RoyLfqyXbHVXIAW0fTzAxfJnxvFOiWqAAKgC2qVQM8Y080kRUuRaXP/w9ywXT PltGzgt8cxsv55m7PQPHMZvn6Ke8xmNqcmEzib8opRwKGrCV6TltKeFlNSg8dwQK
+MzX6tByy5VbTYJYyTjHOH46EWLNdcqEJs4+FCVqOIYrQPQ6pGAhCXmgBy4Vb42J Tl4ktyTkGCVweRQJ37AkBayvEBml5s+QD4vlhqkJPsL/Nsd+fnqngOGc5+59+C6r
ABLwb+Kt+y2Dk15tggVcAHP2Khri+lRXWvda+kZAe2F1IojmuWyCTy3FEYHic5qN s3XpiLlF5ah/z8q92Mnw54nypw1JAgMBAAECgYBE3t2Mj7GbDLZB6rj5yKJioVfI
BsXcf6u1oyFV8MybOuz1zGj3vd2C+dEKO4Ohw9rRwnvHSatjM+CfwiXf8kTXzDBF BD6bSJEQ7bGgqdQkLFwpKMU7BiN+ekjuwvmrRkesYZ7BFgXBPiQrwhU5J28Tpj5B
Z/8W3+6yA49pHxRbG7FE3K1TAPhkrp+BVTIUOcdI74wEA6UEkWFF5sQcmmAth59M EOMYSIOHfzdalhxDGM1q2oK9LDFiCotTaSdEzMYadel5rmKXJ0zcK2Jho0PCuECf
EQrl2CXorftEPhsKZE59dUP1+nYAPvR/mTySNCSw7/rvdf+csRSZ5ollMu/lxsht tf/ghRxK+h1Hm0tKgQJBAO6MdGDSmGKYX6/5kPDje7we/lSLorSDkYmV0tmVShsc
ulJYJI03+IiDTn47FI5D+IF25REK7d4LzGIo6T73ktsT+qpSXHuTWC+IABm8AMF9 JxgaGaapazceA/sHL3Myx7Eenkip+yPYDXEDFvAKNDECQQDmxsT9NOp6mo7ISvky
7ljxHSwMRU/z+O5uiONRItDAgKH/OItFG54PtY2vAhaO0YiZrZcCAwEAAQKCAYB2 GFr2vVHsJ745BMWoma4rFjPBVnS8RkgK+b2EpDCdZSrQ9zw2r8sKTgrEyrDiGTEg
hTo8IVghlySH5B1p5kXCkDcvVaPaypLaLhCp9Blzq9lX9yUF043lU4Ddrf0RaIsY wJyZAkA8OOc0flYMJg2aHnYR6kwVjPmGHI5h5gk648EMPx0rROs1sXkiUwkHLCOz
88/3IjZqxb+cP0lE0Z20fdDfwqORZfQ2BaU+PuwMAm9EEhy9kDYwR/ChoHkHUyT4 HvhCq+Iv+9vX2lnVjbiu/CmxRdIxAkA1YEfzoKeTD+hyXxTgB04Sv5sRGegfXAEz
T7392BWr70Dmt8ddLmp5mK4R/gnTk6+lHJK9p/dhdk4haxWvAyBWHJty2Yk3T6nh i8gC4zG5R/vcCA1lrHmvEiLEZL/QcT6WD3bQvVg0SAU9ZkI8pxARAkA7yqMSvP1l
OYkzdUIFidUVza+6jG2hc1lPGv3tmnYKgNeulkblm10oWphz79C6ycx5WG7TNgef gJXy44R+rzpLYb1/PtiLkIkaKG3x9TUfPnfD2jY09fPkZlfsRU3/uS09IkhSwimV
CQ3z7//Nn89YTiaUBjLvoLvxRTMwO96r7E/FaslSl/fWnF3HP3lut26Z/mNfhiwj d5rWoljEfdou
qn7AhUwpSNPV0qcxFWXr/rXUjdk745wv8wOODK8atjjE/vt/MRBK0rAOIPSm3ecx
37PKNtR4i+sNeDEcY1IyTHE6wFvJSy5y8AFpn5y8tbqYfhlEVWZ4pcnlrKxhWm7j
oBkB/4GBjKQgbQ7ttym9eNG1wIbZ8v9N06+yeLs/NCc4bFZEgcWjFqBH1bLtAYEC
gcEA8tt8iYNqbsDH2ognjEmbbBxrDBmyYcEKRpg1i1SUopcZl8i93IHpG7EgJIaj
l7aWSbASAxjnK02t0VZ3nNS60acibzRwY/+e8OrSqlQdMXlAB2ggBA86drDJpfBl
WGJG8TJVY9bc1TU2uuwtZR1LAMSsRHVp+3IvKLpHrne5exPd3x6KGYcuaM+Uk/rE
u6tLsFNwaCdh+iBFFDT2bnYIw7jAsokJUkwxMVxSC0/21s2blhO/q5LsN1gFC1kN
TbpXAoHBANWE7TmG2szPvujPwrK18v6iJlHCA2n50AgAQXrsetj2JcF3HYHYdHnq
z36MQ6FpBKOiQumozWvb32WTjEwdG2kix7GEfam4DAUBdqYuCHzPcR12K5Tc8hsX
NG7JXUAeS8ZJEiOdu95X59JHyBxUQtNfte5rcbaV17SVw6K6bsWVJnj60YjtJrpa
xHvv1ZRnT2WEzJGpA+ii1h3I52N7ipGBiw172qcW+bKJukMi8eHxx5CC9e5tBpnu
C+Ou/eYewQKBwHxNa0jXQrq9YY2w8s0TP8HuKbxfyrXOIHxRm9ZczFcMD8VosgUT
WUUbO+B2KXWVtwawYAfFz0ySzcy//SkAmT6F1VIl/QCx7aBSENGti+Ous98WpIxv
XvUxN4T/rl+2raj2ok4fw5g9TG4QRIvkmmciQyonDr/sicbG0bmy/fTJDl8NOpIm
ZtKurNWxHNERtAPkMTyeK7/ilHjrQtb3AzVqcvbuvR6qcONa5YN0wlrfkisWoJwo
707EdpCAXBbUsQKBwQCnpzcpu2Sj+t9ZKIElF87T93gFLETH+ppJHgJMRdDz+NqO
fTwTD2XtsNz57aLQ44f8AFVv6NZbQYq41FEOFrDGLcQE9BZDpDrz10FVnMGXVr7n
tjjkK1SCxwapkr0AsoknCYsPojO4kud46loLPHI4TGeq7HyeNCvqJMo3RRHjXIiX
58GNNUD6hHjRI/FdFH14Jf0GxmJGUU20l2Jwb7nPJJuNm9mE53pqoNA7FP4+Pj1H
kD0Q2FSdmxeE0IuWHEECgcBgw6ogJ/FRRGLcym+aApqP9BChK+W8FDfDc9Mi4p/J
g+XmetWNFGCGTlOefGqUDIkwSG+QVOEN3hxziXbsjnvfpGApqoaulAI5oRvrwIcj
QIvD2mt0PB52k5ZL9QL2K9sgBa43BJDyCKooMAlTy2XMM+NyXVxQKmzf3r3jQ5sl
Rptk7ro38a9G8Rs99RFDyOmP1haOM0KXZvPksN4nsXuTlE01cnwnI29XKAlEZaoA
pQPLXD8W/KK4mwDbmokYXmo=
-----END PRIVATE KEY----- -----END PRIVATE KEY-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIEYjCCAsqgAwIBAgIJAJm2YulYpr+6MA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV MIICXTCCAcagAwIBAgIJALVQzebTtrXFMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTAeFw0x IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTAeFw0x
ODA4MjkxNDIzMTZaFw0yODA4MjYxNDIzMTZaMGIxCzAJBgNVBAYTAlhZMRcwFQYD NDExMjMxNzAwMDdaFw0yNDExMjAxNzAwMDdaMGIxCzAJBgNVBAYTAlhZMRcwFQYD
VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv
dW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTCCAaIwDQYJKoZIhvcNAQEB dW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTCBnzANBgkqhkiG9w0BAQEF
BQADggGPADCCAYoCggGBAMqOuNZmV86zUKGq3VGjIt+rJdsdVcgBbR9PMDF8mfG8 AAOBjQAwgYkCgYEA1wtowHtP9aL0MFw+W0bOC3xzGy/nmbs9A8cxm+fop7zGY2py
U6JaoAAqALapVAzxjTzSRFS5Fpc//D3LBdP4zNfq0HLLlVtNgljJOMc4fjoRYs11 YTOJvyilHAoasJXpOW0p4WU1KDx3BApOXiS3JOQYJXB5FAnfsCQFrK8QGaXmz5AP
yoQmzj4UJWo4hitA9DqkYCEJeaAHLhVvjYkAEvBv4q37LYOTXm2CBVwAc/YqGuL6 i+WGqQk+wv82x35+eqeA4Zzn7n34LquzdemIuUXlqH/Pyr3YyfDnifKnDUkCAwEA
VFda91r6RkB7YXUiiOa5bIJPLcURgeJzmo0Gxdx/q7WjIVXwzJs67PXMaPe93YL5 AaMbMBkwFwYDVR0RBBAwDoIMZmFrZWhvc3RuYW1lMA0GCSqGSIb3DQEBBQUAA4GB
0Qo7g6HD2tHCe8dJq2Mz4J/CJd/yRNfMMEVn/xbf7rIDj2kfFFsbsUTcrVMA+GSu AKuay3vDKfWzt5+ch/HHBsert84ISot4fUjzXDA/oOgTOEjVcSShHxqNShMOW1oA
n4FVMhQ5x0jvjAQDpQSRYUXmxByaYC2Hn0wRCuXYJeit+0Q+GwpkTn11Q/X6dgA+ QYBpBB/5Kx5RkD/w6imhucxt2WQPRgjX4x4bwMipVH/HvFDp03mG51/Cpi1TyZ74
9H+ZPJI0JLDv+u91/5yxFJnmiWUy7+XGyG26UlgkjTf4iINOfjsUjkP4gXblEQrt El7qa/Pd4lHhOLzMKBA6503fpeYSFUIBxZbGLqylqRK7
3gvMYijpPveS2xP6qlJce5NYL4gAGbwAwX3uWPEdLAxFT/P47m6I41Ei0MCAof84
i0Ubng+1ja8CFo7RiJmtlwIDAQABoxswGTAXBgNVHREEEDAOggxmYWtlaG9zdG5h
bWUwDQYJKoZIhvcNAQELBQADggGBAMIVLp6e6saH2NQSg8iFg8Ewg/K/etI++jHo
gCJ697AY02wtfrBox1XtljlmI2xpJtVAYZWHhrNqwrEG43aB7YEV6RqTcG6QUVqa
NbD8iNCnMKm7fP89hZizmqA1l4aHnieI3ucOqpgooM7FQwLX6qk+rSue6lD5N/5f
avsublnj8rNKyDfHpQ3AWduLoj8QqctpzI3CqoDZNLNzaDnzVWpxT1SKDQ88q7VI
W5zb+lndpdQlCu3v5HM4w5UpwL/k1htl/z6PnPseS2UdlXv6A8KITnCLg5PLP4tz
2oTAg9gjOtRP/0uwkhvicwoFzFJNVT813lzTLE1jlobMPiZhsS1mjaJGPD9GQZDK
ny3j8ogrIRGjnI4xpOMNNDVphcvwtV8fRbvURSHCj9Y4kCLpD5ODuoyEyLYicJIv
GZP456GP0iSCK5GKO0ij/YzGCkPWD5zA+mYFpMMGZPTwajenMw7TVaPXcc9CZBtr
oOjwwiLEqdkpxUj13mJYTlt5wsS/Kw==
-----END CERTIFICATE----- -----END CERTIFICATE-----
This diff is collapsed.
This diff is collapsed.
Certificate: Certificate:
Data: Data:
Version: 3 (0x2) Version: 3 (0x2)
Serial Number: Serial Number: 12723342612721443280 (0xb09264b1f2da21d0)
cb:2d:80:99:5a:69:52:5b Signature Algorithm: sha1WithRSAEncryption
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Validity Validity
Not Before: Aug 29 14:23:16 2018 GMT Not Before: Jan 4 19:47:07 2013 GMT
Not After : Aug 26 14:23:16 2028 GMT Not After : Jan 2 19:47:07 2023 GMT
Subject: C=XY, O=Python Software Foundation CA, CN=our-ca-server Subject: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Subject Public Key Info: Subject Public Key Info:
Public Key Algorithm: rsaEncryption Public Key Algorithm: rsaEncryption
Public-Key: (3072 bit) Public-Key: (2048 bit)
Modulus: Modulus:
00:97:ed:55:41:ba:36:17:95:db:71:1c:d3:e1:61: 00:e7:de:e9:e3:0c:9f:00:b6:a1:fd:2b:5b:96:d2:
ac:58:73:e3:c6:96:cf:2b:1f:b8:08:f5:9d:4b:4b: 6f:cc:e0:be:86:b9:20:5e:ec:03:7a:55:ab:ea:a4:
c7:30:f6:b8:0b:b3:52:72:a0:bb:c9:4d:3b:8e:df: e9:f9:49:85:d2:66:d5:ed:c7:7a:ea:56:8e:2d:8f:
22:8e:01:57:81:c9:92:73:cc:00:c6:ec:70:b0:3a: e7:42:e2:62:28:a9:9f:d6:1b:8e:eb:b5:b4:9c:9f:
17:40:c1:df:f2:8c:36:4c:c4:a7:81:e7:b6:24:68: 14:ab:df:e6:94:8b:76:1d:3e:6d:24:61:ed:0c:bf:
e2:a0:7e:35:07:2f:a0:5b:f9:45:46:f7:1e:f0:46: 00:8a:61:0c:df:5c:c8:36:73:16:00:cd:47:ba:6d:
11:fe:ca:1a:3c:50:f1:26:a9:5f:9c:22:9c:f8:41: a4:a4:74:88:83:23:0a:19:fc:09:a7:3c:4a:4b:d3:
e1:df:4f:12:95:19:2f:5c:90:01:17:6e:7e:3e:7d: e7:1d:2d:e4:ea:4c:54:21:f3:26:db:89:37:18:d4:
cf:e9:09:af:25:f8:f8:42:77:2d:6d:5f:36:f2:78: 02:bb:40:32:5f:a4:ff:2d:1c:f7:d4:bb:ec:8e:cf:
1e:7d:4a:87:68:63:6c:06:71:1b:8d:fa:25:fe:d4: 5c:82:ac:e6:7c:08:6c:48:85:61:07:7f:25:e0:5c:
d3:f5:a5:17:b1:ef:ea:17:cb:54:c8:27:99:80:cb: e0:bc:34:5f:e0:b9:04:47:75:c8:47:0b:8d:bc:d6:
3c:45:f1:2c:52:1c:dd:1f:51:45:20:50:1e:5e:ab: c8:68:5f:33:83:62:d2:20:44:35:b1:ad:81:1a:8a:
57:73:1b:41:78:96:de:84:a4:7a:dd:8f:30:85:36: cd:bc:35:b0:5c:8b:47:d6:18:e9:9c:18:97:cc:01:
58:79:76:a0:d2:61:c8:1b:a9:94:99:63:c6:ee:f8: 3c:29:cc:e8:1e:e4:e4:c1:b8:de:e7:c2:11:18:87:
14:bf:b4:52:56:31:97:fa:eb:ac:53:9e:95:ce:4c: 5a:93:34:d8:a6:25:f7:14:71:eb:e4:21:a2:d2:0f:
c4:5a:4a:b7:ca:03:27:5b:35:57:ce:02:dc:ec:ca: 2e:2e:d4:62:00:35:d3:d6:ef:5c:60:4b:4c:a9:14:
69:f8:8a:5a:39:cb:16:20:15:03:24:61:6c:f4:7a: e2:dd:15:58:46:37:33:26:b7:e7:2e:5d:ed:42:e4:
fc:b6:48:e5:59:10:5c:49:d0:23:9f:fb:71:5e:3a: c5:4d
e9:68:9f:34:72:80:27:b6:3f:4c:b1:d9:db:63:7f:
67:68:4a:6e:11:f8:e8:c0:f4:5a:16:39:53:0b:68:
de:77:fa:45:e7:f8:91:cd:78:cd:28:94:97:71:54:
fb:cf:f0:37:de:c9:26:c5:dc:1b:9e:89:6d:09:ac:
c8:44:71:cb:6d:f1:97:31:d5:4c:20:33:bf:75:4a:
a0:e0:dc:69:11:ed:2a:b4:64:10:11:30:8b:0e:b0:
a7:10:d8:8a:c5:aa:1b:c8:26:8a:25:e7:66:9f:a5:
6a:1a:2f:7c:5f:83:c6:78:4f:1f
Exponent: 65537 (0x10001) Exponent: 65537 (0x10001)
X509v3 extensions: X509v3 extensions:
X509v3 Subject Key Identifier: X509v3 Subject Key Identifier:
DD:BF:CA:DA:E6:D1:34:BA:37:75:21:CA:6F:9A:08:28:F2:35:B6:48 BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B
X509v3 Authority Key Identifier: X509v3 Authority Key Identifier:
keyid:DD:BF:CA:DA:E6:D1:34:BA:37:75:21:CA:6F:9A:08:28:F2:35:B6:48 keyid:BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B
X509v3 Basic Constraints: X509v3 Basic Constraints:
CA:TRUE CA:TRUE
Signature Algorithm: sha256WithRSAEncryption Signature Algorithm: sha1WithRSAEncryption
33:6a:54:d3:6b:c0:d7:01:5f:9d:f4:05:c1:93:66:90:50:d0: 7d:0a:f5:cb:8d:d3:5d:bd:99:8e:f8:2b:0f:ba:eb:c2:d9:a6:
b7:18:e9:b0:1e:4a:a0:b6:da:76:93:af:84:db:ad:15:54:31: 27:4f:2e:7b:2f:0e:64:d8:1c:35:50:4e:ee:fc:90:b9:8d:6d:
15:13:e4:de:7e:4e:0c:d5:09:1c:34:35:b6:e5:4c:d6:6f:65: a8:c5:c6:06:b0:af:f3:2d:bf:3b:b8:42:07:dd:18:7d:6d:95:
7d:32:5f:eb:fc:a9:6b:07:f7:49:82:e5:81:7e:07:80:9a:63: 54:57:85:18:60:47:2f:eb:78:1b:f9:e8:17:fd:5a:0d:87:17:
f8:2c:c3:40:bc:8f:d4:2a:da:3e:d1:ee:08:b7:4d:a7:84:ca: 28:ac:4c:6a:e6:bc:29:f4:f4:55:70:29:42:de:85:ea:ab:6c:
f4:3f:a1:98:45:be:b1:05:69:e7:df:d7:99:ab:1b:ee:8b:30: 23:06:64:30:75:02:8e:53:bc:5e:01:33:37:cc:1e:cd:b8:a4:
cc:f7:fc:e7:d4:0b:17:ae:97:bf:e4:7b:fd:0f:a7:b4:85:79: fd:ca:e4:5f:65:3b:83:1c:86:f1:55:02:a0:3a:8f:db:91:b7:
e3:59:e2:16:87:bf:1f:29:45:2c:23:93:76:be:c0:87:1d:de: 40:14:b4:e7:8d:d2:ee:73:ba:e3:e5:34:2d:bc:94:6f:4e:24:
ec:2b:42:6a:e5:bb:c8:f4:0a:4a:08:0a:8c:5c:d8:7d:4d:d1: 06:f7:5f:8b:0e:a7:8e:6b:de:5e:75:f4:32:9a:50:b1:44:33:
b8:bf:d5:f7:29:ed:92:d1:94:04:e8:35:06:57:7f:2c:23:97: 9a:d0:05:e2:78:82:ff:db:da:8a:63:eb:a9:dd:d1:bf:a0:61:
87:a5:35:8d:26:d3:1a:47:f2:16:d7:d9:c6:d4:1f:23:43:d3: ad:e3:9e:8a:24:5d:62:0e:e7:4c:91:7f:ef:df:34:36:3b:2f:
26:99:39:ca:20:f4:71:23:6f:0c:4a:76:76:f7:76:1f:b3:fe: 5d:f5:84:b2:2f:c4:6d:93:96:1a:6f:30:28:f1:da:12:9a:64:
bf:47:b0:fc:2a:56:81:e1:d2:dd:ee:08:d8:f4:ff:5a:dc:25: b4:40:33:1d:bd:de:2b:53:a8:ea:be:d6:bc:4e:96:f5:44:fb:
61:8a:91:02:b9:86:1c:f2:50:73:76:25:35:fc:b6:25:26:15: 32:18:ae:d5:1f:f6:69:af:b6:4e:7b:1d:58:ec:3b:a9:53:a3:
cb:eb:c4:2b:61:0c:1c:e7:ee:2f:17:9b:ec:f0:d4:a1:84:e7: 5e:58:c8:9e
d2:af:de:e4:1b:24:14:a7:01:87:e3:ab:29:58:46:a0:d9:c0:
0a:e0:8d:d7:59:d3:1b:f8:54:20:3e:78:a5:a5:c8:4f:8b:03:
c4:96:9f:ec:fb:47:cf:76:2d:8d:65:34:27:bf:fa:ae:01:05:
8a:f3:92:0a:dd:89:6c:97:a1:c7:e7:60:51:e7:ac:eb:4b:7d:
2c:b8:65:c9:fe:5d:6a:48:55:8e:e4:c7:f9:6a:40:e1:b8:64:
45:e9:b5:59:29:a5:5f:cf:7d:58:7d:64:79:e5:a4:09:ac:1e:
76:65:3d:94:c4:68
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
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 9mmvtk57HVjsO6lTo15YyJ4=
fU3RuL/V9yntktGUBOg1Bld/LCOXh6U1jSbTGkfyFtfZxtQfI0PTJpk5yiD0cSNv
DEp2dvd2H7P+v0ew/CpWgeHS3e4I2PT/WtwlYYqRArmGHPJQc3YlNfy2JSYVy+vE
K2EMHOfuLxeb7PDUoYTn0q/e5BskFKcBh+OrKVhGoNnACuCN11nTG/hUID54paXI
T4sDxJaf7PtHz3YtjWU0J7/6rgEFivOSCt2JbJehx+dgUees60t9LLhlyf5dakhV
juTH+WpA4bhkRem1WSmlX899WH1keeWkCawedmU9lMRo
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN X509 CRL----- -----BEGIN X509 CRL-----
MIICJjCBjwIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE MIIBpjCBjwIBATANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE
CgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91ci1j CgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91ci1j
YS1zZXJ2ZXIXDTE4MDgyOTE0MjMxNloXDTI4MDcwNzE0MjMxNlqgDjAMMAoGA1Ud YS1zZXJ2ZXIXDTEzMTEyMTE3MDg0N1oXDTIzMDkzMDE3MDg0N1qgDjAMMAoGA1Ud
FAQDAgEAMA0GCSqGSIb3DQEBCwUAA4IBgQCPhrtGSbuvxPAI3YWQFDB4iOWdBnVk FAQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQCNJXC2mVKauEeN3LlQ3ZtM5gkH3ExH
ugW1lsifmCsE86FfID0EwUut1SRHlksltMtcoULMEIdu8yMLWci++4ve22EEuMKT +i4bmJjtJn497WwvvoIeUdrmVXgJQR93RtV37hZwN0SXMLlNmUZPH4rHhihayw4m
HUc3T/wBIuQUhA7U4deFG8CZPAxRpNoK470y7dkD4OVf0Gxa6WYDl9z8mXKmWCB9 unCzVj/OhCCY7/TPjKuJ1O/0XhaLBpBVjQN7R/1ujoRKbSia/CD3vcn7Fqxzw7LK
hvzqVfLWNSLTAVPsHtkD5PXdi5yRkQr6wYD7poWaIvkpsn7EKCY6Tw5V3rsbRuZq fSRCKRGTj1CZiuxrphtFchwALXSiFDy9mr2ZKhImcyq1PydfgEzU78APpOkMQsIC
AGVCq5TH3mctcmwLloCJ4Xr/1q0DsRrYxeeLYxE+UpvvCbVBKgtjBK7zINS7AbcJ UNJ/cf3c9emzf+dUtcMEcejQ3mynBo4eIGg1EW42bz4q4hSjzQlKcBV0muw5qXhc
CYCYKUwGWv1fYKJ+KQQHf75mT3jQ9lWuzOj/YWK4k1EBnYmVGuKKt73lLFxC6h3y HOxH2iTFhQ7SrvVuK/dM14rYM4B5mSX3nRC1kNmXpS9j3wJDhuwmjHed
MUnaBZc1KZSyJj0IxfHg/o6qx8NgKOl9XRIQ5g5B30cwpPOskGhEhodbTTY3bPtm
RQ36JvQZngzmkhyhr+MDEV5yUTOShfUiclzQOx26CmLmLHWxOZgXtFZob/oKrvbm
Gen/+7K7YTw6hfY52U7J2FuQRGOyzBXfBYQ=
-----END X509 CRL----- -----END X509 CRL-----
This diff is collapsed.
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIEWTCCAsGgAwIBAgIJAJinz4jHSjLtMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA4 IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
MjkxNDIzMTVaFw0yODA4MjYxNDIzMTVaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
DA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5k Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
YXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGP YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
ADCCAYoCggGBALKUqUtopT6E68kN+uJNEt34i2EbmG/bwjcD8IaMsgJPSsMO2Bpd gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
3S6qWgkCeOyCfmAwBxK2kNbxGb63ouysEv7l8GCTJTWv3hG/HQcejJpnAEGi6K1U 6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
fDbyE/db6yZ12SoHVTGkadN4vYGCPd1Wj9ZO1F877SHQ8rDWX3xgTWkxN2ojBw44 pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
T8RHSDiG8D/CvG4uEy+VUszL+Uvny5y2poNSqvI3J56sptWSrh8nIIbkPZPBdUne FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
LYMOHTFK3ZjXSmhlXgziTxK71nnzM3Y9K9gxPnRqoXbvu/wFo55hQCkETiRkYgmm BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
jXcBMZ0TClQVnQWuLjMthRnWFZs4Lfmwqjs7FZD/61581R2BYehvpWbLvvuOJhwv lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
DFzexL2sXcAl7SsxbzeQKRHqGbIDfbnQTXfs3/VC6Ye5P82P2ucj+XC32N9piRmO CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
gCBP8L3ub+YzzdxikZN2gZXXE2jsb3QyE/R2LkWdWyshpKe+RsZP1SBRbHShUyOh
yJ90baoiEwj2mwIDAQABoxgwFjAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZI
hvcNAQELBQADggGBAHRUO/UIHl3jXQENewYayHxkIx8t7nu40iO2DXbicSijz5bo
5//xAB6RxhBAlsDBehgQP1uoZg+WJW+nHu3CIVOU3qZNZRaozxiCl2UFKcNqLOmx
R3NKpo1jYf4REQIeG8Yw9+hSWLRbshNteP6bKUUf+vanhg9+axyOEOH/iOQvgk/m
b8wA8wNa4ujWljPbTQnj7ry8RqhTM0GcAN5LSdSvcKcpzLcs3aYwh+Z8e30sQWna
F40sa5u7izgBTOrwpcDm/w5kC46vpRQ5fnbshVw6pne2by0mdMECASid/p25N103
jMqTFlmO7kpf/jpCSmamp3/JSEE1BJKHwQ6Ql4nzRA2N1mnvWH7Zxcv043gkHeAu
0x8evpvwuhdIyproejNFlBpKmW8OX7yKTCPPMC/VkX8Q1rVkxU0DQ6hmvwZlhoKa
9Wc2uXpw9xF8itV4Uvcdr3dwqByvIqn7iI/gB+4l41e0u8OmH2MKOx4Nxlly5TNW
HcVKQHyOeyvnINuBAQ==
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,8064BE1494B24B13 DEK-Info: DES-EDE3-CBC,1A8D9D2A02EC698A
KJrffOMbo8M0I3PzcYxRZGMpKD1yB3Ii4+bT5XoanxjIJ+4fdx6LfZ0Rsx+riyzs kJYbfZ8L0sfe9Oty3gw0aloNnY5E8fegRfQLZlNoxTl6jNt0nIwI8kDJ36CZgR9c
tymsQu/iYY9j+4rCvN9+eetsL1X6iZpiimKsLexcid9M3fb0vxED5Sgw0dvunCUA u3FDJm/KqrfUoz8vW+qEnWhSG7QPX2wWGPHd4K94Yz/FgrRzZ0DoK7XxXq9gOtVA
xhqjLIKR92MKbODHf6KrDKCpsiPbjq4gZ7P+uCGXAMHL3MXIJSC0hW9rK7Ce6oyO AVGQhnz32p+6WhfGsCr9ArXEwRZrTk/FvzEPaU5fHcoSkrNVAGX8IpSVkSDwEDQr
CjpIcgB8x+GUWZZZhAFdlzIHMZrteNP2P5HK6QcaT71P034Dz1hhqoj4Q0t+Fta2 Gv17+cfk99UV1OCza6yKHoFkTtrC+PZU71LomBabivS2Oc4B9hYuSR2hF01wTHP+
4tfsM/bnTR/l6hwlhPa1e3Uj322tDTDWBScgWANn5+sEWldLmozMaWhZsn22pfk2 YlWNagZOOVtNz4oKK9x9eNQpmfQXQvPPTfusexKIbKfZrMvJoxcm1gfcZ0H/wK6P
KjRMGXG024JVheV882nbdOBvG7oq+lxkZ/ZP+vvqJqnvYtf7WtM8UivzYpe5Hz5b 6wmXSG35qMOOztCZNtperjs1wzEBXznyK8QmLcAJBjkfarABJX9vBEzZV0OUKhy+
kVvWzPjBLUSZ9whM9rDLqSSqMPyPvDTuEmLkuq+xm7pYJmsLqIMP2klZLqRxLX6K noORFwHTllphbmydLhu6ehLUZMHPhzAS5UN7srtpSN81eerDMy0RMUAwA7/PofX1
uqwplb8UG440qauxgnQ905PId1l2fJEnRtV+7vXprA0L0QotgXLVHBhLmTFM+3PH 94Me85Q8jP0PC9ETdsJcPqLzAPETEYu0ELewKRcrdyWi+tlLFrpE5KT/s5ecbl9l
9H3onf31dionUAPrn3nfVE36HhvVgRyvDBnBzJSIMighgq21Qx/d1dk0DRYi1hUI 7B61U4Kfd1PIXc/siINhU3A3bYK+845YyUArUOnKf1kEox7p1RpD7yFqVT04lRTo
nCHl0YJPXheVcXR7JiSF2XQCAaFuS1Mr7NCXfWZOZQC/0dkvmHnl9DUAhuqq9BNZ cibNKATBusXSuBrp2G6GNuhWEOSafWCKJQAzgCYIp6ZTV2khhMUGppc/2H3CF6cO
1cKhZXcKHadg2/r0Zup/oDzmHPUEfTAXT0xbqoWlhkdwbF2veWQ96A/ncx3ISTb4 zX0KtlPVZC7hLkB6HT8SxYUwF1zqWY7+/XPPdc37MeEZ87Q3UuZwqORLY+Z0hpgt
PkXBlX9rdia8nmtyQDQRn4NuvchbaGkj4WKFC8pF8Hn7naHqwjpHaDUimBc0CoQW L5JXBCoklZhCAaN2GqwFLXtGiRSRFGY7xXIhbDTlE65Wv1WGGgDLMKGE1gOz3yAo
edNJqruKWwtSVLuwKHCC2gZFX9AXSKJXJz/QRSUlhFGOhuF/J6yKaXj6n5lxWNiQ 2jjG1+yAHJUdE69XTFHSqSkvaloA1W03LdMXZ9VuQJ/ySXCie6ABAQ==
54J+OP/hz2aS95CD2+Zf1SKpxdWiLZSIQqESpmmUrXROixNJZ/Z7gI74Dd9dSJOH
W+3AU03vrrFZVrJVZhjcINHoH1Skh6JKscH18L6x4U868nSr4SrRLX8BhHllOQyD
bmU+PZAjF8ZBIaCtTGulDXD29F73MeAZeTSsgQjFu0iKLj1wPiphbx8i/SUtR4YP
X6PVA04g66r1NBw+3RQASVorZ3g1MSFvITHXcbKkBDeJH2z1+c6t/VVyTONnQhM5
lLgRSk6HCbetvT9PKxWrWutA12pdBYEHdZhMHVf2+xclky7l09w8hg2/qqcdGRGe
oAOZ72t0l5ObNyaruDKUS6f4AjOyWq/Xj5xuFtf1n3tQHyslSyCTPcAbQhDfTHUx
vixb/V9qvYPt7OCn8py7v1M69NH42QVFAvwveDIFjZdqfIKBoJK2V4qPoevJI6uj
Q5ByMt8OXOjSXNpHXpYQWUiWeCwOEBXJX8rzCHdMtg37jJ0zCmeErR1NTdg+EujM
TWYgd06jlT67tURST0aB2kg4ijKgUJefD313LW1zC6gVsTbjSZxYyRbPfSP6flQB
yCi1C19E2OsgleqbkBVC5GlYUzaJT7SGjCRmGx1eqtbrALu+LVH24Wceexlpjydl
+s2nf/DZlKun/tlPh6YioifPCJjByZMQOCEfIox6BkemZETz8uYA4TTWimG13Z03
gyDGC2jdpEW414J2qcQDvrdUgJ+HlhrAAHaWpMQDbXYxBGoZ+3+ORvQV4kAsCwL8
k3EIrVpePdik+1xgOWsyLj6QxFXlTMvL6Wc5pnArFPORsgHEolJvxSPTf9aAHNPn
V2WBvxiLBtYpGrujAUM40Syx/aN2RPtcXYPAusHUBw+S8/p+/8Kg8GZmnIXG3F89
45Eepl2quZYIrou7a1fwIpIIZ0hFiBQ1mlHVMFtxwVHS1bQb3SU2GeO+JcGjdVXc
04qeGuQ5M164eQ5C0T7ZQ1ULiUlFWKD30m+cjqmZzt3d7Q0mKpMKuESIuZJo/wpD
Nas432aLKUhcNx/pOYLkKJRpGZKOupQoD5iUj/j44o8JoFkDK33v2S57XB5QGz28
9Zuhx49b3W8mbM6EBanlQKLWJGCxXqc/jhYhFWn+b0MhidynFgA0oeWvf6ZDyt6H
Yi5Etxsar09xp0Do3NxtQXLuSUu0ji2pQzSIKuoqQWKqldm6VrpwojiqJhy4WQBQ
aVVyFeWBC7G3Zj76dO+yp2sfJ0itJUQ8AIB9Cg0f34rEZu+r9luPmqBoUeL95Tk7
YvCOU3Jl8Iqysv8aNpVXT8sa8rrSbruWCByEePZ37RIdHLMVBwVY0eVaFQjrjU7E
mXmM9eaoYLfXOllsQ+M2+qPFUITr/GU3Qig13DhK/+yC1R6V2a0l0WRhMltIPYKW
Ztvvr4hK5LcYCeS113BLiMbDIMMZZYGDZGMdC8DnnVbT2loF0Rfmp80Af31KmMQ4
6XvMatW9UDjBoY5a/YMpdm7SRwm+MgV2KNPpc2kST87/yi9oprGAb8qiarHiHTM0
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQCylKlLaKU+hOvJ MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
DfriTRLd+IthG5hv28I3A/CGjLICT0rDDtgaXd0uqloJAnjsgn5gMAcStpDW8Rm+ LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
t6LsrBL+5fBgkyU1r94Rvx0HHoyaZwBBouitVHw28hP3W+smddkqB1UxpGnTeL2B ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
gj3dVo/WTtRfO+0h0PKw1l98YE1pMTdqIwcOOE/ER0g4hvA/wrxuLhMvlVLMy/lL USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
58uctqaDUqryNyeerKbVkq4fJyCG5D2TwXVJ3i2DDh0xSt2Y10poZV4M4k8Su9Z5 CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
8zN2PSvYMT50aqF277v8BaOeYUApBE4kZGIJpo13ATGdEwpUFZ0Fri4zLYUZ1hWb SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
OC35sKo7OxWQ/+tefNUdgWHob6Vmy777jiYcLwxc3sS9rF3AJe0rMW83kCkR6hmy UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
A3250E137N/1QumHuT/Nj9rnI/lwt9jfaYkZjoAgT/C97m/mM83cYpGTdoGV1xNo BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
7G90MhP0di5FnVsrIaSnvkbGT9UgUWx0oVMjocifdG2qIhMI9psCAwEAAQKCAYBT ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
sHmaPmNaZj59jZCqp0YVQlpHWwBYQ5vD3pPE6oCttm0p9nXt/VkfenQRTthOtmT1 oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
POzDp00/feP7zeGLmqSYUjgRekPw4gdnN7Ip2PY5kdW77NWwDSzdLxuOS8Rq1MW9 eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
/Yu+ZPe3RBlDbT8C0IM+Atlh/BqIQ3zIxN4g0pzUlF0M33d6AYfYSzOcUhibOO7H 0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
j84r+YXBNkIRgYKZYbutRXuZYaGuqejRpBj3voVu0d3Ntdb6lCWuClpB9HzfGN0c x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
RTv8g6UYO4sK3qyFn90ibIR/1GB9watvtoWVZqggiWeBzSWVWRsGEf9O+Cx4oJw1 SPIXQuT8RMPDVNQ=
IphglhmhbgNksbj7bD24on/icldSOiVkoUemUOFmHWhCm4PnB1GmbD8YMfEdSbks
qDr1Ps1zg4mGOinVD/4cY7vuPFO/HCH07wfeaUGzRt4g0/yLr+XjVofOA3oowyxv
JAzr+niHA3lg5ecj4r7M68efwzN1OCyjMrVJw2RAzwvGxE+rm5NiT08SWlKQZnkC
gcEA4wvyLpIur/UB84nV3XVJ89UMNBLm++aTFzld047BLJtMaOhvNqx6Cl5c8VuW
l261KHjiVzpfNM3/A2LBQJcYkhX7avkqEXlj57cl+dCWAVwUzKmLJTPjfaTTZnYJ
xeN3dMYjJz2z2WtgvfvDoJLukVwIMmhTY8wtqqYyQBJ/l06pBsfw5TNvmVIOQHds
8ASOiFt+WRLk2bl9xrGGayqt3VV93KVRzF27cpjOgEcG74F3c0ZW9snERN7vIYwB
JfrlAoHBAMlahPwMP2TYylG8OzHe7EiehTekSO26LGh0Cq3wTGXYsK/q8hQCzL14
kWW638vpwXL6L9ntvrd7hjzWRO3vX/VxnYEA6f0bpqHq1tZi6lzix5CTUN5McpDg
QnjenSJNrNjS1zEF8WeY9iLEuDI/M/iUW4y9R6s3WpgQhPDXpSvd2g3gMGRUYhxQ
Xna8auiJeYFq0oNaOxvJj+VeOfJ3ZMJttd+Y7gTOYZcbg3SdRb/kdxYki0RMD2hF
4ZvjJ6CTfwKBwQDiMqiZFTJGQwYqp4vWEmAW+I4r4xkUpWatoI2Fk5eI5T9+1PLX
uYXsho56NxEU1UrOg4Cb/p+TcBc8PErkGqR0BkpxDMOInTOXSrQe6lxIBoECVXc3
HTbrmiay0a5y5GfCgxPKqIJhfcToAceoVjovv0y7S4yoxGZKuUEe7E8JY2iqRNAO
yOvKCCICv/hcN235E44RF+2/rDlOltagNej5tY6rIFkaDdgOF4bD7f9O5eEni1Bg
litfoesDtQP/3rECgcEAkQfvQ7D6tIPmbqsbJBfCr6fmoqZllT4FIJN84b50+OL0
mTGsfjdqC4tdhx3sdu7/VPbaIqm5NmX10bowWgWSY7MbVME4yQPyqSwC5NbIonEC
d6N0mzoLR0kQ+Ai4u+2g82gicgAq2oj1uSNi3WZi48jQjHYFulCbo246o1NgeFFK
77WshYe2R1ioQfQDOU1URKCR0uTaMHClgfu112yiGd12JAD+aF3TM0kxDXz+sXI5
SKy311DFxECZeXRLpcC3AoHBAJkNMJWTyPYbeVu+CTQkec8Uun233EkXa2kUNZc/
5DuXDaK+A3DMgYRufTKSPpDHGaCZ1SYPInX1Uoe2dgVjWssRL2uitR4ENabDoAOA
ICVYXYYNagqQu5wwirF0QeaMXo1fjhuuHQh8GsMdXZvYEaAITZ9/NG5x/oY08+8H
kr78SMBOPy3XQn964uKG+e3JwpOG14GKABdAlrHKFXNWchu/6dgcYXB87mrC/GhO
zNwzC+QhFTZoOomFoqMgFWujng==
-----END PRIVATE KEY----- -----END PRIVATE KEY-----
...@@ -234,11 +234,17 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread): ...@@ -234,11 +234,17 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread):
def run(self): def run(self):
self.active = True self.active = True
self.__flag.set() self.__flag.set()
while self.active and asyncore.socket_map: try:
self.active_lock.acquire() while self.active and asyncore.socket_map:
asyncore.loop(timeout=0.1, count=1) self.active_lock.acquire()
self.active_lock.release() try:
asyncore.close_all(ignore_all=True) asyncore.loop(timeout=0.1, count=1)
except:
self.active_lock.release()
raise
self.active_lock.release()
finally:
asyncore.close_all(ignore_all=True)
def stop(self): def stop(self):
assert self.active assert self.active
......
...@@ -80,11 +80,11 @@ class CloseSocketTest(unittest.TestCase): ...@@ -80,11 +80,11 @@ class CloseSocketTest(unittest.TestCase):
# delve deep into response to fetch socket._socketobject # delve deep into response to fetch socket._socketobject
response = _urlopen_with_retry("http://www.example.com/") response = _urlopen_with_retry("http://www.example.com/")
abused_fileobject = response.fp abused_fileobject = response.fp
# self.assertIs(abused_fileobject.__class__, socket._fileobject) # gevent: disable # self.assertIs(abused_fileobject.__class__, socket._fileobject) # gevent: disabled
httpresponse = abused_fileobject._sock httpresponse = abused_fileobject._sock
self.assertIs(httpresponse.__class__, httplib.HTTPResponse) self.assertIs(httpresponse.__class__, httplib.HTTPResponse)
fileobject = httpresponse.fp fileobject = httpresponse.fp
# self.assertIs(fileobject.__class__, socket._fileobject) # gevent: disable # self.assertIs(fileobject.__class__, socket._fileobject) # gevent: disabled
self.assertTrue(not fileobject.closed) self.assertTrue(not fileobject.closed)
response.close() response.close()
...@@ -286,7 +286,7 @@ class TimeoutTest(unittest.TestCase): ...@@ -286,7 +286,7 @@ class TimeoutTest(unittest.TestCase):
self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 120) self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 120)
u.close() u.close()
FTP_HOST = 'ftp://ftp.debian.org/debian/' FTP_HOST = 'ftp://www.pythontest.net/'
def test_ftp_basic(self): def test_ftp_basic(self):
self.assertIsNone(socket.getdefaulttimeout()) self.assertIsNone(socket.getdefaulttimeout())
......
DH Parameters: (3072 bit)
prime:
00:ff:ff:ff:ff:ff:ff:ff:ff:ad:f8:54:58:a2:bb:
4a:9a:af:dc:56:20:27:3d:3c:f1:d8:b9:c5:83:ce:
2d:36:95:a9:e1:36:41:14:64:33:fb:cc:93:9d:ce:
24:9b:3e:f9:7d:2f:e3:63:63:0c:75:d8:f6:81:b2:
02:ae:c4:61:7a:d3:df:1e:d5:d5:fd:65:61:24:33:
f5:1f:5f:06:6e:d0:85:63:65:55:3d:ed:1a:f3:b5:
57:13:5e:7f:57:c9:35:98:4f:0c:70:e0:e6:8b:77:
e2:a6:89:da:f3:ef:e8:72:1d:f1:58:a1:36:ad:e7:
35:30:ac:ca:4f:48:3a:79:7a:bc:0a:b1:82:b3:24:
fb:61:d1:08:a9:4b:b2:c8:e3:fb:b9:6a:da:b7:60:
d7:f4:68:1d:4f:42:a3:de:39:4d:f4:ae:56:ed:e7:
63:72:bb:19:0b:07:a7:c8:ee:0a:6d:70:9e:02:fc:
e1:cd:f7:e2:ec:c0:34:04:cd:28:34:2f:61:91:72:
fe:9c:e9:85:83:ff:8e:4f:12:32:ee:f2:81:83:c3:
fe:3b:1b:4c:6f:ad:73:3b:b5:fc:bc:2e:c2:20:05:
c5:8e:f1:83:7d:16:83:b2:c6:f3:4a:26:c1:b2:ef:
fa:88:6b:42:38:61:1f:cf:dc:de:35:5b:3b:65:19:
03:5b:bc:34:f4:de:f9:9c:02:38:61:b4:6f:c9:d6:
e6:c9:07:7a:d9:1d:26:91:f7:f7:ee:59:8c:b0:fa:
c1:86:d9:1c:ae:fe:13:09:85:13:92:70:b4:13:0c:
93:bc:43:79:44:f4:fd:44:52:e2:d7:4d:d3:64:f2:
e2:1e:71:f5:4b:ff:5c:ae:82:ab:9c:9d:f6:9e:e8:
6d:2b:c5:22:36:3a:0d:ab:c5:21:97:9b:0d:ea:da:
1d:bf:9a:42:d5:c4:48:4e:0a:bc:d0:6b:fa:53:dd:
ef:3c:1b:20:ee:3f:d5:9d:7c:25:e4:1d:2b:66:c6:
2e:37:ff:ff:ff:ff:ff:ff:ff:ff
generator: 2 (0x2)
recommended-private-length: 276 bits
-----BEGIN DH PARAMETERS-----
MIIBjAKCAYEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3
7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32
nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZsYu
N///////////AgECAgIBFA==
-----END DH PARAMETERS-----
...@@ -32,6 +32,9 @@ class Bunch(object): ...@@ -32,6 +32,9 @@ class Bunch(object):
self.started = [] self.started = []
self.finished = [] self.finished = []
self._can_exit = not wait_before_exit self._can_exit = not wait_before_exit
self.wait_thread = support.wait_threads_exit()
self.wait_thread.__enter__()
def task(): def task():
tid = threading.get_ident() tid = threading.get_ident()
self.started.append(tid) self.started.append(tid)
...@@ -41,6 +44,7 @@ class Bunch(object): ...@@ -41,6 +44,7 @@ class Bunch(object):
self.finished.append(tid) self.finished.append(tid)
while not self._can_exit: while not self._can_exit:
_wait() _wait()
try: try:
for i in range(n): for i in range(n):
start_new_thread(task, ()) start_new_thread(task, ())
...@@ -55,6 +59,8 @@ class Bunch(object): ...@@ -55,6 +59,8 @@ class Bunch(object):
def wait_for_finished(self): def wait_for_finished(self):
while len(self.finished) < self.n: while len(self.finished) < self.n:
_wait() _wait()
# Wait for threads exit
self.wait_thread.__exit__(None, None, None)
def do_finish(self): def do_finish(self):
self._can_exit = True self._can_exit = True
...@@ -222,20 +228,23 @@ class LockTests(BaseLockTests): ...@@ -222,20 +228,23 @@ class LockTests(BaseLockTests):
# Lock needs to be released before re-acquiring. # Lock needs to be released before re-acquiring.
lock = self.locktype() lock = self.locktype()
phase = [] phase = []
def f(): def f():
lock.acquire() lock.acquire()
phase.append(None) phase.append(None)
lock.acquire() lock.acquire()
phase.append(None) phase.append(None)
start_new_thread(f, ())
while len(phase) == 0: with support.wait_threads_exit():
_wait() start_new_thread(f, ())
_wait() while len(phase) == 0:
self.assertEqual(len(phase), 1) _wait()
lock.release()
while len(phase) == 1:
_wait() _wait()
self.assertEqual(len(phase), 2) self.assertEqual(len(phase), 1)
lock.release()
while len(phase) == 1:
_wait()
self.assertEqual(len(phase), 2)
def test_different_thread(self): def test_different_thread(self):
# Lock can be released from a different thread. # Lock can be released from a different thread.
...@@ -306,6 +315,7 @@ class RLockTests(BaseLockTests): ...@@ -306,6 +315,7 @@ class RLockTests(BaseLockTests):
self.assertRaises(RuntimeError, lock.release) self.assertRaises(RuntimeError, lock.release)
finally: finally:
b.do_finish() b.do_finish()
b.wait_for_finished()
def test__is_owned(self): def test__is_owned(self):
lock = self.locktype() lock = self.locktype()
...@@ -397,12 +407,13 @@ class EventTests(BaseTestCase): ...@@ -397,12 +407,13 @@ class EventTests(BaseTestCase):
# cleared before the waiting thread is woken up. # cleared before the waiting thread is woken up.
evt = self.eventtype() evt = self.eventtype()
results = [] results = []
timeout = 0.250
N = 5 N = 5
def f(): def f():
results.append(evt.wait(1)) results.append(evt.wait(timeout * 4))
b = Bunch(f, N) b = Bunch(f, N)
b.wait_for_started() b.wait_for_started()
time.sleep(0.5) time.sleep(timeout)
evt.set() evt.set()
evt.clear() evt.clear()
b.wait_for_finished() b.wait_for_finished()
...@@ -463,21 +474,28 @@ class ConditionTests(BaseTestCase): ...@@ -463,21 +474,28 @@ class ConditionTests(BaseTestCase):
# construct. In particular, it is possible that this can no longer # construct. In particular, it is possible that this can no longer
# be conveniently guaranteed should their implementation ever change. # be conveniently guaranteed should their implementation ever change.
N = 5 N = 5
ready = []
results1 = [] results1 = []
results2 = [] results2 = []
phase_num = 0 phase_num = 0
def f(): def f():
cond.acquire() cond.acquire()
ready.append(phase_num)
result = cond.wait() result = cond.wait()
cond.release() cond.release()
results1.append((result, phase_num)) results1.append((result, phase_num))
cond.acquire() cond.acquire()
ready.append(phase_num)
result = cond.wait() result = cond.wait()
cond.release() cond.release()
results2.append((result, phase_num)) results2.append((result, phase_num))
b = Bunch(f, N) b = Bunch(f, N)
b.wait_for_started() b.wait_for_started()
_wait() # first wait, to ensure all workers settle into cond.wait() before
# we continue. See issues #8799 and #30727.
while len(ready) < 5:
_wait()
ready.clear()
self.assertEqual(results1, []) self.assertEqual(results1, [])
# Notify 3 threads at first # Notify 3 threads at first
cond.acquire() cond.acquire()
...@@ -489,9 +507,9 @@ class ConditionTests(BaseTestCase): ...@@ -489,9 +507,9 @@ class ConditionTests(BaseTestCase):
_wait() _wait()
self.assertEqual(results1, [(True, 1)] * 3) self.assertEqual(results1, [(True, 1)] * 3)
self.assertEqual(results2, []) self.assertEqual(results2, [])
# first wait, to ensure all workers settle into cond.wait() before # make sure all awaken workers settle into cond.wait()
# we continue. See issue #8799 while len(ready) < 3:
_wait() _wait()
# Notify 5 threads: they might be in their first or second wait # Notify 5 threads: they might be in their first or second wait
cond.acquire() cond.acquire()
cond.notify(5) cond.notify(5)
...@@ -502,7 +520,9 @@ class ConditionTests(BaseTestCase): ...@@ -502,7 +520,9 @@ class ConditionTests(BaseTestCase):
_wait() _wait()
self.assertEqual(results1, [(True, 1)] * 3 + [(True, 2)] * 2) self.assertEqual(results1, [(True, 1)] * 3 + [(True, 2)] * 2)
self.assertEqual(results2, [(True, 2)] * 3) self.assertEqual(results2, [(True, 2)] * 3)
_wait() # make sure all workers settle into cond.wait() # make sure all workers settle into cond.wait()
while len(ready) < 5:
_wait()
# Notify all threads: they are all in their second wait # Notify all threads: they are all in their second wait
cond.acquire() cond.acquire()
cond.notify_all() cond.notify_all()
...@@ -612,13 +632,14 @@ class BaseSemaphoreTests(BaseTestCase): ...@@ -612,13 +632,14 @@ class BaseSemaphoreTests(BaseTestCase):
sem = self.semtype(7) sem = self.semtype(7)
sem.acquire() sem.acquire()
N = 10 N = 10
sem_results = []
results1 = [] results1 = []
results2 = [] results2 = []
phase_num = 0 phase_num = 0
def f(): def f():
sem.acquire() sem_results.append(sem.acquire())
results1.append(phase_num) results1.append(phase_num)
sem.acquire() sem_results.append(sem.acquire())
results2.append(phase_num) results2.append(phase_num)
b = Bunch(f, 10) b = Bunch(f, 10)
b.wait_for_started() b.wait_for_started()
...@@ -642,6 +663,7 @@ class BaseSemaphoreTests(BaseTestCase): ...@@ -642,6 +663,7 @@ class BaseSemaphoreTests(BaseTestCase):
# Final release, to let the last thread finish # Final release, to let the last thread finish
sem.release() sem.release()
b.wait_for_finished() b.wait_for_finished()
self.assertEqual(sem_results, [True] * (6 + 7 + 6 + 1))
def test_try_acquire(self): def test_try_acquire(self):
sem = self.semtype(2) sem = self.semtype(2)
......
-----BEGIN X509 CRL----- -----BEGIN X509 CRL-----
MIIBpjCBjwIBATANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE MIICJjCBjwIBATANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE
CgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91ci1j CgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91ci1j
YS1zZXJ2ZXIXDTEzMTEyMTE3MDg0N1oXDTIzMDkzMDE3MDg0N1qgDjAMMAoGA1Ud YS1zZXJ2ZXIXDTE4MDgyOTE0MjMxNloXDTI4MDcwNzE0MjMxNlqgDjAMMAoGA1Ud
FAQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQCNJXC2mVKauEeN3LlQ3ZtM5gkH3ExH FAQDAgEAMA0GCSqGSIb3DQEBCwUAA4IBgQCPhrtGSbuvxPAI3YWQFDB4iOWdBnVk
+i4bmJjtJn497WwvvoIeUdrmVXgJQR93RtV37hZwN0SXMLlNmUZPH4rHhihayw4m ugW1lsifmCsE86FfID0EwUut1SRHlksltMtcoULMEIdu8yMLWci++4ve22EEuMKT
unCzVj/OhCCY7/TPjKuJ1O/0XhaLBpBVjQN7R/1ujoRKbSia/CD3vcn7Fqxzw7LK HUc3T/wBIuQUhA7U4deFG8CZPAxRpNoK470y7dkD4OVf0Gxa6WYDl9z8mXKmWCB9
fSRCKRGTj1CZiuxrphtFchwALXSiFDy9mr2ZKhImcyq1PydfgEzU78APpOkMQsIC hvzqVfLWNSLTAVPsHtkD5PXdi5yRkQr6wYD7poWaIvkpsn7EKCY6Tw5V3rsbRuZq
UNJ/cf3c9emzf+dUtcMEcejQ3mynBo4eIGg1EW42bz4q4hSjzQlKcBV0muw5qXhc AGVCq5TH3mctcmwLloCJ4Xr/1q0DsRrYxeeLYxE+UpvvCbVBKgtjBK7zINS7AbcJ
HOxH2iTFhQ7SrvVuK/dM14rYM4B5mSX3nRC1kNmXpS9j3wJDhuwmjHed CYCYKUwGWv1fYKJ+KQQHf75mT3jQ9lWuzOj/YWK4k1EBnYmVGuKKt73lLFxC6h3y
MUnaBZc1KZSyJj0IxfHg/o6qx8NgKOl9XRIQ5g5B30cwpPOskGhEhodbTTY3bPtm
RQ36JvQZngzmkhyhr+MDEV5yUTOShfUiclzQOx26CmLmLHWxOZgXtFZob/oKrvbm
Gen/+7K7YTw6hfY52U7J2FuQRGOyzBXfBYQ=
-----END X509 CRL----- -----END X509 CRL-----
...@@ -21,25 +21,19 @@ class InterProcessSignalTests(unittest.TestCase): ...@@ -21,25 +21,19 @@ class InterProcessSignalTests(unittest.TestCase):
self.got_signals['SIGUSR1'] += 1 self.got_signals['SIGUSR1'] += 1
raise SIGUSR1Exception raise SIGUSR1Exception
def wait_signal(self, child, signame, exc_class=None): def wait_signal(self, child, signame):
try: if child is not None:
if child is not None: # This wait should be interrupted by exc_class
# This wait should be interrupted by exc_class # (if set)
# (if set) child.wait()
child.wait()
timeout = 10.0
timeout = 10.0 deadline = time.monotonic() + timeout
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
while time.monotonic() < deadline: if self.got_signals[signame]:
if self.got_signals[signame]:
return
signal.pause()
except BaseException as exc:
if exc_class is not None and isinstance(exc, exc_class):
# got the expected exception
return return
raise signal.pause()
self.fail('signal %s not received after %s seconds' self.fail('signal %s not received after %s seconds'
% (signame, timeout)) % (signame, timeout))
...@@ -65,8 +59,9 @@ class InterProcessSignalTests(unittest.TestCase): ...@@ -65,8 +59,9 @@ class InterProcessSignalTests(unittest.TestCase):
self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 0, self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 0,
'SIGALRM': 0}) 'SIGALRM': 0})
with self.subprocess_send_signal(pid, "SIGUSR1") as child: with self.assertRaises(SIGUSR1Exception):
self.wait_signal(child, 'SIGUSR1', SIGUSR1Exception) with self.subprocess_send_signal(pid, "SIGUSR1") as child:
self.wait_signal(child, 'SIGUSR1')
self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1, self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1,
'SIGALRM': 0}) 'SIGALRM': 0})
...@@ -74,10 +69,14 @@ class InterProcessSignalTests(unittest.TestCase): ...@@ -74,10 +69,14 @@ class InterProcessSignalTests(unittest.TestCase):
# Nothing should happen: SIGUSR2 is ignored # Nothing should happen: SIGUSR2 is ignored
child.wait() child.wait()
signal.alarm(1) try:
self.wait_signal(None, 'SIGALRM', KeyboardInterrupt) with self.assertRaises(KeyboardInterrupt):
self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1, signal.alarm(1)
'SIGALRM': 0}) self.wait_signal(None, 'SIGALRM')
self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1,
'SIGALRM': 0})
finally:
signal.alarm(0)
if __name__ == "__main__": if __name__ == "__main__":
......
-----BEGIN CERTIFICATE-----
MIIDqDCCApKgAwIBAgIBAjALBgkqhkiG9w0BAQswHzELMAkGA1UEBhMCVUsxEDAO
BgNVBAMTB2NvZHktY2EwHhcNMTgwNjE4MTgwMDU4WhcNMjgwNjE0MTgwMDU4WjA7
MQswCQYDVQQGEwJVSzEsMCoGA1UEAxMjY29kZW5vbWljb24tdm0tMi50ZXN0Lmxh
bC5jaXNjby5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC63fGB
J80A9Av1GB0bptslKRIUtJm8EeEu34HkDWbL6AJY0P8WfDtlXjlPaLqFa6sqH6ES
V48prSm1ZUbDSVL8R6BYVYpOlK8/48xk4pGTgRzv69gf5SGtQLwHy8UPBKgjSZoD
5a5k5wJXGswhKFFNqyyxqCvWmMnJWxXTt2XDCiWc4g4YAWi4O4+6SeeHVAV9rV7C
1wxqjzKovVe2uZOHjKEzJbbIU6JBPb6TRfMdRdYOw98n1VXDcKVgdX2DuuqjCzHP
WhU4Tw050M9NaK3eXp4Mh69VuiKoBGOLSOcS8reqHIU46Reg0hqeL8LIL6OhFHIF
j7HR6V1X6F+BfRS/AgMBAAGjgdYwgdMwCQYDVR0TBAIwADAdBgNVHQ4EFgQUOktp
HQjxDXXUg8prleY9jeLKeQ4wTwYDVR0jBEgwRoAUx6zgPygZ0ZErF9sPC4+5e2Io
UU+hI6QhMB8xCzAJBgNVBAYTAlVLMRAwDgYDVQQDEwdjb2R5LWNhggkA1QEAuwb7
2s0wCQYDVR0SBAIwADAuBgNVHREEJzAlgiNjb2Rlbm9taWNvbi12bS0yLnRlc3Qu
bGFsLmNpc2NvLmNvbTAOBgNVHQ8BAf8EBAMCBaAwCwYDVR0fBAQwAjAAMAsGCSqG
SIb3DQEBCwOCAQEAvqantx2yBlM11RoFiCfi+AfSblXPdrIrHvccepV4pYc/yO6p
t1f2dxHQb8rWH3i6cWag/EgIZx+HJQvo0rgPY1BFJsX1WnYf1/znZpkUBGbVmlJr
t/dW1gSkNS6sPsM0Q+7HPgEv8CPDNK5eo7vU2seE0iWOkxSyVUuiCEY9ZVGaLVit
p0C78nZ35Pdv4I+1cosmHl28+es1WI22rrnmdBpH8J1eY6WvUw2xuZHLeNVN0TzV
Q3qq53AaCWuLOD1AjESWuUCxMZTK9DPS4JKXTK8RLyDeqOvJGjsSWp3kL0y3GaQ+
10T1rfkKJub2+m9A9duin1fn6tHc2wSvB7m3DA==
-----END CERTIFICATE-----
...@@ -433,7 +433,10 @@ class FileWrapperTest(unittest.TestCase): ...@@ -433,7 +433,10 @@ class FileWrapperTest(unittest.TestCase):
f = asyncore.file_wrapper(fd) f = asyncore.file_wrapper(fd)
os.close(fd) os.close(fd)
f.close() os.close(f.fd) # file_wrapper dupped fd
with self.assertRaises(OSError):
f.close()
self.assertEqual(f.fd, -1) self.assertEqual(f.fd, -1)
# calling close twice should not fail # calling close twice should not fail
f.close() f.close()
...@@ -502,7 +505,7 @@ class BaseClient(BaseTestHandler): ...@@ -502,7 +505,7 @@ class BaseClient(BaseTestHandler):
class BaseTestAPI: class BaseTestAPI:
def tearDown(self): def tearDown(self):
asyncore.close_all() asyncore.close_all(ignore_all=True)
def loop_waiting_for_flag(self, instance, timeout=5): def loop_waiting_for_flag(self, instance, timeout=5):
timeout = float(timeout) / 100 timeout = float(timeout) / 100
...@@ -755,50 +758,50 @@ class BaseTestAPI: ...@@ -755,50 +758,50 @@ class BaseTestAPI:
def test_set_reuse_addr(self): def test_set_reuse_addr(self):
if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX: if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
self.skipTest("Not applicable to AF_UNIX sockets.") self.skipTest("Not applicable to AF_UNIX sockets.")
sock = socket.socket(self.family)
try: with socket.socket(self.family) as sock:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try:
except OSError: sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
unittest.skip("SO_REUSEADDR not supported on this platform") except OSError:
else: unittest.skip("SO_REUSEADDR not supported on this platform")
# if SO_REUSEADDR succeeded for sock we expect asyncore else:
# to do the same # if SO_REUSEADDR succeeded for sock we expect asyncore
s = asyncore.dispatcher(socket.socket(self.family)) # to do the same
self.assertFalse(s.socket.getsockopt(socket.SOL_SOCKET, s = asyncore.dispatcher(socket.socket(self.family))
socket.SO_REUSEADDR)) self.assertFalse(s.socket.getsockopt(socket.SOL_SOCKET,
s.socket.close() socket.SO_REUSEADDR))
s.create_socket(self.family) s.socket.close()
s.set_reuse_addr() s.create_socket(self.family)
self.assertTrue(s.socket.getsockopt(socket.SOL_SOCKET, s.set_reuse_addr()
socket.SO_REUSEADDR)) self.assertTrue(s.socket.getsockopt(socket.SOL_SOCKET,
finally: socket.SO_REUSEADDR))
sock.close()
@unittest.skipUnless(threading, 'Threading required for this test.') @unittest.skipUnless(threading, 'Threading required for this test.')
@support.reap_threads @support.reap_threads
def test_quick_connect(self): def test_quick_connect(self):
# see: http://bugs.python.org/issue10340 # see: http://bugs.python.org/issue10340
if self.family in (socket.AF_INET, getattr(socket, "AF_INET6", object())): if self.family not in (socket.AF_INET, getattr(socket, "AF_INET6", object())):
server = BaseServer(self.family, self.addr) self.skipTest("test specific to AF_INET and AF_INET6")
t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1,
count=500)) server = BaseServer(self.family, self.addr)
t.start() # run the thread 500 ms: the socket should be connected in 200 ms
def cleanup(): t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1,
t.join(timeout=TIMEOUT) count=5))
if t.is_alive(): t.start()
self.fail("join() timed out") try:
self.addCleanup(cleanup) with socket.socket(self.family, socket.SOCK_STREAM) as s:
s.settimeout(.2)
s = socket.socket(self.family, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
s.settimeout(.2) struct.pack('ii', 1, 0))
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
struct.pack('ii', 1, 0)) try:
try: s.connect(server.address)
s.connect(server.address) except OSError:
except OSError: pass
pass finally:
finally: t.join(timeout=TIMEOUT)
s.close() if t.is_alive():
self.fail("join() timed out")
class TestAPI_UseIPv4Sockets(BaseTestAPI): class TestAPI_UseIPv4Sockets(BaseTestAPI):
family = socket.AF_INET family = socket.AF_INET
......
...@@ -52,6 +52,7 @@ class TestServerThread(threading.Thread): ...@@ -52,6 +52,7 @@ class TestServerThread(threading.Thread):
def stop(self): def stop(self):
self.server.shutdown() self.server.shutdown()
self.join()
class BaseTestCase(unittest.TestCase): class BaseTestCase(unittest.TestCase):
...@@ -371,7 +372,8 @@ class SimpleHTTPServerTestCase(BaseTestCase): ...@@ -371,7 +372,8 @@ class SimpleHTTPServerTestCase(BaseTestCase):
reader.close() reader.close()
return body return body
@support.requires_mac_ver(10, 5) @unittest.skipIf(sys.platform == 'darwin',
'undecodable name cannot always be decoded on macOS')
@unittest.skipIf(sys.platform == 'win32', @unittest.skipIf(sys.platform == 'win32',
'undecodable name cannot be decoded on win32') 'undecodable name cannot be decoded on win32')
@unittest.skipUnless(support.TESTFN_UNDECODABLE, @unittest.skipUnless(support.TESTFN_UNDECODABLE,
......
...@@ -46,28 +46,27 @@ class _TriggerThread(threading.Thread): ...@@ -46,28 +46,27 @@ class _TriggerThread(threading.Thread):
class BlockingTestMixin: class BlockingTestMixin:
def tearDown(self):
self.t = None
def do_blocking_test(self, block_func, block_args, trigger_func, trigger_args): def do_blocking_test(self, block_func, block_args, trigger_func, trigger_args):
self.t = _TriggerThread(trigger_func, trigger_args) thread = _TriggerThread(trigger_func, trigger_args)
self.t.start() thread.start()
self.result = block_func(*block_args) try:
# If block_func returned before our thread made the call, we failed! self.result = block_func(*block_args)
if not self.t.startedEvent.is_set(): # If block_func returned before our thread made the call, we failed!
self.fail("blocking function '%r' appeared not to block" % if not thread.startedEvent.is_set():
block_func) self.fail("blocking function '%r' appeared not to block" %
self.t.join(10) # make sure the thread terminates block_func)
if self.t.is_alive(): return self.result
self.fail("trigger function '%r' appeared to not return" % finally:
trigger_func) thread.join(10) # make sure the thread terminates
return self.result if thread.is_alive():
self.fail("trigger function '%r' appeared to not return" %
trigger_func)
# Call this instead if block_func is supposed to raise an exception. # Call this instead if block_func is supposed to raise an exception.
def do_exceptional_blocking_test(self,block_func, block_args, trigger_func, def do_exceptional_blocking_test(self,block_func, block_args, trigger_func,
trigger_args, expected_exception_class): trigger_args, expected_exception_class):
self.t = _TriggerThread(trigger_func, trigger_args) thread = _TriggerThread(trigger_func, trigger_args)
self.t.start() thread.start()
try: try:
try: try:
block_func(*block_args) block_func(*block_args)
...@@ -77,11 +76,11 @@ class BlockingTestMixin: ...@@ -77,11 +76,11 @@ class BlockingTestMixin:
self.fail("expected exception of kind %r" % self.fail("expected exception of kind %r" %
expected_exception_class) expected_exception_class)
finally: finally:
self.t.join(10) # make sure the thread terminates thread.join(10) # make sure the thread terminates
if self.t.is_alive(): if thread.is_alive():
self.fail("trigger function '%r' appeared to not return" % self.fail("trigger function '%r' appeared to not return" %
trigger_func) trigger_func)
if not self.t.startedEvent.is_set(): if not thread.startedEvent.is_set():
self.fail("trigger thread ended but event never set") self.fail("trigger thread ended but event never set")
...@@ -159,8 +158,11 @@ class BaseQueueTestMixin(BlockingTestMixin): ...@@ -159,8 +158,11 @@ class BaseQueueTestMixin(BlockingTestMixin):
def queue_join_test(self, q): def queue_join_test(self, q):
self.cum = 0 self.cum = 0
threads = []
for i in (0,1): for i in (0,1):
threading.Thread(target=self.worker, args=(q,)).start() thread = threading.Thread(target=self.worker, args=(q,))
thread.start()
threads.append(thread)
for i in range(100): for i in range(100):
q.put(i) q.put(i)
q.join() q.join()
...@@ -169,6 +171,8 @@ class BaseQueueTestMixin(BlockingTestMixin): ...@@ -169,6 +171,8 @@ class BaseQueueTestMixin(BlockingTestMixin):
for i in (0,1): for i in (0,1):
q.put(-1) # instruct the threads to close q.put(-1) # instruct the threads to close
q.join() # verify that you can join twice q.join() # verify that you can join twice
for thread in threads:
thread.join()
def test_queue_task_done(self): def test_queue_task_done(self):
# Test to make sure a queue task completed successfully. # Test to make sure a queue task completed successfully.
......
...@@ -3,11 +3,13 @@ from test import support ...@@ -3,11 +3,13 @@ from test import support
from contextlib import closing from contextlib import closing
import enum import enum
import gc import gc
import os
import pickle import pickle
import random
import select import select
import signal import signal
import socket import socket
import struct import statistics
import subprocess import subprocess
import traceback import traceback
import sys, os, time, errno import sys, os, time, errno
...@@ -370,7 +372,6 @@ class WakeupSocketSignalTests(unittest.TestCase): ...@@ -370,7 +372,6 @@ class WakeupSocketSignalTests(unittest.TestCase):
signal.signal(signum, handler) signal.signal(signum, handler)
read, write = socket.socketpair() read, write = socket.socketpair()
read.setblocking(False)
write.setblocking(False) write.setblocking(False)
signal.set_wakeup_fd(write.fileno()) signal.set_wakeup_fd(write.fileno())
...@@ -615,6 +616,15 @@ class ItimerTest(unittest.TestCase): ...@@ -615,6 +616,15 @@ class ItimerTest(unittest.TestCase):
# and the handler should have been called # and the handler should have been called
self.assertEqual(self.hndl_called, True) self.assertEqual(self.hndl_called, True)
def test_setitimer_tiny(self):
# bpo-30807: C setitimer() takes a microsecond-resolution interval.
# Check that float -> timeval conversion doesn't round
# the interval down to zero, which would disable the timer.
self.itimer = signal.ITIMER_REAL
signal.setitimer(self.itimer, 1e-6)
time.sleep(1)
self.assertEqual(self.hndl_called, True)
class PendingSignalsTests(unittest.TestCase): class PendingSignalsTests(unittest.TestCase):
""" """
...@@ -950,6 +960,135 @@ class PendingSignalsTests(unittest.TestCase): ...@@ -950,6 +960,135 @@ class PendingSignalsTests(unittest.TestCase):
(exitcode, stdout)) (exitcode, stdout))
class StressTest(unittest.TestCase):
"""
Stress signal delivery, especially when a signal arrives in
the middle of recomputing the signal state or executing
previously tripped signal handlers.
"""
def setsig(self, signum, handler):
old_handler = signal.signal(signum, handler)
self.addCleanup(signal.signal, signum, old_handler)
def measure_itimer_resolution(self):
N = 20
times = []
def handler(signum=None, frame=None):
if len(times) < N:
times.append(time.perf_counter())
# 1 µs is the smallest possible timer interval,
# we want to measure what the concrete duration
# will be on this platform
signal.setitimer(signal.ITIMER_REAL, 1e-6)
self.addCleanup(signal.setitimer, signal.ITIMER_REAL, 0)
self.setsig(signal.SIGALRM, handler)
handler()
while len(times) < N:
time.sleep(1e-3)
durations = [times[i+1] - times[i] for i in range(len(times) - 1)]
med = statistics.median(durations)
if support.verbose:
print("detected median itimer() resolution: %.6f s." % (med,))
return med
def decide_itimer_count(self):
# Some systems have poor setitimer() resolution (for example
# measured around 20 ms. on FreeBSD 9), so decide on a reasonable
# number of sequential timers based on that.
reso = self.measure_itimer_resolution()
if reso <= 1e-4:
return 10000
elif reso <= 1e-2:
return 100
else:
self.skipTest("detected itimer resolution (%.3f s.) too high "
"(> 10 ms.) on this platform (or system too busy)"
% (reso,))
@unittest.skipUnless(hasattr(signal, "setitimer"),
"test needs setitimer()")
def test_stress_delivery_dependent(self):
"""
This test uses dependent signal handlers.
"""
N = self.decide_itimer_count()
sigs = []
def first_handler(signum, frame):
# 1e-6 is the minimum non-zero value for `setitimer()`.
# Choose a random delay so as to improve chances of
# triggering a race condition. Ideally the signal is received
# when inside critical signal-handling routines such as
# Py_MakePendingCalls().
signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
def second_handler(signum=None, frame=None):
sigs.append(signum)
# Here on Linux, SIGPROF > SIGALRM > SIGUSR1. By using both
# ascending and descending sequences (SIGUSR1 then SIGALRM,
# SIGPROF then SIGALRM), we maximize chances of hitting a bug.
self.setsig(signal.SIGPROF, first_handler)
self.setsig(signal.SIGUSR1, first_handler)
self.setsig(signal.SIGALRM, second_handler) # for ITIMER_REAL
expected_sigs = 0
deadline = time.time() + 15.0
while expected_sigs < N:
os.kill(os.getpid(), signal.SIGPROF)
expected_sigs += 1
# Wait for handlers to run to avoid signal coalescing
while len(sigs) < expected_sigs and time.time() < deadline:
time.sleep(1e-5)
os.kill(os.getpid(), signal.SIGUSR1)
expected_sigs += 1
while len(sigs) < expected_sigs and time.time() < deadline:
time.sleep(1e-5)
# All ITIMER_REAL signals should have been delivered to the
# Python handler
self.assertEqual(len(sigs), N, "Some signals were lost")
@unittest.skipUnless(hasattr(signal, "setitimer"),
"test needs setitimer()")
def test_stress_delivery_simultaneous(self):
"""
This test uses simultaneous signal handlers.
"""
N = self.decide_itimer_count()
sigs = []
def handler(signum, frame):
sigs.append(signum)
self.setsig(signal.SIGUSR1, handler)
self.setsig(signal.SIGALRM, handler) # for ITIMER_REAL
expected_sigs = 0
deadline = time.time() + 15.0
while expected_sigs < N:
# Hopefully the SIGALRM will be received somewhere during
# initial processing of SIGUSR1.
signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
os.kill(os.getpid(), signal.SIGUSR1)
expected_sigs += 2
# Wait for handlers to run to avoid signal coalescing
while len(sigs) < expected_sigs and time.time() < deadline:
time.sleep(1e-5)
# All ITIMER_REAL signals should have been delivered to the
# Python handler
self.assertEqual(len(sigs), N, "Some signals were lost")
def tearDownModule(): def tearDownModule():
support.reap_children() support.reap_children()
......
...@@ -18,6 +18,11 @@ import textwrap ...@@ -18,6 +18,11 @@ import textwrap
import unittest import unittest
from test import support, mock_socket from test import support, mock_socket
from unittest.mock import Mock
HOST = "localhost"
HOSTv4 = "127.0.0.1"
HOSTv6 = "::1"
try: try:
import threading import threading
...@@ -569,6 +574,33 @@ class NonConnectingTests(unittest.TestCase): ...@@ -569,6 +574,33 @@ class NonConnectingTests(unittest.TestCase):
"localhost:bogus") "localhost:bogus")
class DefaultArgumentsTests(unittest.TestCase):
def setUp(self):
self.msg = EmailMessage()
self.msg['From'] = 'Páolo <főo@bar.com>'
self.smtp = smtplib.SMTP()
self.smtp.ehlo = Mock(return_value=(200, 'OK'))
self.smtp.has_extn, self.smtp.sendmail = Mock(), Mock()
def testSendMessage(self):
expected_mail_options = ('SMTPUTF8', 'BODY=8BITMIME')
self.smtp.send_message(self.msg)
self.smtp.send_message(self.msg)
self.assertEqual(self.smtp.sendmail.call_args_list[0][0][3],
expected_mail_options)
self.assertEqual(self.smtp.sendmail.call_args_list[1][0][3],
expected_mail_options)
def testSendMessageWithMailOptions(self):
mail_options = ['STARTTLS']
expected_mail_options = ('STARTTLS', 'SMTPUTF8', 'BODY=8BITMIME')
self.smtp.send_message(self.msg, None, None, mail_options)
self.assertEqual(mail_options, ['STARTTLS'])
self.assertEqual(self.smtp.sendmail.call_args_list[0][0][3],
expected_mail_options)
# test response of client to a non-successful HELO message # test response of client to a non-successful HELO message
@unittest.skipUnless(threading, 'Threading required for this test.') @unittest.skipUnless(threading, 'Threading required for this test.')
class BadHELOServerTests(unittest.TestCase): class BadHELOServerTests(unittest.TestCase):
...@@ -604,7 +636,9 @@ class TooLongLineTests(unittest.TestCase): ...@@ -604,7 +636,9 @@ class TooLongLineTests(unittest.TestCase):
self.sock.settimeout(15) self.sock.settimeout(15)
self.port = support.bind_port(self.sock) self.port = support.bind_port(self.sock)
servargs = (self.evt, self.respdata, self.sock) servargs = (self.evt, self.respdata, self.sock)
threading.Thread(target=server, args=servargs).start() thread = threading.Thread(target=server, args=servargs)
thread.start()
self.addCleanup(thread.join)
self.evt.wait() self.evt.wait()
self.evt.clear() self.evt.clear()
...@@ -733,7 +767,7 @@ class SimSMTPChannel(smtpd.SMTPChannel): ...@@ -733,7 +767,7 @@ class SimSMTPChannel(smtpd.SMTPChannel):
try: try:
user, hashed_pass = logpass.split() user, hashed_pass = logpass.split()
except ValueError as e: except ValueError as e:
self.push('535 Splitting response {!r} into user and password' self.push('535 Splitting response {!r} into user and password '
'failed: {}'.format(logpass, e)) 'failed: {}'.format(logpass, e))
return False return False
valid_hashed_pass = hmac.HMAC( valid_hashed_pass = hmac.HMAC(
...@@ -816,6 +850,7 @@ class SimSMTPServer(smtpd.SMTPServer): ...@@ -816,6 +850,7 @@ class SimSMTPServer(smtpd.SMTPServer):
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
self._extra_features = [] self._extra_features = []
self._addresses = {}
smtpd.SMTPServer.__init__(self, *args, **kw) smtpd.SMTPServer.__init__(self, *args, **kw)
def handle_accepted(self, conn, addr): def handle_accepted(self, conn, addr):
...@@ -824,7 +859,8 @@ class SimSMTPServer(smtpd.SMTPServer): ...@@ -824,7 +859,8 @@ class SimSMTPServer(smtpd.SMTPServer):
decode_data=self._decode_data) decode_data=self._decode_data)
def process_message(self, peer, mailfrom, rcpttos, data): def process_message(self, peer, mailfrom, rcpttos, data):
pass self._addresses['from'] = mailfrom
self._addresses['tos'] = rcpttos
def add_feature(self, feature): def add_feature(self, feature):
self._extra_features.append(feature) self._extra_features.append(feature)
...@@ -1064,6 +1100,34 @@ class SMTPSimTests(unittest.TestCase): ...@@ -1064,6 +1100,34 @@ class SMTPSimTests(unittest.TestCase):
self.assertRaises(UnicodeEncodeError, smtp.sendmail, 'Alice', 'Böb', '') self.assertRaises(UnicodeEncodeError, smtp.sendmail, 'Alice', 'Böb', '')
self.assertRaises(UnicodeEncodeError, smtp.mail, 'Älice') self.assertRaises(UnicodeEncodeError, smtp.mail, 'Älice')
def test_send_message_error_on_non_ascii_addrs_if_no_smtputf8(self):
# This test is located here and not in the SMTPUTF8SimTests
# class because it needs a "regular" SMTP server to work
msg = EmailMessage()
msg['From'] = "Páolo <főo@bar.com>"
msg['To'] = 'Dinsdale'
msg['Subject'] = 'Nudge nudge, wink, wink \u1F609'
smtp = smtplib.SMTP(
HOST, self.port, local_hostname='localhost', timeout=3)
self.addCleanup(smtp.close)
with self.assertRaises(smtplib.SMTPNotSupportedError):
smtp.send_message(msg)
def test_name_field_not_included_in_envelop_addresses(self):
smtp = smtplib.SMTP(
HOST, self.port, local_hostname='localhost', timeout=3
)
self.addCleanup(smtp.close)
message = EmailMessage()
message['From'] = email.utils.formataddr(('Michaël', 'michael@example.com'))
message['To'] = email.utils.formataddr(('René', 'rene@example.com'))
self.assertDictEqual(smtp.send_message(message), {})
self.assertEqual(self.serv._addresses['from'], 'michael@example.com')
self.assertEqual(self.serv._addresses['tos'], ['rene@example.com'])
class SimSMTPUTF8Server(SimSMTPServer): class SimSMTPUTF8Server(SimSMTPServer):
...@@ -1194,17 +1258,6 @@ class SMTPUTF8SimTests(unittest.TestCase): ...@@ -1194,17 +1258,6 @@ class SMTPUTF8SimTests(unittest.TestCase):
self.assertIn('SMTPUTF8', self.serv.last_mail_options) self.assertIn('SMTPUTF8', self.serv.last_mail_options)
self.assertEqual(self.serv.last_rcpt_options, []) self.assertEqual(self.serv.last_rcpt_options, [])
def test_send_message_error_on_non_ascii_addrs_if_no_smtputf8(self):
msg = EmailMessage()
msg['From'] = "Páolo <főo@bar.com>"
msg['To'] = 'Dinsdale'
msg['Subject'] = 'Nudge nudge, wink, wink \u1F609'
smtp = smtplib.SMTP(
HOST, self.port, local_hostname='localhost', timeout=3)
self.addCleanup(smtp.close)
self.assertRaises(smtplib.SMTPNotSupportedError,
smtp.send_message(msg))
EXPECTED_RESPONSE = encode_base64(b'\0psu\0doesnotexist', eol='') EXPECTED_RESPONSE = encode_base64(b'\0psu\0doesnotexist', eol='')
...@@ -1273,18 +1326,5 @@ class SMTPAUTHInitialResponseSimTests(unittest.TestCase): ...@@ -1273,18 +1326,5 @@ class SMTPAUTHInitialResponseSimTests(unittest.TestCase):
self.assertEqual(code, 235) self.assertEqual(code, 235)
@support.reap_threads
def test_main(verbose=None):
support.run_unittest(
BadHELOServerTests,
DebuggingServerTests,
GeneralTests,
NonConnectingTests,
SMTPAUTHInitialResponseSimTests,
SMTPSimTests,
TooLongLineTests,
)
if __name__ == '__main__': if __name__ == '__main__':
test_main() unittest.main()
This diff is collapsed.
...@@ -48,11 +48,11 @@ def receive(sock, n, timeout=20): ...@@ -48,11 +48,11 @@ def receive(sock, n, timeout=20):
if HAVE_UNIX_SOCKETS and HAVE_FORKING: if HAVE_UNIX_SOCKETS and HAVE_FORKING:
class ForkingUnixStreamServer(socketserver.ForkingMixIn, class ForkingUnixStreamServer(socketserver.ForkingMixIn,
socketserver.UnixStreamServer): socketserver.UnixStreamServer):
pass _block_on_close = True
class ForkingUnixDatagramServer(socketserver.ForkingMixIn, class ForkingUnixDatagramServer(socketserver.ForkingMixIn,
socketserver.UnixDatagramServer): socketserver.UnixDatagramServer):
pass _block_on_close = True
@contextlib.contextmanager @contextlib.contextmanager
...@@ -62,10 +62,14 @@ def simple_subprocess(testcase): ...@@ -62,10 +62,14 @@ def simple_subprocess(testcase):
if pid == 0: if pid == 0:
# Don't raise an exception; it would be caught by the test harness. # Don't raise an exception; it would be caught by the test harness.
os._exit(72) os._exit(72)
yield None try:
pid2, status = os.waitpid(pid, 0) yield None
testcase.assertEqual(pid2, pid) except:
testcase.assertEqual(72 << 8, status) raise
finally:
pid2, status = os.waitpid(pid, 0)
testcase.assertEqual(pid2, pid)
testcase.assertEqual(72 << 8, status)
@unittest.skipUnless(threading, 'Threading required for this test.') @unittest.skipUnless(threading, 'Threading required for this test.')
...@@ -101,6 +105,8 @@ class SocketServerTest(unittest.TestCase): ...@@ -101,6 +105,8 @@ class SocketServerTest(unittest.TestCase):
def make_server(self, addr, svrcls, hdlrbase): def make_server(self, addr, svrcls, hdlrbase):
class MyServer(svrcls): class MyServer(svrcls):
_block_on_close = True
def handle_error(self, request, client_address): def handle_error(self, request, client_address):
self.close_request(request) self.close_request(request)
raise raise
...@@ -144,6 +150,10 @@ class SocketServerTest(unittest.TestCase): ...@@ -144,6 +150,10 @@ class SocketServerTest(unittest.TestCase):
t.join() t.join()
server.server_close() server.server_close()
self.assertEqual(-1, server.socket.fileno()) self.assertEqual(-1, server.socket.fileno())
if HAVE_FORKING and isinstance(server, socketserver.ForkingMixIn):
# bpo-31151: Check that ForkingMixIn.server_close() waits until
# all children completed
self.assertFalse(server.active_children)
if verbose: print("done") if verbose: print("done")
def stream_examine(self, proto, addr): def stream_examine(self, proto, addr):
...@@ -292,6 +302,7 @@ class ErrorHandlerTest(unittest.TestCase): ...@@ -292,6 +302,7 @@ class ErrorHandlerTest(unittest.TestCase):
def tearDown(self): def tearDown(self):
test.support.unlink(test.support.TESTFN) test.support.unlink(test.support.TESTFN)
reap_children()
def test_sync_handled(self): def test_sync_handled(self):
BaseErrorTestServer(ValueError) BaseErrorTestServer(ValueError)
...@@ -329,6 +340,8 @@ class ErrorHandlerTest(unittest.TestCase): ...@@ -329,6 +340,8 @@ class ErrorHandlerTest(unittest.TestCase):
class BaseErrorTestServer(socketserver.TCPServer): class BaseErrorTestServer(socketserver.TCPServer):
_block_on_close = True
def __init__(self, exception): def __init__(self, exception):
self.exception = exception self.exception = exception
super().__init__((HOST, 0), BadHandler) super().__init__((HOST, 0), BadHandler)
...@@ -371,10 +384,7 @@ class ThreadingErrorTestServer(socketserver.ThreadingMixIn, ...@@ -371,10 +384,7 @@ class ThreadingErrorTestServer(socketserver.ThreadingMixIn,
if HAVE_FORKING: if HAVE_FORKING:
class ForkingErrorTestServer(socketserver.ForkingMixIn, BaseErrorTestServer): class ForkingErrorTestServer(socketserver.ForkingMixIn, BaseErrorTestServer):
def wait_done(self): _block_on_close = True
[child] = self.active_children
os.waitpid(child, 0)
self.active_children.clear()
class SocketWriterTest(unittest.TestCase): class SocketWriterTest(unittest.TestCase):
......
This diff is collapsed.
This diff is collapsed.
...@@ -398,5 +398,4 @@ class ExpectTests(ExpectAndReadTestCase): ...@@ -398,5 +398,4 @@ class ExpectTests(ExpectAndReadTestCase):
if __name__ == '__main__': if __name__ == '__main__':
import unittest
unittest.main() unittest.main()
...@@ -11,6 +11,7 @@ from test import lock_tests ...@@ -11,6 +11,7 @@ from test import lock_tests
NUMTASKS = 10 NUMTASKS = 10
NUMTRIPS = 3 NUMTRIPS = 3
POLL_SLEEP = 0.010 # seconds = 10 ms
_print_mutex = thread.allocate_lock() _print_mutex = thread.allocate_lock()
...@@ -20,6 +21,7 @@ def verbose_print(arg): ...@@ -20,6 +21,7 @@ def verbose_print(arg):
with _print_mutex: with _print_mutex:
print(arg) print(arg)
class BasicThreadTest(unittest.TestCase): class BasicThreadTest(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -31,6 +33,9 @@ class BasicThreadTest(unittest.TestCase): ...@@ -31,6 +33,9 @@ class BasicThreadTest(unittest.TestCase):
self.running = 0 self.running = 0
self.next_ident = 0 self.next_ident = 0
key = support.threading_setup()
self.addCleanup(support.threading_cleanup, *key)
class ThreadRunningTests(BasicThreadTest): class ThreadRunningTests(BasicThreadTest):
...@@ -54,12 +59,13 @@ class ThreadRunningTests(BasicThreadTest): ...@@ -54,12 +59,13 @@ class ThreadRunningTests(BasicThreadTest):
self.done_mutex.release() self.done_mutex.release()
def test_starting_threads(self): def test_starting_threads(self):
# Basic test for thread creation. with support.wait_threads_exit():
for i in range(NUMTASKS): # Basic test for thread creation.
self.newtask() for i in range(NUMTASKS):
verbose_print("waiting for tasks to complete...") self.newtask()
self.done_mutex.acquire() verbose_print("waiting for tasks to complete...")
verbose_print("all tasks done") self.done_mutex.acquire()
verbose_print("all tasks done")
def test_stack_size(self): def test_stack_size(self):
# Various stack size tests. # Various stack size tests.
...@@ -89,12 +95,13 @@ class ThreadRunningTests(BasicThreadTest): ...@@ -89,12 +95,13 @@ class ThreadRunningTests(BasicThreadTest):
verbose_print("trying stack_size = (%d)" % tss) verbose_print("trying stack_size = (%d)" % tss)
self.next_ident = 0 self.next_ident = 0
self.created = 0 self.created = 0
for i in range(NUMTASKS): with support.wait_threads_exit():
self.newtask() for i in range(NUMTASKS):
self.newtask()
verbose_print("waiting for all tasks to complete") verbose_print("waiting for all tasks to complete")
self.done_mutex.acquire() self.done_mutex.acquire()
verbose_print("all tasks done") verbose_print("all tasks done")
thread.stack_size(0) thread.stack_size(0)
...@@ -104,26 +111,29 @@ class ThreadRunningTests(BasicThreadTest): ...@@ -104,26 +111,29 @@ class ThreadRunningTests(BasicThreadTest):
mut = thread.allocate_lock() mut = thread.allocate_lock()
mut.acquire() mut.acquire()
started = [] started = []
def task(): def task():
started.append(None) started.append(None)
mut.acquire() mut.acquire()
mut.release() mut.release()
thread.start_new_thread(task, ())
while not started: with support.wait_threads_exit():
time.sleep(0.01) thread.start_new_thread(task, ())
self.assertEqual(thread._count(), orig + 1) while not started:
# Allow the task to finish. time.sleep(POLL_SLEEP)
mut.release() self.assertEqual(thread._count(), orig + 1)
# The only reliable way to be sure that the thread ended from the # Allow the task to finish.
# interpreter's point of view is to wait for the function object to be mut.release()
# destroyed. # The only reliable way to be sure that the thread ended from the
done = [] # interpreter's point of view is to wait for the function object to be
wr = weakref.ref(task, lambda _: done.append(None)) # destroyed.
del task done = []
while not done: wr = weakref.ref(task, lambda _: done.append(None))
time.sleep(0.01) del task
support.gc_collect() while not done:
self.assertEqual(thread._count(), orig) time.sleep(POLL_SLEEP)
support.gc_collect()
self.assertEqual(thread._count(), orig)
def test_save_exception_state_on_error(self): def test_save_exception_state_on_error(self):
# See issue #14474 # See issue #14474
...@@ -136,16 +146,14 @@ class ThreadRunningTests(BasicThreadTest): ...@@ -136,16 +146,14 @@ class ThreadRunningTests(BasicThreadTest):
except ValueError: except ValueError:
pass pass
real_write(self, *args) real_write(self, *args)
c = thread._count()
started = thread.allocate_lock() started = thread.allocate_lock()
with support.captured_output("stderr") as stderr: with support.captured_output("stderr") as stderr:
real_write = stderr.write real_write = stderr.write
stderr.write = mywrite stderr.write = mywrite
started.acquire() started.acquire()
thread.start_new_thread(task, ()) with support.wait_threads_exit():
started.acquire() thread.start_new_thread(task, ())
while thread._count() > c: started.acquire()
time.sleep(0.01)
self.assertIn("Traceback", stderr.getvalue()) self.assertIn("Traceback", stderr.getvalue())
...@@ -177,13 +185,14 @@ class Barrier: ...@@ -177,13 +185,14 @@ class Barrier:
class BarrierTest(BasicThreadTest): class BarrierTest(BasicThreadTest):
def test_barrier(self): def test_barrier(self):
self.bar = Barrier(NUMTASKS) with support.wait_threads_exit():
self.running = NUMTASKS self.bar = Barrier(NUMTASKS)
for i in range(NUMTASKS): self.running = NUMTASKS
thread.start_new_thread(self.task2, (i,)) for i in range(NUMTASKS):
verbose_print("waiting for tasks to end") thread.start_new_thread(self.task2, (i,))
self.done_mutex.acquire() verbose_print("waiting for tasks to end")
verbose_print("tasks done") self.done_mutex.acquire()
verbose_print("tasks done")
def task2(self, ident): def task2(self, ident):
for i in range(NUMTRIPS): for i in range(NUMTRIPS):
...@@ -225,28 +234,33 @@ class TestForkInThread(unittest.TestCase): ...@@ -225,28 +234,33 @@ class TestForkInThread(unittest.TestCase):
def setUp(self): def setUp(self):
self.read_fd, self.write_fd = os.pipe() self.read_fd, self.write_fd = os.pipe()
@unittest.skipIf(sys.platform.startswith('win'), @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork')
"This test is only appropriate for POSIX-like systems.")
@support.reap_threads @support.reap_threads
def test_forkinthread(self): def test_forkinthread(self):
status = "not set"
def thread1(): def thread1():
try: nonlocal status
pid = os.fork() # fork in a thread
except RuntimeError:
os._exit(1) # exit the child
if pid == 0: # child # fork in a thread
pid = os.fork()
if pid == 0:
# child
try: try:
os.close(self.read_fd) os.close(self.read_fd)
os.write(self.write_fd, b"OK") os.write(self.write_fd, b"OK")
finally: finally:
os._exit(0) os._exit(0)
else: # parent else:
# parent
os.close(self.write_fd) os.close(self.write_fd)
pid, status = os.waitpid(pid, 0)
thread.start_new_thread(thread1, ()) with support.wait_threads_exit():
self.assertEqual(os.read(self.read_fd, 2), b"OK", thread.start_new_thread(thread1, ())
"Unable to fork() in thread") self.assertEqual(os.read(self.read_fd, 2), b"OK",
"Unable to fork() in thread")
self.assertEqual(status, 0)
def tearDown(self): def tearDown(self):
try: try:
......
...@@ -125,9 +125,10 @@ class ThreadTests(BaseTestCase): ...@@ -125,9 +125,10 @@ class ThreadTests(BaseTestCase):
done.set() done.set()
done = threading.Event() done = threading.Event()
ident = [] ident = []
_thread.start_new_thread(f, ()) with support.wait_threads_exit():
done.wait() tid = _thread.start_new_thread(f, ())
self.assertIsNotNone(ident[0]) done.wait()
self.assertEqual(ident[0], tid)
# Kill the "immortal" _DummyThread # Kill the "immortal" _DummyThread
del threading._active[ident[0]] del threading._active[ident[0]]
...@@ -165,9 +166,10 @@ class ThreadTests(BaseTestCase): ...@@ -165,9 +166,10 @@ class ThreadTests(BaseTestCase):
mutex = threading.Lock() mutex = threading.Lock()
mutex.acquire() mutex.acquire()
tid = _thread.start_new_thread(f, (mutex,)) with support.wait_threads_exit():
# Wait for the thread to finish. tid = _thread.start_new_thread(f, (mutex,))
mutex.acquire() # Wait for the thread to finish.
mutex.acquire()
self.assertIn(tid, threading._active) self.assertIn(tid, threading._active)
self.assertIsInstance(threading._active[tid], threading._DummyThread) self.assertIsInstance(threading._active[tid], threading._DummyThread)
#Issue 29376 #Issue 29376
...@@ -483,13 +485,15 @@ class ThreadTests(BaseTestCase): ...@@ -483,13 +485,15 @@ class ThreadTests(BaseTestCase):
for i in range(20): for i in range(20):
t = threading.Thread(target=lambda: None) t = threading.Thread(target=lambda: None)
t.start() t.start()
self.addCleanup(t.join)
pid = os.fork() pid = os.fork()
if pid == 0: if pid == 0:
os._exit(1 if t.is_alive() else 0) os._exit(11 if t.is_alive() else 10)
else: else:
t.join()
pid, status = os.waitpid(pid, 0) pid, status = os.waitpid(pid, 0)
self.assertEqual(0, status) self.assertTrue(os.WIFEXITED(status))
self.assertEqual(10, os.WEXITSTATUS(status))
def test_main_thread(self): def test_main_thread(self):
main = threading.main_thread() main = threading.main_thread()
...@@ -553,6 +557,37 @@ class ThreadTests(BaseTestCase): ...@@ -553,6 +557,37 @@ class ThreadTests(BaseTestCase):
self.assertEqual(err, b"") self.assertEqual(err, b"")
self.assertEqual(data, "Thread-1\nTrue\nTrue\n") self.assertEqual(data, "Thread-1\nTrue\nTrue\n")
@test.support.cpython_only
@requires_type_collecting
def test_main_thread_during_shutdown(self):
# bpo-31516: current_thread() should still point to the main thread
# at shutdown
code = """if 1:
import gc, threading
main_thread = threading.current_thread()
assert main_thread is threading.main_thread() # sanity check
class RefCycle:
def __init__(self):
self.cycle = self
def __del__(self):
print("GC:",
threading.current_thread() is main_thread,
threading.main_thread() is main_thread,
threading.enumerate() == [main_thread])
RefCycle()
gc.collect() # sanity check
x = RefCycle()
"""
_, out, err = assert_python_ok("-c", code)
data = out.decode()
self.assertEqual(err, b"")
self.assertEqual(data.splitlines(),
["GC: True True True"] * 2)
def test_tstate_lock(self): def test_tstate_lock(self):
# Test an implementation detail of Thread objects. # Test an implementation detail of Thread objects.
started = _thread.allocate_lock() started = _thread.allocate_lock()
...@@ -586,6 +621,7 @@ class ThreadTests(BaseTestCase): ...@@ -586,6 +621,7 @@ class ThreadTests(BaseTestCase):
self.assertFalse(t.is_alive()) self.assertFalse(t.is_alive())
# And verify the thread disposed of _tstate_lock. # And verify the thread disposed of _tstate_lock.
self.assertIsNone(t._tstate_lock) self.assertIsNone(t._tstate_lock)
t.join()
def test_repr_stopped(self): def test_repr_stopped(self):
# Verify that "stopped" shows up in repr(Thread) appropriately. # Verify that "stopped" shows up in repr(Thread) appropriately.
...@@ -612,6 +648,7 @@ class ThreadTests(BaseTestCase): ...@@ -612,6 +648,7 @@ class ThreadTests(BaseTestCase):
break break
time.sleep(0.01) time.sleep(0.01)
self.assertIn(LOOKING_FOR, repr(t)) # we waited at least 5 seconds self.assertIn(LOOKING_FOR, repr(t)) # we waited at least 5 seconds
t.join()
def test_BoundedSemaphore_limit(self): def test_BoundedSemaphore_limit(self):
# BoundedSemaphore should raise ValueError if released too often. # BoundedSemaphore should raise ValueError if released too often.
...@@ -928,6 +965,7 @@ class ThreadingExceptionTests(BaseTestCase): ...@@ -928,6 +965,7 @@ class ThreadingExceptionTests(BaseTestCase):
thread = threading.Thread() thread = threading.Thread()
thread.start() thread.start()
self.assertRaises(RuntimeError, thread.start) self.assertRaises(RuntimeError, thread.start)
thread.join()
def test_joining_current_thread(self): def test_joining_current_thread(self):
current_thread = threading.current_thread() current_thread = threading.current_thread()
...@@ -941,6 +979,7 @@ class ThreadingExceptionTests(BaseTestCase): ...@@ -941,6 +979,7 @@ class ThreadingExceptionTests(BaseTestCase):
thread = threading.Thread() thread = threading.Thread()
thread.start() thread.start()
self.assertRaises(RuntimeError, setattr, thread, "daemon", True) self.assertRaises(RuntimeError, setattr, thread, "daemon", True)
thread.join()
def test_releasing_unacquired_lock(self): def test_releasing_unacquired_lock(self):
lock = threading.Lock() lock = threading.Lock()
...@@ -1079,6 +1118,8 @@ class ThreadingExceptionTests(BaseTestCase): ...@@ -1079,6 +1118,8 @@ class ThreadingExceptionTests(BaseTestCase):
thread.join() thread.join()
self.assertIsNotNone(thread.exc) self.assertIsNotNone(thread.exc)
self.assertIsInstance(thread.exc, RuntimeError) self.assertIsInstance(thread.exc, RuntimeError)
# explicitly break the reference cycle to not leak a dangling thread
thread.exc = None
class TimerTests(BaseTestCase): class TimerTests(BaseTestCase):
...@@ -1101,6 +1142,8 @@ class TimerTests(BaseTestCase): ...@@ -1101,6 +1142,8 @@ class TimerTests(BaseTestCase):
self.callback_event.wait() self.callback_event.wait()
self.assertEqual(len(self.callback_args), 2) self.assertEqual(len(self.callback_args), 2)
self.assertEqual(self.callback_args, [((), {}), ((), {})]) self.assertEqual(self.callback_args, [((), {}), ((), {})])
timer1.join()
timer2.join()
def _callback_spy(self, *args, **kwargs): def _callback_spy(self, *args, **kwargs):
self.callback_args.append((args[:], kwargs.copy())) self.callback_args.append((args[:], kwargs.copy()))
...@@ -1127,10 +1170,6 @@ class CRLockTests(lock_tests.RLockTests): ...@@ -1127,10 +1170,6 @@ class CRLockTests(lock_tests.RLockTests):
class EventTests(lock_tests.EventTests): class EventTests(lock_tests.EventTests):
eventtype = staticmethod(threading.Event) eventtype = staticmethod(threading.Event)
@unittest.skip("not on gevent")
def test_reset_internal_locks(self):
pass
class ConditionAsRLockTests(lock_tests.RLockTests): class ConditionAsRLockTests(lock_tests.RLockTests):
# Condition uses an RLock by default and exports its API. # Condition uses an RLock by default and exports its API.
locktype = staticmethod(threading.Condition) locktype = staticmethod(threading.Condition)
......
...@@ -16,6 +16,7 @@ except ImportError: ...@@ -16,6 +16,7 @@ except ImportError:
ssl = None ssl = None
import sys import sys
import tempfile import tempfile
import warnings
from nturl2path import url2pathname, pathname2url from nturl2path import url2pathname, pathname2url
from base64 import b64encode from base64 import b64encode
...@@ -206,6 +207,7 @@ class urlopen_FileTests(unittest.TestCase): ...@@ -206,6 +207,7 @@ class urlopen_FileTests(unittest.TestCase):
def test_relativelocalfile(self): def test_relativelocalfile(self):
self.assertRaises(ValueError,urllib.request.urlopen,'./' + self.pathname) self.assertRaises(ValueError,urllib.request.urlopen,'./' + self.pathname)
class ProxyTests(unittest.TestCase): class ProxyTests(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -259,6 +261,7 @@ class ProxyTests(unittest.TestCase): ...@@ -259,6 +261,7 @@ class ProxyTests(unittest.TestCase):
self.assertFalse(bypass('newdomain.com')) # no port self.assertFalse(bypass('newdomain.com')) # no port
self.assertFalse(bypass('newdomain.com:1235')) # wrong port self.assertFalse(bypass('newdomain.com:1235')) # wrong port
class ProxyTests_withOrderedEnv(unittest.TestCase): class ProxyTests_withOrderedEnv(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -294,6 +297,7 @@ class ProxyTests_withOrderedEnv(unittest.TestCase): ...@@ -294,6 +297,7 @@ class ProxyTests_withOrderedEnv(unittest.TestCase):
proxies = urllib.request.getproxies_environment() proxies = urllib.request.getproxies_environment()
self.assertEqual('http://somewhere:3128', proxies['http']) self.assertEqual('http://somewhere:3128', proxies['http'])
class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin): class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin):
"""Test urlopen() opening a fake http connection.""" """Test urlopen() opening a fake http connection."""
...@@ -326,6 +330,59 @@ class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin): ...@@ -326,6 +330,59 @@ class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin):
finally: finally:
self.unfakehttp() self.unfakehttp()
@unittest.skipUnless(ssl, "ssl module required")
def test_url_with_control_char_rejected(self):
for char_no in list(range(0, 0x21)) + [0x7f]:
char = chr(char_no)
schemeless_url = f"//localhost:7777/test{char}/"
self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.")
try:
# We explicitly test urllib.request.urlopen() instead of the top
# level 'def urlopen()' function defined in this... (quite ugly)
# test suite. They use different url opening codepaths. Plain
# urlopen uses FancyURLOpener which goes via a codepath that
# calls urllib.parse.quote() on the URL which makes all of the
# above attempts at injection within the url _path_ safe.
escaped_char_repr = repr(char).replace('\\', r'\\')
InvalidURL = http.client.InvalidURL
with self.assertRaisesRegex(
InvalidURL, f"contain control.*{escaped_char_repr}"):
urllib.request.urlopen(f"http:{schemeless_url}")
with self.assertRaisesRegex(
InvalidURL, f"contain control.*{escaped_char_repr}"):
urllib.request.urlopen(f"https:{schemeless_url}")
# This code path quotes the URL so there is no injection.
resp = urlopen(f"http:{schemeless_url}")
self.assertNotIn(char, resp.geturl())
finally:
self.unfakehttp()
@unittest.skipUnless(ssl, "ssl module required")
def test_url_with_newline_header_injection_rejected(self):
self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.")
host = "localhost:7777?a=1 HTTP/1.1\r\nX-injected: header\r\nTEST: 123"
schemeless_url = "//" + host + ":8080/test/?test=a"
try:
# We explicitly test urllib.request.urlopen() instead of the top
# level 'def urlopen()' function defined in this... (quite ugly)
# test suite. They use different url opening codepaths. Plain
# urlopen uses FancyURLOpener which goes via a codepath that
# calls urllib.parse.quote() on the URL which makes all of the
# above attempts at injection within the url _path_ safe.
InvalidURL = http.client.InvalidURL
with self.assertRaisesRegex(
InvalidURL, r"contain control.*\\r.*(found at least . .)"):
urllib.request.urlopen(f"http:{schemeless_url}")
with self.assertRaisesRegex(InvalidURL, r"contain control.*\\n"):
urllib.request.urlopen(f"https:{schemeless_url}")
# This code path quotes the URL so there is no injection.
resp = urlopen(f"http:{schemeless_url}")
self.assertNotIn(' ', resp.geturl())
self.assertNotIn('\r', resp.geturl())
self.assertNotIn('\n', resp.geturl())
finally:
self.unfakehttp()
def test_read_0_9(self): def test_read_0_9(self):
# "0.9" response accepted (but not "simple responses" without # "0.9" response accepted (but not "simple responses" without
# a status line) # a status line)
...@@ -432,7 +489,6 @@ Connection: close ...@@ -432,7 +489,6 @@ Connection: close
finally: finally:
self.unfakeftp() self.unfakeftp()
def test_userpass_inurl(self): def test_userpass_inurl(self):
self.fakehttp(b"HTTP/1.0 200 OK\r\n\r\nHello!") self.fakehttp(b"HTTP/1.0 200 OK\r\n\r\nHello!")
try: try:
...@@ -476,6 +532,7 @@ Connection: close ...@@ -476,6 +532,7 @@ Connection: close
"https://localhost", cafile="/nonexistent/path", context=context "https://localhost", cafile="/nonexistent/path", context=context
) )
class urlopen_DataTests(unittest.TestCase): class urlopen_DataTests(unittest.TestCase):
"""Test urlopen() opening a data URL.""" """Test urlopen() opening a data URL."""
...@@ -549,6 +606,7 @@ class urlopen_DataTests(unittest.TestCase): ...@@ -549,6 +606,7 @@ class urlopen_DataTests(unittest.TestCase):
# missing padding character # missing padding character
self.assertRaises(ValueError,urllib.request.urlopen,'data:;base64,Cg=') self.assertRaises(ValueError,urllib.request.urlopen,'data:;base64,Cg=')
class urlretrieve_FileTests(unittest.TestCase): class urlretrieve_FileTests(unittest.TestCase):
"""Test urllib.urlretrieve() on local files""" """Test urllib.urlretrieve() on local files"""
...@@ -1406,6 +1464,23 @@ class URLopener_Tests(unittest.TestCase): ...@@ -1406,6 +1464,23 @@ class URLopener_Tests(unittest.TestCase):
"spam://c:|windows%/:=&?~#+!$,;'@()*[]|/path/"), "spam://c:|windows%/:=&?~#+!$,;'@()*[]|/path/"),
"//c:|windows%/:=&?~#+!$,;'@()*[]|/path/") "//c:|windows%/:=&?~#+!$,;'@()*[]|/path/")
def test_local_file_open(self):
# bpo-35907, CVE-2019-9948: urllib must reject local_file:// scheme
class DummyURLopener(urllib.request.URLopener):
def open_local_file(self, url):
return url
with warnings.catch_warnings(record=True):
warnings.simplefilter("ignore", DeprecationWarning)
for url in ('local_file://example', 'local-file://example'):
self.assertRaises(OSError, urllib.request.urlopen, url)
self.assertRaises(OSError, urllib.request.URLopener().open, url)
self.assertRaises(OSError, urllib.request.URLopener().retrieve, url)
self.assertRaises(OSError, DummyURLopener().open, url)
self.assertRaises(OSError, DummyURLopener().retrieve, url)
# Just commented them out. # Just commented them out.
# Can't really tell why keep failing in windows and sparc. # Can't really tell why keep failing in windows and sparc.
# Everywhere else they work ok, but on those machines, sometimes # Everywhere else they work ok, but on those machines, sometimes
......
...@@ -141,44 +141,55 @@ class RequestHdrsTests(unittest.TestCase): ...@@ -141,44 +141,55 @@ class RequestHdrsTests(unittest.TestCase):
mgr = urllib.request.HTTPPasswordMgr() mgr = urllib.request.HTTPPasswordMgr()
add = mgr.add_password add = mgr.add_password
find_user_pass = mgr.find_user_password find_user_pass = mgr.find_user_password
add("Some Realm", "http://example.com/", "joe", "password") add("Some Realm", "http://example.com/", "joe", "password")
add("Some Realm", "http://example.com/ni", "ni", "ni") add("Some Realm", "http://example.com/ni", "ni", "ni")
add("c", "http://example.com/foo", "foo", "ni")
add("c", "http://example.com/bar", "bar", "nini")
add("b", "http://example.com/", "first", "blah")
add("b", "http://example.com/", "second", "spam")
add("a", "http://example.com", "1", "a")
add("Some Realm", "http://c.example.com:3128", "3", "c") add("Some Realm", "http://c.example.com:3128", "3", "c")
add("Some Realm", "d.example.com", "4", "d") add("Some Realm", "d.example.com", "4", "d")
add("Some Realm", "e.example.com:3128", "5", "e") add("Some Realm", "e.example.com:3128", "5", "e")
# For the same realm, password set the highest path is the winner.
self.assertEqual(find_user_pass("Some Realm", "example.com"), self.assertEqual(find_user_pass("Some Realm", "example.com"),
('joe', 'password')) ('joe', 'password'))
self.assertEqual(find_user_pass("Some Realm", "http://example.com/ni"),
#self.assertEqual(find_user_pass("Some Realm", "http://example.com/ni"), ('joe', 'password'))
# ('ni', 'ni'))
self.assertEqual(find_user_pass("Some Realm", "http://example.com"), self.assertEqual(find_user_pass("Some Realm", "http://example.com"),
('joe', 'password')) ('joe', 'password'))
self.assertEqual(find_user_pass("Some Realm", "http://example.com/"), self.assertEqual(find_user_pass("Some Realm", "http://example.com/"),
('joe', 'password')) ('joe', 'password'))
self.assertEqual( self.assertEqual(find_user_pass("Some Realm",
find_user_pass("Some Realm", "http://example.com/spam"), "http://example.com/spam"),
('joe', 'password')) ('joe', 'password'))
self.assertEqual(
find_user_pass("Some Realm", "http://example.com/spam/spam"), self.assertEqual(find_user_pass("Some Realm",
('joe', 'password')) "http://example.com/spam/spam"),
('joe', 'password'))
# You can have different passwords for different paths.
add("c", "http://example.com/foo", "foo", "ni")
add("c", "http://example.com/bar", "bar", "nini")
self.assertEqual(find_user_pass("c", "http://example.com/foo"), self.assertEqual(find_user_pass("c", "http://example.com/foo"),
('foo', 'ni')) ('foo', 'ni'))
self.assertEqual(find_user_pass("c", "http://example.com/bar"), self.assertEqual(find_user_pass("c", "http://example.com/bar"),
('bar', 'nini')) ('bar', 'nini'))
# For the same path, newer password should be considered.
add("b", "http://example.com/", "first", "blah")
add("b", "http://example.com/", "second", "spam")
self.assertEqual(find_user_pass("b", "http://example.com/"), self.assertEqual(find_user_pass("b", "http://example.com/"),
('second', 'spam')) ('second', 'spam'))
# No special relationship between a.example.com and example.com: # No special relationship between a.example.com and example.com:
add("a", "http://example.com", "1", "a")
self.assertEqual(find_user_pass("a", "http://example.com/"), self.assertEqual(find_user_pass("a", "http://example.com/"),
('1', 'a')) ('1', 'a'))
self.assertEqual(find_user_pass("a", "http://a.example.com/"), self.assertEqual(find_user_pass("a", "http://a.example.com/"),
(None, None)) (None, None))
...@@ -830,7 +841,6 @@ class HandlerTests(unittest.TestCase): ...@@ -830,7 +841,6 @@ class HandlerTests(unittest.TestCase):
for url, ftp in [ for url, ftp in [
("file://ftp.example.com//foo.txt", False), ("file://ftp.example.com//foo.txt", False),
("file://ftp.example.com///foo.txt", False), ("file://ftp.example.com///foo.txt", False),
# XXXX bug: fails with OSError, should be URLError
("file://ftp.example.com/foo.txt", False), ("file://ftp.example.com/foo.txt", False),
("file://somehost//foo/something.txt", False), ("file://somehost//foo/something.txt", False),
("file://localhost//foo/something.txt", False), ("file://localhost//foo/something.txt", False),
...@@ -838,8 +848,7 @@ class HandlerTests(unittest.TestCase): ...@@ -838,8 +848,7 @@ class HandlerTests(unittest.TestCase):
req = Request(url) req = Request(url)
try: try:
h.file_open(req) h.file_open(req)
# XXXX remove OSError when bug fixed except urllib.error.URLError:
except (urllib.error.URLError, OSError):
self.assertFalse(ftp) self.assertFalse(ftp)
else: else:
self.assertIs(o.req, req) self.assertIs(o.req, req)
...@@ -1414,7 +1423,6 @@ class HandlerTests(unittest.TestCase): ...@@ -1414,7 +1423,6 @@ class HandlerTests(unittest.TestCase):
self.assertEqual(req.host, "proxy.example.com:3128") self.assertEqual(req.host, "proxy.example.com:3128")
self.assertEqual(req.get_header("Proxy-authorization"), "FooBar") self.assertEqual(req.get_header("Proxy-authorization"), "FooBar")
# TODO: This should be only for OSX
@unittest.skipUnless(sys.platform == 'darwin', "only relevant for OSX") @unittest.skipUnless(sys.platform == 'darwin', "only relevant for OSX")
def test_osx_proxy_bypass(self): def test_osx_proxy_bypass(self):
bypass = { bypass = {
...@@ -1690,7 +1698,6 @@ class HandlerTests(unittest.TestCase): ...@@ -1690,7 +1698,6 @@ class HandlerTests(unittest.TestCase):
self.assertTrue(conn.fakesock.closed, "Connection not closed") self.assertTrue(conn.fakesock.closed, "Connection not closed")
class MiscTests(unittest.TestCase): class MiscTests(unittest.TestCase):
def opener_has_handler(self, opener, handler_class): def opener_has_handler(self, opener, handler_class):
......
...@@ -289,11 +289,15 @@ class BasicAuthTests(unittest.TestCase): ...@@ -289,11 +289,15 @@ class BasicAuthTests(unittest.TestCase):
def http_server_with_basic_auth_handler(*args, **kwargs): def http_server_with_basic_auth_handler(*args, **kwargs):
return BasicAuthHandler(*args, **kwargs) return BasicAuthHandler(*args, **kwargs)
self.server = LoopbackHttpServerThread(http_server_with_basic_auth_handler) self.server = LoopbackHttpServerThread(http_server_with_basic_auth_handler)
self.addCleanup(self.server.stop) self.addCleanup(self.stop_server)
self.server_url = 'http://127.0.0.1:%s' % self.server.port self.server_url = 'http://127.0.0.1:%s' % self.server.port
self.server.start() self.server.start()
self.server.ready.wait() self.server.ready.wait()
def stop_server(self):
self.server.stop()
self.server = None
def tearDown(self): def tearDown(self):
super(BasicAuthTests, self).tearDown() super(BasicAuthTests, self).tearDown()
...@@ -304,7 +308,7 @@ class BasicAuthTests(unittest.TestCase): ...@@ -304,7 +308,7 @@ class BasicAuthTests(unittest.TestCase):
try: try:
self.assertTrue(urllib.request.urlopen(self.server_url)) self.assertTrue(urllib.request.urlopen(self.server_url))
except urllib.error.HTTPError: except urllib.error.HTTPError:
self.fail("Basic auth failed for the url: %s", self.server_url) self.fail("Basic auth failed for the url: %s" % self.server_url)
def test_basic_auth_httperror(self): def test_basic_auth_httperror(self):
ah = urllib.request.HTTPBasicAuthHandler() ah = urllib.request.HTTPBasicAuthHandler()
...@@ -339,6 +343,7 @@ class ProxyAuthTests(unittest.TestCase): ...@@ -339,6 +343,7 @@ class ProxyAuthTests(unittest.TestCase):
return FakeProxyHandler(self.digest_auth_handler, *args, **kwargs) return FakeProxyHandler(self.digest_auth_handler, *args, **kwargs)
self.server = LoopbackHttpServerThread(create_fake_proxy_handler) self.server = LoopbackHttpServerThread(create_fake_proxy_handler)
self.addCleanup(self.stop_server)
self.server.start() self.server.start()
self.server.ready.wait() self.server.ready.wait()
proxy_url = "http://127.0.0.1:%d" % self.server.port proxy_url = "http://127.0.0.1:%d" % self.server.port
...@@ -347,9 +352,9 @@ class ProxyAuthTests(unittest.TestCase): ...@@ -347,9 +352,9 @@ class ProxyAuthTests(unittest.TestCase):
self.opener = urllib.request.build_opener( self.opener = urllib.request.build_opener(
handler, self.proxy_digest_handler) handler, self.proxy_digest_handler)
def tearDown(self): def stop_server(self):
self.server.stop() self.server.stop()
super(ProxyAuthTests, self).tearDown() self.server = None
def test_proxy_with_bad_password_raises_httperror(self): def test_proxy_with_bad_password_raises_httperror(self):
self.proxy_digest_handler.add_password(self.REALM, self.URL, self.proxy_digest_handler.add_password(self.REALM, self.URL,
...@@ -468,13 +473,17 @@ class TestUrlopen(unittest.TestCase): ...@@ -468,13 +473,17 @@ class TestUrlopen(unittest.TestCase):
f.close() f.close()
return b"".join(l) return b"".join(l)
def stop_server(self):
self.server.stop()
self.server = None
def start_server(self, responses=None): def start_server(self, responses=None):
if responses is None: if responses is None:
responses = [(200, [], b"we don't care")] responses = [(200, [], b"we don't care")]
handler = GetRequestHandler(responses) handler = GetRequestHandler(responses)
self.server = LoopbackHttpServerThread(handler) self.server = LoopbackHttpServerThread(handler)
self.addCleanup(self.server.stop) self.addCleanup(self.stop_server)
self.server.start() self.server.start()
self.server.ready.wait() self.server.ready.wait()
port = self.server.port port = self.server.port
...@@ -589,7 +598,7 @@ class TestUrlopen(unittest.TestCase): ...@@ -589,7 +598,7 @@ class TestUrlopen(unittest.TestCase):
def cb_sni(ssl_sock, server_name, initial_context): def cb_sni(ssl_sock, server_name, initial_context):
nonlocal sni_name nonlocal sni_name
sni_name = server_name sni_name = server_name
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context = ssl.SSLContext(ssl.PROTOCOL_TLS)
context.set_servername_callback(cb_sni) context.set_servername_callback(cb_sni)
handler = self.start_https_server(context=context, certfile=CERT_localhost) handler = self.start_https_server(context=context, certfile=CERT_localhost)
context = ssl.create_default_context(cafile=CERT_localhost) context = ssl.create_default_context(cafile=CERT_localhost)
...@@ -664,7 +673,7 @@ def setUpModule(): ...@@ -664,7 +673,7 @@ def setUpModule():
def tearDownModule(): def tearDownModule():
if threads_key: if threads_key:
support.threading_cleanup(threads_key) support.threading_cleanup(*threads_key)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()
...@@ -27,6 +27,13 @@ def _wrap_with_retry_thrice(func, exc): ...@@ -27,6 +27,13 @@ def _wrap_with_retry_thrice(func, exc):
return _retry_thrice(func, exc, *args, **kwargs) return _retry_thrice(func, exc, *args, **kwargs)
return wrapped return wrapped
# bpo-35411: FTP tests of test_urllib2net randomly fail
# with "425 Security: Bad IP connecting" on Travis CI
skip_ftp_test_on_travis = unittest.skipIf('TRAVIS' in os.environ,
'bpo-35411: skip FTP test '
'on Travis CI')
# Connecting to remote hosts is flaky. Make it more robust by retrying # Connecting to remote hosts is flaky. Make it more robust by retrying
# the connection several times. # the connection several times.
_urlopen_with_retry = _wrap_with_retry_thrice(urllib.request.urlopen, _urlopen_with_retry = _wrap_with_retry_thrice(urllib.request.urlopen,
...@@ -95,10 +102,11 @@ class OtherNetworkTests(unittest.TestCase): ...@@ -95,10 +102,11 @@ class OtherNetworkTests(unittest.TestCase):
# XXX The rest of these tests aren't very good -- they don't check much. # XXX The rest of these tests aren't very good -- they don't check much.
# They do sometimes catch some major disasters, though. # They do sometimes catch some major disasters, though.
@skip_ftp_test_on_travis
def test_ftp(self): def test_ftp(self):
urls = [ urls = [
'ftp://ftp.debian.org/debian/README', 'ftp://www.pythontest.net/README',
('ftp://ftp.debian.org/debian/non-existent-file', ('ftp://www.pythontest.net/non-existent-file',
None, urllib.error.URLError), None, urllib.error.URLError),
] ]
self._test_urls(urls, self._extra_handlers()) self._test_urls(urls, self._extra_handlers())
...@@ -177,6 +185,7 @@ class OtherNetworkTests(unittest.TestCase): ...@@ -177,6 +185,7 @@ class OtherNetworkTests(unittest.TestCase):
opener.open(request) opener.open(request)
self.assertEqual(request.get_header('User-agent'),'Test-Agent') self.assertEqual(request.get_header('User-agent'),'Test-Agent')
@unittest.skip('XXX: http://www.imdb.com is gone')
def test_sites_no_connection_close(self): def test_sites_no_connection_close(self):
# Some sites do not send Connection: close header. # Some sites do not send Connection: close header.
# Verify that those work properly. (#issue12576) # Verify that those work properly. (#issue12576)
...@@ -287,8 +296,9 @@ class TimeoutTest(unittest.TestCase): ...@@ -287,8 +296,9 @@ class TimeoutTest(unittest.TestCase):
self.addCleanup(u.close) self.addCleanup(u.close)
self.assertEqual(u.fp.raw._sock.gettimeout(), 120) self.assertEqual(u.fp.raw._sock.gettimeout(), 120)
FTP_HOST = 'ftp://ftp.debian.org/debian/' FTP_HOST = 'ftp://www.pythontest.net/'
@skip_ftp_test_on_travis
def test_ftp_basic(self): def test_ftp_basic(self):
self.assertIsNone(socket.getdefaulttimeout()) self.assertIsNone(socket.getdefaulttimeout())
with support.transient_internet(self.FTP_HOST, timeout=None): with support.transient_internet(self.FTP_HOST, timeout=None):
...@@ -296,6 +306,7 @@ class TimeoutTest(unittest.TestCase): ...@@ -296,6 +306,7 @@ class TimeoutTest(unittest.TestCase):
self.addCleanup(u.close) self.addCleanup(u.close)
self.assertIsNone(u.fp.fp.raw._sock.gettimeout()) self.assertIsNone(u.fp.fp.raw._sock.gettimeout())
@skip_ftp_test_on_travis
def test_ftp_default_timeout(self): def test_ftp_default_timeout(self):
self.assertIsNone(socket.getdefaulttimeout()) self.assertIsNone(socket.getdefaulttimeout())
with support.transient_internet(self.FTP_HOST): with support.transient_internet(self.FTP_HOST):
...@@ -307,6 +318,7 @@ class TimeoutTest(unittest.TestCase): ...@@ -307,6 +318,7 @@ class TimeoutTest(unittest.TestCase):
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertEqual(u.fp.fp.raw._sock.gettimeout(), 60) self.assertEqual(u.fp.fp.raw._sock.gettimeout(), 60)
@skip_ftp_test_on_travis
def test_ftp_no_timeout(self): def test_ftp_no_timeout(self):
self.assertIsNone(socket.getdefaulttimeout()) self.assertIsNone(socket.getdefaulttimeout())
with support.transient_internet(self.FTP_HOST): with support.transient_internet(self.FTP_HOST):
...@@ -318,6 +330,7 @@ class TimeoutTest(unittest.TestCase): ...@@ -318,6 +330,7 @@ class TimeoutTest(unittest.TestCase):
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertIsNone(u.fp.fp.raw._sock.gettimeout()) self.assertIsNone(u.fp.fp.raw._sock.gettimeout())
@skip_ftp_test_on_travis
def test_ftp_timeout(self): def test_ftp_timeout(self):
with support.transient_internet(self.FTP_HOST): with support.transient_internet(self.FTP_HOST):
u = _urlopen_with_retry(self.FTP_HOST, timeout=60) u = _urlopen_with_retry(self.FTP_HOST, timeout=60)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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