Commit 8600b68d authored by Jason Madden's avatar Jason Madden

Update 2.7 tests to 2.7.11. Fixes #735.

Also update the test_ssl.py to cpython rev 2c9ff9e (head). This fixes the
problems with invalid certs for svn.python.org.

These tests include much more testing of the new-in-2.7.9 SSLContext
settings, which revealed some problems in our hostname validation, our
handling of read/write/do_handshake for closed sockets, and the missing
alpn_selected method.
parent 5fd0f6ef
...@@ -18,6 +18,14 @@ ...@@ -18,6 +18,14 @@
Hoad. Hoad.
- ``BaseServer`` and its subclasses like ``WSGIServer`` avoid - ``BaseServer`` and its subclasses like ``WSGIServer`` avoid
allocating a new closure for each request, reducing overhead. allocating a new closure for each request, reducing overhead.
- Python 2: Under 2.7.9 and above (or when the PEP 466 SSL interfaces
are available), perform the same hostname validation that the
standard library does; previously some cases were ignored. Also,
reading, writing, or handshaking a closed ``SSLSocket`` now raises
the same ``ValueError`` the standard library does, instead of an
``AttributeError``. Found by updating gevent's copy of the
standard library test cases. Initially reported in :issue:`735` by
Dmitrij D. Czarkoff.
1.1rc3 (Jan 04, 2016) 1.1rc3 (Jan 04, 2016)
===================== =====================
......
...@@ -39,7 +39,7 @@ else: ...@@ -39,7 +39,7 @@ else:
#_fileobject.__exit__ = lambda self, *args: self.close() if not self.closed else None #_fileobject.__exit__ = lambda self, *args: self.close() if not self.closed else None
# or we could subclass. subclassing has the benefit of not # or we could subclass. subclassing has the benefit of not
# changing the behaviour of the stdlib if we're just imported; OTOH, # changing the behaviour of the stdlib if we're just imported; OTOH,
# under Python 2.6, test_urllib2net.py asserts that the class IS # under Python 2.6/2.7, test_urllib2net.py asserts that the class IS
# socket._fileobject (sigh), so we have to work around that. # socket._fileobject (sigh), so we have to work around that.
class _fileobject(_fileobject): class _fileobject(_fileobject):
......
...@@ -227,6 +227,8 @@ class SSLSocket(socket): ...@@ -227,6 +227,8 @@ class SSLSocket(socket):
if server_side and server_hostname: if server_side and server_hostname:
raise ValueError("server_hostname can only be specified " raise ValueError("server_hostname can only be specified "
"in client mode") "in client mode")
if self._context.check_hostname and not server_hostname:
raise ValueError("check_hostname requires server_hostname")
self.server_side = server_side self.server_side = server_side
self.server_hostname = server_hostname self.server_hostname = server_hostname
self.do_handshake_on_connect = do_handshake_on_connect self.do_handshake_on_connect = do_handshake_on_connect
...@@ -292,6 +294,9 @@ class SSLSocket(socket): ...@@ -292,6 +294,9 @@ class SSLSocket(socket):
def read(self, len=0, buffer=None): def read(self, len=0, buffer=None):
"""Read up to LEN bytes and return them. """Read up to LEN bytes and return them.
Return zero-length string on EOF.""" Return zero-length string on EOF."""
self._checkClosed()
if not self._sslobj:
raise ValueError("Read on closed or unwrapped SSL socket.")
while True: while True:
try: try:
if buffer is not None: if buffer is not None:
...@@ -319,6 +324,9 @@ class SSLSocket(socket): ...@@ -319,6 +324,9 @@ class SSLSocket(socket):
def write(self, data): def write(self, data):
"""Write DATA to the underlying SSL channel. Returns """Write DATA to the underlying SSL channel. Returns
number of bytes of DATA actually transmitted.""" number of bytes of DATA actually transmitted."""
self._checkClosed()
if not self._sslobj:
raise ValueError("Write on closed or unwrapped SSL socket.")
while True: while True:
try: try:
return self._sslobj.write(data) return self._sslobj.write(data)
...@@ -351,6 +359,15 @@ class SSLSocket(socket): ...@@ -351,6 +359,15 @@ class SSLSocket(socket):
else: else:
return self._sslobj.selected_npn_protocol() return self._sslobj.selected_npn_protocol()
if hasattr(_ssl, 'HAS_ALPN'):
# 2.7.10+
def selected_alpn_protocol(self):
self._checkClosed()
if not self._sslobj or not _ssl.HAS_ALPN:
return None
else:
return self._sslobj.selected_alpn_protocol()
def cipher(self): def cipher(self):
self._checkClosed() self._checkClosed()
if not self._sslobj: if not self._sslobj:
...@@ -537,9 +554,11 @@ class SSLSocket(socket): ...@@ -537,9 +554,11 @@ class SSLSocket(socket):
def do_handshake(self): def do_handshake(self):
"""Perform a TLS/SSL handshake.""" """Perform a TLS/SSL handshake."""
self._check_connected()
while True: while True:
try: try:
return self._sslobj.do_handshake() self._sslobj.do_handshake()
break
except SSLWantReadError: except SSLWantReadError:
if self.timeout == 0.0: if self.timeout == 0.0:
raise raise
......
-----BEGIN CERTIFICATE-----
MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv
bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG
A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo
b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0
aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ
Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm
Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv
EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl
bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h
TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515
C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD
VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv
bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy
dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X
DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw
EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l
dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT
EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw
L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN
BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX
9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO
BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi
MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ
ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ
8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6
zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y
fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7
w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc
G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k
epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q
laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ
QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU
fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826
YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w
ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY
gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe
MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0
IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy
dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw
czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0
dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl
aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC
AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg
b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB
ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc
nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg
18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c
gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl
Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY
sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T
SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF
CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum
GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk
zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW
omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD
VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv
bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy
dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X
DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw
EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l
dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT
EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw
L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN
BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX
9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO
BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi
MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ
ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ
8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6
zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y
fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7
w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc
G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k
epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q
laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ
QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU
fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826
YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w
ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY
gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe
MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0
IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy
dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw
czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0
dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl
aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC
AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg
b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB
ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc
nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg
18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c
gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl
Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY
sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T
SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF
CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum
GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk
zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW
omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv
bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG
A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo
b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0
aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ
Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm
Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv
EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl
bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h
TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515
C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM=
-----END CERTIFICATE-----
-----BEGIN DH PARAMETERS-----
MIGHAoGBAIbzw1s9CT8SV5yv6L7esdAdZYZjPi3qWFs61CYTFFQnf2s/d09NYaJt
rrvJhIzWavqnue71qXCf83/J3nz3FEwUU/L0mGyheVbsSHiI64wUo3u50wK5Igo0
RNs/LD0irs7m0icZ//hijafTU+JOBiuA8zMI+oZfU7BGuc9XrUprAgEC
-----END DH PARAMETERS-----
Generated with: openssl dhparam -out dh1024.pem 1024
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,1A8D9D2A02EC698A
kJYbfZ8L0sfe9Oty3gw0aloNnY5E8fegRfQLZlNoxTl6jNt0nIwI8kDJ36CZgR9c
u3FDJm/KqrfUoz8vW+qEnWhSG7QPX2wWGPHd4K94Yz/FgrRzZ0DoK7XxXq9gOtVA
AVGQhnz32p+6WhfGsCr9ArXEwRZrTk/FvzEPaU5fHcoSkrNVAGX8IpSVkSDwEDQr
Gv17+cfk99UV1OCza6yKHoFkTtrC+PZU71LomBabivS2Oc4B9hYuSR2hF01wTHP+
YlWNagZOOVtNz4oKK9x9eNQpmfQXQvPPTfusexKIbKfZrMvJoxcm1gfcZ0H/wK6P
6wmXSG35qMOOztCZNtperjs1wzEBXznyK8QmLcAJBjkfarABJX9vBEzZV0OUKhy+
noORFwHTllphbmydLhu6ehLUZMHPhzAS5UN7srtpSN81eerDMy0RMUAwA7/PofX1
94Me85Q8jP0PC9ETdsJcPqLzAPETEYu0ELewKRcrdyWi+tlLFrpE5KT/s5ecbl9l
7B61U4Kfd1PIXc/siINhU3A3bYK+845YyUArUOnKf1kEox7p1RpD7yFqVT04lRTo
cibNKATBusXSuBrp2G6GNuhWEOSafWCKJQAzgCYIp6ZTV2khhMUGppc/2H3CF6cO
zX0KtlPVZC7hLkB6HT8SxYUwF1zqWY7+/XPPdc37MeEZ87Q3UuZwqORLY+Z0hpgt
L5JXBCoklZhCAaN2GqwFLXtGiRSRFGY7xXIhbDTlE65Wv1WGGgDLMKGE1gOz3yAo
2jjG1+yAHJUdE69XTFHSqSkvaloA1W03LdMXZ9VuQJ/ySXCie6ABAQ==
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANcLaMB7T/Wi9DBc
PltGzgt8cxsv55m7PQPHMZvn6Ke8xmNqcmEzib8opRwKGrCV6TltKeFlNSg8dwQK
Tl4ktyTkGCVweRQJ37AkBayvEBml5s+QD4vlhqkJPsL/Nsd+fnqngOGc5+59+C6r
s3XpiLlF5ah/z8q92Mnw54nypw1JAgMBAAECgYBE3t2Mj7GbDLZB6rj5yKJioVfI
BD6bSJEQ7bGgqdQkLFwpKMU7BiN+ekjuwvmrRkesYZ7BFgXBPiQrwhU5J28Tpj5B
EOMYSIOHfzdalhxDGM1q2oK9LDFiCotTaSdEzMYadel5rmKXJ0zcK2Jho0PCuECf
tf/ghRxK+h1Hm0tKgQJBAO6MdGDSmGKYX6/5kPDje7we/lSLorSDkYmV0tmVShsc
JxgaGaapazceA/sHL3Myx7Eenkip+yPYDXEDFvAKNDECQQDmxsT9NOp6mo7ISvky
GFr2vVHsJ745BMWoma4rFjPBVnS8RkgK+b2EpDCdZSrQ9zw2r8sKTgrEyrDiGTEg
wJyZAkA8OOc0flYMJg2aHnYR6kwVjPmGHI5h5gk648EMPx0rROs1sXkiUwkHLCOz
HvhCq+Iv+9vX2lnVjbiu/CmxRdIxAkA1YEfzoKeTD+hyXxTgB04Sv5sRGegfXAEz
i8gC4zG5R/vcCA1lrHmvEiLEZL/QcT6WD3bQvVg0SAU9ZkI8pxARAkA7yqMSvP1l
gJXy44R+rzpLYb1/PtiLkIkaKG3x9TUfPnfD2jY09fPkZlfsRU3/uS09IkhSwimV
d5rWoljEfdou
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICXTCCAcagAwIBAgIJALVQzebTtrXFMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTAeFw0x
NDExMjMxNzAwMDdaFw0yNDExMjAxNzAwMDdaMGIxCzAJBgNVBAYTAlhZMRcwFQYD
VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv
dW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEA1wtowHtP9aL0MFw+W0bOC3xzGy/nmbs9A8cxm+fop7zGY2py
YTOJvyilHAoasJXpOW0p4WU1KDx3BApOXiS3JOQYJXB5FAnfsCQFrK8QGaXmz5AP
i+WGqQk+wv82x35+eqeA4Zzn7n34LquzdemIuUXlqH/Pyr3YyfDnifKnDUkCAwEA
AaMbMBkwFwYDVR0RBBAwDoIMZmFrZWhvc3RuYW1lMA0GCSqGSIb3DQEBBQUAA4GB
AKuay3vDKfWzt5+ch/HHBsert84ISot4fUjzXDA/oOgTOEjVcSShHxqNShMOW1oA
QYBpBB/5Kx5RkD/w6imhucxt2WQPRgjX4x4bwMipVH/HvFDp03mG51/Cpi1TyZ74
El7qa/Pd4lHhOLzMKBA6503fpeYSFUIBxZbGLqylqRK7
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMLgD0kAKDb5cFyP
jbwNfR5CtewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM
9z2j1OlaN+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZ
aggEdkj1TsSsv1zWIYKlPIjlvhuxAgMBAAECgYA0aH+T2Vf3WOPv8KdkcJg6gCRe
yJKXOWgWRcicx/CUzOEsTxmFIDPLxqAWA3k7v0B+3vjGw5Y9lycV/5XqXNoQI14j
y09iNsumds13u5AKkGdTJnZhQ7UKdoVHfuP44ZdOv/rJ5/VD6F4zWywpe90pcbK+
AWDVtusgGQBSieEl1QJBAOyVrUG5l2yoUBtd2zr/kiGm/DYyXlIthQO/A3/LngDW
5/ydGxVsT7lAVOgCsoT+0L4efTh90PjzW8LPQrPBWVMCQQDS3h/FtYYd5lfz+FNL
9CEe1F1w9l8P749uNUD0g317zv1tatIqVCsQWHfVHNdVvfQ+vSFw38OORO00Xqs9
1GJrAkBkoXXEkxCZoy4PteheO/8IWWLGGr6L7di6MzFl1lIqwT6D8L9oaV2vynFT
DnKop0pa09Unhjyw57KMNmSE2SUJAkEArloTEzpgRmCq4IK2/NpCeGdHS5uqRlbh
1VIa/xGps7EWQl5Mn8swQDel/YP3WGHTjfx7pgSegQfkyaRtGpZ9OQJAa9Vumj8m
JAAtI0Bnga8hgQx7BhTQY4CadDxyiRGOGYhwUzYVCqkb2sbVRH9HnwUaJT7cWBY3
RnJdHOMXWem7/w==
-----END PRIVATE KEY-----
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 12723342612721443281 (0xb09264b1f2da21d1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Validity
Not Before: Jan 4 19:47:07 2013 GMT
Not After : Nov 13 19:47:07 2022 GMT
Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:c2:e0:0f:49:00:28:36:f9:70:5c:8f:8d:bc:0d:
7d:1e:42:b5:ec:1d:5c:2f:a4:31:70:16:0f:c0:cb:
c6:24:d3:be:13:16:ee:a5:67:97:03:a6:df:a9:99:
96:cc:c7:2a:fb:11:7f:4e:65:4f:8a:5e:82:21:4c:
f7:3d:a3:d4:e9:5a:37:e7:22:fd:7e:cd:53:6d:93:
34:de:9c:ad:84:a2:37:be:c5:8d:82:4f:e3:ae:23:
f3:be:a7:75:2c:72:0f:ea:f3:ca:cd:fc:e9:3f:b5:
af:56:99:6a:08:04:76:48:f5:4e:c4:ac:bf:5c:d6:
21:82:a5:3c:88:e5:be:1b:b1
Exponent: 65537 (0x10001)
Signature Algorithm: sha1WithRSAEncryption
2f:42:5f:a3:09:2c:fa:51:88:c7:37:7f:ea:0e:63:f0:a2:9a:
e5:5a:e2:c8:20:f0:3f:60:bc:c8:0f:b6:c6:76:ce:db:83:93:
f5:a3:33:67:01:8e:04:cd:00:9a:73:fd:f3:35:86:fa:d7:13:
e2:46:c6:9d:c0:29:53:d4:a9:90:b8:77:4b:e6:83:76:e4:92:
d6:9c:50:cf:43:d0:c6:01:77:61:9a:de:9b:70:f7:72:cd:59:
00:31:69:d9:b4:ca:06:9c:6d:c3:c7:80:8c:68:e6:b5:a2:f8:
ef:1d:bb:16:9f:77:77:ef:87:62:22:9b:4d:69:a4:3a:1a:f1:
21:5e:8c:32:ac:92:fd:15:6b:18:c2:7f:15:0d:98:30:ca:75:
8f:1a:71:df:da:1d:b2:ef:9a:e8:2d:2e:02:fd:4a:3c:aa:96:
0b:06:5d:35:b3:3d:24:87:4b:e0:b0:58:60:2f:45:ac:2e:48:
8a:b0:99:10:65:27:ff:cc:b1:d8:fd:bd:26:6b:b9:0c:05:2a:
f4:45:63:35:51:07:ed:83:85:fe:6f:69:cb:bb:40:a8:ae:b6:
3b:56:4a:2d:a4:ed:6d:11:2c:4d:ed:17:24:fd:47:bc:d3:41:
a2:d3:06:fe:0c:90:d8:d8:94:26:c4:ff:cc:a1:d8:42:77:eb:
fc:a9:94:71
-----BEGIN CERTIFICATE-----
MIICpDCCAYwCCQCwkmSx8toh0TANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJY
WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV
BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTMwMTA0MTk0NzA3WhcNMjIxMTEzMTk0NzA3
WjBfMQswCQYDVQQGEwJYWTEXMBUGA1UEBxMOQ2FzdGxlIEFudGhyYXgxIzAhBgNV
BAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMRIwEAYDVQQDEwlsb2NhbGhv
c3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMLgD0kAKDb5cFyPjbwNfR5C
tewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM9z2j1Ola
N+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZaggEdkj1
TsSsv1zWIYKlPIjlvhuxAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAC9CX6MJLPpR
iMc3f+oOY/CimuVa4sgg8D9gvMgPtsZ2ztuDk/WjM2cBjgTNAJpz/fM1hvrXE+JG
xp3AKVPUqZC4d0vmg3bkktacUM9D0MYBd2Ga3ptw93LNWQAxadm0ygacbcPHgIxo
5rWi+O8duxafd3fvh2Iim01ppDoa8SFejDKskv0VaxjCfxUNmDDKdY8acd/aHbLv
mugtLgL9SjyqlgsGXTWzPSSHS+CwWGAvRawuSIqwmRBlJ//Msdj9vSZruQwFKvRF
YzVRB+2Dhf5vacu7QKiutjtWSi2k7W0RLE3tFyT9R7zTQaLTBv4MkNjYlCbE/8yh
2EJ36/yplHE=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK5UQiMI5VkNs2Qv
L7gUaiDdFevNUXRjU4DHAe3ZzzYLZNE69h9gO9VCSS16tJ5fT5VEu0EZyGr0e3V2
NkX0ZoU0Hc/UaY4qx7LHmn5SYZpIxhJnkf7SyHJK1zUaGlU0/LxYqIuGCtF5dqx1
L2OQhEx1GM6RydHdgX69G64LXcY5AgMBAAECgYAhsRMfJkb9ERLMl/oG/5sLQu9L
pWDKt6+ZwdxzlZbggQ85CMYshjLKIod2DLL/sLf2x1PRXyRG131M1E3k8zkkz6de
R1uDrIN/x91iuYzfLQZGh8bMY7Yjd2eoroa6R/7DjpElGejLxOAaDWO0ST2IFQy9
myTGS2jSM97wcXfsSQJBANP3jelJoS5X6BRjTSneY21wcocxVuQh8pXpErALVNsT
drrFTeaBuZp7KvbtnIM5g2WRNvaxLZlAY/hXPJvi6ncCQQDSix1cebml6EmPlEZS
Mm8gwI2F9ufUunwJmBJcz826Do0ZNGByWDAM/JQZH4FX4GfAFNuj8PUb+GQfadkx
i1DPAkEA0lVsNHojvuDsIo8HGuzarNZQT2beWjJ1jdxh9t7HrTx7LIps6rb/fhOK
Zs0R6gVAJaEbcWAPZ2tFyECInAdnsQJAUjaeXXjuxFkjOFym5PvqpvhpivEx78Bu
JPTr3rAKXmfGMxxfuOa0xK1wSyshP6ZR/RBn/+lcXPKubhHQDOegwwJAJF1DBQnN
+/tLmOPULtDwfP4Zixn+/8GmGOahFoRcu6VIGHmRilJTn6MOButw7Glv2YdeC6l/
e83Gq6ffLVfKNQ==
-----END PRIVATE KEY-----
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 12723342612721443282 (0xb09264b1f2da21d2)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Validity
Not Before: Jan 4 19:47:07 2013 GMT
Not After : Nov 13 19:47:07 2022 GMT
Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=fakehostname
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:ae:54:42:23:08:e5:59:0d:b3:64:2f:2f:b8:14:
6a:20:dd:15:eb:cd:51:74:63:53:80:c7:01:ed:d9:
cf:36:0b:64:d1:3a:f6:1f:60:3b:d5:42:49:2d:7a:
b4:9e:5f:4f:95:44:bb:41:19:c8:6a:f4:7b:75:76:
36:45:f4:66:85:34:1d:cf:d4:69:8e:2a:c7:b2:c7:
9a:7e:52:61:9a:48:c6:12:67:91:fe:d2:c8:72:4a:
d7:35:1a:1a:55:34:fc:bc:58:a8:8b:86:0a:d1:79:
76:ac:75:2f:63:90:84:4c:75:18:ce:91:c9:d1:dd:
81:7e:bd:1b:ae:0b:5d:c6:39
Exponent: 65537 (0x10001)
Signature Algorithm: sha1WithRSAEncryption
ad:45:8a:8e:ef:c6:ef:04:41:5c:2c:4a:84:dc:02:76:0c:d0:
66:0f:f0:16:04:58:4d:fd:68:b7:b8:d3:a8:41:a5:5c:3c:6f:
65:3c:d1:f8:ce:43:35:e7:41:5f:53:3d:c9:2c:c3:7d:fc:56:
4a:fa:47:77:38:9d:bb:97:28:0a:3b:91:19:7f:bc:74:ae:15:
6b:bd:20:36:67:45:a5:1e:79:d7:75:e6:89:5c:6d:54:84:d1:
95:d7:a7:b4:33:3c:af:37:c4:79:8f:5e:75:dc:75:c2:18:fb:
61:6f:2d:dc:38:65:5b:ba:67:28:d0:88:d7:8d:b9:23:5a:8e:
e8:c6:bb:db:ce:d5:b8:41:2a:ce:93:08:b6:95:ad:34:20:18:
d5:3b:37:52:74:50:0b:07:2c:b0:6d:a4:4c:7b:f4:e0:fd:d1:
af:17:aa:20:cd:62:e3:f0:9d:37:69:db:41:bd:d4:1c:fb:53:
20:da:88:9d:76:26:67:ce:01:90:a7:80:1d:a9:5b:39:73:68:
54:0a:d1:2a:03:1b:8f:3c:43:5d:5d:c4:51:f1:a7:e7:11:da:
31:2c:49:06:af:04:f4:b8:3c:99:c4:20:b9:06:36:a2:00:92:
61:1d:0c:6d:24:05:e2:82:e1:47:db:a0:5f:ba:b9:fb:ba:fa:
49:12:1e:ce
-----BEGIN CERTIFICATE-----
MIICpzCCAY8CCQCwkmSx8toh0jANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJY
WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV
BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTMwMTA0MTk0NzA3WhcNMjIxMTEzMTk0NzA3
WjBiMQswCQYDVQQGEwJYWTEXMBUGA1UEBxMOQ2FzdGxlIEFudGhyYXgxIzAhBgNV
BAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMRUwEwYDVQQDEwxmYWtlaG9z
dG5hbWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK5UQiMI5VkNs2QvL7gU
aiDdFevNUXRjU4DHAe3ZzzYLZNE69h9gO9VCSS16tJ5fT5VEu0EZyGr0e3V2NkX0
ZoU0Hc/UaY4qx7LHmn5SYZpIxhJnkf7SyHJK1zUaGlU0/LxYqIuGCtF5dqx1L2OQ
hEx1GM6RydHdgX69G64LXcY5AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAK1Fio7v
xu8EQVwsSoTcAnYM0GYP8BYEWE39aLe406hBpVw8b2U80fjOQzXnQV9TPcksw338
Vkr6R3c4nbuXKAo7kRl/vHSuFWu9IDZnRaUeedd15olcbVSE0ZXXp7QzPK83xHmP
XnXcdcIY+2FvLdw4ZVu6ZyjQiNeNuSNajujGu9vO1bhBKs6TCLaVrTQgGNU7N1J0
UAsHLLBtpEx79OD90a8XqiDNYuPwnTdp20G91Bz7UyDaiJ12JmfOAZCngB2pWzlz
aFQK0SoDG488Q11dxFHxp+cR2jEsSQavBPS4PJnEILkGNqIAkmEdDG0kBeKC4Ufb
oF+6ufu6+kkSHs4=
-----END CERTIFICATE-----
...@@ -39,8 +39,12 @@ class Bunch(object): ...@@ -39,8 +39,12 @@ class Bunch(object):
self.finished.append(tid) self.finished.append(tid)
while not self._can_exit: while not self._can_exit:
_wait() _wait()
for i in range(n): try:
start_new_thread(task, ()) for i in range(n):
start_new_thread(task, ())
except:
self._can_exit = True
raise
def wait_for_started(self): def wait_for_started(self):
while len(self.started) < self.n: while len(self.started) < self.n:
...@@ -301,6 +305,16 @@ class EventTests(BaseTestCase): ...@@ -301,6 +305,16 @@ class EventTests(BaseTestCase):
for r, dt in results2: for r, dt in results2:
self.assertTrue(r) self.assertTrue(r)
def test_reset_internal_locks(self):
evt = self.eventtype()
if not hasattr(evt, '_Event__cond'):
self.skipTest("gevent: internal impl difference")
old_lock = evt._Event__cond._Condition__lock
evt._reset_internal_locks()
new_lock = evt._Event__cond._Condition__lock
self.assertIsNot(new_lock, old_lock)
self.assertIs(type(new_lock), type(old_lock))
class ConditionTests(BaseTestCase): class ConditionTests(BaseTestCase):
""" """
......
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, ST=Oregon, L=Beaverton, O=Python Software Foundation, OU=Python Core Development, CN=null.python.org\x00example.org/emailAddress=python-dev@python.org
Validity
Not Before: Aug 7 13:11:52 2013 GMT
Not After : Aug 7 13:12:52 2013 GMT
Subject: C=US, ST=Oregon, L=Beaverton, O=Python Software Foundation, OU=Python Core Development, CN=null.python.org\x00example.org/emailAddress=python-dev@python.org
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:b5:ea:ed:c9:fb:46:7d:6f:3b:76:80:dd:3a:f3:
03:94:0b:a7:a6:db:ec:1d:df:ff:23:74:08:9d:97:
16:3f:a3:a4:7b:3e:1b:0e:96:59:25:03:a7:26:e2:
88:a9:cf:79:cd:f7:04:56:b0:ab:79:32:6e:59:c1:
32:30:54:eb:58:a8:cb:91:f0:42:a5:64:27:cb:d4:
56:31:88:52:ad:cf:bd:7f:f0:06:64:1f:cc:27:b8:
a3:8b:8c:f3:d8:29:1f:25:0b:f5:46:06:1b:ca:02:
45:ad:7b:76:0a:9c:bf:bb:b9:ae:0d:16:ab:60:75:
ae:06:3e:9c:7c:31:dc:92:2f:29:1a:e0:4b:0c:91:
90:6c:e9:37:c5:90:d7:2a:d7:97:15:a3:80:8f:5d:
7b:49:8f:54:30:d4:97:2c:1c:5b:37:b5:ab:69:30:
68:43:d3:33:78:4b:02:60:f5:3c:44:80:a1:8f:e7:
f0:0f:d1:5e:87:9e:46:cf:62:fc:f9:bf:0c:65:12:
f1:93:c8:35:79:3f:c8:ec:ec:47:f5:ef:be:44:d5:
ae:82:1e:2d:9a:9f:98:5a:67:65:e1:74:70:7c:cb:
d3:c2:ce:0e:45:49:27:dc:e3:2d:d4:fb:48:0e:2f:
9e:77:b8:14:46:c0:c4:36:ca:02:ae:6a:91:8c:da:
2f:85
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
88:5A:55:C0:52:FF:61:CD:52:A3:35:0F:EA:5A:9C:24:38:22:F7:5C
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment
X509v3 Subject Alternative Name:
*************************************************************
WARNING: The values for DNS, email and URI are WRONG. OpenSSL
doesn't print the text after a NULL byte.
*************************************************************
DNS:altnull.python.org, email:null@python.org, URI:http://null.python.org, IP Address:192.0.2.1, IP Address:2001:DB8:0:0:0:0:0:1
Signature Algorithm: sha1WithRSAEncryption
ac:4f:45:ef:7d:49:a8:21:70:8e:88:59:3e:d4:36:42:70:f5:
a3:bd:8b:d7:a8:d0:58:f6:31:4a:b1:a4:a6:dd:6f:d9:e8:44:
3c:b6:0a:71:d6:7f:b1:08:61:9d:60:ce:75:cf:77:0c:d2:37:
86:02:8d:5e:5d:f9:0f:71:b4:16:a8:c1:3d:23:1c:f1:11:b3:
56:6e:ca:d0:8d:34:94:e6:87:2a:99:f2:ae:ae:cc:c2:e8:86:
de:08:a8:7f:c5:05:fa:6f:81:a7:82:e6:d0:53:9d:34:f4:ac:
3e:40:fe:89:57:7a:29:a4:91:7e:0b:c6:51:31:e5:10:2f:a4:
60:76:cd:95:51:1a:be:8b:a1:b0:fd:ad:52:bd:d7:1b:87:60:
d2:31:c7:17:c4:18:4f:2d:08:25:a3:a7:4f:b7:92:ca:e2:f5:
25:f1:54:75:81:9d:b3:3d:61:a2:f7:da:ed:e1:c6:6f:2c:60:
1f:d8:6f:c5:92:05:ab:c9:09:62:49:a9:14:ad:55:11:cc:d6:
4a:19:94:99:97:37:1d:81:5f:8b:cf:a3:a8:96:44:51:08:3d:
0b:05:65:12:eb:b6:70:80:88:48:72:4f:c6:c2:da:cf:cd:8e:
5b:ba:97:2f:60:b4:96:56:49:5e:3a:43:76:63:04:be:2a:f6:
c1:ca:a9:94
-----BEGIN CERTIFICATE-----
MIIE2DCCA8CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBxTELMAkGA1UEBhMCVVMx
DzANBgNVBAgMBk9yZWdvbjESMBAGA1UEBwwJQmVhdmVydG9uMSMwIQYDVQQKDBpQ
eXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEgMB4GA1UECwwXUHl0aG9uIENvcmUg
RGV2ZWxvcG1lbnQxJDAiBgNVBAMMG251bGwucHl0aG9uLm9yZwBleGFtcGxlLm9y
ZzEkMCIGCSqGSIb3DQEJARYVcHl0aG9uLWRldkBweXRob24ub3JnMB4XDTEzMDgw
NzEzMTE1MloXDTEzMDgwNzEzMTI1MlowgcUxCzAJBgNVBAYTAlVTMQ8wDQYDVQQI
DAZPcmVnb24xEjAQBgNVBAcMCUJlYXZlcnRvbjEjMCEGA1UECgwaUHl0aG9uIFNv
ZnR3YXJlIEZvdW5kYXRpb24xIDAeBgNVBAsMF1B5dGhvbiBDb3JlIERldmVsb3Bt
ZW50MSQwIgYDVQQDDBtudWxsLnB5dGhvbi5vcmcAZXhhbXBsZS5vcmcxJDAiBgkq
hkiG9w0BCQEWFXB5dGhvbi1kZXZAcHl0aG9uLm9yZzCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBALXq7cn7Rn1vO3aA3TrzA5QLp6bb7B3f/yN0CJ2XFj+j
pHs+Gw6WWSUDpybiiKnPec33BFawq3kyblnBMjBU61ioy5HwQqVkJ8vUVjGIUq3P
vX/wBmQfzCe4o4uM89gpHyUL9UYGG8oCRa17dgqcv7u5rg0Wq2B1rgY+nHwx3JIv
KRrgSwyRkGzpN8WQ1yrXlxWjgI9de0mPVDDUlywcWze1q2kwaEPTM3hLAmD1PESA
oY/n8A/RXoeeRs9i/Pm/DGUS8ZPINXk/yOzsR/XvvkTVroIeLZqfmFpnZeF0cHzL
08LODkVJJ9zjLdT7SA4vnne4FEbAxDbKAq5qkYzaL4UCAwEAAaOB0DCBzTAMBgNV
HRMBAf8EAjAAMB0GA1UdDgQWBBSIWlXAUv9hzVKjNQ/qWpwkOCL3XDALBgNVHQ8E
BAMCBeAwgZAGA1UdEQSBiDCBhYIeYWx0bnVsbC5weXRob24ub3JnAGV4YW1wbGUu
Y29tgSBudWxsQHB5dGhvbi5vcmcAdXNlckBleGFtcGxlLm9yZ4YpaHR0cDovL251
bGwucHl0aG9uLm9yZwBodHRwOi8vZXhhbXBsZS5vcmeHBMAAAgGHECABDbgAAAAA
AAAAAAAAAAEwDQYJKoZIhvcNAQEFBQADggEBAKxPRe99SaghcI6IWT7UNkJw9aO9
i9eo0Fj2MUqxpKbdb9noRDy2CnHWf7EIYZ1gznXPdwzSN4YCjV5d+Q9xtBaowT0j
HPERs1ZuytCNNJTmhyqZ8q6uzMLoht4IqH/FBfpvgaeC5tBTnTT0rD5A/olXeimk
kX4LxlEx5RAvpGB2zZVRGr6LobD9rVK91xuHYNIxxxfEGE8tCCWjp0+3ksri9SXx
VHWBnbM9YaL32u3hxm8sYB/Yb8WSBavJCWJJqRStVRHM1koZlJmXNx2BX4vPo6iW
RFEIPQsFZRLrtnCAiEhyT8bC2s/Njlu6ly9gtJZWSV46Q3ZjBL4q9sHKqZQ=
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 12723342612721443280 (0xb09264b1f2da21d0)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Validity
Not Before: Jan 4 19:47:07 2013 GMT
Not After : Jan 2 19:47:07 2023 GMT
Subject: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:e7:de:e9:e3:0c:9f:00:b6:a1:fd:2b:5b:96:d2:
6f:cc:e0:be:86:b9:20:5e:ec:03:7a:55:ab:ea:a4:
e9:f9:49:85:d2:66:d5:ed:c7:7a:ea:56:8e:2d:8f:
e7:42:e2:62:28:a9:9f:d6:1b:8e:eb:b5:b4:9c:9f:
14:ab:df:e6:94:8b:76:1d:3e:6d:24:61:ed:0c:bf:
00:8a:61:0c:df:5c:c8:36:73:16:00:cd:47:ba:6d:
a4:a4:74:88:83:23:0a:19:fc:09:a7:3c:4a:4b:d3:
e7:1d:2d:e4:ea:4c:54:21:f3:26:db:89:37:18:d4:
02:bb:40:32:5f:a4:ff:2d:1c:f7:d4:bb:ec:8e:cf:
5c:82:ac:e6:7c:08:6c:48:85:61:07:7f:25:e0:5c:
e0:bc:34:5f:e0:b9:04:47:75:c8:47:0b:8d:bc:d6:
c8:68:5f:33:83:62:d2:20:44:35:b1:ad:81:1a:8a:
cd:bc:35:b0:5c:8b:47:d6:18:e9:9c:18:97:cc:01:
3c:29:cc:e8:1e:e4:e4:c1:b8:de:e7:c2:11:18:87:
5a:93:34:d8:a6:25:f7:14:71:eb:e4:21:a2:d2:0f:
2e:2e:d4:62:00:35:d3:d6:ef:5c:60:4b:4c:a9:14:
e2:dd:15:58:46:37:33:26:b7:e7:2e:5d:ed:42:e4:
c5:4d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B
X509v3 Authority Key Identifier:
keyid:BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
7d:0a:f5:cb:8d:d3:5d:bd:99:8e:f8:2b:0f:ba:eb:c2:d9:a6:
27:4f:2e:7b:2f:0e:64:d8:1c:35:50:4e:ee:fc:90:b9:8d:6d:
a8:c5:c6:06:b0:af:f3:2d:bf:3b:b8:42:07:dd:18:7d:6d:95:
54:57:85:18:60:47:2f:eb:78:1b:f9:e8:17:fd:5a:0d:87:17:
28:ac:4c:6a:e6:bc:29:f4:f4:55:70:29:42:de:85:ea:ab:6c:
23:06:64:30:75:02:8e:53:bc:5e:01:33:37:cc:1e:cd:b8:a4:
fd:ca:e4:5f:65:3b:83:1c:86:f1:55:02:a0:3a:8f:db:91:b7:
40:14:b4:e7:8d:d2:ee:73:ba:e3:e5:34:2d:bc:94:6f:4e:24:
06:f7:5f:8b:0e:a7:8e:6b:de:5e:75:f4:32:9a:50:b1:44:33:
9a:d0:05:e2:78:82:ff:db:da:8a:63:eb:a9:dd:d1:bf:a0:61:
ad:e3:9e:8a:24:5d:62:0e:e7:4c:91:7f:ef:df:34:36:3b:2f:
5d:f5:84:b2:2f:c4:6d:93:96:1a:6f:30:28:f1:da:12:9a:64:
b4:40:33:1d:bd:de:2b:53:a8:ea:be:d6:bc:4e:96:f5:44:fb:
32:18:ae:d5:1f:f6:69:af:b6:4e:7b:1d:58:ec:3b:a9:53:a3:
5e:58:c8:9e
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIJALCSZLHy2iHQMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xMzAxMDQxOTQ3MDdaFw0yMzAxMDIx
OTQ3MDdaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAOfe6eMMnwC2of0rW5bSb8zgvoa5IF7sA3pV
q+qk6flJhdJm1e3HeupWji2P50LiYiipn9Ybjuu1tJyfFKvf5pSLdh0+bSRh7Qy/
AIphDN9cyDZzFgDNR7ptpKR0iIMjChn8Cac8SkvT5x0t5OpMVCHzJtuJNxjUArtA
Ml+k/y0c99S77I7PXIKs5nwIbEiFYQd/JeBc4Lw0X+C5BEd1yEcLjbzWyGhfM4Ni
0iBENbGtgRqKzbw1sFyLR9YY6ZwYl8wBPCnM6B7k5MG43ufCERiHWpM02KYl9xRx
6+QhotIPLi7UYgA109bvXGBLTKkU4t0VWEY3Mya35y5d7ULkxU0CAwEAAaNQME4w
HQYDVR0OBBYEFLzdYtl22hvSVGvP4GabHh57VgwLMB8GA1UdIwQYMBaAFLzdYtl2
2hvSVGvP4GabHh57VgwLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
AH0K9cuN0129mY74Kw+668LZpidPLnsvDmTYHDVQTu78kLmNbajFxgawr/Mtvzu4
QgfdGH1tlVRXhRhgRy/reBv56Bf9Wg2HFyisTGrmvCn09FVwKULeheqrbCMGZDB1
Ao5TvF4BMzfMHs24pP3K5F9lO4MchvFVAqA6j9uRt0AUtOeN0u5zuuPlNC28lG9O
JAb3X4sOp45r3l519DKaULFEM5rQBeJ4gv/b2opj66nd0b+gYa3jnookXWIO50yR
f+/fNDY7L131hLIvxG2TlhpvMCjx2hKaZLRAMx293itTqOq+1rxOlvVE+zIYrtUf
9mmvtk57HVjsO6lTo15YyJ4=
-----END CERTIFICATE-----
-----BEGIN X509 CRL-----
MIIBpjCBjwIBATANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE
CgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91ci1j
YS1zZXJ2ZXIXDTEzMTEyMTE3MDg0N1oXDTIzMDkzMDE3MDg0N1qgDjAMMAoGA1Ud
FAQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQCNJXC2mVKauEeN3LlQ3ZtM5gkH3ExH
+i4bmJjtJn497WwvvoIeUdrmVXgJQR93RtV37hZwN0SXMLlNmUZPH4rHhihayw4m
unCzVj/OhCCY7/TPjKuJ1O/0XhaLBpBVjQN7R/1ujoRKbSia/CD3vcn7Fqxzw7LK
fSRCKRGTj1CZiuxrphtFchwALXSiFDy9mr2ZKhImcyq1PydfgEzU78APpOkMQsIC
UNJ/cf3c9emzf+dUtcMEcejQ3mynBo4eIGg1EW42bz4q4hSjzQlKcBV0muw5qXhc
HOxH2iTFhQ7SrvVuK/dM14rYM4B5mSX3nRC1kNmXpS9j3wJDhuwmjHed
-----END X509 CRL-----
-----BEGIN CERTIFICATE-----
MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv
bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG
A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo
b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0
aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ
Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm
Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv
EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl
bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h
TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515
C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,1A8D9D2A02EC698A
kJYbfZ8L0sfe9Oty3gw0aloNnY5E8fegRfQLZlNoxTl6jNt0nIwI8kDJ36CZgR9c
u3FDJm/KqrfUoz8vW+qEnWhSG7QPX2wWGPHd4K94Yz/FgrRzZ0DoK7XxXq9gOtVA
AVGQhnz32p+6WhfGsCr9ArXEwRZrTk/FvzEPaU5fHcoSkrNVAGX8IpSVkSDwEDQr
Gv17+cfk99UV1OCza6yKHoFkTtrC+PZU71LomBabivS2Oc4B9hYuSR2hF01wTHP+
YlWNagZOOVtNz4oKK9x9eNQpmfQXQvPPTfusexKIbKfZrMvJoxcm1gfcZ0H/wK6P
6wmXSG35qMOOztCZNtperjs1wzEBXznyK8QmLcAJBjkfarABJX9vBEzZV0OUKhy+
noORFwHTllphbmydLhu6ehLUZMHPhzAS5UN7srtpSN81eerDMy0RMUAwA7/PofX1
94Me85Q8jP0PC9ETdsJcPqLzAPETEYu0ELewKRcrdyWi+tlLFrpE5KT/s5ecbl9l
7B61U4Kfd1PIXc/siINhU3A3bYK+845YyUArUOnKf1kEox7p1RpD7yFqVT04lRTo
cibNKATBusXSuBrp2G6GNuhWEOSafWCKJQAzgCYIp6ZTV2khhMUGppc/2H3CF6cO
zX0KtlPVZC7hLkB6HT8SxYUwF1zqWY7+/XPPdc37MeEZ87Q3UuZwqORLY+Z0hpgt
L5JXBCoklZhCAaN2GqwFLXtGiRSRFGY7xXIhbDTlE65Wv1WGGgDLMKGE1gOz3yAo
2jjG1+yAHJUdE69XTFHSqSkvaloA1W03LdMXZ9VuQJ/ySXCie6ABAQ==
-----END RSA PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
SPIXQuT8RMPDVNQ=
-----END PRIVATE KEY-----
...@@ -7,9 +7,10 @@ import sys ...@@ -7,9 +7,10 @@ import sys
import time import time
import warnings import warnings
import errno import errno
import struct
from test import test_support from test import test_support
from test.test_support import TESTFN, run_unittest, unlink from test.test_support import TESTFN, run_unittest, unlink, HOST
from StringIO import StringIO from StringIO import StringIO
try: try:
...@@ -17,7 +18,6 @@ try: ...@@ -17,7 +18,6 @@ try:
except ImportError: except ImportError:
threading = None threading = None
HOST = test_support.HOST
class dummysocket: class dummysocket:
def __init__(self): def __init__(self):
...@@ -483,8 +483,9 @@ class TCPServer(asyncore.dispatcher): ...@@ -483,8 +483,9 @@ class TCPServer(asyncore.dispatcher):
return self.socket.getsockname()[:2] return self.socket.getsockname()[:2]
def handle_accept(self): def handle_accept(self):
sock, addr = self.accept() pair = self.accept()
self.handler(sock) if pair is not None:
self.handler(pair[0])
def handle_error(self): def handle_error(self):
raise raise
...@@ -703,6 +704,27 @@ class BaseTestAPI(unittest.TestCase): ...@@ -703,6 +704,27 @@ class BaseTestAPI(unittest.TestCase):
finally: finally:
sock.close() sock.close()
@unittest.skipUnless(threading, 'Threading required for this test.')
@test_support.reap_threads
def test_quick_connect(self):
# see: http://bugs.python.org/issue10340
server = TCPServer()
t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1, count=500))
t.start()
self.addCleanup(t.join)
for x in xrange(20):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(.2)
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
struct.pack('ii', 1, 0))
try:
s.connect(server.address)
except socket.error:
pass
finally:
s.close()
class TestAPI_UseSelect(BaseTestAPI): class TestAPI_UseSelect(BaseTestAPI):
use_poll = False use_poll = False
......
...@@ -15,12 +15,12 @@ try: ...@@ -15,12 +15,12 @@ try:
except ImportError: except ImportError:
ssl = None ssl = None
from unittest import TestCase from unittest import TestCase, SkipTest, skipUnless
from test import test_support from test import test_support
from test.test_support import HOST from test.test_support import HOST, HOSTv6
threading = test_support.import_module('threading') threading = test_support.import_module('threading')
TIMEOUT = 3
# the dummy data returned by server over the data channel when # the dummy data returned by server over the data channel when
# RETR, LIST and NLST commands are issued # RETR, LIST and NLST commands are issued
RETR_DATA = 'abcde12345\r\n' * 1000 RETR_DATA = 'abcde12345\r\n' * 1000
...@@ -65,6 +65,7 @@ class DummyFTPHandler(asynchat.async_chat): ...@@ -65,6 +65,7 @@ class DummyFTPHandler(asynchat.async_chat):
self.last_received_data = '' self.last_received_data = ''
self.next_response = '' self.next_response = ''
self.rest = None self.rest = None
self.next_retr_data = RETR_DATA
self.push('220 welcome') self.push('220 welcome')
def collect_incoming_data(self, data): def collect_incoming_data(self, data):
...@@ -189,7 +190,7 @@ class DummyFTPHandler(asynchat.async_chat): ...@@ -189,7 +190,7 @@ class DummyFTPHandler(asynchat.async_chat):
offset = int(self.rest) offset = int(self.rest)
else: else:
offset = 0 offset = 0
self.dtp.push(RETR_DATA[offset:]) self.dtp.push(self.next_retr_data[offset:])
self.dtp.close_when_done() self.dtp.close_when_done()
self.rest = None self.rest = None
...@@ -203,6 +204,11 @@ class DummyFTPHandler(asynchat.async_chat): ...@@ -203,6 +204,11 @@ class DummyFTPHandler(asynchat.async_chat):
self.dtp.push(NLST_DATA) self.dtp.push(NLST_DATA)
self.dtp.close_when_done() self.dtp.close_when_done()
def cmd_setlongretr(self, arg):
# For testing. Next RETR will return long line.
self.next_retr_data = 'x' * int(arg)
self.push('125 setlongretr ok')
class DummyFTPServer(asyncore.dispatcher, threading.Thread): class DummyFTPServer(asyncore.dispatcher, threading.Thread):
...@@ -217,6 +223,7 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread): ...@@ -217,6 +223,7 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread):
self.active = False self.active = False
self.active_lock = threading.Lock() self.active_lock = threading.Lock()
self.host, self.port = self.socket.getsockname()[:2] self.host, self.port = self.socket.getsockname()[:2]
self.handler_instance = None
def start(self): def start(self):
assert not self.active assert not self.active
...@@ -240,8 +247,7 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread): ...@@ -240,8 +247,7 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread):
def handle_accept(self): def handle_accept(self):
conn, addr = self.accept() conn, addr = self.accept()
self.handler = self.handler(conn) self.handler_instance = self.handler(conn)
self.close()
def handle_connect(self): def handle_connect(self):
self.close() self.close()
...@@ -256,7 +262,8 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread): ...@@ -256,7 +262,8 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread):
if ssl is not None: if ssl is not None:
CERTFILE = os.path.join(os.path.dirname(__file__), "keycert.pem") CERTFILE = os.path.join(os.path.dirname(__file__), "keycert3.pem")
CAFILE = os.path.join(os.path.dirname(__file__), "pycacert.pem")
class SSLConnection(object, asyncore.dispatcher): class SSLConnection(object, asyncore.dispatcher):
"""An asyncore.dispatcher subclass supporting TLS/SSL.""" """An asyncore.dispatcher subclass supporting TLS/SSL."""
...@@ -265,23 +272,25 @@ if ssl is not None: ...@@ -265,23 +272,25 @@ if ssl is not None:
_ssl_closing = False _ssl_closing = False
def secure_connection(self): def secure_connection(self):
self.socket = ssl.wrap_socket(self.socket, suppress_ragged_eofs=False, socket = ssl.wrap_socket(self.socket, suppress_ragged_eofs=False,
certfile=CERTFILE, server_side=True, certfile=CERTFILE, server_side=True,
do_handshake_on_connect=False, do_handshake_on_connect=False,
ssl_version=ssl.PROTOCOL_SSLv23) ssl_version=ssl.PROTOCOL_SSLv23)
self.del_channel()
self.set_socket(socket)
self._ssl_accepting = True self._ssl_accepting = True
def _do_ssl_handshake(self): def _do_ssl_handshake(self):
try: try:
self.socket.do_handshake() self.socket.do_handshake()
except ssl.SSLError, err: except ssl.SSLError as err:
if err.args[0] in (ssl.SSL_ERROR_WANT_READ, if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
ssl.SSL_ERROR_WANT_WRITE): ssl.SSL_ERROR_WANT_WRITE):
return return
elif err.args[0] == ssl.SSL_ERROR_EOF: elif err.args[0] == ssl.SSL_ERROR_EOF:
return self.handle_close() return self.handle_close()
raise raise
except socket.error, err: except socket.error as err:
if err.args[0] == errno.ECONNABORTED: if err.args[0] == errno.ECONNABORTED:
return self.handle_close() return self.handle_close()
else: else:
...@@ -291,18 +300,21 @@ if ssl is not None: ...@@ -291,18 +300,21 @@ if ssl is not None:
self._ssl_closing = True self._ssl_closing = True
try: try:
self.socket = self.socket.unwrap() self.socket = self.socket.unwrap()
except ssl.SSLError, err: except ssl.SSLError as err:
if err.args[0] in (ssl.SSL_ERROR_WANT_READ, if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
ssl.SSL_ERROR_WANT_WRITE): ssl.SSL_ERROR_WANT_WRITE):
return return
except socket.error, err: except socket.error as err:
# Any "socket error" corresponds to a SSL_ERROR_SYSCALL return # Any "socket error" corresponds to a SSL_ERROR_SYSCALL return
# from OpenSSL's SSL_shutdown(), corresponding to a # from OpenSSL's SSL_shutdown(), corresponding to a
# closed socket condition. See also: # closed socket condition. See also:
# http://www.mail-archive.com/openssl-users@openssl.org/msg60710.html # http://www.mail-archive.com/openssl-users@openssl.org/msg60710.html
pass pass
self._ssl_closing = False self._ssl_closing = False
super(SSLConnection, self).close() if getattr(self, '_ccc', False) is False:
super(SSLConnection, self).close()
else:
pass
def handle_read_event(self): def handle_read_event(self):
if self._ssl_accepting: if self._ssl_accepting:
...@@ -323,7 +335,7 @@ if ssl is not None: ...@@ -323,7 +335,7 @@ if ssl is not None:
def send(self, data): def send(self, data):
try: try:
return super(SSLConnection, self).send(data) return super(SSLConnection, self).send(data)
except ssl.SSLError, err: except ssl.SSLError as err:
if err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN, if err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN,
ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_READ,
ssl.SSL_ERROR_WANT_WRITE): ssl.SSL_ERROR_WANT_WRITE):
...@@ -333,13 +345,13 @@ if ssl is not None: ...@@ -333,13 +345,13 @@ if ssl is not None:
def recv(self, buffer_size): def recv(self, buffer_size):
try: try:
return super(SSLConnection, self).recv(buffer_size) return super(SSLConnection, self).recv(buffer_size)
except ssl.SSLError, err: except ssl.SSLError as err:
if err.args[0] in (ssl.SSL_ERROR_WANT_READ, if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
ssl.SSL_ERROR_WANT_WRITE): ssl.SSL_ERROR_WANT_WRITE):
return '' return b''
if err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN): if err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN):
self.handle_close() self.handle_close()
return '' return b''
raise raise
def handle_error(self): def handle_error(self):
...@@ -349,6 +361,8 @@ if ssl is not None: ...@@ -349,6 +361,8 @@ if ssl is not None:
if (isinstance(self.socket, ssl.SSLSocket) and if (isinstance(self.socket, ssl.SSLSocket) and
self.socket._sslobj is not None): self.socket._sslobj is not None):
self._do_ssl_shutdown() self._do_ssl_shutdown()
else:
super(SSLConnection, self).close()
class DummyTLS_DTPHandler(SSLConnection, DummyDTPHandler): class DummyTLS_DTPHandler(SSLConnection, DummyDTPHandler):
...@@ -456,12 +470,12 @@ class TestFTPClass(TestCase): ...@@ -456,12 +470,12 @@ class TestFTPClass(TestCase):
def test_rename(self): def test_rename(self):
self.client.rename('a', 'b') self.client.rename('a', 'b')
self.server.handler.next_response = '200' self.server.handler_instance.next_response = '200'
self.assertRaises(ftplib.error_reply, self.client.rename, 'a', 'b') self.assertRaises(ftplib.error_reply, self.client.rename, 'a', 'b')
def test_delete(self): def test_delete(self):
self.client.delete('foo') self.client.delete('foo')
self.server.handler.next_response = '199' self.server.handler_instance.next_response = '199'
self.assertRaises(ftplib.error_reply, self.client.delete, 'foo') self.assertRaises(ftplib.error_reply, self.client.delete, 'foo')
def test_size(self): def test_size(self):
...@@ -474,6 +488,10 @@ class TestFTPClass(TestCase): ...@@ -474,6 +488,10 @@ class TestFTPClass(TestCase):
def test_rmd(self): def test_rmd(self):
self.client.rmd('foo') self.client.rmd('foo')
def test_cwd(self):
dir = self.client.cwd('/foo')
self.assertEqual(dir, '250 cwd ok')
def test_pwd(self): def test_pwd(self):
dir = self.client.pwd() dir = self.client.pwd()
self.assertEqual(dir, 'pwd ok') self.assertEqual(dir, 'pwd ok')
...@@ -505,7 +523,7 @@ class TestFTPClass(TestCase): ...@@ -505,7 +523,7 @@ class TestFTPClass(TestCase):
def test_storbinary(self): def test_storbinary(self):
f = StringIO.StringIO(RETR_DATA) f = StringIO.StringIO(RETR_DATA)
self.client.storbinary('stor', f) self.client.storbinary('stor', f)
self.assertEqual(self.server.handler.last_received_data, RETR_DATA) self.assertEqual(self.server.handler_instance.last_received_data, RETR_DATA)
# test new callback arg # test new callback arg
flag = [] flag = []
f.seek(0) f.seek(0)
...@@ -517,12 +535,12 @@ class TestFTPClass(TestCase): ...@@ -517,12 +535,12 @@ class TestFTPClass(TestCase):
for r in (30, '30'): for r in (30, '30'):
f.seek(0) f.seek(0)
self.client.storbinary('stor', f, rest=r) self.client.storbinary('stor', f, rest=r)
self.assertEqual(self.server.handler.rest, str(r)) self.assertEqual(self.server.handler_instance.rest, str(r))
def test_storlines(self): def test_storlines(self):
f = StringIO.StringIO(RETR_DATA.replace('\r\n', '\n')) f = StringIO.StringIO(RETR_DATA.replace('\r\n', '\n'))
self.client.storlines('stor', f) self.client.storlines('stor', f)
self.assertEqual(self.server.handler.last_received_data, RETR_DATA) self.assertEqual(self.server.handler_instance.last_received_data, RETR_DATA)
# test new callback arg # test new callback arg
flag = [] flag = []
f.seek(0) f.seek(0)
...@@ -541,20 +559,42 @@ class TestFTPClass(TestCase): ...@@ -541,20 +559,42 @@ class TestFTPClass(TestCase):
def test_makeport(self): def test_makeport(self):
self.client.makeport() self.client.makeport()
# IPv4 is in use, just make sure send_eprt has not been used # IPv4 is in use, just make sure send_eprt has not been used
self.assertEqual(self.server.handler.last_received_cmd, 'port') self.assertEqual(self.server.handler_instance.last_received_cmd, 'port')
def test_makepasv(self): def test_makepasv(self):
host, port = self.client.makepasv() host, port = self.client.makepasv()
conn = socket.create_connection((host, port), 10) conn = socket.create_connection((host, port), 10)
conn.close() conn.close()
# IPv4 is in use, just make sure send_epsv has not been used # IPv4 is in use, just make sure send_epsv has not been used
self.assertEqual(self.server.handler.last_received_cmd, 'pasv') self.assertEqual(self.server.handler_instance.last_received_cmd, 'pasv')
def test_line_too_long(self):
self.assertRaises(ftplib.Error, self.client.sendcmd,
'x' * self.client.maxline * 2)
def test_retrlines_too_long(self):
self.client.sendcmd('SETLONGRETR %d' % (self.client.maxline * 2))
received = []
self.assertRaises(ftplib.Error,
self.client.retrlines, 'retr', received.append)
def test_storlines_too_long(self):
f = StringIO.StringIO('x' * self.client.maxline * 2)
self.assertRaises(ftplib.Error, self.client.storlines, 'stor', f)
@skipUnless(socket.has_ipv6, "IPv6 not enabled")
class TestIPv6Environment(TestCase): class TestIPv6Environment(TestCase):
@classmethod
def setUpClass(cls):
try:
DummyFTPServer((HOST, 0), af=socket.AF_INET6)
except socket.error:
raise SkipTest("IPv6 not enabled")
def setUp(self): def setUp(self):
self.server = DummyFTPServer((HOST, 0), af=socket.AF_INET6) self.server = DummyFTPServer((HOSTv6, 0), af=socket.AF_INET6)
self.server.start() self.server.start()
self.client = ftplib.FTP() self.client = ftplib.FTP()
self.client.connect(self.server.host, self.server.port) self.client.connect(self.server.host, self.server.port)
...@@ -568,13 +608,13 @@ class TestIPv6Environment(TestCase): ...@@ -568,13 +608,13 @@ class TestIPv6Environment(TestCase):
def test_makeport(self): def test_makeport(self):
self.client.makeport() self.client.makeport()
self.assertEqual(self.server.handler.last_received_cmd, 'eprt') self.assertEqual(self.server.handler_instance.last_received_cmd, 'eprt')
def test_makepasv(self): def test_makepasv(self):
host, port = self.client.makepasv() host, port = self.client.makepasv()
conn = socket.create_connection((host, port), 10) conn = socket.create_connection((host, port), 10)
conn.close() conn.close()
self.assertEqual(self.server.handler.last_received_cmd, 'epsv') self.assertEqual(self.server.handler_instance.last_received_cmd, 'epsv')
def test_transfer(self): def test_transfer(self):
def retr(): def retr():
...@@ -587,6 +627,7 @@ class TestIPv6Environment(TestCase): ...@@ -587,6 +627,7 @@ class TestIPv6Environment(TestCase):
retr() retr()
@skipUnless(ssl, "SSL not available")
class TestTLS_FTPClassMixin(TestFTPClass): class TestTLS_FTPClassMixin(TestFTPClass):
"""Repeat TestFTPClass tests starting the TLS layer for both control """Repeat TestFTPClass tests starting the TLS layer for both control
and data connections first. and data connections first.
...@@ -602,13 +643,14 @@ class TestTLS_FTPClassMixin(TestFTPClass): ...@@ -602,13 +643,14 @@ class TestTLS_FTPClassMixin(TestFTPClass):
self.client.prot_p() self.client.prot_p()
@skipUnless(ssl, "SSL not available")
class TestTLS_FTPClass(TestCase): class TestTLS_FTPClass(TestCase):
"""Specific TLS_FTP class tests.""" """Specific TLS_FTP class tests."""
def setUp(self): def setUp(self):
self.server = DummyTLS_FTPServer((HOST, 0)) self.server = DummyTLS_FTPServer((HOST, 0))
self.server.start() self.server.start()
self.client = ftplib.FTP_TLS(timeout=10) self.client = ftplib.FTP_TLS(timeout=TIMEOUT)
self.client.connect(self.server.host, self.server.port) self.client.connect(self.server.host, self.server.port)
def tearDown(self): def tearDown(self):
...@@ -655,12 +697,65 @@ class TestTLS_FTPClass(TestCase): ...@@ -655,12 +697,65 @@ class TestTLS_FTPClass(TestCase):
def test_auth_ssl(self): def test_auth_ssl(self):
try: try:
self.client.ssl_version = ssl.PROTOCOL_SSLv3 self.client.ssl_version = ssl.PROTOCOL_SSLv23
self.client.auth() self.client.auth()
self.assertRaises(ValueError, self.client.auth) self.assertRaises(ValueError, self.client.auth)
finally: finally:
self.client.ssl_version = ssl.PROTOCOL_TLSv1 self.client.ssl_version = ssl.PROTOCOL_TLSv1
def test_context(self):
self.client.quit()
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
self.assertRaises(ValueError, ftplib.FTP_TLS, keyfile=CERTFILE,
context=ctx)
self.assertRaises(ValueError, ftplib.FTP_TLS, certfile=CERTFILE,
context=ctx)
self.assertRaises(ValueError, ftplib.FTP_TLS, certfile=CERTFILE,
keyfile=CERTFILE, context=ctx)
self.client = ftplib.FTP_TLS(context=ctx, timeout=TIMEOUT)
self.client.connect(self.server.host, self.server.port)
self.assertNotIsInstance(self.client.sock, ssl.SSLSocket)
self.client.auth()
self.assertIs(self.client.sock.context, ctx)
self.assertIsInstance(self.client.sock, ssl.SSLSocket)
self.client.prot_p()
sock = self.client.transfercmd('list')
try:
self.assertIs(sock.context, ctx)
self.assertIsInstance(sock, ssl.SSLSocket)
finally:
sock.close()
def test_check_hostname(self):
self.client.quit()
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.check_hostname = True
ctx.load_verify_locations(CAFILE)
self.client = ftplib.FTP_TLS(context=ctx, timeout=TIMEOUT)
# 127.0.0.1 doesn't match SAN
self.client.connect(self.server.host, self.server.port)
with self.assertRaises(ssl.CertificateError):
self.client.auth()
# exception quits connection
self.client.connect(self.server.host, self.server.port)
self.client.prot_p()
with self.assertRaises(ssl.CertificateError):
self.client.transfercmd("list").close()
self.client.quit()
self.client.connect("localhost", self.server.port)
self.client.auth()
self.client.quit()
self.client.connect("localhost", self.server.port)
self.client.prot_p()
self.client.transfercmd("list").close()
class TestTimeouts(TestCase): class TestTimeouts(TestCase):
...@@ -702,10 +797,10 @@ class TestTimeouts(TestCase): ...@@ -702,10 +797,10 @@ class TestTimeouts(TestCase):
def testTimeoutDefault(self): def testTimeoutDefault(self):
# default -- use global socket timeout # default -- use global socket timeout
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
ftp = ftplib.FTP("localhost") ftp = ftplib.FTP(HOST)
finally: finally:
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertEqual(ftp.sock.gettimeout(), 30) self.assertEqual(ftp.sock.gettimeout(), 30)
...@@ -714,13 +809,13 @@ class TestTimeouts(TestCase): ...@@ -714,13 +809,13 @@ class TestTimeouts(TestCase):
def testTimeoutNone(self): def testTimeoutNone(self):
# no timeout -- do not use global socket timeout # no timeout -- do not use global socket timeout
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
ftp = ftplib.FTP("localhost", timeout=None) ftp = ftplib.FTP(HOST, timeout=None)
finally: finally:
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertTrue(ftp.sock.gettimeout() is None) self.assertIsNone(ftp.sock.gettimeout())
self.evt.wait() self.evt.wait()
ftp.close() ftp.close()
...@@ -755,17 +850,9 @@ class TestTimeouts(TestCase): ...@@ -755,17 +850,9 @@ class TestTimeouts(TestCase):
def test_main(): def test_main():
tests = [TestFTPClass, TestTimeouts] tests = [TestFTPClass, TestTimeouts,
if socket.has_ipv6: TestIPv6Environment,
try: TestTLS_FTPClassMixin, TestTLS_FTPClass]
DummyFTPServer((HOST, 0), af=socket.AF_INET6)
except socket.error:
pass
else:
tests.append(TestIPv6Environment)
if ssl is not None:
tests.extend([TestTLS_FTPClassMixin, TestTLS_FTPClass])
thread_info = test_support.threading_setup() thread_info = test_support.threading_setup()
try: try:
......
import httplib import httplib
import itertools
import array import array
import httplib
import StringIO import StringIO
import socket import socket
import errno import errno
import os
import tempfile
import unittest import unittest
TestCase = unittest.TestCase TestCase = unittest.TestCase
from test import test_support from test import test_support
here = os.path.dirname(__file__)
# Self-signed cert file for 'localhost'
CERT_localhost = os.path.join(here, 'keycert.pem')
# Self-signed cert file for 'fakehostname'
CERT_fakehostname = os.path.join(here, 'keycert2.pem')
# Self-signed cert file for self-signed.pythontest.net
CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem')
HOST = test_support.HOST HOST = test_support.HOST
class FakeSocket: class FakeSocket:
def __init__(self, text, fileclass=StringIO.StringIO): def __init__(self, text, fileclass=StringIO.StringIO, host=None, port=None):
self.text = text self.text = text
self.fileclass = fileclass self.fileclass = fileclass
self.data = '' self.data = ''
self.file_closed = False
self.host = host
self.port = port
def sendall(self, data): def sendall(self, data):
self.data += ''.join(data) self.data += ''.join(data)
...@@ -24,7 +37,16 @@ class FakeSocket: ...@@ -24,7 +37,16 @@ class FakeSocket:
def makefile(self, mode, bufsize=None): def makefile(self, mode, bufsize=None):
if mode != 'r' and mode != 'rb': if mode != 'r' and mode != 'rb':
raise httplib.UnimplementedFileMode() raise httplib.UnimplementedFileMode()
return self.fileclass(self.text) # keep the file around so we can check how much was read from it
self.file = self.fileclass(self.text)
self.file.close = self.file_close #nerf close ()
return self.file
def file_close(self):
self.file_closed = True
def close(self):
pass
class EPipeSocket(FakeSocket): class EPipeSocket(FakeSocket):
...@@ -90,12 +112,105 @@ class HeaderTests(TestCase): ...@@ -90,12 +112,105 @@ class HeaderTests(TestCase):
conn.request('POST', '/', body, headers) conn.request('POST', '/', body, headers)
self.assertEqual(conn._buffer.count[header.lower()], 1) self.assertEqual(conn._buffer.count[header.lower()], 1)
def test_content_length_0(self):
class ContentLengthChecker(list):
def __init__(self):
list.__init__(self)
self.content_length = None
def append(self, item):
kv = item.split(':', 1)
if len(kv) > 1 and kv[0].lower() == 'content-length':
self.content_length = kv[1].strip()
list.append(self, item)
# Here, we're testing that methods expecting a body get a
# content-length set to zero if the body is empty (either None or '')
bodies = (None, '')
methods_with_body = ('PUT', 'POST', 'PATCH')
for method, body in itertools.product(methods_with_body, bodies):
conn = httplib.HTTPConnection('example.com')
conn.sock = FakeSocket(None)
conn._buffer = ContentLengthChecker()
conn.request(method, '/', body)
self.assertEqual(
conn._buffer.content_length, '0',
'Header Content-Length incorrect on {}'.format(method)
)
# For these methods, we make sure that content-length is not set when
# the body is None because it might cause unexpected behaviour on the
# server.
methods_without_body = (
'GET', 'CONNECT', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE',
)
for method in methods_without_body:
conn = httplib.HTTPConnection('example.com')
conn.sock = FakeSocket(None)
conn._buffer = ContentLengthChecker()
conn.request(method, '/', None)
self.assertEqual(
conn._buffer.content_length, None,
'Header Content-Length set for empty body on {}'.format(method)
)
# If the body is set to '', that's considered to be "present but
# empty" rather than "missing", so content length would be set, even
# for methods that don't expect a body.
for method in methods_without_body:
conn = httplib.HTTPConnection('example.com')
conn.sock = FakeSocket(None)
conn._buffer = ContentLengthChecker()
conn.request(method, '/', '')
self.assertEqual(
conn._buffer.content_length, '0',
'Header Content-Length incorrect on {}'.format(method)
)
# If the body is set, make sure Content-Length is set.
for method in itertools.chain(methods_without_body, methods_with_body):
conn = httplib.HTTPConnection('example.com')
conn.sock = FakeSocket(None)
conn._buffer = ContentLengthChecker()
conn.request(method, '/', ' ')
self.assertEqual(
conn._buffer.content_length, '1',
'Header Content-Length incorrect on {}'.format(method)
)
def test_putheader(self): def test_putheader(self):
conn = httplib.HTTPConnection('example.com') conn = httplib.HTTPConnection('example.com')
conn.sock = FakeSocket(None) conn.sock = FakeSocket(None)
conn.putrequest('GET','/') conn.putrequest('GET','/')
conn.putheader('Content-length',42) conn.putheader('Content-length',42)
self.assertTrue('Content-length: 42' in conn._buffer) self.assertIn('Content-length: 42', conn._buffer)
conn.putheader('Foo', ' bar ')
self.assertIn(b'Foo: bar ', conn._buffer)
conn.putheader('Bar', '\tbaz\t')
self.assertIn(b'Bar: \tbaz\t', conn._buffer)
conn.putheader('Authorization', 'Bearer mytoken')
self.assertIn(b'Authorization: Bearer mytoken', conn._buffer)
conn.putheader('IterHeader', 'IterA', 'IterB')
self.assertIn(b'IterHeader: IterA\r\n\tIterB', conn._buffer)
conn.putheader('LatinHeader', b'\xFF')
self.assertIn(b'LatinHeader: \xFF', conn._buffer)
conn.putheader('Utf8Header', b'\xc3\x80')
self.assertIn(b'Utf8Header: \xc3\x80', conn._buffer)
conn.putheader('C1-Control', b'next\x85line')
self.assertIn(b'C1-Control: next\x85line', conn._buffer)
conn.putheader('Embedded-Fold-Space', 'is\r\n allowed')
self.assertIn(b'Embedded-Fold-Space: is\r\n allowed', conn._buffer)
conn.putheader('Embedded-Fold-Tab', 'is\r\n\tallowed')
self.assertIn(b'Embedded-Fold-Tab: is\r\n\tallowed', conn._buffer)
conn.putheader('Key Space', 'value')
self.assertIn(b'Key Space: value', conn._buffer)
conn.putheader('KeySpace ', 'value')
self.assertIn(b'KeySpace : value', conn._buffer)
conn.putheader(b'Nonbreak\xa0Space', 'value')
self.assertIn(b'Nonbreak\xa0Space: value', conn._buffer)
conn.putheader(b'\xa0NonbreakSpace', 'value')
self.assertIn(b'\xa0NonbreakSpace: value', conn._buffer)
def test_ipv6host_header(self): def test_ipv6host_header(self):
# Default host header on IPv6 transaction should wrapped by [] if # Default host header on IPv6 transaction should wrapped by [] if
...@@ -116,6 +231,45 @@ class HeaderTests(TestCase): ...@@ -116,6 +231,45 @@ class HeaderTests(TestCase):
conn.request('GET', '/foo') conn.request('GET', '/foo')
self.assertTrue(sock.data.startswith(expected)) self.assertTrue(sock.data.startswith(expected))
def test_malformed_headers_coped_with(self):
# Issue 19996
body = "HTTP/1.1 200 OK\r\nFirst: val\r\n: nval\r\nSecond: val\r\n\r\n"
sock = FakeSocket(body)
resp = httplib.HTTPResponse(sock)
resp.begin()
self.assertEqual(resp.getheader('First'), 'val')
self.assertEqual(resp.getheader('Second'), 'val')
def test_invalid_headers(self):
conn = httplib.HTTPConnection('example.com')
conn.sock = FakeSocket('')
conn.putrequest('GET', '/')
# http://tools.ietf.org/html/rfc7230#section-3.2.4, whitespace is no
# longer allowed in header names
cases = (
(b'Invalid\r\nName', b'ValidValue'),
(b'Invalid\rName', b'ValidValue'),
(b'Invalid\nName', b'ValidValue'),
(b'\r\nInvalidName', b'ValidValue'),
(b'\rInvalidName', b'ValidValue'),
(b'\nInvalidName', b'ValidValue'),
(b' InvalidName', b'ValidValue'),
(b'\tInvalidName', b'ValidValue'),
(b'Invalid:Name', b'ValidValue'),
(b':InvalidName', b'ValidValue'),
(b'ValidName', b'Invalid\r\nValue'),
(b'ValidName', b'Invalid\rValue'),
(b'ValidName', b'Invalid\nValue'),
(b'ValidName', b'InvalidValue\r\n'),
(b'ValidName', b'InvalidValue\r'),
(b'ValidName', b'InvalidValue\n'),
)
for name, value in cases:
with self.assertRaisesRegexp(ValueError, 'Invalid header'):
conn.putheader(name, value)
class BasicTest(TestCase): class BasicTest(TestCase):
def test_status_lines(self): def test_status_lines(self):
...@@ -125,6 +279,8 @@ class BasicTest(TestCase): ...@@ -125,6 +279,8 @@ class BasicTest(TestCase):
sock = FakeSocket(body) sock = FakeSocket(body)
resp = httplib.HTTPResponse(sock) resp = httplib.HTTPResponse(sock)
resp.begin() resp.begin()
self.assertEqual(resp.read(0), '') # Issue #20007
self.assertFalse(resp.isclosed())
self.assertEqual(resp.read(), 'Text') self.assertEqual(resp.read(), 'Text')
self.assertTrue(resp.isclosed()) self.assertTrue(resp.isclosed())
...@@ -138,7 +294,7 @@ class BasicTest(TestCase): ...@@ -138,7 +294,7 @@ class BasicTest(TestCase):
self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''') self.assertEqual(repr(exc), '''BadStatusLine("\'\'",)''')
def test_partial_reads(self): def test_partial_reads(self):
# if we have a lenght, the system knows when to close itself # if we have a length, the system knows when to close itself
# same behaviour than when we read the whole thing with read() # same behaviour than when we read the whole thing with read()
body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText" body = "HTTP/1.1 200 Ok\r\nContent-Length: 4\r\n\r\nText"
sock = FakeSocket(body) sock = FakeSocket(body)
...@@ -149,6 +305,32 @@ class BasicTest(TestCase): ...@@ -149,6 +305,32 @@ class BasicTest(TestCase):
self.assertEqual(resp.read(2), 'xt') self.assertEqual(resp.read(2), 'xt')
self.assertTrue(resp.isclosed()) self.assertTrue(resp.isclosed())
def test_partial_reads_no_content_length(self):
# when no length is present, the socket should be gracefully closed when
# all data was read
body = "HTTP/1.1 200 Ok\r\n\r\nText"
sock = FakeSocket(body)
resp = httplib.HTTPResponse(sock)
resp.begin()
self.assertEqual(resp.read(2), 'Te')
self.assertFalse(resp.isclosed())
self.assertEqual(resp.read(2), 'xt')
self.assertEqual(resp.read(1), '')
self.assertTrue(resp.isclosed())
def test_partial_reads_incomplete_body(self):
# if the server shuts down the connection before the whole
# content-length is delivered, the socket is gracefully closed
body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
sock = FakeSocket(body)
resp = httplib.HTTPResponse(sock)
resp.begin()
self.assertEqual(resp.read(2), 'Te')
self.assertFalse(resp.isclosed())
self.assertEqual(resp.read(2), 'xt')
self.assertEqual(resp.read(1), '')
self.assertTrue(resp.isclosed())
def test_host_port(self): def test_host_port(self):
# Check invalid host_port # Check invalid host_port
...@@ -201,6 +383,13 @@ class BasicTest(TestCase): ...@@ -201,6 +383,13 @@ class BasicTest(TestCase):
if resp.read() != "": if resp.read() != "":
self.fail("Did not expect response from HEAD request") self.fail("Did not expect response from HEAD request")
def test_too_many_headers(self):
headers = '\r\n'.join('Header%d: foo' % i for i in xrange(200)) + '\r\n'
text = ('HTTP/1.1 200 OK\r\n' + headers)
s = FakeSocket(text)
r = httplib.HTTPResponse(s)
self.assertRaises(httplib.HTTPException, r.begin)
def test_send_file(self): def test_send_file(self):
expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \ expected = 'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \
'Accept-Encoding: identity\r\nContent-Length:' 'Accept-Encoding: identity\r\nContent-Length:'
...@@ -211,6 +400,22 @@ class BasicTest(TestCase): ...@@ -211,6 +400,22 @@ class BasicTest(TestCase):
conn.sock = sock conn.sock = sock
conn.request('GET', '/foo', body) conn.request('GET', '/foo', body)
self.assertTrue(sock.data.startswith(expected)) self.assertTrue(sock.data.startswith(expected))
self.assertIn('def test_send_file', sock.data)
def test_send_tempfile(self):
expected = ('GET /foo HTTP/1.1\r\nHost: example.com\r\n'
'Accept-Encoding: identity\r\nContent-Length: 9\r\n\r\n'
'fake\ndata')
with tempfile.TemporaryFile() as body:
body.write('fake\ndata')
body.seek(0)
conn = httplib.HTTPConnection('example.com')
sock = FakeSocket(body)
conn.sock = sock
conn.request('GET', '/foo', body)
self.assertEqual(sock.data, expected)
def test_send(self): def test_send(self):
expected = 'this is a test this is only a test' expected = 'this is a test this is only a test'
...@@ -279,7 +484,7 @@ class BasicTest(TestCase): ...@@ -279,7 +484,7 @@ class BasicTest(TestCase):
resp = httplib.HTTPResponse(sock, method="GET") resp = httplib.HTTPResponse(sock, method="GET")
resp.begin() resp.begin()
self.assertEqual(resp.read(), 'Hello\r\n') self.assertEqual(resp.read(), 'Hello\r\n')
resp.close() self.assertTrue(resp.isclosed())
def test_incomplete_read(self): def test_incomplete_read(self):
sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n') sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
...@@ -293,10 +498,9 @@ class BasicTest(TestCase): ...@@ -293,10 +498,9 @@ class BasicTest(TestCase):
"IncompleteRead(7 bytes read, 3 more expected)") "IncompleteRead(7 bytes read, 3 more expected)")
self.assertEqual(str(i), self.assertEqual(str(i),
"IncompleteRead(7 bytes read, 3 more expected)") "IncompleteRead(7 bytes read, 3 more expected)")
self.assertTrue(resp.isclosed())
else: else:
self.fail('IncompleteRead expected') self.fail('IncompleteRead expected')
finally:
resp.close()
def test_epipe(self): def test_epipe(self):
sock = EPipeSocket( sock = EPipeSocket(
...@@ -349,13 +553,51 @@ class BasicTest(TestCase): ...@@ -349,13 +553,51 @@ class BasicTest(TestCase):
resp.begin() resp.begin()
self.assertRaises(httplib.LineTooLong, resp.read) self.assertRaises(httplib.LineTooLong, resp.read)
def test_early_eof(self):
# Test httpresponse with no \r\n termination,
body = "HTTP/1.1 200 Ok"
sock = FakeSocket(body)
resp = httplib.HTTPResponse(sock)
resp.begin()
self.assertEqual(resp.read(), '')
self.assertTrue(resp.isclosed())
def test_error_leak(self):
# Test that the socket is not leaked if getresponse() fails
conn = httplib.HTTPConnection('example.com')
response = []
class Response(httplib.HTTPResponse):
def __init__(self, *pos, **kw):
response.append(self) # Avoid garbage collector closing the socket
httplib.HTTPResponse.__init__(self, *pos, **kw)
conn.response_class = Response
conn.sock = FakeSocket('') # Emulate server dropping connection
conn.request('GET', '/')
self.assertRaises(httplib.BadStatusLine, conn.getresponse)
self.assertTrue(response)
#self.assertTrue(response[0].closed)
self.assertTrue(conn.sock.file_closed)
def test_proxy_tunnel_without_status_line(self):
# Issue 17849: If a proxy tunnel is created that does not return
# a status code, fail.
body = 'hello world'
conn = httplib.HTTPConnection('example.com', strict=False)
conn.set_tunnel('foo')
conn.sock = FakeSocket(body)
with self.assertRaisesRegexp(socket.error, "Invalid response"):
conn._tunnel()
class OfflineTest(TestCase): class OfflineTest(TestCase):
def test_responses(self): def test_responses(self):
self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found") self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found")
class SourceAddressTest(TestCase): class TestServerMixin:
"""A limited socket server mixin.
This is used by test cases for testing http connection end points.
"""
def setUp(self): def setUp(self):
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.port = test_support.bind_port(self.serv) self.port = test_support.bind_port(self.serv)
...@@ -370,6 +612,7 @@ class SourceAddressTest(TestCase): ...@@ -370,6 +612,7 @@ class SourceAddressTest(TestCase):
self.serv.close() self.serv.close()
self.serv = None self.serv = None
class SourceAddressTest(TestServerMixin, TestCase):
def testHTTPConnectionSourceAddress(self): def testHTTPConnectionSourceAddress(self):
self.conn = httplib.HTTPConnection(HOST, self.port, self.conn = httplib.HTTPConnection(HOST, self.port,
source_address=('', self.source_port)) source_address=('', self.source_port))
...@@ -386,6 +629,24 @@ class SourceAddressTest(TestCase): ...@@ -386,6 +629,24 @@ class SourceAddressTest(TestCase):
# for an ssl_wrapped connect() to actually return from. # for an ssl_wrapped connect() to actually return from.
class HTTPTest(TestServerMixin, TestCase):
def testHTTPConnection(self):
self.conn = httplib.HTTP(host=HOST, port=self.port, strict=None)
self.conn.connect()
self.assertEqual(self.conn._conn.host, HOST)
self.assertEqual(self.conn._conn.port, self.port)
def testHTTPWithConnectHostPort(self):
testhost = 'unreachable.test.domain'
testport = '80'
self.conn = httplib.HTTP(host=testhost, port=testport)
self.conn.connect(host=HOST, port=self.port)
self.assertNotEqual(self.conn._conn.host, testhost)
self.assertNotEqual(self.conn._conn.port, testport)
self.assertEqual(self.conn._conn.host, HOST)
self.assertEqual(self.conn._conn.port, self.port)
class TimeoutTest(TestCase): class TimeoutTest(TestCase):
PORT = None PORT = None
...@@ -403,7 +664,7 @@ class TimeoutTest(TestCase): ...@@ -403,7 +664,7 @@ class TimeoutTest(TestCase):
HTTPConnection and into the socket. HTTPConnection and into the socket.
''' '''
# default -- use global socket timeout # default -- use global socket timeout
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT) httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT)
...@@ -414,7 +675,7 @@ class TimeoutTest(TestCase): ...@@ -414,7 +675,7 @@ class TimeoutTest(TestCase):
httpConn.close() httpConn.close()
# no timeout -- do not use global socket default # no timeout -- do not use global socket default
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT, httpConn = httplib.HTTPConnection(HOST, TimeoutTest.PORT,
...@@ -432,40 +693,187 @@ class TimeoutTest(TestCase): ...@@ -432,40 +693,187 @@ class TimeoutTest(TestCase):
httpConn.close() httpConn.close()
class HTTPSTimeoutTest(TestCase): class HTTPSTest(TestCase):
# XXX Here should be tests for HTTPS, there isn't any right now!
def setUp(self):
if not hasattr(httplib, 'HTTPSConnection'):
self.skipTest('ssl support required')
def make_server(self, certfile):
from test.ssl_servers import make_https_server
return make_https_server(self, certfile=certfile)
def test_attributes(self): def test_attributes(self):
# simple test to check it's storing it # simple test to check it's storing the timeout
if hasattr(httplib, 'HTTPSConnection'): h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) self.assertEqual(h.timeout, 30)
self.assertEqual(h.timeout, 30)
def test_networked(self):
# Default settings: requires a valid cert from a trusted CA
import ssl
test_support.requires('network')
with test_support.transient_internet('self-signed.pythontest.net'):
h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
with self.assertRaises(ssl.SSLError) as exc_info:
h.request('GET', '/')
self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
def test_networked_noverification(self):
# Switch off cert verification
import ssl
test_support.requires('network')
with test_support.transient_internet('self-signed.pythontest.net'):
context = ssl._create_stdlib_context()
h = httplib.HTTPSConnection('self-signed.pythontest.net', 443,
context=context)
h.request('GET', '/')
resp = h.getresponse()
self.assertIn('nginx', resp.getheader('server'))
@test_support.system_must_validate_cert
def test_networked_trusted_by_default_cert(self):
# Default settings: requires a valid cert from a trusted CA
test_support.requires('network')
with test_support.transient_internet('www.python.org'):
h = httplib.HTTPSConnection('www.python.org', 443)
h.request('GET', '/')
resp = h.getresponse()
content_type = resp.getheader('content-type')
self.assertIn('text/html', content_type)
def test_networked_good_cert(self):
# We feed the server's cert as a validating cert
import ssl
test_support.requires('network')
with test_support.transient_internet('self-signed.pythontest.net'):
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
h.request('GET', '/')
resp = h.getresponse()
server_string = resp.getheader('server')
self.assertIn('nginx', server_string)
def test_networked_bad_cert(self):
# We feed a "CA" cert that is unrelated to the server's cert
import ssl
test_support.requires('network')
with test_support.transient_internet('self-signed.pythontest.net'):
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(CERT_localhost)
h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
with self.assertRaises(ssl.SSLError) as exc_info:
h.request('GET', '/')
self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
def test_local_unknown_cert(self):
# The custom cert isn't known to the default trust bundle
import ssl
server = self.make_server(CERT_localhost)
h = httplib.HTTPSConnection('localhost', server.port)
with self.assertRaises(ssl.SSLError) as exc_info:
h.request('GET', '/')
self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
def test_local_good_hostname(self):
# The (valid) cert validates the HTTP hostname
import ssl
server = self.make_server(CERT_localhost)
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(CERT_localhost)
h = httplib.HTTPSConnection('localhost', server.port, context=context)
h.request('GET', '/nonexistent')
resp = h.getresponse()
self.assertEqual(resp.status, 404)
def test_local_bad_hostname(self):
# The (valid) cert doesn't validate the HTTP hostname
import ssl
server = self.make_server(CERT_fakehostname)
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
context.load_verify_locations(CERT_fakehostname)
h = httplib.HTTPSConnection('localhost', server.port, context=context)
with self.assertRaises(ssl.CertificateError):
h.request('GET', '/')
h.close()
# With context.check_hostname=False, the mismatching is ignored
context.check_hostname = False
h = httplib.HTTPSConnection('localhost', server.port, context=context)
h.request('GET', '/nonexistent')
resp = h.getresponse()
self.assertEqual(resp.status, 404)
h.close()
@unittest.skipIf(not hasattr(httplib, 'HTTPS'), 'httplib.HTTPS not available')
def test_host_port(self): def test_host_port(self):
# Check invalid host_port # Check invalid host_port
# Note that httplib does not accept user:password@ in the host-port.
for hp in ("www.python.org:abc", "user:password@www.python.org"): for hp in ("www.python.org:abc", "user:password@www.python.org"):
self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp) self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp)
for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
"fe80::207:e9ff:fe9b", 8000),
("www.python.org:443", "www.python.org", 443),
("www.python.org:", "www.python.org", 443),
("www.python.org", "www.python.org", 443),
("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
443)):
c = httplib.HTTPSConnection(hp)
self.assertEqual(h, c.host)
self.assertEqual(p, c.port)
class TunnelTests(TestCase):
def test_connect(self):
response_text = (
'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
'HTTP/1.1 200 OK\r\n' # Reply to HEAD
'Content-Length: 42\r\n\r\n'
)
for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b", def create_connection(address, timeout=None, source_address=None):
8000), return FakeSocket(response_text, host=address[0], port=address[1])
("pypi.python.org:443", "pypi.python.org", 443),
("pypi.python.org", "pypi.python.org", 443), conn = httplib.HTTPConnection('proxy.com')
("pypi.python.org:", "pypi.python.org", 443), conn._create_connection = create_connection
("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443)):
http = httplib.HTTPS(hp) # Once connected, we should not be able to tunnel anymore
c = http._conn conn.connect()
if h != c.host: self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com')
self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
if p != c.port: # But if close the connection, we are good.
self.fail("Port incorrectly parsed: %s != %s" % (p, c.host)) conn.close()
conn.set_tunnel('destination.com')
conn.request('HEAD', '/', '')
self.assertEqual(conn.sock.host, 'proxy.com')
self.assertEqual(conn.sock.port, 80)
self.assertIn('CONNECT destination.com', conn.sock.data)
# issue22095
self.assertNotIn('Host: destination.com:None', conn.sock.data)
self.assertIn('Host: destination.com', conn.sock.data)
self.assertNotIn('Host: proxy.com', conn.sock.data)
conn.close()
conn.request('PUT', '/', '')
self.assertEqual(conn.sock.host, 'proxy.com')
self.assertEqual(conn.sock.port, 80)
self.assertTrue('CONNECT destination.com' in conn.sock.data)
self.assertTrue('Host: destination.com' in conn.sock.data)
@test_support.reap_threads
def test_main(verbose=None): def test_main(verbose=None):
test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
HTTPSTimeoutTest, SourceAddressTest) HTTPTest, HTTPSTest, SourceAddressTest,
TunnelTests)
if __name__ == '__main__': if __name__ == '__main__':
test_main() test_main()
...@@ -4,11 +4,6 @@ Written by Cody A.W. Somerville <cody-somerville@ubuntu.com>, ...@@ -4,11 +4,6 @@ Written by Cody A.W. Somerville <cody-somerville@ubuntu.com>,
Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest. Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest.
""" """
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from CGIHTTPServer import CGIHTTPRequestHandler
import CGIHTTPServer
import os import os
import sys import sys
import re import re
...@@ -17,12 +12,17 @@ import shutil ...@@ -17,12 +12,17 @@ import shutil
import urllib import urllib
import httplib import httplib
import tempfile import tempfile
import unittest import unittest
import CGIHTTPServer
from StringIO import StringIO
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from CGIHTTPServer import CGIHTTPRequestHandler
from StringIO import StringIO
from test import test_support from test import test_support
threading = test_support.import_module('threading') threading = test_support.import_module('threading')
...@@ -43,7 +43,7 @@ class SocketlessRequestHandler(SimpleHTTPRequestHandler): ...@@ -43,7 +43,7 @@ class SocketlessRequestHandler(SimpleHTTPRequestHandler):
self.end_headers() self.end_headers()
self.wfile.write(b'<html><body>Data</body></html>\r\n') self.wfile.write(b'<html><body>Data</body></html>\r\n')
def log_message(self, format, *args): def log_message(self, fmt, *args):
pass pass
...@@ -97,9 +97,9 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase): ...@@ -97,9 +97,9 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase):
self.handler = SocketlessRequestHandler() self.handler = SocketlessRequestHandler()
def send_typical_request(self, message): def send_typical_request(self, message):
input = StringIO(message) input_msg = StringIO(message)
output = StringIO() output = StringIO()
self.handler.rfile = input self.handler.rfile = input_msg
self.handler.wfile = output self.handler.wfile = output
self.handler.handle_one_request() self.handler.handle_one_request()
output.seek(0) output.seek(0)
...@@ -114,7 +114,7 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase): ...@@ -114,7 +114,7 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase):
def verify_http_server_response(self, response): def verify_http_server_response(self, response):
match = self.HTTPResponseMatch.search(response) match = self.HTTPResponseMatch.search(response)
self.assertTrue(match is not None) self.assertIsNotNone(match)
def test_http_1_1(self): def test_http_1_1(self):
result = self.send_typical_request('GET / HTTP/1.1\r\n\r\n') result = self.send_typical_request('GET / HTTP/1.1\r\n\r\n')
...@@ -189,7 +189,7 @@ class BaseHTTPServerTestCase(BaseTestCase): ...@@ -189,7 +189,7 @@ class BaseHTTPServerTestCase(BaseTestCase):
def test_request_line_trimming(self): def test_request_line_trimming(self):
self.con._http_vsn_str = 'HTTP/1.1\n' self.con._http_vsn_str = 'HTTP/1.1\n'
self.con.putrequest('GET', '/') self.con.putrequest('XYZBOGUS', '/')
self.con.endheaders() self.con.endheaders()
res = self.con.getresponse() res = self.con.getresponse()
self.assertEqual(res.status, 501) self.assertEqual(res.status, 501)
...@@ -216,8 +216,9 @@ class BaseHTTPServerTestCase(BaseTestCase): ...@@ -216,8 +216,9 @@ class BaseHTTPServerTestCase(BaseTestCase):
self.assertEqual(res.status, 501) self.assertEqual(res.status, 501)
def test_version_none(self): def test_version_none(self):
# Test that a valid method is rejected when not HTTP/1.x
self.con._http_vsn_str = '' self.con._http_vsn_str = ''
self.con.putrequest('PUT', '/') self.con.putrequest('CUSTOM', '/')
self.con.endheaders() self.con.endheaders()
res = self.con.getresponse() res = self.con.getresponse()
self.assertEqual(res.status, 400) self.assertEqual(res.status, 400)
...@@ -296,7 +297,7 @@ class SimpleHTTPServerTestCase(BaseTestCase): ...@@ -296,7 +297,7 @@ class SimpleHTTPServerTestCase(BaseTestCase):
os.chdir(self.cwd) os.chdir(self.cwd)
try: try:
shutil.rmtree(self.tempdir) shutil.rmtree(self.tempdir)
except: except OSError:
pass pass
finally: finally:
BaseTestCase.tearDown(self) BaseTestCase.tearDown(self)
...@@ -313,25 +314,33 @@ class SimpleHTTPServerTestCase(BaseTestCase): ...@@ -313,25 +314,33 @@ class SimpleHTTPServerTestCase(BaseTestCase):
#constructs the path relative to the root directory of the HTTPServer #constructs the path relative to the root directory of the HTTPServer
response = self.request(self.tempdir_name + '/test') response = self.request(self.tempdir_name + '/test')
self.check_status_and_reason(response, 200, data=self.data) self.check_status_and_reason(response, 200, data=self.data)
# check for trailing "/" which should return 404. See Issue17324
response = self.request(self.tempdir_name + '/test/')
self.check_status_and_reason(response, 404)
response = self.request(self.tempdir_name + '/') response = self.request(self.tempdir_name + '/')
self.check_status_and_reason(response, 200) self.check_status_and_reason(response, 200)
response = self.request(self.tempdir_name) response = self.request(self.tempdir_name)
self.check_status_and_reason(response, 301) self.check_status_and_reason(response, 301)
response = self.request(self.tempdir_name + '/?hi=2')
self.check_status_and_reason(response, 200)
response = self.request(self.tempdir_name + '?hi=1')
self.check_status_and_reason(response, 301)
self.assertEqual(response.getheader("Location"),
self.tempdir_name + "/?hi=1")
response = self.request('/ThisDoesNotExist') response = self.request('/ThisDoesNotExist')
self.check_status_and_reason(response, 404) self.check_status_and_reason(response, 404)
response = self.request('/' + 'ThisDoesNotExist' + '/') response = self.request('/' + 'ThisDoesNotExist' + '/')
self.check_status_and_reason(response, 404) self.check_status_and_reason(response, 404)
f = open(os.path.join(self.tempdir_name, 'index.html'), 'w') with open(os.path.join(self.tempdir_name, 'index.html'), 'w') as fp:
response = self.request('/' + self.tempdir_name + '/') response = self.request('/' + self.tempdir_name + '/')
self.check_status_and_reason(response, 200) self.check_status_and_reason(response, 200)
# chmod() doesn't work as expected on Windows, and filesystem
# chmod() doesn't work as expected on Windows, and filesystem # permissions are ignored by root on Unix.
# permissions are ignored by root on Unix. if os.name == 'posix' and os.geteuid() != 0:
if os.name == 'posix' and os.geteuid() != 0: os.chmod(self.tempdir, 0)
os.chmod(self.tempdir, 0) response = self.request(self.tempdir_name + '/')
response = self.request(self.tempdir_name + '/') self.check_status_and_reason(response, 404)
self.check_status_and_reason(response, 404) os.chmod(self.tempdir, 0755)
os.chmod(self.tempdir, 0755)
def test_head(self): def test_head(self):
response = self.request( response = self.request(
...@@ -346,7 +355,7 @@ class SimpleHTTPServerTestCase(BaseTestCase): ...@@ -346,7 +355,7 @@ class SimpleHTTPServerTestCase(BaseTestCase):
response = self.request('/', method='FOO') response = self.request('/', method='FOO')
self.check_status_and_reason(response, 501) self.check_status_and_reason(response, 501)
# requests must be case sensitive,so this should fail too # requests must be case sensitive,so this should fail too
response = self.request('/', method='get') response = self.request('/', method='custom')
self.check_status_and_reason(response, 501) self.check_status_and_reason(response, 501)
response = self.request('/', method='GETs') response = self.request('/', method='GETs')
self.check_status_and_reason(response, 501) self.check_status_and_reason(response, 501)
...@@ -372,6 +381,16 @@ print "%%s, %%s, %%s" %% (form.getfirst("spam"), form.getfirst("eggs"), ...@@ -372,6 +381,16 @@ print "%%s, %%s, %%s" %% (form.getfirst("spam"), form.getfirst("eggs"),
form.getfirst("bacon")) form.getfirst("bacon"))
""" """
cgi_file4 = """\
#!%s
import os
print("Content-type: text/html")
print()
print(os.environ["%s"])
"""
@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0, @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
"This test can't be run reliably as root (issue #13308).") "This test can't be run reliably as root (issue #13308).")
...@@ -383,7 +402,9 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -383,7 +402,9 @@ class CGIHTTPServerTestCase(BaseTestCase):
BaseTestCase.setUp(self) BaseTestCase.setUp(self)
self.parent_dir = tempfile.mkdtemp() self.parent_dir = tempfile.mkdtemp()
self.cgi_dir = os.path.join(self.parent_dir, 'cgi-bin') self.cgi_dir = os.path.join(self.parent_dir, 'cgi-bin')
self.cgi_child_dir = os.path.join(self.cgi_dir, 'child-dir')
os.mkdir(self.cgi_dir) os.mkdir(self.cgi_dir)
os.mkdir(self.cgi_child_dir)
# The shebang line should be pure ASCII: use symlink if possible. # The shebang line should be pure ASCII: use symlink if possible.
# See issue #7668. # See issue #7668.
...@@ -393,6 +414,11 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -393,6 +414,11 @@ class CGIHTTPServerTestCase(BaseTestCase):
else: else:
self.pythonexe = sys.executable self.pythonexe = sys.executable
self.nocgi_path = os.path.join(self.parent_dir, 'nocgi.py')
with open(self.nocgi_path, 'w') as fp:
fp.write(cgi_file1 % self.pythonexe)
os.chmod(self.nocgi_path, 0777)
self.file1_path = os.path.join(self.cgi_dir, 'file1.py') self.file1_path = os.path.join(self.cgi_dir, 'file1.py')
with open(self.file1_path, 'w') as file1: with open(self.file1_path, 'w') as file1:
file1.write(cgi_file1 % self.pythonexe) file1.write(cgi_file1 % self.pythonexe)
...@@ -403,6 +429,16 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -403,6 +429,16 @@ class CGIHTTPServerTestCase(BaseTestCase):
file2.write(cgi_file2 % self.pythonexe) file2.write(cgi_file2 % self.pythonexe)
os.chmod(self.file2_path, 0777) os.chmod(self.file2_path, 0777)
self.file3_path = os.path.join(self.cgi_child_dir, 'file3.py')
with open(self.file3_path, 'w') as file3:
file3.write(cgi_file1 % self.pythonexe)
os.chmod(self.file3_path, 0777)
self.file4_path = os.path.join(self.cgi_dir, 'file4.py')
with open(self.file4_path, 'w') as file4:
file4.write(cgi_file4 % (self.pythonexe, 'QUERY_STRING'))
os.chmod(self.file4_path, 0o777)
self.cwd = os.getcwd() self.cwd = os.getcwd()
os.chdir(self.parent_dir) os.chdir(self.parent_dir)
...@@ -411,56 +447,17 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -411,56 +447,17 @@ class CGIHTTPServerTestCase(BaseTestCase):
os.chdir(self.cwd) os.chdir(self.cwd)
if self.pythonexe != sys.executable: if self.pythonexe != sys.executable:
os.remove(self.pythonexe) os.remove(self.pythonexe)
os.remove(self.nocgi_path)
os.remove(self.file1_path) os.remove(self.file1_path)
os.remove(self.file2_path) os.remove(self.file2_path)
os.remove(self.file3_path)
os.remove(self.file4_path)
os.rmdir(self.cgi_child_dir)
os.rmdir(self.cgi_dir) os.rmdir(self.cgi_dir)
os.rmdir(self.parent_dir) os.rmdir(self.parent_dir)
finally: finally:
BaseTestCase.tearDown(self) BaseTestCase.tearDown(self)
@unittest.skipIf(hasattr(CGIHTTPServer, '_url_collapse_path'),
"Only on <= 2.7.3")
def test_url_collapse_path_split(self):
test_vectors = {
'': ('/', ''),
'..': IndexError,
'/.//..': IndexError,
'/': ('/', ''),
'//': ('/', ''),
'/\\': ('/', '\\'),
'/.//': ('/', ''),
'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'),
'/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'),
'a': ('/', 'a'),
'/a': ('/', 'a'),
'//a': ('/', 'a'),
'./a': ('/', 'a'),
'./C:/': ('/C:', ''),
'/a/b': ('/a', 'b'),
'/a/b/': ('/a/b', ''),
'/a/b/c/..': ('/a/b', ''),
'/a/b/c/../d': ('/a/b', 'd'),
'/a/b/c/../d/e/../f': ('/a/b/d', 'f'),
'/a/b/c/../d/e/../../f': ('/a/b', 'f'),
'/a/b/c/../d/e/.././././..//f': ('/a/b', 'f'),
'../a/b/c/../d/e/.././././..//f': IndexError,
'/a/b/c/../d/e/../../../f': ('/a', 'f'),
'/a/b/c/../d/e/../../../../f': ('/', 'f'),
'/a/b/c/../d/e/../../../../../f': IndexError,
'/a/b/c/../d/e/../../../../f/..': ('/', ''),
}
for path, expected in test_vectors.iteritems():
if isinstance(expected, type) and issubclass(expected, Exception):
self.assertRaises(expected,
CGIHTTPServer._url_collapse_path_split, path)
else:
actual = CGIHTTPServer._url_collapse_path_split(path)
self.assertEqual(expected, actual,
msg='path = %r\nGot: %r\nWanted: %r' %
(path, actual, expected))
@unittest.skipIf(hasattr(CGIHTTPServer, '_url_collapse_path_split'),
"Only on >= 2.7.3")
def test_url_collapse_path(self): def test_url_collapse_path(self):
# verify tail is the last portion and head is the rest on proper urls # verify tail is the last portion and head is the rest on proper urls
test_vectors = { test_vectors = {
...@@ -508,6 +505,10 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -508,6 +505,10 @@ class CGIHTTPServerTestCase(BaseTestCase):
self.assertEqual(('Hello World\n', 'text/html', 200), self.assertEqual(('Hello World\n', 'text/html', 200),
(res.read(), res.getheader('Content-type'), res.status)) (res.read(), res.getheader('Content-type'), res.status))
def test_issue19435(self):
res = self.request('///////////nocgi.py/../cgi-bin/nothere.sh')
self.assertEqual(res.status, 404)
def test_post(self): def test_post(self):
params = urllib.urlencode({'spam' : 1, 'eggs' : 'python', 'bacon' : 123456}) params = urllib.urlencode({'spam' : 1, 'eggs' : 'python', 'bacon' : 123456})
headers = {'Content-type' : 'application/x-www-form-urlencoded'} headers = {'Content-type' : 'application/x-www-form-urlencoded'}
...@@ -541,6 +542,29 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -541,6 +542,29 @@ class CGIHTTPServerTestCase(BaseTestCase):
(res.read(), res.getheader('Content-type'), res.status)) (res.read(), res.getheader('Content-type'), res.status))
self.assertEqual(os.environ['SERVER_SOFTWARE'], signature) self.assertEqual(os.environ['SERVER_SOFTWARE'], signature)
def test_urlquote_decoding_in_cgi_check(self):
res = self.request('/cgi-bin%2ffile1.py')
self.assertEqual((b'Hello World\n', 'text/html', 200),
(res.read(), res.getheader('Content-type'), res.status))
def test_nested_cgi_path_issue21323(self):
res = self.request('/cgi-bin/child-dir/file3.py')
self.assertEqual((b'Hello World\n', 'text/html', 200),
(res.read(), res.getheader('Content-type'), res.status))
def test_query_with_multiple_question_mark(self):
res = self.request('/cgi-bin/file4.py?a=b?c=d')
self.assertEqual(
(b'a=b?c=d\n', 'text/html', 200),
(res.read(), res.getheader('Content-type'), res.status))
def test_query_with_continuous_slashes(self):
res = self.request('/cgi-bin/file4.py?k=aa%2F%2Fbb&//q//p//=//a//b//')
self.assertEqual(
(b'k=aa%2F%2Fbb&//q//p//=//a//b//\n',
'text/html', 200),
(res.read(), res.getheader('Content-type'), res.status))
class SimpleHTTPRequestHandlerTestCase(unittest.TestCase): class SimpleHTTPRequestHandlerTestCase(unittest.TestCase):
""" Test url parsing """ """ Test url parsing """
......
...@@ -43,6 +43,9 @@ class _TriggerThread(threading.Thread): ...@@ -43,6 +43,9 @@ 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) self.t = _TriggerThread(trigger_func, trigger_args)
self.t.start() self.t.start()
...@@ -79,7 +82,7 @@ class BlockingTestMixin: ...@@ -79,7 +82,7 @@ class BlockingTestMixin:
self.fail("trigger thread ended but event never set") self.fail("trigger thread ended but event never set")
class BaseQueueTest(unittest.TestCase, BlockingTestMixin): class BaseQueueTest(BlockingTestMixin):
def setUp(self): def setUp(self):
self.cum = 0 self.cum = 0
self.cumlock = threading.Lock() self.cumlock = threading.Lock()
...@@ -191,13 +194,13 @@ class BaseQueueTest(unittest.TestCase, BlockingTestMixin): ...@@ -191,13 +194,13 @@ class BaseQueueTest(unittest.TestCase, BlockingTestMixin):
self.simple_queue_test(q) self.simple_queue_test(q)
class QueueTest(BaseQueueTest): class QueueTest(BaseQueueTest, unittest.TestCase):
type2test = Queue.Queue type2test = Queue.Queue
class LifoQueueTest(BaseQueueTest): class LifoQueueTest(BaseQueueTest, unittest.TestCase):
type2test = Queue.LifoQueue type2test = Queue.LifoQueue
class PriorityQueueTest(BaseQueueTest): class PriorityQueueTest(BaseQueueTest, unittest.TestCase):
type2test = Queue.PriorityQueue type2test = Queue.PriorityQueue
...@@ -222,7 +225,7 @@ class FailingQueue(Queue.Queue): ...@@ -222,7 +225,7 @@ class FailingQueue(Queue.Queue):
raise FailingQueueException, "You Lose" raise FailingQueueException, "You Lose"
return Queue.Queue._get(self) return Queue.Queue._get(self)
class FailingQueueTest(unittest.TestCase, BlockingTestMixin): class FailingQueueTest(BlockingTestMixin, unittest.TestCase):
def failing_queue_test(self, q): def failing_queue_test(self, q):
if not q.empty(): if not q.empty():
......
...@@ -29,9 +29,9 @@ class SelectTestCase(unittest.TestCase): ...@@ -29,9 +29,9 @@ class SelectTestCase(unittest.TestCase):
self.assertIsNot(w, x) self.assertIsNot(w, x)
def test_select(self): def test_select(self):
cmd = 'for i in 0 1 2 3 4 5 6 7 8 9; do echo testing...; sleep 0.1; done' cmd = 'for i in 0 1 2 3 4 5 6 7 8 9; do echo testing...; sleep 1; done'
p = os.popen(cmd, 'r') p = os.popen(cmd, 'r')
for tout in (0, 0.1, 0.2, 0.4, 0.8, 1.6) + (None,)*10: for tout in (0, 1, 2, 4, 8, 16) + (None,)*10:
if test_support.verbose: if test_support.verbose:
print 'timeout =', tout print 'timeout =', tout
rfd, wfd, xfd = select.select([p], [], [], tout) rfd, wfd, xfd = select.select([p], [], [], tout)
...@@ -49,6 +49,15 @@ class SelectTestCase(unittest.TestCase): ...@@ -49,6 +49,15 @@ class SelectTestCase(unittest.TestCase):
self.fail('Unexpected return values from select():', rfd, wfd, xfd) self.fail('Unexpected return values from select():', rfd, wfd, xfd)
p.close() p.close()
# Issue 16230: Crash on select resized list
def test_select_mutated(self):
a = []
class F:
def fileno(self):
del a[-1]
return sys.__stdout__.fileno()
a[:] = [F()] * 10
self.assertEqual(select.select([], a, []), ([], a[:5], []))
def test_main(): def test_main():
test_support.run_unittest(SelectTestCase) test_support.run_unittest(SelectTestCase)
......
...@@ -109,7 +109,7 @@ class InterProcessSignalTests(unittest.TestCase): ...@@ -109,7 +109,7 @@ class InterProcessSignalTests(unittest.TestCase):
# This wait should be interrupted by the signal's exception. # This wait should be interrupted by the signal's exception.
self.wait(child) self.wait(child)
time.sleep(1) # Give the signal time to be delivered. time.sleep(1) # Give the signal time to be delivered.
self.fail('HandlerBCalled exception not thrown') self.fail('HandlerBCalled exception not raised')
except HandlerBCalled: except HandlerBCalled:
self.assertTrue(self.b_called) self.assertTrue(self.b_called)
self.assertFalse(self.a_called) self.assertFalse(self.a_called)
...@@ -148,7 +148,7 @@ class InterProcessSignalTests(unittest.TestCase): ...@@ -148,7 +148,7 @@ class InterProcessSignalTests(unittest.TestCase):
# test-running process from all the signals. It then # test-running process from all the signals. It then
# communicates with that child process over a pipe and # communicates with that child process over a pipe and
# re-raises information about any exceptions the child # re-raises information about any exceptions the child
# throws. The real work happens in self.run_test(). # raises. The real work happens in self.run_test().
os_done_r, os_done_w = os.pipe() os_done_r, os_done_w = os.pipe()
with closing(os.fdopen(os_done_r)) as done_r, \ with closing(os.fdopen(os_done_r)) as done_r, \
closing(os.fdopen(os_done_w, 'w')) as done_w: closing(os.fdopen(os_done_w, 'w')) as done_w:
...@@ -227,6 +227,13 @@ class WindowsSignalTests(unittest.TestCase): ...@@ -227,6 +227,13 @@ class WindowsSignalTests(unittest.TestCase):
signal.signal(7, handler) signal.signal(7, handler)
class WakeupFDTests(unittest.TestCase):
def test_invalid_fd(self):
fd = test_support.make_bad_fd()
self.assertRaises(ValueError, signal.set_wakeup_fd, fd)
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows") @unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
class WakeupSignalTests(unittest.TestCase): class WakeupSignalTests(unittest.TestCase):
TIMEOUT_FULL = 10 TIMEOUT_FULL = 10
...@@ -485,8 +492,9 @@ class ItimerTest(unittest.TestCase): ...@@ -485,8 +492,9 @@ class ItimerTest(unittest.TestCase):
def test_main(): def test_main():
test_support.run_unittest(BasicSignalTests, InterProcessSignalTests, test_support.run_unittest(BasicSignalTests, InterProcessSignalTests,
WakeupSignalTests, SiginterruptTest, WakeupFDTests, WakeupSignalTests,
ItimerTest, WindowsSignalTests) SiginterruptTest, ItimerTest,
WindowsSignalTests)
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -77,7 +77,7 @@ class GeneralTests(unittest.TestCase): ...@@ -77,7 +77,7 @@ class GeneralTests(unittest.TestCase):
smtp.close() smtp.close()
def testTimeoutDefault(self): def testTimeoutDefault(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
smtp = smtplib.SMTP(HOST, self.port) smtp = smtplib.SMTP(HOST, self.port)
...@@ -87,13 +87,13 @@ class GeneralTests(unittest.TestCase): ...@@ -87,13 +87,13 @@ class GeneralTests(unittest.TestCase):
smtp.close() smtp.close()
def testTimeoutNone(self): def testTimeoutNone(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
try: try:
smtp = smtplib.SMTP(HOST, self.port, timeout=None) smtp = smtplib.SMTP(HOST, self.port, timeout=None)
finally: finally:
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertTrue(smtp.sock.gettimeout() is None) self.assertIsNone(smtp.sock.gettimeout())
smtp.close() smtp.close()
def testTimeoutValue(self): def testTimeoutValue(self):
...@@ -292,6 +292,33 @@ class BadHELOServerTests(unittest.TestCase): ...@@ -292,6 +292,33 @@ class BadHELOServerTests(unittest.TestCase):
HOST, self.port, 'localhost', 3) HOST, self.port, 'localhost', 3)
@unittest.skipUnless(threading, 'Threading required for this test.')
class TooLongLineTests(unittest.TestCase):
respdata = '250 OK' + ('.' * smtplib._MAXLINE * 2) + '\n'
def setUp(self):
self.old_stdout = sys.stdout
self.output = StringIO.StringIO()
sys.stdout = self.output
self.evt = threading.Event()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(15)
self.port = test_support.bind_port(self.sock)
servargs = (self.evt, self.respdata, self.sock)
threading.Thread(target=server, args=servargs).start()
self.evt.wait()
self.evt.clear()
def tearDown(self):
self.evt.wait()
sys.stdout = self.old_stdout
def testLineTooLong(self):
self.assertRaises(smtplib.SMTPResponseException, smtplib.SMTP,
HOST, self.port, 'localhost', 3)
sim_users = {'Mr.A@somewhere.com':'John A', sim_users = {'Mr.A@somewhere.com':'John A',
'Ms.B@somewhere.com':'Sally B', 'Ms.B@somewhere.com':'Sally B',
'Mrs.C@somewhereesle.com':'Ruth C', 'Mrs.C@somewhereesle.com':'Ruth C',
...@@ -507,11 +534,27 @@ class SMTPSimTests(unittest.TestCase): ...@@ -507,11 +534,27 @@ class SMTPSimTests(unittest.TestCase):
#TODO: add tests for correct AUTH method fallback now that the #TODO: add tests for correct AUTH method fallback now that the
#test infrastructure can support it. #test infrastructure can support it.
def test_quit_resets_greeting(self):
smtp = smtplib.SMTP(HOST, self.port,
local_hostname='localhost',
timeout=15)
code, message = smtp.ehlo()
self.assertEqual(code, 250)
self.assertIn('size', smtp.esmtp_features)
smtp.quit()
self.assertNotIn('size', smtp.esmtp_features)
smtp.connect(HOST, self.port)
self.assertNotIn('size', smtp.esmtp_features)
smtp.ehlo_or_helo_if_needed()
self.assertIn('size', smtp.esmtp_features)
smtp.quit()
def test_main(verbose=None): def test_main(verbose=None):
test_support.run_unittest(GeneralTests, DebuggingServerTests, test_support.run_unittest(GeneralTests, DebuggingServerTests,
NonConnectingTests, NonConnectingTests,
BadHELOServerTests, SMTPSimTests) BadHELOServerTests, SMTPSimTests,
TooLongLineTests)
if __name__ == '__main__': if __name__ == '__main__':
test_main() test_main()
#!/usr/bin/env python
import unittest import unittest
from test import test_support from test import test_support
import errno import errno
import itertools
import socket import socket
import select import select
import time import time
...@@ -13,9 +12,14 @@ import sys ...@@ -13,9 +12,14 @@ import sys
import os import os
import array import array
import contextlib import contextlib
from weakref import proxy
import signal import signal
import math import math
import weakref
try:
import _socket
except ImportError:
_socket = None
def try_address(host, port=0, family=socket.AF_INET): def try_address(host, port=0, family=socket.AF_INET):
"""Try to bind a socket on the given host:port and return True """Try to bind a socket on the given host:port and return True
...@@ -245,9 +249,22 @@ class SocketPairTest(unittest.TestCase, ThreadableTest): ...@@ -245,9 +249,22 @@ class SocketPairTest(unittest.TestCase, ThreadableTest):
class GeneralModuleTests(unittest.TestCase): class GeneralModuleTests(unittest.TestCase):
@unittest.skipUnless(_socket is not None, 'need _socket module')
def test_csocket_repr(self):
s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
try:
expected = ('<socket object, fd=%s, family=%s, type=%s, protocol=%s>'
% (s.fileno(), s.family, s.type, s.proto))
self.assertEqual(repr(s), expected)
finally:
s.close()
expected = ('<socket object, fd=-1, family=%s, type=%s, protocol=%s>'
% (s.family, s.type, s.proto))
self.assertEqual(repr(s), expected)
def test_weakref(self): def test_weakref(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
p = proxy(s) p = weakref.proxy(s)
self.assertEqual(p.fileno(), s.fileno()) self.assertEqual(p.fileno(), s.fileno())
s.close() s.close()
s = None s = None
...@@ -258,6 +275,14 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -258,6 +275,14 @@ class GeneralModuleTests(unittest.TestCase):
else: else:
self.fail('Socket proxy still exists') self.fail('Socket proxy still exists')
def test_weakref__sock(self):
s = socket.socket()._sock
w = weakref.ref(s)
self.assertIs(w(), s)
del s
test_support.gc_collect()
self.assertIsNone(w())
def testSocketError(self): def testSocketError(self):
# Testing socket module exceptions # Testing socket module exceptions
def raise_error(*args, **kwargs): def raise_error(*args, **kwargs):
...@@ -330,28 +355,29 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -330,28 +355,29 @@ class GeneralModuleTests(unittest.TestCase):
ip = socket.gethostbyname(hostname) ip = socket.gethostbyname(hostname)
except socket.error: except socket.error:
# Probably name lookup wasn't set up right; skip this test # Probably name lookup wasn't set up right; skip this test
return self.skipTest('name lookup failure')
self.assertTrue(ip.find('.') >= 0, "Error resolving host to ip.") self.assertTrue(ip.find('.') >= 0, "Error resolving host to ip.")
try: try:
hname, aliases, ipaddrs = socket.gethostbyaddr(ip) hname, aliases, ipaddrs = socket.gethostbyaddr(ip)
except socket.error: except socket.error:
# Probably a similar problem as above; skip this test # Probably a similar problem as above; skip this test
return self.skipTest('address lookup failure')
all_host_names = [hostname, hname] + aliases all_host_names = [hostname, hname] + aliases
fqhn = socket.getfqdn(ip) fqhn = socket.getfqdn(ip)
if not fqhn in all_host_names: if not fqhn in all_host_names:
self.fail("Error testing host resolution mechanisms. (fqdn: %s, all: %s)" % (fqhn, repr(all_host_names))) self.fail("Error testing host resolution mechanisms. (fqdn: %s, all: %s)" % (fqhn, repr(all_host_names)))
@unittest.skipUnless(hasattr(sys, 'getrefcount'),
'test needs sys.getrefcount()')
def testRefCountGetNameInfo(self): def testRefCountGetNameInfo(self):
# Testing reference count for getnameinfo # Testing reference count for getnameinfo
if hasattr(sys, "getrefcount"): try:
try: # On some versions, this loses a reference
# On some versions, this loses a reference orig = sys.getrefcount(__name__)
orig = sys.getrefcount(__name__) socket.getnameinfo(__name__,0)
socket.getnameinfo(__name__,0) except TypeError:
except TypeError: self.assertEqual(sys.getrefcount(__name__), orig,
self.assertEqual(sys.getrefcount(__name__), orig, "socket.getnameinfo loses a reference")
"socket.getnameinfo loses a reference")
def testInterpreterCrash(self): def testInterpreterCrash(self):
# Making sure getnameinfo doesn't crash the interpreter # Making sure getnameinfo doesn't crash the interpreter
...@@ -414,7 +440,7 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -414,7 +440,7 @@ class GeneralModuleTests(unittest.TestCase):
# Try same call with optional protocol omitted # Try same call with optional protocol omitted
port2 = socket.getservbyname(service) port2 = socket.getservbyname(service)
eq(port, port2) eq(port, port2)
# Try udp, but don't barf it it doesn't exist # Try udp, but don't barf if it doesn't exist
try: try:
udpport = socket.getservbyname(service, 'udp') udpport = socket.getservbyname(service, 'udp')
except socket.error: except socket.error:
...@@ -458,17 +484,17 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -458,17 +484,17 @@ class GeneralModuleTests(unittest.TestCase):
# Check that setting it to an invalid type raises TypeError # Check that setting it to an invalid type raises TypeError
self.assertRaises(TypeError, socket.setdefaulttimeout, "spam") self.assertRaises(TypeError, socket.setdefaulttimeout, "spam")
@unittest.skipUnless(hasattr(socket, 'inet_aton'),
'test needs socket.inet_aton()')
def testIPv4_inet_aton_fourbytes(self): def testIPv4_inet_aton_fourbytes(self):
if not hasattr(socket, 'inet_aton'):
return # No inet_aton, nothing to check
# Test that issue1008086 and issue767150 are fixed. # Test that issue1008086 and issue767150 are fixed.
# It must return 4 bytes. # It must return 4 bytes.
self.assertEqual('\x00'*4, socket.inet_aton('0.0.0.0')) self.assertEqual('\x00'*4, socket.inet_aton('0.0.0.0'))
self.assertEqual('\xff'*4, socket.inet_aton('255.255.255.255')) self.assertEqual('\xff'*4, socket.inet_aton('255.255.255.255'))
@unittest.skipUnless(hasattr(socket, 'inet_pton'),
'test needs socket.inet_pton()')
def testIPv4toString(self): def testIPv4toString(self):
if not hasattr(socket, 'inet_pton'):
return # No inet_pton() on this platform
from socket import inet_aton as f, inet_pton, AF_INET from socket import inet_aton as f, inet_pton, AF_INET
g = lambda a: inet_pton(AF_INET, a) g = lambda a: inet_pton(AF_INET, a)
...@@ -483,15 +509,15 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -483,15 +509,15 @@ class GeneralModuleTests(unittest.TestCase):
self.assertEqual('\xaa\xaa\xaa\xaa', g('170.170.170.170')) self.assertEqual('\xaa\xaa\xaa\xaa', g('170.170.170.170'))
self.assertEqual('\xff\xff\xff\xff', g('255.255.255.255')) self.assertEqual('\xff\xff\xff\xff', g('255.255.255.255'))
@unittest.skipUnless(hasattr(socket, 'inet_pton'),
'test needs socket.inet_pton()')
def testIPv6toString(self): def testIPv6toString(self):
if not hasattr(socket, 'inet_pton'):
return # No inet_pton() on this platform
try: try:
from socket import inet_pton, AF_INET6, has_ipv6 from socket import inet_pton, AF_INET6, has_ipv6
if not has_ipv6: if not has_ipv6:
return self.skipTest('IPv6 not available')
except ImportError: except ImportError:
return self.skipTest('could not import needed symbols from socket')
f = lambda a: inet_pton(AF_INET6, a) f = lambda a: inet_pton(AF_INET6, a)
self.assertEqual('\x00' * 16, f('::')) self.assertEqual('\x00' * 16, f('::'))
...@@ -502,9 +528,9 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -502,9 +528,9 @@ class GeneralModuleTests(unittest.TestCase):
f('45ef:76cb:1a:56ef:afeb:bac:1924:aeae') f('45ef:76cb:1a:56ef:afeb:bac:1924:aeae')
) )
@unittest.skipUnless(hasattr(socket, 'inet_ntop'),
'test needs socket.inet_ntop()')
def testStringToIPv4(self): def testStringToIPv4(self):
if not hasattr(socket, 'inet_ntop'):
return # No inet_ntop() on this platform
from socket import inet_ntoa as f, inet_ntop, AF_INET from socket import inet_ntoa as f, inet_ntop, AF_INET
g = lambda a: inet_ntop(AF_INET, a) g = lambda a: inet_ntop(AF_INET, a)
...@@ -517,15 +543,15 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -517,15 +543,15 @@ class GeneralModuleTests(unittest.TestCase):
self.assertEqual('170.85.170.85', g('\xaa\x55\xaa\x55')) self.assertEqual('170.85.170.85', g('\xaa\x55\xaa\x55'))
self.assertEqual('255.255.255.255', g('\xff\xff\xff\xff')) self.assertEqual('255.255.255.255', g('\xff\xff\xff\xff'))
@unittest.skipUnless(hasattr(socket, 'inet_ntop'),
'test needs socket.inet_ntop()')
def testStringToIPv6(self): def testStringToIPv6(self):
if not hasattr(socket, 'inet_ntop'):
return # No inet_ntop() on this platform
try: try:
from socket import inet_ntop, AF_INET6, has_ipv6 from socket import inet_ntop, AF_INET6, has_ipv6
if not has_ipv6: if not has_ipv6:
return self.skipTest('IPv6 not available')
except ImportError: except ImportError:
return self.skipTest('could not import needed symbols from socket')
f = lambda a: inet_ntop(AF_INET6, a) f = lambda a: inet_ntop(AF_INET6, a)
self.assertEqual('::', f('\x00' * 16)) self.assertEqual('::', f('\x00' * 16))
...@@ -565,7 +591,7 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -565,7 +591,7 @@ class GeneralModuleTests(unittest.TestCase):
my_ip_addr = socket.gethostbyname(socket.gethostname()) my_ip_addr = socket.gethostbyname(socket.gethostname())
except socket.error: except socket.error:
# Probably name lookup wasn't set up right; skip this test # Probably name lookup wasn't set up right; skip this test
return self.skipTest('name lookup failure')
self.assertIn(name[0], ("0.0.0.0", my_ip_addr), '%s invalid' % name[0]) self.assertIn(name[0], ("0.0.0.0", my_ip_addr), '%s invalid' % name[0])
self.assertEqual(name[1], port) self.assertEqual(name[1], port)
...@@ -601,17 +627,24 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -601,17 +627,24 @@ class GeneralModuleTests(unittest.TestCase):
sock.close() sock.close()
def test_getsockaddrarg(self): def test_getsockaddrarg(self):
host = '0.0.0.0' sock = socket.socket()
port = self._get_unused_port(bind_address=host) self.addCleanup(sock.close)
port = test_support.find_unused_port()
big_port = port + 65536 big_port = port + 65536
neg_port = port - 65536 neg_port = port - 65536
sock = socket.socket() self.assertRaises(OverflowError, sock.bind, (HOST, big_port))
try: self.assertRaises(OverflowError, sock.bind, (HOST, neg_port))
self.assertRaises(OverflowError, sock.bind, (host, big_port)) # Since find_unused_port() is inherently subject to race conditions, we
self.assertRaises(OverflowError, sock.bind, (host, neg_port)) # call it a couple times if necessary.
sock.bind((host, port)) for i in itertools.count():
finally: port = test_support.find_unused_port()
sock.close() try:
sock.bind((HOST, port))
except OSError as e:
if e.errno != errno.EADDRINUSE or i == 5:
raise
else:
break
@unittest.skipUnless(os.name == "nt", "Windows specific") @unittest.skipUnless(os.name == "nt", "Windows specific")
def test_sock_ioctl(self): def test_sock_ioctl(self):
...@@ -644,9 +677,10 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -644,9 +677,10 @@ class GeneralModuleTests(unittest.TestCase):
if SUPPORTS_IPV6: if SUPPORTS_IPV6:
socket.getaddrinfo('::1', 80) socket.getaddrinfo('::1', 80)
# port can be a string service name such as "http", a numeric # port can be a string service name such as "http", a numeric
# port number or None # port number (int or long), or None
socket.getaddrinfo(HOST, "http") socket.getaddrinfo(HOST, "http")
socket.getaddrinfo(HOST, 80) socket.getaddrinfo(HOST, 80)
socket.getaddrinfo(HOST, 80L)
socket.getaddrinfo(HOST, None) socket.getaddrinfo(HOST, None)
# test family and socktype filters # test family and socktype filters
infos = socket.getaddrinfo(HOST, None, socket.AF_INET) infos = socket.getaddrinfo(HOST, None, socket.AF_INET)
...@@ -663,6 +697,15 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -663,6 +697,15 @@ class GeneralModuleTests(unittest.TestCase):
socket.getaddrinfo(None, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.getaddrinfo(None, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0,
socket.AI_PASSIVE) socket.AI_PASSIVE)
# Issue 17269: test workaround for OS X platform bug segfault
if hasattr(socket, 'AI_NUMERICSERV'):
try:
# The arguments here are undefined and the call may succeed
# or fail. All we care here is that it doesn't segfault.
socket.getaddrinfo("localhost", None, 0, 0, 0,
socket.AI_NUMERICSERV)
except socket.gaierror:
pass
def check_sendall_interrupted(self, with_timeout): def check_sendall_interrupted(self, with_timeout):
# socketpair() is not stricly required, but it makes things easier. # socketpair() is not stricly required, but it makes things easier.
...@@ -683,11 +726,12 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -683,11 +726,12 @@ class GeneralModuleTests(unittest.TestCase):
c.settimeout(1.5) c.settimeout(1.5)
with self.assertRaises(ZeroDivisionError): with self.assertRaises(ZeroDivisionError):
signal.alarm(1) signal.alarm(1)
c.sendall(b"x" * (1024**2)) c.sendall(b"x" * test_support.SOCK_MAX_SIZE)
if with_timeout: if with_timeout:
signal.signal(signal.SIGALRM, ok_handler) signal.signal(signal.SIGALRM, ok_handler)
signal.alarm(1) signal.alarm(1)
self.assertRaises(socket.timeout, c.sendall, b"x" * (1024**2)) self.assertRaises(socket.timeout, c.sendall,
b"x" * test_support.SOCK_MAX_SIZE)
finally: finally:
signal.signal(signal.SIGALRM, old_alarm) signal.signal(signal.SIGALRM, old_alarm)
c.close() c.close()
...@@ -699,11 +743,20 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -699,11 +743,20 @@ class GeneralModuleTests(unittest.TestCase):
def test_sendall_interrupted_with_timeout(self): def test_sendall_interrupted_with_timeout(self):
self.check_sendall_interrupted(True) self.check_sendall_interrupted(True)
def testListenBacklog0(self): def test_listen_backlog(self):
for backlog in 0, -1:
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.bind((HOST, 0))
srv.listen(backlog)
srv.close()
@test_support.cpython_only
def test_listen_backlog_overflow(self):
# Issue 15989
import _testcapi
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.bind((HOST, 0)) srv.bind((HOST, 0))
# backlog = 0 self.assertRaises(OverflowError, srv.listen, _testcapi.INT_MAX + 1)
srv.listen(0)
srv.close() srv.close()
@unittest.skipUnless(SUPPORTS_IPV6, 'IPv6 required for this test.') @unittest.skipUnless(SUPPORTS_IPV6, 'IPv6 required for this test.')
...@@ -773,10 +826,10 @@ class BasicTCPTest(SocketConnectedTest): ...@@ -773,10 +826,10 @@ class BasicTCPTest(SocketConnectedTest):
big_chunk = 'f' * 2048 big_chunk = 'f' * 2048
self.serv_conn.sendall(big_chunk) self.serv_conn.sendall(big_chunk)
@unittest.skipUnless(hasattr(socket, 'fromfd'),
'socket.fromfd not availble')
def testFromFd(self): def testFromFd(self):
# Testing fromfd() # Testing fromfd()
if not hasattr(socket, "fromfd"):
return # On Windows, this doesn't exist
fd = self.cli_conn.fileno() fd = self.cli_conn.fileno()
sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM) sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
self.addCleanup(sock.close) self.addCleanup(sock.close)
...@@ -809,6 +862,19 @@ class BasicTCPTest(SocketConnectedTest): ...@@ -809,6 +862,19 @@ class BasicTCPTest(SocketConnectedTest):
self.serv_conn.send(MSG) self.serv_conn.send(MSG)
self.serv_conn.shutdown(2) self.serv_conn.shutdown(2)
testShutdown_overflow = test_support.cpython_only(testShutdown)
@test_support.cpython_only
def _testShutdown_overflow(self):
import _testcapi
self.serv_conn.send(MSG)
# Issue 15989
self.assertRaises(OverflowError, self.serv_conn.shutdown,
_testcapi.INT_MAX + 1)
self.assertRaises(OverflowError, self.serv_conn.shutdown,
2 + (_testcapi.UINT_MAX + 1))
self.serv_conn.shutdown(2)
@unittest.skipUnless(thread, 'Threading required for this test.') @unittest.skipUnless(thread, 'Threading required for this test.')
class BasicUDPTest(ThreadedUDPSocketTest): class BasicUDPTest(ThreadedUDPSocketTest):
...@@ -854,6 +920,8 @@ class TCPCloserTest(ThreadedTCPSocketTest): ...@@ -854,6 +920,8 @@ class TCPCloserTest(ThreadedTCPSocketTest):
self.cli.connect((HOST, self.port)) self.cli.connect((HOST, self.port))
time.sleep(1.0) time.sleep(1.0)
@unittest.skipUnless(hasattr(socket, 'socketpair'),
'test needs socket.socketpair()')
@unittest.skipUnless(thread, 'Threading required for this test.') @unittest.skipUnless(thread, 'Threading required for this test.')
class BasicSocketPairTest(SocketPairTest): class BasicSocketPairTest(SocketPairTest):
...@@ -882,7 +950,10 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest): ...@@ -882,7 +950,10 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
def testSetBlocking(self): def testSetBlocking(self):
# Testing whether set blocking works # Testing whether set blocking works
self.serv.setblocking(0) self.serv.setblocking(True)
self.assertIsNone(self.serv.gettimeout())
self.serv.setblocking(False)
self.assertEqual(self.serv.gettimeout(), 0.0)
start = time.time() start = time.time()
try: try:
self.serv.accept() self.serv.accept()
...@@ -894,6 +965,19 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest): ...@@ -894,6 +965,19 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
def _testSetBlocking(self): def _testSetBlocking(self):
pass pass
@test_support.cpython_only
def testSetBlocking_overflow(self):
# Issue 15989
import _testcapi
if _testcapi.UINT_MAX >= _testcapi.ULONG_MAX:
self.skipTest('needs UINT_MAX < ULONG_MAX')
self.serv.setblocking(False)
self.assertEqual(self.serv.gettimeout(), 0.0)
self.serv.setblocking(_testcapi.UINT_MAX + 1)
self.assertIsNone(self.serv.gettimeout())
_testSetBlocking_overflow = test_support.cpython_only(_testSetBlocking)
def testAccept(self): def testAccept(self):
# Testing non-blocking accept # Testing non-blocking accept
self.serv.setblocking(0) self.serv.setblocking(0)
...@@ -961,8 +1045,8 @@ class FileObjectClassTestCase(SocketConnectedTest): ...@@ -961,8 +1045,8 @@ class FileObjectClassTestCase(SocketConnectedTest):
def tearDown(self): def tearDown(self):
self.serv_file.close() self.serv_file.close()
self.assertTrue(self.serv_file.closed) self.assertTrue(self.serv_file.closed)
self.serv_file = None
SocketConnectedTest.tearDown(self) SocketConnectedTest.tearDown(self)
self.serv_file = None
def clientSetUp(self): def clientSetUp(self):
SocketConnectedTest.clientSetUp(self) SocketConnectedTest.clientSetUp(self)
...@@ -1150,6 +1234,64 @@ class LineBufferedFileObjectClassTestCase(FileObjectClassTestCase): ...@@ -1150,6 +1234,64 @@ class LineBufferedFileObjectClassTestCase(FileObjectClassTestCase):
bufsize = 1 # Default-buffered for reading; line-buffered for writing bufsize = 1 # Default-buffered for reading; line-buffered for writing
class SocketMemo(object):
"""A wrapper to keep track of sent data, needed to examine write behaviour"""
def __init__(self, sock):
self._sock = sock
self.sent = []
def send(self, data, flags=0):
n = self._sock.send(data, flags)
self.sent.append(data[:n])
return n
def sendall(self, data, flags=0):
self._sock.sendall(data, flags)
self.sent.append(data)
def __getattr__(self, attr):
return getattr(self._sock, attr)
def getsent(self):
return [e.tobytes() if isinstance(e, memoryview) else e for e in self.sent]
def setUp(self):
FileObjectClassTestCase.setUp(self)
self.serv_file._sock = self.SocketMemo(self.serv_file._sock)
def testLinebufferedWrite(self):
# Write two lines, in small chunks
msg = MSG.strip()
print >> self.serv_file, msg,
print >> self.serv_file, msg
# second line:
print >> self.serv_file, msg,
print >> self.serv_file, msg,
print >> self.serv_file, msg
# third line
print >> self.serv_file, ''
self.serv_file.flush()
msg1 = "%s %s\n"%(msg, msg)
msg2 = "%s %s %s\n"%(msg, msg, msg)
msg3 = "\n"
self.assertEqual(self.serv_file._sock.getsent(), [msg1, msg2, msg3])
def _testLinebufferedWrite(self):
msg = MSG.strip()
msg1 = "%s %s\n"%(msg, msg)
msg2 = "%s %s %s\n"%(msg, msg, msg)
msg3 = "\n"
l1 = self.cli_file.readline()
self.assertEqual(l1, msg1)
l2 = self.cli_file.readline()
self.assertEqual(l2, msg2)
l3 = self.cli_file.readline()
self.assertEqual(l3, msg3)
class SmallBufferedFileObjectClassTestCase(FileObjectClassTestCase): class SmallBufferedFileObjectClassTestCase(FileObjectClassTestCase):
...@@ -1201,7 +1343,26 @@ class NetworkConnectionNoServer(unittest.TestCase): ...@@ -1201,7 +1343,26 @@ class NetworkConnectionNoServer(unittest.TestCase):
port = test_support.find_unused_port() port = test_support.find_unused_port()
with self.assertRaises(socket.error) as cm: with self.assertRaises(socket.error) as cm:
socket.create_connection((HOST, port)) socket.create_connection((HOST, port))
self.assertEqual(cm.exception.errno, errno.ECONNREFUSED)
# Issue #16257: create_connection() calls getaddrinfo() against
# 'localhost'. This may result in an IPV6 addr being returned
# as well as an IPV4 one:
# >>> socket.getaddrinfo('localhost', port, 0, SOCK_STREAM)
# >>> [(2, 2, 0, '', ('127.0.0.1', 41230)),
# (26, 2, 0, '', ('::1', 41230, 0, 0))]
#
# create_connection() enumerates through all the addresses returned
# and if it doesn't successfully bind to any of them, it propagates
# the last exception it encountered.
#
# On Solaris, ENETUNREACH is returned in this circumstance instead
# of ECONNREFUSED. So, if that errno exists, add it to our list of
# expected errnos.
expected_errnos = [ errno.ECONNREFUSED, ]
if hasattr(errno, 'ENETUNREACH'):
expected_errnos.append(errno.ENETUNREACH)
self.assertIn(cm.exception.errno, expected_errnos)
def test_create_connection_timeout(self): def test_create_connection_timeout(self):
# Issue #9792: create_connection() should not recast timeout errors # Issue #9792: create_connection() should not recast timeout errors
...@@ -1359,12 +1520,12 @@ class TCPTimeoutTest(SocketTCPTest): ...@@ -1359,12 +1520,12 @@ class TCPTimeoutTest(SocketTCPTest):
if not ok: if not ok:
self.fail("accept() returned success when we did not expect it") self.fail("accept() returned success when we did not expect it")
@unittest.skipUnless(hasattr(signal, 'alarm'),
'test needs signal.alarm()')
def testInterruptedTimeout(self): def testInterruptedTimeout(self):
# XXX I don't know how to do this test on MSWindows or any other # XXX I don't know how to do this test on MSWindows or any other
# plaform that doesn't support signal.alarm() or os.kill(), though # plaform that doesn't support signal.alarm() or os.kill(), though
# the bug should have existed on all platforms. # the bug should have existed on all platforms.
if not hasattr(signal, "alarm"):
return # can only test on *nix
self.serv.settimeout(5.0) # must be longer than alarm self.serv.settimeout(5.0) # must be longer than alarm
class Alarm(Exception): class Alarm(Exception):
pass pass
...@@ -1424,6 +1585,7 @@ class TestExceptions(unittest.TestCase): ...@@ -1424,6 +1585,7 @@ class TestExceptions(unittest.TestCase):
self.assertTrue(issubclass(socket.gaierror, socket.error)) self.assertTrue(issubclass(socket.gaierror, socket.error))
self.assertTrue(issubclass(socket.timeout, socket.error)) self.assertTrue(issubclass(socket.timeout, socket.error))
@unittest.skipUnless(sys.platform == 'linux', 'Linux specific test')
class TestLinuxAbstractNamespace(unittest.TestCase): class TestLinuxAbstractNamespace(unittest.TestCase):
UNIX_PATH_MAX = 108 UNIX_PATH_MAX = 108
...@@ -1519,6 +1681,23 @@ class BufferIOTest(SocketConnectedTest): ...@@ -1519,6 +1681,23 @@ class BufferIOTest(SocketConnectedTest):
_testRecvFromIntoMemoryview = _testRecvFromIntoArray _testRecvFromIntoMemoryview = _testRecvFromIntoArray
def testRecvFromIntoSmallBuffer(self):
# See issue #20246.
buf = bytearray(8)
self.assertRaises(ValueError, self.cli_conn.recvfrom_into, buf, 1024)
def _testRecvFromIntoSmallBuffer(self):
with test_support.check_py3k_warnings():
buf = buffer(MSG)
self.serv_conn.send(buf)
def testRecvFromIntoEmptyBuffer(self):
buf = bytearray()
self.cli_conn.recvfrom_into(buf)
self.cli_conn.recvfrom_into(buf, 0)
_testRecvFromIntoEmptyBuffer = _testRecvFromIntoArray
TIPC_STYPE = 2000 TIPC_STYPE = 2000
TIPC_LOWER = 200 TIPC_LOWER = 200
...@@ -1538,11 +1717,11 @@ def isTipcAvailable(): ...@@ -1538,11 +1717,11 @@ def isTipcAvailable():
for line in f: for line in f:
if line.startswith("tipc "): if line.startswith("tipc "):
return True return True
if test_support.verbose:
print "TIPC module is not loaded, please 'sudo modprobe tipc'"
return False return False
class TIPCTest (unittest.TestCase): @unittest.skipUnless(isTipcAvailable(),
"TIPC module is not loaded, please 'sudo modprobe tipc'")
class TIPCTest(unittest.TestCase):
def testRDM(self): def testRDM(self):
srv = socket.socket(socket.AF_TIPC, socket.SOCK_RDM) srv = socket.socket(socket.AF_TIPC, socket.SOCK_RDM)
cli = socket.socket(socket.AF_TIPC, socket.SOCK_RDM) cli = socket.socket(socket.AF_TIPC, socket.SOCK_RDM)
...@@ -1562,7 +1741,9 @@ class TIPCTest (unittest.TestCase): ...@@ -1562,7 +1741,9 @@ class TIPCTest (unittest.TestCase):
self.assertEqual(msg, MSG) self.assertEqual(msg, MSG)
class TIPCThreadableTest (unittest.TestCase, ThreadableTest): @unittest.skipUnless(isTipcAvailable(),
"TIPC module is not loaded, please 'sudo modprobe tipc'")
class TIPCThreadableTest(unittest.TestCase, ThreadableTest):
def __init__(self, methodName = 'runTest'): def __init__(self, methodName = 'runTest'):
unittest.TestCase.__init__(self, methodName = methodName) unittest.TestCase.__init__(self, methodName = methodName)
ThreadableTest.__init__(self) ThreadableTest.__init__(self)
...@@ -1615,13 +1796,9 @@ def test_main(): ...@@ -1615,13 +1796,9 @@ def test_main():
NetworkConnectionAttributesTest, NetworkConnectionAttributesTest,
NetworkConnectionBehaviourTest, NetworkConnectionBehaviourTest,
]) ])
if hasattr(socket, "socketpair"): tests.append(BasicSocketPairTest)
tests.append(BasicSocketPairTest) tests.append(TestLinuxAbstractNamespace)
if sys.platform == 'linux2': tests.extend([TIPCTest, TIPCThreadableTest])
tests.append(TestLinuxAbstractNamespace)
if isTipcAvailable():
tests.append(TIPCTest)
tests.append(TIPCThreadableTest)
thread_info = test_support.threading_setup() thread_info = test_support.threading_setup()
test_support.run_unittest(*tests) test_support.run_unittest(*tests)
......
...@@ -8,6 +8,8 @@ import os ...@@ -8,6 +8,8 @@ import os
import select import select
import signal import signal
import socket import socket
import select
import errno
import tempfile import tempfile
import unittest import unittest
import SocketServer import SocketServer
...@@ -25,15 +27,21 @@ TEST_STR = "hello world\n" ...@@ -25,15 +27,21 @@ TEST_STR = "hello world\n"
HOST = test.test_support.HOST HOST = test.test_support.HOST
HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX") HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
requires_unix_sockets = unittest.skipUnless(HAVE_UNIX_SOCKETS,
'requires Unix sockets')
HAVE_FORKING = hasattr(os, "fork") and os.name != "os2" HAVE_FORKING = hasattr(os, "fork") and os.name != "os2"
requires_forking = unittest.skipUnless(HAVE_FORKING, 'requires forking')
def signal_alarm(n): def signal_alarm(n):
"""Call signal.alarm when it exists (i.e. not on Windows).""" """Call signal.alarm when it exists (i.e. not on Windows)."""
if hasattr(signal, 'alarm'): if hasattr(signal, 'alarm'):
signal.alarm(n) signal.alarm(n)
# Remember real select() to avoid interferences with mocking
_real_select = select.select
def receive(sock, n, timeout=20): def receive(sock, n, timeout=20):
r, w, x = select.select([sock], [], [], timeout) r, w, x = _real_select([sock], [], [], timeout)
if sock in r: if sock in r:
return sock.recv(n) return sock.recv(n)
else: else:
...@@ -53,7 +61,7 @@ if HAVE_UNIX_SOCKETS: ...@@ -53,7 +61,7 @@ if HAVE_UNIX_SOCKETS:
def simple_subprocess(testcase): def simple_subprocess(testcase):
pid = os.fork() pid = os.fork()
if pid == 0: if pid == 0:
# Don't throw 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 yield None
pid2, status = os.waitpid(pid, 0) pid2, status = os.waitpid(pid, 0)
...@@ -150,6 +158,8 @@ class SocketServerTest(unittest.TestCase): ...@@ -150,6 +158,8 @@ class SocketServerTest(unittest.TestCase):
if verbose: print "waiting for server" if verbose: print "waiting for server"
server.shutdown() server.shutdown()
t.join() t.join()
server.server_close()
self.assertRaises(socket.error, server.socket.fileno)
if verbose: print "done" if verbose: print "done"
def stream_examine(self, proto, addr): def stream_examine(self, proto, addr):
...@@ -183,31 +193,33 @@ class SocketServerTest(unittest.TestCase): ...@@ -183,31 +193,33 @@ class SocketServerTest(unittest.TestCase):
SocketServer.StreamRequestHandler, SocketServer.StreamRequestHandler,
self.stream_examine) self.stream_examine)
if HAVE_FORKING: @requires_forking
def test_ForkingTCPServer(self): def test_ForkingTCPServer(self):
with simple_subprocess(self): with simple_subprocess(self):
self.run_server(SocketServer.ForkingTCPServer, self.run_server(SocketServer.ForkingTCPServer,
SocketServer.StreamRequestHandler,
self.stream_examine)
if HAVE_UNIX_SOCKETS:
def test_UnixStreamServer(self):
self.run_server(SocketServer.UnixStreamServer,
SocketServer.StreamRequestHandler, SocketServer.StreamRequestHandler,
self.stream_examine) self.stream_examine)
def test_ThreadingUnixStreamServer(self): @requires_unix_sockets
self.run_server(SocketServer.ThreadingUnixStreamServer, def test_UnixStreamServer(self):
self.run_server(SocketServer.UnixStreamServer,
SocketServer.StreamRequestHandler,
self.stream_examine)
@requires_unix_sockets
def test_ThreadingUnixStreamServer(self):
self.run_server(SocketServer.ThreadingUnixStreamServer,
SocketServer.StreamRequestHandler,
self.stream_examine)
@requires_unix_sockets
@requires_forking
def test_ForkingUnixStreamServer(self):
with simple_subprocess(self):
self.run_server(ForkingUnixStreamServer,
SocketServer.StreamRequestHandler, SocketServer.StreamRequestHandler,
self.stream_examine) self.stream_examine)
if HAVE_FORKING:
def test_ForkingUnixStreamServer(self):
with simple_subprocess(self):
self.run_server(ForkingUnixStreamServer,
SocketServer.StreamRequestHandler,
self.stream_examine)
def test_UDPServer(self): def test_UDPServer(self):
self.run_server(SocketServer.UDPServer, self.run_server(SocketServer.UDPServer,
SocketServer.DatagramRequestHandler, SocketServer.DatagramRequestHandler,
...@@ -218,32 +230,66 @@ class SocketServerTest(unittest.TestCase): ...@@ -218,32 +230,66 @@ class SocketServerTest(unittest.TestCase):
SocketServer.DatagramRequestHandler, SocketServer.DatagramRequestHandler,
self.dgram_examine) self.dgram_examine)
if HAVE_FORKING: @requires_forking
def test_ForkingUDPServer(self): def test_ForkingUDPServer(self):
with simple_subprocess(self): with simple_subprocess(self):
self.run_server(SocketServer.ForkingUDPServer, self.run_server(SocketServer.ForkingUDPServer,
SocketServer.DatagramRequestHandler, SocketServer.DatagramRequestHandler,
self.dgram_examine) self.dgram_examine)
@contextlib.contextmanager
def mocked_select_module(self):
"""Mocks the select.select() call to raise EINTR for first call"""
old_select = select.select
class MockSelect:
def __init__(self):
self.called = 0
def __call__(self, *args):
self.called += 1
if self.called == 1:
# raise the exception on first call
raise select.error(errno.EINTR, os.strerror(errno.EINTR))
else:
# Return real select value for consecutive calls
return old_select(*args)
select.select = MockSelect()
try:
yield select.select
finally:
select.select = old_select
def test_InterruptServerSelectCall(self):
with self.mocked_select_module() as mock_select:
pid = self.run_server(SocketServer.TCPServer,
SocketServer.StreamRequestHandler,
self.stream_examine)
# Make sure select was called again:
self.assertGreater(mock_select.called, 1)
# Alas, on Linux (at least) recvfrom() doesn't return a meaningful # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
# client address so this cannot work: # client address so this cannot work:
# if HAVE_UNIX_SOCKETS: # @requires_unix_sockets
# def test_UnixDatagramServer(self): # def test_UnixDatagramServer(self):
# self.run_server(SocketServer.UnixDatagramServer, # self.run_server(SocketServer.UnixDatagramServer,
# SocketServer.DatagramRequestHandler, # SocketServer.DatagramRequestHandler,
# self.dgram_examine) # self.dgram_examine)
# #
# def test_ThreadingUnixDatagramServer(self): # @requires_unix_sockets
# self.run_server(SocketServer.ThreadingUnixDatagramServer, # def test_ThreadingUnixDatagramServer(self):
# SocketServer.DatagramRequestHandler, # self.run_server(SocketServer.ThreadingUnixDatagramServer,
# self.dgram_examine) # SocketServer.DatagramRequestHandler,
# self.dgram_examine)
# #
# if HAVE_FORKING: # @requires_unix_sockets
# def test_ForkingUnixDatagramServer(self): # @requires_forking
# self.run_server(SocketServer.ForkingUnixDatagramServer, # def test_ForkingUnixDatagramServer(self):
# SocketServer.DatagramRequestHandler, # self.run_server(SocketServer.ForkingUnixDatagramServer,
# self.dgram_examine) # SocketServer.DatagramRequestHandler,
# self.dgram_examine)
@reap_threads @reap_threads
def test_shutdown(self): def test_shutdown(self):
...@@ -270,6 +316,16 @@ class SocketServerTest(unittest.TestCase): ...@@ -270,6 +316,16 @@ class SocketServerTest(unittest.TestCase):
for t, s in threads: for t, s in threads:
t.join() t.join()
def test_tcpserver_bind_leak(self):
# Issue #22435: the server socket wouldn't be closed if bind()/listen()
# failed.
# Create many servers for which bind() will fail, to see if this result
# in FD exhaustion.
for i in range(1024):
with self.assertRaises(OverflowError):
SocketServer.TCPServer((HOST, -1),
SocketServer.StreamRequestHandler)
def test_main(): def test_main():
if imp.lock_held(): if imp.lock_held():
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -14,6 +14,10 @@ try: ...@@ -14,6 +14,10 @@ try:
import resource import resource
except ImportError: except ImportError:
resource = None resource = None
try:
import threading
except ImportError:
threading = None
mswindows = (sys.platform == "win32") mswindows = (sys.platform == "win32")
...@@ -28,16 +32,6 @@ else: ...@@ -28,16 +32,6 @@ else:
SETBINARY = '' SETBINARY = ''
try:
mkstemp = tempfile.mkstemp
except AttributeError:
# tempfile.mkstemp is not available
def mkstemp():
"""Replacement for mkstemp, calling mktemp."""
fname = tempfile.mktemp()
return os.open(fname, os.O_RDWR|os.O_CREAT), fname
class BaseTestCase(unittest.TestCase): class BaseTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
# Try to minimize the number of children we have so this test # Try to minimize the number of children we have so this test
...@@ -58,6 +52,18 @@ class BaseTestCase(unittest.TestCase): ...@@ -58,6 +52,18 @@ class BaseTestCase(unittest.TestCase):
self.assertEqual(actual, expected, msg) self.assertEqual(actual, expected, msg)
class PopenTestException(Exception):
pass
class PopenExecuteChildRaises(subprocess.Popen):
"""Popen subclass for testing cleanup of subprocess.PIPE filehandles when
_execute_child fails.
"""
def _execute_child(self, *args, **kwargs):
raise PopenTestException("Forced Exception for Test")
class ProcessTestCase(BaseTestCase): class ProcessTestCase(BaseTestCase):
def test_call_seq(self): def test_call_seq(self):
...@@ -138,16 +144,27 @@ class ProcessTestCase(BaseTestCase): ...@@ -138,16 +144,27 @@ class ProcessTestCase(BaseTestCase):
self.assertEqual(p.stdin, None) self.assertEqual(p.stdin, None)
def test_stdout_none(self): def test_stdout_none(self):
# .stdout is None when not redirected # .stdout is None when not redirected, and the child's stdout will
p = subprocess.Popen([sys.executable, "-c", # be inherited from the parent. In order to test this we run a
'print " this bit of output is from a ' # subprocess in a subprocess:
'test of stdout in a different ' # this_test
'process ..."'], # \-- subprocess created by this test (parent)
stdin=subprocess.PIPE, stderr=subprocess.PIPE) # \-- subprocess created by the parent subprocess (child)
self.addCleanup(p.stdin.close) # The parent doesn't specify stdout, so the child will use the
# parent's stdout. This test checks that the message printed by the
# child goes to the parent stdout. The parent also checks that the
# child's stdout is None. See #11963.
code = ('import sys; from subprocess import Popen, PIPE;'
'p = Popen([sys.executable, "-c", "print \'test_stdout_none\'"],'
' stdin=PIPE, stderr=PIPE);'
'p.wait(); assert p.stdout is None;')
p = subprocess.Popen([sys.executable, "-c", code],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.addCleanup(p.stdout.close)
self.addCleanup(p.stderr.close) self.addCleanup(p.stderr.close)
p.wait() out, err = p.communicate()
self.assertEqual(p.stdout, None) self.assertEqual(p.returncode, 0, err)
self.assertEqual(out.rstrip(), 'test_stdout_none')
def test_stderr_none(self): def test_stderr_none(self):
# .stderr is None when not redirected # .stderr is None when not redirected
...@@ -296,9 +313,22 @@ class ProcessTestCase(BaseTestCase): ...@@ -296,9 +313,22 @@ class ProcessTestCase(BaseTestCase):
def test_stdout_filedes_of_stdout(self): def test_stdout_filedes_of_stdout(self):
# stdout is set to 1 (#1531862). # stdout is set to 1 (#1531862).
cmd = r"import sys, os; sys.exit(os.write(sys.stdout.fileno(), '.\n'))" # To avoid printing the text on stdout, we do something similar to
rc = subprocess.call([sys.executable, "-c", cmd], stdout=1) # test_stdout_none (see above). The parent subprocess calls the child
self.assertEqual(rc, 2) # subprocess passing stdout=1, and this test uses stdout=PIPE in
# order to capture and check the output of the parent. See #11963.
code = ('import sys, subprocess; '
'rc = subprocess.call([sys.executable, "-c", '
' "import os, sys; sys.exit(os.write(sys.stdout.fileno(), '
'\'test with stdout=1\'))"], stdout=1); '
'assert rc == 18')
p = subprocess.Popen([sys.executable, "-c", code],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.addCleanup(p.stdout.close)
self.addCleanup(p.stderr.close)
out, err = p.communicate()
self.assertEqual(p.returncode, 0, err)
self.assertEqual(out.rstrip(), 'test with stdout=1')
def test_cwd(self): def test_cwd(self):
tmpdir = tempfile.gettempdir() tmpdir = tempfile.gettempdir()
...@@ -526,6 +556,7 @@ class ProcessTestCase(BaseTestCase): ...@@ -526,6 +556,7 @@ class ProcessTestCase(BaseTestCase):
finally: finally:
for h in handles: for h in handles:
os.close(h) os.close(h)
test_support.unlink(test_support.TESTFN)
def test_list2cmdline(self): def test_list2cmdline(self):
self.assertEqual(subprocess.list2cmdline(['a b c', 'd', 'e']), self.assertEqual(subprocess.list2cmdline(['a b c', 'd', 'e']),
...@@ -592,12 +623,42 @@ class ProcessTestCase(BaseTestCase): ...@@ -592,12 +623,42 @@ class ProcessTestCase(BaseTestCase):
if c.exception.errno not in (errno.ENOENT, errno.EACCES): if c.exception.errno not in (errno.ENOENT, errno.EACCES):
raise c.exception raise c.exception
@unittest.skipIf(threading is None, "threading required")
def test_double_close_on_error(self):
# Issue #18851
fds = []
def open_fds():
for i in range(20):
fds.extend(os.pipe())
time.sleep(0.001)
t = threading.Thread(target=open_fds)
t.start()
try:
with self.assertRaises(EnvironmentError):
subprocess.Popen(['nonexisting_i_hope'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
finally:
t.join()
exc = None
for fd in fds:
# If a double close occurred, some of those fds will
# already have been closed by mistake, and os.close()
# here will raise.
try:
os.close(fd)
except OSError as e:
exc = e
if exc is not None:
raise exc
def test_handles_closed_on_exception(self): def test_handles_closed_on_exception(self):
# If CreateProcess exits with an error, ensure the # If CreateProcess exits with an error, ensure the
# duplicate output handles are released # duplicate output handles are released
ifhandle, ifname = mkstemp() ifhandle, ifname = tempfile.mkstemp()
ofhandle, ofname = mkstemp() ofhandle, ofname = tempfile.mkstemp()
efhandle, efname = mkstemp() efhandle, efname = tempfile.mkstemp()
try: try:
subprocess.Popen (["*"], stdin=ifhandle, stdout=ofhandle, subprocess.Popen (["*"], stdin=ifhandle, stdout=ofhandle,
stderr=efhandle) stderr=efhandle)
...@@ -631,6 +692,27 @@ class ProcessTestCase(BaseTestCase): ...@@ -631,6 +692,27 @@ class ProcessTestCase(BaseTestCase):
time.sleep(2) time.sleep(2)
p.communicate("x" * 2**20) p.communicate("x" * 2**20)
# This test is Linux-ish specific for simplicity to at least have
# some coverage. It is not a platform specific bug.
@unittest.skipUnless(os.path.isdir('/proc/%d/fd' % os.getpid()),
"Linux specific")
def test_failed_child_execute_fd_leak(self):
"""Test for the fork() failure fd leak reported in issue16327."""
fd_directory = '/proc/%d/fd' % os.getpid()
fds_before_popen = os.listdir(fd_directory)
with self.assertRaises(PopenTestException):
PopenExecuteChildRaises(
[sys.executable, '-c', 'pass'], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# NOTE: This test doesn't verify that the real _execute_child
# does not close the file descriptors itself on the way out
# during an exception. Code inspection has confirmed that.
fds_after_exception = os.listdir(fd_directory)
self.assertEqual(fds_before_popen, fds_after_exception)
# context manager # context manager
class _SuppressCoreFiles(object): class _SuppressCoreFiles(object):
"""Try to prevent core files from being created.""" """Try to prevent core files from being created."""
...@@ -717,9 +799,56 @@ class POSIXProcessTestCase(BaseTestCase): ...@@ -717,9 +799,56 @@ class POSIXProcessTestCase(BaseTestCase):
self.addCleanup(p.stdout.close) self.addCleanup(p.stdout.close)
self.assertEqual(p.stdout.read(), "apple") self.assertEqual(p.stdout.read(), "apple")
class _TestExecuteChildPopen(subprocess.Popen):
"""Used to test behavior at the end of _execute_child."""
def __init__(self, testcase, *args, **kwargs):
self._testcase = testcase
subprocess.Popen.__init__(self, *args, **kwargs)
def _execute_child(
self, args, executable, preexec_fn, close_fds, cwd, env,
universal_newlines, startupinfo, creationflags, shell, to_close,
p2cread, p2cwrite,
c2pread, c2pwrite,
errread, errwrite):
try:
subprocess.Popen._execute_child(
self, args, executable, preexec_fn, close_fds,
cwd, env, universal_newlines,
startupinfo, creationflags, shell, to_close,
p2cread, p2cwrite,
c2pread, c2pwrite,
errread, errwrite)
finally:
# Open a bunch of file descriptors and verify that
# none of them are the same as the ones the Popen
# instance is using for stdin/stdout/stderr.
devzero_fds = [os.open("/dev/zero", os.O_RDONLY)
for _ in range(8)]
try:
for fd in devzero_fds:
self._testcase.assertNotIn(
fd, (p2cwrite, c2pread, errread))
finally:
for fd in devzero_fds:
os.close(fd)
@unittest.skipIf(not os.path.exists("/dev/zero"), "/dev/zero required.")
def test_preexec_errpipe_does_not_double_close_pipes(self):
"""Issue16140: Don't double close pipes on preexec error."""
def raise_it():
raise RuntimeError("force the _execute_child() errpipe_data path.")
with self.assertRaises(RuntimeError):
self._TestExecuteChildPopen(
self, [sys.executable, "-c", "pass"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, preexec_fn=raise_it)
def test_args_string(self): def test_args_string(self):
# args is a string # args is a string
f, fname = mkstemp() f, fname = tempfile.mkstemp()
os.write(f, "#!/bin/sh\n") os.write(f, "#!/bin/sh\n")
os.write(f, "exec '%s' -c 'import sys; sys.exit(47)'\n" % os.write(f, "exec '%s' -c 'import sys; sys.exit(47)'\n" %
sys.executable) sys.executable)
...@@ -763,7 +892,7 @@ class POSIXProcessTestCase(BaseTestCase): ...@@ -763,7 +892,7 @@ class POSIXProcessTestCase(BaseTestCase):
def test_call_string(self): def test_call_string(self):
# call() function with string argument on UNIX # call() function with string argument on UNIX
f, fname = mkstemp() f, fname = tempfile.mkstemp()
os.write(f, "#!/bin/sh\n") os.write(f, "#!/bin/sh\n")
os.write(f, "exec '%s' -c 'import sys; sys.exit(47)'\n" % os.write(f, "exec '%s' -c 'import sys; sys.exit(47)'\n" %
sys.executable) sys.executable)
...@@ -812,6 +941,29 @@ class POSIXProcessTestCase(BaseTestCase): ...@@ -812,6 +941,29 @@ class POSIXProcessTestCase(BaseTestCase):
getattr(p, method)(*args) getattr(p, method)(*args)
return p return p
@unittest.skipIf(sys.platform.startswith(('netbsd', 'openbsd')),
"Due to known OS bug (issue #16762)")
def _kill_dead_process(self, method, *args):
# Do not inherit file handles from the parent.
# It should fix failures on some platforms.
p = subprocess.Popen([sys.executable, "-c", """if 1:
import sys, time
sys.stdout.write('x\\n')
sys.stdout.flush()
"""],
close_fds=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# Wait for the interpreter to be completely initialized before
# sending any signal.
p.stdout.read(1)
# The process should end after this
time.sleep(1)
# This shouldn't raise even though the child is now dead
getattr(p, method)(*args)
p.communicate()
def test_send_signal(self): def test_send_signal(self):
p = self._kill_process('send_signal', signal.SIGINT) p = self._kill_process('send_signal', signal.SIGINT)
_, stderr = p.communicate() _, stderr = p.communicate()
...@@ -830,6 +982,18 @@ class POSIXProcessTestCase(BaseTestCase): ...@@ -830,6 +982,18 @@ class POSIXProcessTestCase(BaseTestCase):
self.assertStderrEqual(stderr, '') self.assertStderrEqual(stderr, '')
self.assertEqual(p.wait(), -signal.SIGTERM) self.assertEqual(p.wait(), -signal.SIGTERM)
def test_send_signal_dead(self):
# Sending a signal to a dead process
self._kill_dead_process('send_signal', signal.SIGINT)
def test_kill_dead(self):
# Killing a dead process
self._kill_dead_process('kill')
def test_terminate_dead(self):
# Terminating a dead process
self._kill_dead_process('terminate')
def check_close_std_fds(self, fds): def check_close_std_fds(self, fds):
# Issue #9905: test that subprocess pipes still work properly with # Issue #9905: test that subprocess pipes still work properly with
# some standard fds closed # some standard fds closed
...@@ -884,7 +1048,7 @@ class POSIXProcessTestCase(BaseTestCase): ...@@ -884,7 +1048,7 @@ class POSIXProcessTestCase(BaseTestCase):
def check_swap_fds(self, stdin_no, stdout_no, stderr_no): def check_swap_fds(self, stdin_no, stdout_no, stderr_no):
# open up some temporary files # open up some temporary files
temps = [mkstemp() for i in range(3)] temps = [tempfile.mkstemp() for i in range(3)]
temp_fds = [fd for fd, fname in temps] temp_fds = [fd for fd, fname in temps]
try: try:
# unlink the files -- we won't need to reopen them # unlink the files -- we won't need to reopen them
...@@ -1126,6 +1290,31 @@ class Win32ProcessTestCase(BaseTestCase): ...@@ -1126,6 +1290,31 @@ class Win32ProcessTestCase(BaseTestCase):
returncode = p.wait() returncode = p.wait()
self.assertNotEqual(returncode, 0) self.assertNotEqual(returncode, 0)
def _kill_dead_process(self, method, *args):
p = subprocess.Popen([sys.executable, "-c", """if 1:
import sys, time
sys.stdout.write('x\\n')
sys.stdout.flush()
sys.exit(42)
"""],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.addCleanup(p.stdout.close)
self.addCleanup(p.stderr.close)
self.addCleanup(p.stdin.close)
# Wait for the interpreter to be completely initialized before
# sending any signal.
p.stdout.read(1)
# The process should end after this
time.sleep(1)
# This shouldn't raise even though the child is now dead
getattr(p, method)(*args)
_, stderr = p.communicate()
self.assertStderrEqual(stderr, b'')
rc = p.wait()
self.assertEqual(rc, 42)
def test_send_signal(self): def test_send_signal(self):
self._kill_process('send_signal', signal.SIGTERM) self._kill_process('send_signal', signal.SIGTERM)
...@@ -1135,6 +1324,15 @@ class Win32ProcessTestCase(BaseTestCase): ...@@ -1135,6 +1324,15 @@ class Win32ProcessTestCase(BaseTestCase):
def test_terminate(self): def test_terminate(self):
self._kill_process('terminate') self._kill_process('terminate')
def test_send_signal_dead(self):
self._kill_dead_process('send_signal', signal.SIGTERM)
def test_kill_dead(self):
self._kill_dead_process('kill')
def test_terminate_dead(self):
self._kill_dead_process('terminate')
@unittest.skipUnless(getattr(subprocess, '_has_poll', False), @unittest.skipUnless(getattr(subprocess, '_has_poll', False),
"poll system call not supported") "poll system call not supported")
...@@ -1171,7 +1369,7 @@ class CommandsWithSpaces (BaseTestCase): ...@@ -1171,7 +1369,7 @@ class CommandsWithSpaces (BaseTestCase):
def setUp(self): def setUp(self):
super(CommandsWithSpaces, self).setUp() super(CommandsWithSpaces, self).setUp()
f, fname = mkstemp(".py", "te st") f, fname = tempfile.mkstemp(".py", "te st")
self.fname = fname.lower () self.fname = fname.lower ()
os.write(f, b"import sys;" os.write(f, b"import sys;"
b"sys.stdout.write('%d %s' % (len(sys.argv), [a.lower () for a in sys.argv]))" b"sys.stdout.write('%d %s' % (len(sys.argv), [a.lower () for a in sys.argv]))"
......
...@@ -3,6 +3,7 @@ import telnetlib ...@@ -3,6 +3,7 @@ import telnetlib
import time import time
import Queue import Queue
import unittest
from unittest import TestCase from unittest import TestCase
from test import test_support from test import test_support
threading = test_support.import_module('threading') threading = test_support.import_module('threading')
...@@ -91,6 +92,14 @@ class GeneralTests(TestCase): ...@@ -91,6 +92,14 @@ class GeneralTests(TestCase):
self.assertEqual(telnet.sock.gettimeout(), 30) self.assertEqual(telnet.sock.gettimeout(), 30)
telnet.sock.close() telnet.sock.close()
def testGetters(self):
# Test telnet getter methods
telnet = telnetlib.Telnet(HOST, self.port, timeout=30)
t_sock = telnet.sock
self.assertEqual(telnet.get_socket(), t_sock)
self.assertEqual(telnet.fileno(), t_sock.fileno())
telnet.sock.close()
def _read_setUp(self): def _read_setUp(self):
self.evt = threading.Event() self.evt = threading.Event()
self.dataq = Queue.Queue() self.dataq = Queue.Queue()
...@@ -135,6 +144,28 @@ class ReadTests(TestCase): ...@@ -135,6 +144,28 @@ class ReadTests(TestCase):
self.assertEqual(data, want[0]) self.assertEqual(data, want[0])
self.assertEqual(telnet.read_all(), 'not seen') self.assertEqual(telnet.read_all(), 'not seen')
def test_read_until_with_poll(self):
"""Use select.poll() to implement telnet.read_until()."""
want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
if not telnet._has_poll:
raise unittest.SkipTest('select.poll() is required')
telnet._has_poll = True
self.dataq.join()
data = telnet.read_until('match')
self.assertEqual(data, ''.join(want[:-2]))
def test_read_until_with_select(self):
"""Use select.select() to implement telnet.read_until()."""
want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
telnet._has_poll = False
self.dataq.join()
data = telnet.read_until('match')
self.assertEqual(data, ''.join(want[:-2]))
def test_read_all_A(self): def test_read_all_A(self):
""" """
read_all() read_all()
...@@ -146,7 +177,6 @@ class ReadTests(TestCase): ...@@ -146,7 +177,6 @@ class ReadTests(TestCase):
self.dataq.join() self.dataq.join()
data = telnet.read_all() data = telnet.read_all()
self.assertEqual(data, ''.join(want[:-1])) self.assertEqual(data, ''.join(want[:-1]))
return
def _test_blocking(self, func): def _test_blocking(self, func):
self.dataq.put([self.block_long, EOF_sigil]) self.dataq.put([self.block_long, EOF_sigil])
...@@ -357,8 +387,75 @@ class OptionTests(TestCase): ...@@ -357,8 +387,75 @@ class OptionTests(TestCase):
self.assertEqual('', telnet.read_sb_data()) self.assertEqual('', telnet.read_sb_data())
nego.sb_getter = None # break the nego => telnet cycle nego.sb_getter = None # break the nego => telnet cycle
class ExpectTests(TestCase):
def setUp(self):
self.evt = threading.Event()
self.dataq = Queue.Queue()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(10)
self.port = test_support.bind_port(self.sock)
self.thread = threading.Thread(target=server, args=(self.evt,self.sock,
self.dataq))
self.thread.start()
self.evt.wait()
def tearDown(self):
self.thread.join()
# use a similar approach to testing timeouts as test_timeout.py
# these will never pass 100% but make the fuzz big enough that it is rare
block_long = 0.6
block_short = 0.3
def test_expect_A(self):
"""
expect(expected, [timeout])
Read until the expected string has been seen, or a timeout is
hit (default is no timeout); may block.
"""
want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
self.dataq.join()
(_,_,data) = telnet.expect(['match'])
self.assertEqual(data, ''.join(want[:-2]))
def test_expect_B(self):
# test the timeout - it does NOT raise socket.timeout
want = ['hello', self.block_long, 'not seen', EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
self.dataq.join()
(_,_,data) = telnet.expect(['not seen'], self.block_short)
self.assertEqual(data, want[0])
self.assertEqual(telnet.read_all(), 'not seen')
def test_expect_with_poll(self):
"""Use select.poll() to implement telnet.expect()."""
want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
if not telnet._has_poll:
raise unittest.SkipTest('select.poll() is required')
telnet._has_poll = True
self.dataq.join()
(_,_,data) = telnet.expect(['match'])
self.assertEqual(data, ''.join(want[:-2]))
def test_expect_with_select(self):
"""Use select.select() to implement telnet.expect()."""
want = ['x' * 10, 'match', 'y' * 10, EOF_sigil]
self.dataq.put(want)
telnet = telnetlib.Telnet(HOST, self.port)
telnet._has_poll = False
self.dataq.join()
(_,_,data) = telnet.expect(['match'])
self.assertEqual(data, ''.join(want[:-2]))
def test_main(verbose=None): def test_main(verbose=None):
test_support.run_unittest(GeneralTests, ReadTests, OptionTests) test_support.run_unittest(GeneralTests, ReadTests, OptionTests,
ExpectTests)
if __name__ == '__main__': if __name__ == '__main__':
test_main() test_main()
...@@ -7,7 +7,7 @@ import time ...@@ -7,7 +7,7 @@ import time
import sys import sys
import weakref import weakref
import lock_tests from test import lock_tests
NUMTASKS = 10 NUMTASKS = 10
NUMTRIPS = 3 NUMTRIPS = 3
...@@ -70,39 +70,35 @@ class ThreadRunningTests(BasicThreadTest): ...@@ -70,39 +70,35 @@ class ThreadRunningTests(BasicThreadTest):
thread.stack_size(0) thread.stack_size(0)
self.assertEqual(thread.stack_size(), 0, "stack_size not reset to default") self.assertEqual(thread.stack_size(), 0, "stack_size not reset to default")
if os.name not in ("nt", "os2", "posix"): @unittest.skipIf(os.name not in ("nt", "os2", "posix"), 'test meant for nt, os2, and posix')
return def test_nt_and_posix_stack_size(self):
tss_supported = True
try: try:
thread.stack_size(4096) thread.stack_size(4096)
except ValueError: except ValueError:
verbose_print("caught expected ValueError setting " verbose_print("caught expected ValueError setting "
"stack_size(4096)") "stack_size(4096)")
except thread.error: except thread.error:
tss_supported = False self.skipTest("platform does not support changing thread stack "
verbose_print("platform does not support changing thread stack " "size")
"size")
fail_msg = "stack_size(%d) failed - should succeed"
if tss_supported: for tss in (262144, 0x100000, 0):
fail_msg = "stack_size(%d) failed - should succeed" thread.stack_size(tss)
for tss in (262144, 0x100000, 0): self.assertEqual(thread.stack_size(), tss, fail_msg % tss)
thread.stack_size(tss) verbose_print("successfully set stack_size(%d)" % tss)
self.assertEqual(thread.stack_size(), tss, fail_msg % tss)
verbose_print("successfully set stack_size(%d)" % tss) for tss in (262144, 0x100000):
verbose_print("trying stack_size = (%d)" % tss)
for tss in (262144, 0x100000): self.next_ident = 0
verbose_print("trying stack_size = (%d)" % tss) self.created = 0
self.next_ident = 0 for i in range(NUMTASKS):
self.created = 0 self.newtask()
for i in range(NUMTASKS):
self.newtask() verbose_print("waiting for all tasks to complete")
self.done_mutex.acquire()
verbose_print("waiting for all tasks to complete") verbose_print("all tasks done")
self.done_mutex.acquire()
verbose_print("all tasks done") thread.stack_size(0)
thread.stack_size(0)
def test__count(self): def test__count(self):
# Test the _count() function. # Test the _count() function.
...@@ -130,6 +126,29 @@ class ThreadRunningTests(BasicThreadTest): ...@@ -130,6 +126,29 @@ class ThreadRunningTests(BasicThreadTest):
time.sleep(0.01) time.sleep(0.01)
self.assertEqual(thread._count(), orig) self.assertEqual(thread._count(), orig)
def test_save_exception_state_on_error(self):
# See issue #14474
def task():
started.release()
raise SyntaxError
def mywrite(self, *args):
try:
raise ValueError
except ValueError:
pass
real_write(self, *args)
c = thread._count()
started = thread.allocate_lock()
with test_support.captured_output("stderr") as stderr:
real_write = stderr.write
stderr.write = mywrite
started.acquire()
thread.start_new_thread(task, ())
started.acquire()
while thread._count() > c:
time.sleep(0.01)
self.assertIn("Traceback", stderr.getvalue())
class Barrier: class Barrier:
def __init__(self, num_threads): def __init__(self, num_threads):
......
# Very rudimentary test of threading module # Very rudimentary test of threading module
import test.test_support import test.test_support
from test.test_support import verbose from test.test_support import verbose, cpython_only
from test.script_helper import assert_python_ok
import random import random
import re import re
import sys import sys
...@@ -12,8 +14,12 @@ import unittest ...@@ -12,8 +14,12 @@ import unittest
import weakref import weakref
import os import os
import subprocess import subprocess
try:
import _testcapi
except ImportError:
_testcapi = None
import lock_tests import lock_tests # gevent: use local copy
# A trivial mutable counter. # A trivial mutable counter.
class Counter(object): class Counter(object):
...@@ -123,9 +129,7 @@ class ThreadTests(BaseTestCase): ...@@ -123,9 +129,7 @@ class ThreadTests(BaseTestCase):
try: try:
threading.stack_size(262144) threading.stack_size(262144)
except thread.error: except thread.error:
if verbose: self.skipTest('platform does not support changing thread stack size')
print 'platform does not support changing thread stack size'
return
self.test_various_ops() self.test_various_ops()
threading.stack_size(0) threading.stack_size(0)
...@@ -136,9 +140,7 @@ class ThreadTests(BaseTestCase): ...@@ -136,9 +140,7 @@ class ThreadTests(BaseTestCase):
try: try:
threading.stack_size(0x100000) threading.stack_size(0x100000)
except thread.error: except thread.error:
if verbose: self.skipTest('platform does not support changing thread stack size')
print 'platform does not support changing thread stack size'
return
self.test_various_ops() self.test_various_ops()
threading.stack_size(0) threading.stack_size(0)
...@@ -165,9 +167,7 @@ class ThreadTests(BaseTestCase): ...@@ -165,9 +167,7 @@ class ThreadTests(BaseTestCase):
try: try:
import ctypes import ctypes
except ImportError: except ImportError:
if verbose: self.skipTest('requires ctypes')
print "test_PyThreadState_SetAsyncExc can't import ctypes"
return # can't do anything
set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc
...@@ -273,9 +273,7 @@ class ThreadTests(BaseTestCase): ...@@ -273,9 +273,7 @@ class ThreadTests(BaseTestCase):
try: try:
import ctypes import ctypes
except ImportError: except ImportError:
if verbose: self.skipTest('requires ctypes')
print("test_finalize_with_runnning_thread can't import ctypes")
return # can't do anything
rc = subprocess.call([sys.executable, "-c", """if 1: rc = subprocess.call([sys.executable, "-c", """if 1:
import ctypes, sys, time, thread import ctypes, sys, time, thread
...@@ -414,6 +412,73 @@ class ThreadTests(BaseTestCase): ...@@ -414,6 +412,73 @@ class ThreadTests(BaseTestCase):
msg=('%d references still around' % msg=('%d references still around' %
sys.getrefcount(weak_raising_cyclic_object()))) sys.getrefcount(weak_raising_cyclic_object())))
@unittest.skipUnless(hasattr(os, 'fork'), 'test needs fork()')
def test_dummy_thread_after_fork(self):
# Issue #14308: a dummy thread in the active list doesn't mess up
# the after-fork mechanism.
code = """if 1:
import thread, threading, os, time
def background_thread(evt):
# Creates and registers the _DummyThread instance
threading.current_thread()
evt.set()
time.sleep(10)
evt = threading.Event()
thread.start_new_thread(background_thread, (evt,))
evt.wait()
assert threading.active_count() == 2, threading.active_count()
if os.fork() == 0:
assert threading.active_count() == 1, threading.active_count()
os._exit(0)
else:
os.wait()
"""
_, out, err = assert_python_ok("-c", code)
self.assertEqual(out, '')
self.assertEqual(err, '')
@unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
def test_is_alive_after_fork(self):
# Try hard to trigger #18418: is_alive() could sometimes be True on
# threads that vanished after a fork.
old_interval = sys.getcheckinterval()
# Make the bug more likely to manifest.
sys.setcheckinterval(10)
try:
for i in range(20):
t = threading.Thread(target=lambda: None)
t.start()
pid = os.fork()
if pid == 0:
os._exit(1 if t.is_alive() else 0)
else:
t.join()
pid, status = os.waitpid(pid, 0)
self.assertEqual(0, status)
finally:
sys.setcheckinterval(old_interval)
def test_BoundedSemaphore_limit(self):
# BoundedSemaphore should raise ValueError if released too often.
for limit in range(1, 10):
bs = threading.BoundedSemaphore(limit)
threads = [threading.Thread(target=bs.acquire)
for _ in range(limit)]
for t in threads:
t.start()
for t in threads:
t.join()
threads = [threading.Thread(target=bs.release)
for _ in range(limit)]
for t in threads:
t.start()
for t in threads:
t.join()
self.assertRaises(ValueError, bs.release)
class ThreadJoinOnShutdown(BaseTestCase): class ThreadJoinOnShutdown(BaseTestCase):
...@@ -659,6 +724,46 @@ class ThreadJoinOnShutdown(BaseTestCase): ...@@ -659,6 +724,46 @@ class ThreadJoinOnShutdown(BaseTestCase):
for t in threads: for t in threads:
t.join() t.join()
@cpython_only
@unittest.skipIf(_testcapi is None, "need _testcapi module")
def test_frame_tstate_tracing(self):
# Issue #14432: Crash when a generator is created in a C thread that is
# destroyed while the generator is still used. The issue was that a
# generator contains a frame, and the frame kept a reference to the
# Python state of the destroyed C thread. The crash occurs when a trace
# function is setup.
def noop_trace(frame, event, arg):
# no operation
return noop_trace
def generator():
while 1:
yield "genereator"
def callback():
if callback.gen is None:
callback.gen = generator()
return next(callback.gen)
callback.gen = None
old_trace = sys.gettrace()
sys.settrace(noop_trace)
try:
# Install a trace function
threading.settrace(noop_trace)
# Create a generator in a C thread which exits after the call
_testcapi.call_in_temporary_c_thread(callback)
# Call the generator in a different Python thread, check that the
# generator didn't keep a reference to the destroyed thread state
for test in range(3):
# The trace function is still called here
callback()
finally:
sys.settrace(old_trace)
class ThreadingExceptionTests(BaseTestCase): class ThreadingExceptionTests(BaseTestCase):
# A RuntimeError should be raised if Thread.start() is called # A RuntimeError should be raised if Thread.start() is called
...@@ -681,6 +786,85 @@ class ThreadingExceptionTests(BaseTestCase): ...@@ -681,6 +786,85 @@ class ThreadingExceptionTests(BaseTestCase):
thread.start() thread.start()
self.assertRaises(RuntimeError, setattr, thread, "daemon", True) self.assertRaises(RuntimeError, setattr, thread, "daemon", True)
def test_print_exception(self):
script = r"""if 1:
import threading
import time
running = False
def run():
global running
running = True
while running:
time.sleep(0.01)
1.0/0.0
t = threading.Thread(target=run)
t.start()
while not running:
time.sleep(0.01)
running = False
t.join()
"""
rc, out, err = assert_python_ok("-c", script)
self.assertEqual(out, '')
self.assertIn("Exception in thread", err)
self.assertIn("Traceback (most recent call last):", err)
self.assertIn("ZeroDivisionError", err)
self.assertNotIn("Unhandled exception", err)
def test_print_exception_stderr_is_none_1(self):
script = r"""if 1:
import sys
import threading
import time
running = False
def run():
global running
running = True
while running:
time.sleep(0.01)
1.0/0.0
t = threading.Thread(target=run)
t.start()
while not running:
time.sleep(0.01)
sys.stderr = None
running = False
t.join()
"""
rc, out, err = assert_python_ok("-c", script)
self.assertEqual(out, '')
self.assertIn("Exception in thread", err)
self.assertIn("Traceback (most recent call last):", err)
self.assertIn("ZeroDivisionError", err)
self.assertNotIn("Unhandled exception", err)
def test_print_exception_stderr_is_none_2(self):
script = r"""if 1:
import sys
import threading
import time
running = False
def run():
global running
running = True
while running:
time.sleep(0.01)
1.0/0.0
sys.stderr = None
t = threading.Thread(target=run)
t.start()
while not running:
time.sleep(0.01)
running = False
t.join()
"""
rc, out, err = assert_python_ok("-c", script)
self.assertEqual(out, '')
self.assertNotIn("Unhandled exception", err)
class LockTests(lock_tests.LockTests): class LockTests(lock_tests.LockTests):
locktype = staticmethod(threading.Lock) locktype = staticmethod(threading.Lock)
......
import unittest import unittest
from doctest import DocTestSuite from doctest import DocTestSuite
from test import test_support from test import test_support as support
import weakref import weakref
import gc import gc
# Modules under test # Modules under test
_thread = test_support.import_module('thread') _thread = support.import_module('thread')
threading = test_support.import_module('threading') threading = support.import_module('threading')
import _threading_local import _threading_local
...@@ -63,14 +63,9 @@ class BaseLocalTest: ...@@ -63,14 +63,9 @@ class BaseLocalTest:
# Simply check that the variable is correctly set # Simply check that the variable is correctly set
self.assertEqual(local.x, i) self.assertEqual(local.x, i)
threads= [] with support.start_threads(threading.Thread(target=f, args=(i,))
for i in range(10): for i in range(10)):
t = threading.Thread(target=f, args=(i,)) pass
t.start()
threads.append(t)
for t in threads:
t.join()
def test_derived_cycle_dealloc(self): def test_derived_cycle_dealloc(self):
# http://bugs.python.org/issue6990 # http://bugs.python.org/issue6990
...@@ -228,7 +223,7 @@ def test_main(): ...@@ -228,7 +223,7 @@ def test_main():
setUp=setUp, tearDown=tearDown) setUp=setUp, tearDown=tearDown)
) )
test_support.run_unittest(suite) support.run_unittest(suite)
if __name__ == '__main__': if __name__ == '__main__':
test_main() test_main()
...@@ -178,16 +178,19 @@ class TimeoutTestCase(unittest.TestCase): ...@@ -178,16 +178,19 @@ class TimeoutTestCase(unittest.TestCase):
"timeout (%g) is %g seconds more than expected (%g)" "timeout (%g) is %g seconds more than expected (%g)"
%(_delta, self.fuzz, _timeout)) %(_delta, self.fuzz, _timeout))
@unittest.skip('test not implemented')
def testSend(self): def testSend(self):
# Test send() timeout # Test send() timeout
# couldn't figure out how to test it # couldn't figure out how to test it
pass pass
@unittest.skip('test not implemented')
def testSendto(self): def testSendto(self):
# Test sendto() timeout # Test sendto() timeout
# couldn't figure out how to test it # couldn't figure out how to test it
pass pass
@unittest.skip('test not implemented')
def testSendall(self): def testSendall(self):
# Test sendall() timeout # Test sendall() timeout
# couldn't figure out how to test it # couldn't figure out how to test it
......
...@@ -222,6 +222,27 @@ Content-Type: text/html; charset=iso-8859-1 ...@@ -222,6 +222,27 @@ Content-Type: text/html; charset=iso-8859-1
finally: finally:
self.unfakehttp() self.unfakehttp()
def test_missing_localfile(self):
self.assertRaises(IOError, urllib.urlopen,
'file://localhost/a/missing/file.py')
fd, tmp_file = tempfile.mkstemp()
tmp_fileurl = 'file://localhost/' + tmp_file.replace(os.path.sep, '/')
self.assertTrue(os.path.exists(tmp_file))
try:
fp = urllib.urlopen(tmp_fileurl)
fp.close()
finally:
os.close(fd)
os.unlink(tmp_file)
self.assertFalse(os.path.exists(tmp_file))
self.assertRaises(IOError, urllib.urlopen, tmp_fileurl)
def test_ftp_nonexisting(self):
self.assertRaises(IOError, urllib.urlopen,
'ftp://localhost/not/existing/file.py')
def test_userpass_inurl(self): def test_userpass_inurl(self):
self.fakehttp('Hello!') self.fakehttp('Hello!')
try: try:
...@@ -752,21 +773,131 @@ class Pathname_Tests(unittest.TestCase): ...@@ -752,21 +773,131 @@ class Pathname_Tests(unittest.TestCase):
class Utility_Tests(unittest.TestCase): class Utility_Tests(unittest.TestCase):
"""Testcase to test the various utility functions in the urllib.""" """Testcase to test the various utility functions in the urllib."""
# In Python 3 this test class is moved to test_urlparse.
def test_splittype(self):
splittype = urllib.splittype
self.assertEqual(splittype('type:opaquestring'), ('type', 'opaquestring'))
self.assertEqual(splittype('opaquestring'), (None, 'opaquestring'))
self.assertEqual(splittype(':opaquestring'), (None, ':opaquestring'))
self.assertEqual(splittype('type:'), ('type', ''))
self.assertEqual(splittype('type:opaque:string'), ('type', 'opaque:string'))
def test_splithost(self):
splithost = urllib.splithost
self.assertEqual(splithost('//www.example.org:80/foo/bar/baz.html'),
('www.example.org:80', '/foo/bar/baz.html'))
self.assertEqual(splithost('//www.example.org:80'),
('www.example.org:80', ''))
self.assertEqual(splithost('/foo/bar/baz.html'),
(None, '/foo/bar/baz.html'))
def test_splituser(self):
splituser = urllib.splituser
self.assertEqual(splituser('User:Pass@www.python.org:080'),
('User:Pass', 'www.python.org:080'))
self.assertEqual(splituser('@www.python.org:080'),
('', 'www.python.org:080'))
self.assertEqual(splituser('www.python.org:080'),
(None, 'www.python.org:080'))
self.assertEqual(splituser('User:Pass@'),
('User:Pass', ''))
self.assertEqual(splituser('User@example.com:Pass@www.python.org:080'),
('User@example.com:Pass', 'www.python.org:080'))
def test_splitpasswd(self): def test_splitpasswd(self):
"""Some of the password examples are not sensible, but it is added to # Some of the password examples are not sensible, but it is added to
confirming to RFC2617 and addressing issue4675. # confirming to RFC2617 and addressing issue4675.
""" splitpasswd = urllib.splitpasswd
self.assertEqual(('user', 'ab'),urllib.splitpasswd('user:ab')) self.assertEqual(splitpasswd('user:ab'), ('user', 'ab'))
self.assertEqual(('user', 'a\nb'),urllib.splitpasswd('user:a\nb')) self.assertEqual(splitpasswd('user:a\nb'), ('user', 'a\nb'))
self.assertEqual(('user', 'a\tb'),urllib.splitpasswd('user:a\tb')) self.assertEqual(splitpasswd('user:a\tb'), ('user', 'a\tb'))
self.assertEqual(('user', 'a\rb'),urllib.splitpasswd('user:a\rb')) self.assertEqual(splitpasswd('user:a\rb'), ('user', 'a\rb'))
self.assertEqual(('user', 'a\fb'),urllib.splitpasswd('user:a\fb')) self.assertEqual(splitpasswd('user:a\fb'), ('user', 'a\fb'))
self.assertEqual(('user', 'a\vb'),urllib.splitpasswd('user:a\vb')) self.assertEqual(splitpasswd('user:a\vb'), ('user', 'a\vb'))
self.assertEqual(('user', 'a:b'),urllib.splitpasswd('user:a:b')) self.assertEqual(splitpasswd('user:a:b'), ('user', 'a:b'))
self.assertEqual(('user', 'a b'),urllib.splitpasswd('user:a b')) self.assertEqual(splitpasswd('user:a b'), ('user', 'a b'))
self.assertEqual(('user 2', 'ab'),urllib.splitpasswd('user 2:ab')) self.assertEqual(splitpasswd('user 2:ab'), ('user 2', 'ab'))
self.assertEqual(('user+1', 'a+b'),urllib.splitpasswd('user+1:a+b')) self.assertEqual(splitpasswd('user+1:a+b'), ('user+1', 'a+b'))
self.assertEqual(splitpasswd('user:'), ('user', ''))
self.assertEqual(splitpasswd('user'), ('user', None))
self.assertEqual(splitpasswd(':ab'), ('', 'ab'))
def test_splitport(self):
splitport = urllib.splitport
self.assertEqual(splitport('parrot:88'), ('parrot', '88'))
self.assertEqual(splitport('parrot'), ('parrot', None))
self.assertEqual(splitport('parrot:'), ('parrot', None))
self.assertEqual(splitport('127.0.0.1'), ('127.0.0.1', None))
self.assertEqual(splitport('parrot:cheese'), ('parrot:cheese', None))
self.assertEqual(splitport('[::1]:88'), ('[::1]', '88'))
self.assertEqual(splitport('[::1]'), ('[::1]', None))
self.assertEqual(splitport(':88'), ('', '88'))
def test_splitnport(self):
splitnport = urllib.splitnport
self.assertEqual(splitnport('parrot:88'), ('parrot', 88))
self.assertEqual(splitnport('parrot'), ('parrot', -1))
self.assertEqual(splitnport('parrot', 55), ('parrot', 55))
self.assertEqual(splitnport('parrot:'), ('parrot', -1))
self.assertEqual(splitnport('parrot:', 55), ('parrot', 55))
self.assertEqual(splitnport('127.0.0.1'), ('127.0.0.1', -1))
self.assertEqual(splitnport('127.0.0.1', 55), ('127.0.0.1', 55))
self.assertEqual(splitnport('parrot:cheese'), ('parrot', None))
self.assertEqual(splitnport('parrot:cheese', 55), ('parrot', None))
def test_splitquery(self):
# Normal cases are exercised by other tests; ensure that we also
# catch cases with no port specified (testcase ensuring coverage)
splitquery = urllib.splitquery
self.assertEqual(splitquery('http://python.org/fake?foo=bar'),
('http://python.org/fake', 'foo=bar'))
self.assertEqual(splitquery('http://python.org/fake?foo=bar?'),
('http://python.org/fake?foo=bar', ''))
self.assertEqual(splitquery('http://python.org/fake'),
('http://python.org/fake', None))
self.assertEqual(splitquery('?foo=bar'), ('', 'foo=bar'))
def test_splittag(self):
splittag = urllib.splittag
self.assertEqual(splittag('http://example.com?foo=bar#baz'),
('http://example.com?foo=bar', 'baz'))
self.assertEqual(splittag('http://example.com?foo=bar#'),
('http://example.com?foo=bar', ''))
self.assertEqual(splittag('#baz'), ('', 'baz'))
self.assertEqual(splittag('http://example.com?foo=bar'),
('http://example.com?foo=bar', None))
self.assertEqual(splittag('http://example.com?foo=bar#baz#boo'),
('http://example.com?foo=bar#baz', 'boo'))
def test_splitattr(self):
splitattr = urllib.splitattr
self.assertEqual(splitattr('/path;attr1=value1;attr2=value2'),
('/path', ['attr1=value1', 'attr2=value2']))
self.assertEqual(splitattr('/path;'), ('/path', ['']))
self.assertEqual(splitattr(';attr1=value1;attr2=value2'),
('', ['attr1=value1', 'attr2=value2']))
self.assertEqual(splitattr('/path'), ('/path', []))
def test_splitvalue(self):
# Normal cases are exercised by other tests; test pathological cases
# with no key/value pairs. (testcase ensuring coverage)
splitvalue = urllib.splitvalue
self.assertEqual(splitvalue('foo=bar'), ('foo', 'bar'))
self.assertEqual(splitvalue('foo='), ('foo', ''))
self.assertEqual(splitvalue('=bar'), ('', 'bar'))
self.assertEqual(splitvalue('foobar'), ('foobar', None))
self.assertEqual(splitvalue('foo=bar=baz'), ('foo', 'bar=baz'))
def test_toBytes(self):
result = urllib.toBytes(u'http://www.python.org')
self.assertEqual(result, 'http://www.python.org')
self.assertRaises(UnicodeError, urllib.toBytes,
test_support.u(r'http://www.python.org/medi\u00e6val'))
def test_unwrap(self):
url = urllib.unwrap('<URL:type://host/path>')
self.assertEqual(url, 'type://host/path')
class URLopener_Tests(unittest.TestCase): class URLopener_Tests(unittest.TestCase):
...@@ -791,7 +922,7 @@ class URLopener_Tests(unittest.TestCase): ...@@ -791,7 +922,7 @@ class URLopener_Tests(unittest.TestCase):
# Everywhere else they work ok, but on those machines, sometimes # Everywhere else they work ok, but on those machines, sometimes
# fail in one of the tests, sometimes in other. I have a linux, and # fail in one of the tests, sometimes in other. I have a linux, and
# the tests go ok. # the tests go ok.
# If anybody has one of the problematic enviroments, please help! # If anybody has one of the problematic environments, please help!
# . Facundo # . Facundo
# #
# def server(evt): # def server(evt):
...@@ -837,7 +968,7 @@ class URLopener_Tests(unittest.TestCase): ...@@ -837,7 +968,7 @@ class URLopener_Tests(unittest.TestCase):
# def testTimeoutNone(self): # def testTimeoutNone(self):
# # global default timeout is ignored # # global default timeout is ignored
# import socket # import socket
# self.assertTrue(socket.getdefaulttimeout() is None) # self.assertIsNone(socket.getdefaulttimeout())
# socket.setdefaulttimeout(30) # socket.setdefaulttimeout(30)
# try: # try:
# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, []) # ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
...@@ -849,7 +980,7 @@ class URLopener_Tests(unittest.TestCase): ...@@ -849,7 +980,7 @@ class URLopener_Tests(unittest.TestCase):
# def testTimeoutDefault(self): # def testTimeoutDefault(self):
# # global default timeout is used # # global default timeout is used
# import socket # import socket
# self.assertTrue(socket.getdefaulttimeout() is None) # self.assertIsNone(socket.getdefaulttimeout())
# socket.setdefaulttimeout(30) # socket.setdefaulttimeout(30)
# try: # try:
# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, []) # ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
......
...@@ -8,6 +8,11 @@ import StringIO ...@@ -8,6 +8,11 @@ import StringIO
import urllib2 import urllib2
from urllib2 import Request, OpenerDirector from urllib2 import Request, OpenerDirector
try:
import ssl
except ImportError:
ssl = None
# XXX # XXX
# Request # Request
# CacheFTPHandler (hard to write) # CacheFTPHandler (hard to write)
...@@ -20,7 +25,7 @@ class TrivialTests(unittest.TestCase): ...@@ -20,7 +25,7 @@ class TrivialTests(unittest.TestCase):
self.assertRaises(ValueError, urllib2.urlopen, 'bogus url') self.assertRaises(ValueError, urllib2.urlopen, 'bogus url')
# XXX Name hacking to get this to work on Windows. # XXX Name hacking to get this to work on Windows.
fname = os.path.abspath(urllib2.__file__).replace('\\', '/') fname = os.path.abspath(urllib2.__file__).replace(os.sep, '/')
# And more hacking to get it to work on MacOS. This assumes # And more hacking to get it to work on MacOS. This assumes
# urllib.pathname2url works, unfortunately... # urllib.pathname2url works, unfortunately...
...@@ -47,6 +52,14 @@ class TrivialTests(unittest.TestCase): ...@@ -47,6 +52,14 @@ class TrivialTests(unittest.TestCase):
for string, list in tests: for string, list in tests:
self.assertEqual(urllib2.parse_http_list(string), list) self.assertEqual(urllib2.parse_http_list(string), list)
@unittest.skipUnless(ssl, "ssl module required")
def test_cafile_and_context(self):
context = ssl.create_default_context()
with self.assertRaises(ValueError):
urllib2.urlopen(
"https://localhost", cafile="/nonexistent/path", context=context
)
def test_request_headers_dict(): def test_request_headers_dict():
""" """
...@@ -591,8 +604,8 @@ class OpenerDirectorTests(unittest.TestCase): ...@@ -591,8 +604,8 @@ class OpenerDirectorTests(unittest.TestCase):
self.assertIsInstance(args[0], Request) self.assertIsInstance(args[0], Request)
# response from opener.open is None, because there's no # response from opener.open is None, because there's no
# handler that defines http_open to handle it # handler that defines http_open to handle it
self.assertTrue(args[1] is None or if args[1] is not None:
isinstance(args[1], MockResponse)) self.assertIsInstance(args[1], MockResponse)
def sanepathname2url(path): def sanepathname2url(path):
...@@ -924,7 +937,8 @@ class HandlerTests(unittest.TestCase): ...@@ -924,7 +937,8 @@ class HandlerTests(unittest.TestCase):
MockHeaders({"location": to_url})) MockHeaders({"location": to_url}))
except urllib2.HTTPError: except urllib2.HTTPError:
# 307 in response to POST requires user OK # 307 in response to POST requires user OK
self.assertTrue(code == 307 and data is not None) self.assertEqual(code, 307)
self.assertIsNotNone(data)
self.assertEqual(o.req.get_full_url(), to_url) self.assertEqual(o.req.get_full_url(), to_url)
try: try:
self.assertEqual(o.req.get_method(), "GET") self.assertEqual(o.req.get_method(), "GET")
...@@ -1001,7 +1015,7 @@ class HandlerTests(unittest.TestCase): ...@@ -1001,7 +1015,7 @@ class HandlerTests(unittest.TestCase):
# cookies shouldn't leak into redirected requests # cookies shouldn't leak into redirected requests
from cookielib import CookieJar from cookielib import CookieJar
from test_cookielib import interact_netscape from test.test_cookielib import interact_netscape
cj = CookieJar() cj = CookieJar()
interact_netscape(cj, "http://www.example.com/", "spam=eggs") interact_netscape(cj, "http://www.example.com/", "spam=eggs")
...@@ -1106,12 +1120,30 @@ class HandlerTests(unittest.TestCase): ...@@ -1106,12 +1120,30 @@ class HandlerTests(unittest.TestCase):
self._test_basic_auth(opener, auth_handler, "Authorization", self._test_basic_auth(opener, auth_handler, "Authorization",
realm, http_handler, password_manager, realm, http_handler, password_manager,
"http://acme.example.com/protected", "http://acme.example.com/protected",
"http://acme.example.com/protected", "http://acme.example.com/protected"
) )
def test_basic_auth_with_single_quoted_realm(self): def test_basic_auth_with_single_quoted_realm(self):
self.test_basic_auth(quote_char="'") self.test_basic_auth(quote_char="'")
def test_basic_auth_with_unquoted_realm(self):
opener = OpenerDirector()
password_manager = MockPasswordManager()
auth_handler = urllib2.HTTPBasicAuthHandler(password_manager)
realm = "ACME Widget Store"
http_handler = MockHTTPHandler(
401, 'WWW-Authenticate: Basic realm=%s\r\n\r\n' % realm)
opener.add_handler(auth_handler)
opener.add_handler(http_handler)
msg = "Basic Auth Realm was unquoted"
with test_support.check_warnings((msg, UserWarning)):
self._test_basic_auth(opener, auth_handler, "Authorization",
realm, http_handler, password_manager,
"http://acme.example.com/protected",
"http://acme.example.com/protected"
)
def test_proxy_basic_auth(self): def test_proxy_basic_auth(self):
opener = OpenerDirector() opener = OpenerDirector()
ph = urllib2.ProxyHandler(dict(http="proxy.example.com:3128")) ph = urllib2.ProxyHandler(dict(http="proxy.example.com:3128"))
...@@ -1130,7 +1162,7 @@ class HandlerTests(unittest.TestCase): ...@@ -1130,7 +1162,7 @@ class HandlerTests(unittest.TestCase):
) )
def test_basic_and_digest_auth_handlers(self): def test_basic_and_digest_auth_handlers(self):
# HTTPDigestAuthHandler threw an exception if it couldn't handle a 40* # HTTPDigestAuthHandler raised an exception if it couldn't handle a 40*
# response (http://python.org/sf/1479302), where it should instead # response (http://python.org/sf/1479302), where it should instead
# return None to allow another handler (especially # return None to allow another handler (especially
# HTTPBasicAuthHandler) to handle the response. # HTTPBasicAuthHandler) to handle the response.
...@@ -1318,19 +1350,35 @@ class RequestTests(unittest.TestCase): ...@@ -1318,19 +1350,35 @@ class RequestTests(unittest.TestCase):
req = Request(url) req = Request(url)
self.assertEqual(req.get_full_url(), url) self.assertEqual(req.get_full_url(), url)
def test_HTTPError_interface(): def test_HTTPError_interface(self):
""" """
Issue 13211 reveals that HTTPError didn't implement the URLError Issue 13211 reveals that HTTPError didn't implement the URLError
interface even though HTTPError is a subclass of URLError. interface even though HTTPError is a subclass of URLError.
>>> err = urllib2.HTTPError(msg='something bad happened', url=None, code=None, hdrs=None, fp=None) >>> err = urllib2.HTTPError(msg='something bad happened', url=None, code=None, hdrs=None, fp=None)
>>> assert hasattr(err, 'reason') >>> assert hasattr(err, 'reason')
>>> err.reason >>> err.reason
'something bad happened' 'something bad happened'
""" """
def test_HTTPError_interface_call(self):
"""
Issue 15701= - HTTPError interface has info method available from URLError.
"""
err = urllib2.HTTPError(msg='something bad happened', url=None,
code=None, hdrs='Content-Length:42', fp=None)
self.assertTrue(hasattr(err, 'reason'))
assert hasattr(err, 'reason')
assert hasattr(err, 'info')
assert callable(err.info)
try:
err.info()
except AttributeError:
self.fail("err.info() failed")
self.assertEqual(err.info(), "Content-Length:42")
def test_main(verbose=None): def test_main(verbose=None):
import test_urllib2 from test import test_urllib2
test_support.run_doctest(test_urllib2, verbose) test_support.run_doctest(test_urllib2, verbose)
test_support.run_doctest(urllib2, verbose) test_support.run_doctest(urllib2, verbose)
tests = (TrivialTests, tests = (TrivialTests,
......
#!/usr/bin/env python import os
import base64
import urlparse import urlparse
import urllib2 import urllib2
import BaseHTTPServer import BaseHTTPServer
import unittest import unittest
import hashlib import hashlib
from test import test_support from test import test_support
mimetools = test_support.import_module('mimetools', deprecated=True) mimetools = test_support.import_module('mimetools', deprecated=True)
threading = test_support.import_module('threading') threading = test_support.import_module('threading')
try:
import ssl
except ImportError:
ssl = None
here = os.path.dirname(__file__)
# Self-signed cert file for 'localhost'
CERT_localhost = os.path.join(here, 'keycert.pem')
# Self-signed cert file for 'fakehostname'
CERT_fakehostname = os.path.join(here, 'keycert2.pem')
# Loopback http server infrastructure # Loopback http server infrastructure
class LoopbackHttpServer(BaseHTTPServer.HTTPServer): class LoopbackHttpServer(BaseHTTPServer.HTTPServer):
...@@ -33,7 +46,7 @@ class LoopbackHttpServer(BaseHTTPServer.HTTPServer): ...@@ -33,7 +46,7 @@ class LoopbackHttpServer(BaseHTTPServer.HTTPServer):
# It's a loopback connection, so setting the timeout # It's a loopback connection, so setting the timeout
# really low shouldn't affect anything, but should make # really low shouldn't affect anything, but should make
# deadlocks less likely to occur. # deadlocks less likely to occur.
request.settimeout(1.0) request.settimeout(10.0)
return (request, client_address) return (request, client_address)
...@@ -66,6 +79,46 @@ class LoopbackHttpServerThread(threading.Thread): ...@@ -66,6 +79,46 @@ class LoopbackHttpServerThread(threading.Thread):
# Authentication infrastructure # Authentication infrastructure
class BasicAuthHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""Handler for performing Basic Authentication."""
# Server side values
USER = "testUser"
PASSWD = "testPass"
REALM = "Test"
USER_PASSWD = "%s:%s" % (USER, PASSWD)
ENCODED_AUTH = base64.b64encode(USER_PASSWD)
def __init__(self, *args, **kwargs):
BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
def log_message(self, format, *args):
# Supress the HTTP Console log output
pass
def do_HEAD(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
def do_AUTHHEAD(self):
self.send_response(401)
self.send_header("WWW-Authenticate", "Basic realm=\"%s\"" % self.REALM)
self.send_header("Content-type", "text/html")
self.end_headers()
def do_GET(self):
if self.headers.getheader("Authorization") == None:
self.do_AUTHHEAD()
self.wfile.write("No Auth Header Received")
elif self.headers.getheader(
"Authorization") == "Basic " + self.ENCODED_AUTH:
self.wfile.write("It works!")
else:
# Unauthorized Request
self.do_AUTHHEAD()
class DigestAuthHandler: class DigestAuthHandler:
"""Handler for performing digest authentication.""" """Handler for performing digest authentication."""
...@@ -228,6 +281,45 @@ class BaseTestCase(unittest.TestCase): ...@@ -228,6 +281,45 @@ class BaseTestCase(unittest.TestCase):
test_support.threading_cleanup(*self._threads) test_support.threading_cleanup(*self._threads)
class BasicAuthTests(BaseTestCase):
USER = "testUser"
PASSWD = "testPass"
INCORRECT_PASSWD = "Incorrect"
REALM = "Test"
def setUp(self):
super(BasicAuthTests, self).setUp()
# With Basic Authentication
def http_server_with_basic_auth_handler(*args, **kwargs):
return BasicAuthHandler(*args, **kwargs)
self.server = LoopbackHttpServerThread(http_server_with_basic_auth_handler)
self.server_url = 'http://127.0.0.1:%s' % self.server.port
self.server.start()
self.server.ready.wait()
def tearDown(self):
self.server.stop()
super(BasicAuthTests, self).tearDown()
def test_basic_auth_success(self):
ah = urllib2.HTTPBasicAuthHandler()
ah.add_password(self.REALM, self.server_url, self.USER, self.PASSWD)
urllib2.install_opener(urllib2.build_opener(ah))
try:
self.assertTrue(urllib2.urlopen(self.server_url))
except urllib2.HTTPError:
self.fail("Basic Auth Failed for url: %s" % self.server_url)
except Exception as e:
raise e
def test_basic_auth_httperror(self):
ah = urllib2.HTTPBasicAuthHandler()
ah.add_password(self.REALM, self.server_url, self.USER,
self.INCORRECT_PASSWD)
urllib2.install_opener(urllib2.build_opener(ah))
self.assertRaises(urllib2.HTTPError, urllib2.urlopen, self.server_url)
class ProxyAuthTests(BaseTestCase): class ProxyAuthTests(BaseTestCase):
URL = "http://localhost" URL = "http://localhost"
...@@ -240,6 +332,7 @@ class ProxyAuthTests(BaseTestCase): ...@@ -240,6 +332,7 @@ class ProxyAuthTests(BaseTestCase):
self.digest_auth_handler = DigestAuthHandler() self.digest_auth_handler = DigestAuthHandler()
self.digest_auth_handler.set_users({self.USER: self.PASSWD}) self.digest_auth_handler.set_users({self.USER: self.PASSWD})
self.digest_auth_handler.set_realm(self.REALM) self.digest_auth_handler.set_realm(self.REALM)
# With Digest Authentication
def create_fake_proxy_handler(*args, **kwargs): def create_fake_proxy_handler(*args, **kwargs):
return FakeProxyHandler(self.digest_auth_handler, *args, **kwargs) return FakeProxyHandler(self.digest_auth_handler, *args, **kwargs)
...@@ -346,6 +439,25 @@ class TestUrlopen(BaseTestCase): ...@@ -346,6 +439,25 @@ class TestUrlopen(BaseTestCase):
for transparent redirection have been written. for transparent redirection have been written.
""" """
def setUp(self):
proxy_handler = urllib2.ProxyHandler({})
opener = urllib2.build_opener(proxy_handler)
urllib2.install_opener(opener)
super(TestUrlopen, self).setUp()
def urlopen(self, url, data=None, **kwargs):
l = []
f = urllib2.urlopen(url, data, **kwargs)
try:
# Exercise various methods
l.extend(f.readlines(200))
l.append(f.readline())
l.append(f.read(1024))
l.append(f.read())
finally:
f.close()
return b"".join(l)
def start_server(self, responses): def start_server(self, responses):
handler = GetRequestHandler(responses) handler = GetRequestHandler(responses)
...@@ -356,6 +468,16 @@ class TestUrlopen(BaseTestCase): ...@@ -356,6 +468,16 @@ class TestUrlopen(BaseTestCase):
handler.port = port handler.port = port
return handler return handler
def start_https_server(self, responses=None, **kwargs):
if not hasattr(urllib2, 'HTTPSHandler'):
self.skipTest('ssl support required')
from test.ssl_servers import make_https_server
if responses is None:
responses = [(200, [], b"we care a bit")]
handler = GetRequestHandler(responses)
server = make_https_server(self, handler_class=handler, **kwargs)
handler.port = server.port
return handler
def test_redirection(self): def test_redirection(self):
expected_response = 'We got here...' expected_response = 'We got here...'
...@@ -426,6 +548,49 @@ class TestUrlopen(BaseTestCase): ...@@ -426,6 +548,49 @@ class TestUrlopen(BaseTestCase):
finally: finally:
self.server.stop() self.server.stop()
def test_https(self):
handler = self.start_https_server()
context = ssl.create_default_context(cafile=CERT_localhost)
data = self.urlopen("https://localhost:%s/bizarre" % handler.port, context=context)
self.assertEqual(data, b"we care a bit")
def test_https_with_cafile(self):
handler = self.start_https_server(certfile=CERT_localhost)
# Good cert
data = self.urlopen("https://localhost:%s/bizarre" % handler.port,
cafile=CERT_localhost)
self.assertEqual(data, b"we care a bit")
# Bad cert
with self.assertRaises(urllib2.URLError):
self.urlopen("https://localhost:%s/bizarre" % handler.port,
cafile=CERT_fakehostname)
# Good cert, but mismatching hostname
handler = self.start_https_server(certfile=CERT_fakehostname)
with self.assertRaises(ssl.CertificateError):
self.urlopen("https://localhost:%s/bizarre" % handler.port,
cafile=CERT_fakehostname)
def test_https_with_cadefault(self):
handler = self.start_https_server(certfile=CERT_localhost)
# Self-signed cert should fail verification with system certificate store
with self.assertRaises(urllib2.URLError):
self.urlopen("https://localhost:%s/bizarre" % handler.port,
cadefault=True)
def test_https_sni(self):
if ssl is None:
self.skipTest("ssl module required")
if not ssl.HAS_SNI:
self.skipTest("SNI support required in OpenSSL")
sni_name = [None]
def cb_sni(ssl_sock, server_name, initial_context):
sni_name[0] = server_name
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.set_servername_callback(cb_sni)
handler = self.start_https_server(context=context, certfile=CERT_localhost)
context = ssl.create_default_context(cafile=CERT_localhost)
self.urlopen("https://localhost:%s" % handler.port, context=context)
self.assertEqual(sni_name[0], "localhost")
def test_sending_headers(self): def test_sending_headers(self):
handler = self.start_server([(200, [], "we don't care")]) handler = self.start_server([(200, [], "we don't care")])
...@@ -481,6 +646,11 @@ class TestUrlopen(BaseTestCase): ...@@ -481,6 +646,11 @@ class TestUrlopen(BaseTestCase):
def test_bad_address(self): def test_bad_address(self):
# Make sure proper exception is raised when connecting to a bogus # Make sure proper exception is raised when connecting to a bogus
# address. # address.
# as indicated by the comment below, this might fail with some ISP,
# so we run the test only when -unetwork/-uall is specified to
# mitigate the problem a bit (see #17564)
test_support.requires('network')
self.assertRaises(IOError, self.assertRaises(IOError,
# Given that both VeriSign and various ISPs have in # Given that both VeriSign and various ISPs have in
# the past or are presently hijacking various invalid # the past or are presently hijacking various invalid
...@@ -533,7 +703,7 @@ def test_main(): ...@@ -533,7 +703,7 @@ def test_main():
# the next line. # the next line.
#test_support.requires("network") #test_support.requires("network")
test_support.run_unittest(ProxyAuthTests, TestUrlopen) test_support.run_unittest(BasicAuthTests, ProxyAuthTests, TestUrlopen)
if __name__ == "__main__": if __name__ == "__main__":
test_main() test_main()
#!/usr/bin/env python
import unittest import unittest
from test import test_support from test import test_support
from test_urllib2 import sanepathname2url from test.test_urllib2 import sanepathname2url
import socket import socket
import urllib2 import urllib2
...@@ -80,13 +78,13 @@ class CloseSocketTest(unittest.TestCase): ...@@ -80,13 +78,13 @@ class CloseSocketTest(unittest.TestCase):
# underlying socket # underlying socket
# delve deep into response to fetch socket._socketobject # delve deep into response to fetch socket._socketobject
response = _urlopen_with_retry("http://www.python.org/") response = _urlopen_with_retry("http://www.example.com/")
abused_fileobject = response.fp abused_fileobject = response.fp
self.assertTrue(abused_fileobject.__class__ is socket._fileobject) #self.assertIs(abused_fileobject.__class__, socket._fileobject) # JAM: gevent: disable
httpresponse = abused_fileobject._sock httpresponse = abused_fileobject._sock
self.assertTrue(httpresponse.__class__ is httplib.HTTPResponse) self.assertIs(httpresponse.__class__, httplib.HTTPResponse)
fileobject = httpresponse.fp fileobject = httpresponse.fp
self.assertTrue(fileobject.__class__ is socket._fileobject) #self.assertIs(fileobject.__class__, socket._fileobject) # JAM: gevent: disable
self.assertTrue(not fileobject.closed) self.assertTrue(not fileobject.closed)
response.close() response.close()
...@@ -104,11 +102,9 @@ class OtherNetworkTests(unittest.TestCase): ...@@ -104,11 +102,9 @@ class OtherNetworkTests(unittest.TestCase):
def test_ftp(self): def test_ftp(self):
urls = [ urls = [
'ftp://ftp.kernel.org/pub/linux/kernel/README', 'ftp://ftp.debian.org/debian/README',
'ftp://ftp.kernel.org/pub/linux/kernel/non-existent-file', ('ftp://ftp.debian.org/debian/non-existent-file',
#'ftp://ftp.kernel.org/pub/leenox/kernel/test', None, urllib2.URLError),
'ftp://gatekeeper.research.compaq.com/pub/DEC/SRC'
'/research-reports/00README-Legal-Rules-Regs',
] ]
self._test_urls(urls, self._extra_handlers()) self._test_urls(urls, self._extra_handlers())
...@@ -157,15 +153,15 @@ class OtherNetworkTests(unittest.TestCase): ...@@ -157,15 +153,15 @@ class OtherNetworkTests(unittest.TestCase):
## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) ## self._test_urls(urls, self._extra_handlers()+[bauth, dauth])
def test_urlwithfrag(self): def test_urlwithfrag(self):
urlwith_frag = "http://docs.python.org/glossary.html#glossary" urlwith_frag = "http://www.pythontest.net/index.html#frag"
with test_support.transient_internet(urlwith_frag): with test_support.transient_internet(urlwith_frag):
req = urllib2.Request(urlwith_frag) req = urllib2.Request(urlwith_frag)
res = urllib2.urlopen(req) res = urllib2.urlopen(req)
self.assertEqual(res.geturl(), self.assertEqual(res.geturl(),
"http://docs.python.org/glossary.html#glossary") "http://www.pythontest.net/index.html#frag")
def test_fileno(self): def test_fileno(self):
req = urllib2.Request("http://www.python.org") req = urllib2.Request("http://www.example.com")
opener = urllib2.build_opener() opener = urllib2.build_opener()
res = opener.open(req) res = opener.open(req)
try: try:
...@@ -252,15 +248,15 @@ class OtherNetworkTests(unittest.TestCase): ...@@ -252,15 +248,15 @@ class OtherNetworkTests(unittest.TestCase):
class TimeoutTest(unittest.TestCase): class TimeoutTest(unittest.TestCase):
def test_http_basic(self): def test_http_basic(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
url = "http://www.python.org" url = "http://www.example.com"
with test_support.transient_internet(url, timeout=None): with test_support.transient_internet(url, timeout=None):
u = _urlopen_with_retry(url) u = _urlopen_with_retry(url)
self.assertTrue(u.fp._sock.fp._sock.gettimeout() is None) self.assertIsNone(u.fp._sock.fp._sock.gettimeout())
def test_http_default_timeout(self): def test_http_default_timeout(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
url = "http://www.python.org" url = "http://www.example.com"
with test_support.transient_internet(url): with test_support.transient_internet(url):
socket.setdefaulttimeout(60) socket.setdefaulttimeout(60)
try: try:
...@@ -270,32 +266,32 @@ class TimeoutTest(unittest.TestCase): ...@@ -270,32 +266,32 @@ class TimeoutTest(unittest.TestCase):
self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 60) self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 60)
def test_http_no_timeout(self): def test_http_no_timeout(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
url = "http://www.python.org" url = "http://www.example.com"
with test_support.transient_internet(url): with test_support.transient_internet(url):
socket.setdefaulttimeout(60) socket.setdefaulttimeout(60)
try: try:
u = _urlopen_with_retry(url, timeout=None) u = _urlopen_with_retry(url, timeout=None)
finally: finally:
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertTrue(u.fp._sock.fp._sock.gettimeout() is None) self.assertIsNone(u.fp._sock.fp._sock.gettimeout())
def test_http_timeout(self): def test_http_timeout(self):
url = "http://www.python.org" url = "http://www.example.com"
with test_support.transient_internet(url): with test_support.transient_internet(url):
u = _urlopen_with_retry(url, timeout=120) u = _urlopen_with_retry(url, timeout=120)
self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 120) self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 120)
FTP_HOST = "ftp://ftp.mirror.nl/pub/gnu/" FTP_HOST = 'ftp://ftp.debian.org/debian/'
def test_ftp_basic(self): def test_ftp_basic(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
with test_support.transient_internet(self.FTP_HOST, timeout=None): with test_support.transient_internet(self.FTP_HOST, timeout=None):
u = _urlopen_with_retry(self.FTP_HOST) u = _urlopen_with_retry(self.FTP_HOST)
self.assertTrue(u.fp.fp._sock.gettimeout() is None) self.assertIsNone(u.fp.fp._sock.gettimeout())
def test_ftp_default_timeout(self): def test_ftp_default_timeout(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout())
with test_support.transient_internet(self.FTP_HOST): with test_support.transient_internet(self.FTP_HOST):
socket.setdefaulttimeout(60) socket.setdefaulttimeout(60)
try: try:
...@@ -305,14 +301,14 @@ class TimeoutTest(unittest.TestCase): ...@@ -305,14 +301,14 @@ class TimeoutTest(unittest.TestCase):
self.assertEqual(u.fp.fp._sock.gettimeout(), 60) self.assertEqual(u.fp.fp._sock.gettimeout(), 60)
def test_ftp_no_timeout(self): def test_ftp_no_timeout(self):
self.assertTrue(socket.getdefaulttimeout() is None) self.assertIsNone(socket.getdefaulttimeout(),)
with test_support.transient_internet(self.FTP_HOST): with test_support.transient_internet(self.FTP_HOST):
socket.setdefaulttimeout(60) socket.setdefaulttimeout(60)
try: try:
u = _urlopen_with_retry(self.FTP_HOST, timeout=None) u = _urlopen_with_retry(self.FTP_HOST, timeout=None)
finally: finally:
socket.setdefaulttimeout(None) socket.setdefaulttimeout(None)
self.assertTrue(u.fp.fp._sock.gettimeout() is None) self.assertIsNone(u.fp.fp._sock.gettimeout())
def test_ftp_timeout(self): def test_ftp_timeout(self):
with test_support.transient_internet(self.FTP_HOST): with test_support.transient_internet(self.FTP_HOST):
......
from __future__ import nested_scopes # Backward compat for 2.1
from unittest import TestCase from unittest import TestCase
from wsgiref.util import setup_testing_defaults from wsgiref.util import setup_testing_defaults
from wsgiref.headers import Headers from wsgiref.headers import Headers
from wsgiref.handlers import BaseHandler, BaseCGIHandler from wsgiref.handlers import BaseHandler, BaseCGIHandler
from wsgiref import util from wsgiref import util
from wsgiref.validate import validator from wsgiref.validate import validator
from wsgiref.simple_server import WSGIServer, WSGIRequestHandler, demo_app from wsgiref.simple_server import WSGIServer, WSGIRequestHandler
from wsgiref.simple_server import make_server from wsgiref.simple_server import make_server
from StringIO import StringIO from StringIO import StringIO
from SocketServer import BaseServer from SocketServer import BaseServer
import os import os
import re import re
import sys import sys
...@@ -39,9 +39,6 @@ class MockHandler(WSGIRequestHandler): ...@@ -39,9 +39,6 @@ class MockHandler(WSGIRequestHandler):
pass pass
def hello_app(environ,start_response): def hello_app(environ,start_response):
start_response("200 OK", [ start_response("200 OK", [
('Content-Type','text/plain'), ('Content-Type','text/plain'),
...@@ -62,27 +59,6 @@ def run_amock(app=hello_app, data="GET / HTTP/1.0\n\n"): ...@@ -62,27 +59,6 @@ def run_amock(app=hello_app, data="GET / HTTP/1.0\n\n"):
return out.getvalue(), err.getvalue() return out.getvalue(), err.getvalue()
def compare_generic_iter(make_it,match): def compare_generic_iter(make_it,match):
"""Utility to compare a generic 2.1/2.2+ iterator with an iterable """Utility to compare a generic 2.1/2.2+ iterator with an iterable
...@@ -120,10 +96,6 @@ def compare_generic_iter(make_it,match): ...@@ -120,10 +96,6 @@ def compare_generic_iter(make_it,match):
raise AssertionError("Too many items from .next()",it) raise AssertionError("Too many items from .next()",it)
class IntegrationTests(TestCase): class IntegrationTests(TestCase):
def check_hello(self, out, has_length=True): def check_hello(self, out, has_length=True):
...@@ -141,6 +113,11 @@ class IntegrationTests(TestCase): ...@@ -141,6 +113,11 @@ class IntegrationTests(TestCase):
out, err = run_amock() out, err = run_amock()
self.check_hello(out) self.check_hello(out)
def test_request_length(self):
out, err = run_amock(data="GET " + ("x" * 65537) + " HTTP/1.0\n\n")
self.assertEqual(out.splitlines()[0],
"HTTP/1.0 414 Request-URI Too Long")
def test_validated_hello(self): def test_validated_hello(self):
out, err = run_amock(validator(hello_app)) out, err = run_amock(validator(hello_app))
# the middleware doesn't support len(), so content-length isn't there # the middleware doesn't support len(), so content-length isn't there
...@@ -161,10 +138,6 @@ class IntegrationTests(TestCase): ...@@ -161,10 +138,6 @@ class IntegrationTests(TestCase):
) )
class UtilityTests(TestCase): class UtilityTests(TestCase):
def checkShift(self,sn_in,pi_in,part,sn_out,pi_out): def checkShift(self,sn_in,pi_in,part,sn_out,pi_out):
...@@ -187,7 +160,7 @@ class UtilityTests(TestCase): ...@@ -187,7 +160,7 @@ class UtilityTests(TestCase):
# Check existing value # Check existing value
env = {key:alt} env = {key:alt}
util.setup_testing_defaults(env) util.setup_testing_defaults(env)
self.assertTrue(env[key] is alt) self.assertIs(env[key], alt)
def checkCrossDefault(self,key,value,**kw): def checkCrossDefault(self,key,value,**kw):
util.setup_testing_defaults(kw) util.setup_testing_defaults(kw)
...@@ -201,11 +174,6 @@ class UtilityTests(TestCase): ...@@ -201,11 +174,6 @@ class UtilityTests(TestCase):
util.setup_testing_defaults(kw) util.setup_testing_defaults(kw)
self.assertEqual(util.request_uri(kw,query),uri) self.assertEqual(util.request_uri(kw,query),uri)
def checkFW(self,text,size,match): def checkFW(self,text,size,match):
def make_it(text=text,size=size): def make_it(text=text,size=size):
...@@ -224,7 +192,6 @@ class UtilityTests(TestCase): ...@@ -224,7 +192,6 @@ class UtilityTests(TestCase):
it.close() it.close()
self.assertTrue(it.filelike.closed) self.assertTrue(it.filelike.closed)
def testSimpleShifts(self): def testSimpleShifts(self):
self.checkShift('','/', '', '/', '') self.checkShift('','/', '', '/', '')
self.checkShift('','/x', 'x', '/x', '') self.checkShift('','/x', 'x', '/x', '')
...@@ -232,7 +199,6 @@ class UtilityTests(TestCase): ...@@ -232,7 +199,6 @@ class UtilityTests(TestCase):
self.checkShift('/a','/x/y', 'x', '/a/x', '/y') self.checkShift('/a','/x/y', 'x', '/a/x', '/y')
self.checkShift('/a','/x/', 'x', '/a/x', '/') self.checkShift('/a','/x/', 'x', '/a/x', '/')
def testNormalizedShifts(self): def testNormalizedShifts(self):
self.checkShift('/a/b', '/../y', '..', '/a', '/y') self.checkShift('/a/b', '/../y', '..', '/a', '/y')
self.checkShift('', '/../y', '..', '', '/y') self.checkShift('', '/../y', '..', '', '/y')
...@@ -246,7 +212,6 @@ class UtilityTests(TestCase): ...@@ -246,7 +212,6 @@ class UtilityTests(TestCase):
self.checkShift('/a/b', '/x//', 'x', '/a/b/x', '/') self.checkShift('/a/b', '/x//', 'x', '/a/b/x', '/')
self.checkShift('/a/b', '/.', None, '/a/b', '') self.checkShift('/a/b', '/.', None, '/a/b', '')
def testDefaults(self): def testDefaults(self):
for key, value in [ for key, value in [
('SERVER_NAME','127.0.0.1'), ('SERVER_NAME','127.0.0.1'),
...@@ -266,7 +231,6 @@ class UtilityTests(TestCase): ...@@ -266,7 +231,6 @@ class UtilityTests(TestCase):
]: ]:
self.checkDefault(key,value) self.checkDefault(key,value)
def testCrossDefaults(self): def testCrossDefaults(self):
self.checkCrossDefault('HTTP_HOST',"foo.bar",SERVER_NAME="foo.bar") self.checkCrossDefault('HTTP_HOST',"foo.bar",SERVER_NAME="foo.bar")
self.checkCrossDefault('wsgi.url_scheme',"https",HTTPS="on") self.checkCrossDefault('wsgi.url_scheme',"https",HTTPS="on")
...@@ -276,7 +240,6 @@ class UtilityTests(TestCase): ...@@ -276,7 +240,6 @@ class UtilityTests(TestCase):
self.checkCrossDefault('SERVER_PORT',"80",HTTPS="foo") self.checkCrossDefault('SERVER_PORT',"80",HTTPS="foo")
self.checkCrossDefault('SERVER_PORT',"443",HTTPS="on") self.checkCrossDefault('SERVER_PORT',"443",HTTPS="on")
def testGuessScheme(self): def testGuessScheme(self):
self.assertEqual(util.guess_scheme({}), "http") self.assertEqual(util.guess_scheme({}), "http")
self.assertEqual(util.guess_scheme({'HTTPS':"foo"}), "http") self.assertEqual(util.guess_scheme({'HTTPS':"foo"}), "http")
...@@ -284,13 +247,10 @@ class UtilityTests(TestCase): ...@@ -284,13 +247,10 @@ class UtilityTests(TestCase):
self.assertEqual(util.guess_scheme({'HTTPS':"yes"}), "https") self.assertEqual(util.guess_scheme({'HTTPS':"yes"}), "https")
self.assertEqual(util.guess_scheme({'HTTPS':"1"}), "https") self.assertEqual(util.guess_scheme({'HTTPS':"1"}), "https")
def testAppURIs(self): def testAppURIs(self):
self.checkAppURI("http://127.0.0.1/") self.checkAppURI("http://127.0.0.1/")
self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam")
self.checkAppURI("http://127.0.0.1/sp%E4m", SCRIPT_NAME="/sp\xe4m")
self.checkAppURI("http://spam.example.com:2071/", self.checkAppURI("http://spam.example.com:2071/",
HTTP_HOST="spam.example.com:2071", SERVER_PORT="2071") HTTP_HOST="spam.example.com:2071", SERVER_PORT="2071")
self.checkAppURI("http://spam.example.com/", self.checkAppURI("http://spam.example.com/",
...@@ -304,14 +264,19 @@ class UtilityTests(TestCase): ...@@ -304,14 +264,19 @@ class UtilityTests(TestCase):
def testReqURIs(self): def testReqURIs(self):
self.checkReqURI("http://127.0.0.1/") self.checkReqURI("http://127.0.0.1/")
self.checkReqURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") self.checkReqURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam")
self.checkReqURI("http://127.0.0.1/sp%E4m", SCRIPT_NAME="/sp\xe4m")
self.checkReqURI("http://127.0.0.1/spammity/spam", self.checkReqURI("http://127.0.0.1/spammity/spam",
SCRIPT_NAME="/spammity", PATH_INFO="/spam") SCRIPT_NAME="/spammity", PATH_INFO="/spam")
self.checkReqURI("http://127.0.0.1/spammity/sp%E4m",
SCRIPT_NAME="/spammity", PATH_INFO="/sp\xe4m")
self.checkReqURI("http://127.0.0.1/spammity/spam;ham", self.checkReqURI("http://127.0.0.1/spammity/spam;ham",
SCRIPT_NAME="/spammity", PATH_INFO="/spam;ham") SCRIPT_NAME="/spammity", PATH_INFO="/spam;ham")
self.checkReqURI("http://127.0.0.1/spammity/spam;cookie=1234,5678", self.checkReqURI("http://127.0.0.1/spammity/spam;cookie=1234,5678",
SCRIPT_NAME="/spammity", PATH_INFO="/spam;cookie=1234,5678") SCRIPT_NAME="/spammity", PATH_INFO="/spam;cookie=1234,5678")
self.checkReqURI("http://127.0.0.1/spammity/spam?say=ni", self.checkReqURI("http://127.0.0.1/spammity/spam?say=ni",
SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni")
self.checkReqURI("http://127.0.0.1/spammity/spam?s%E4y=ni",
SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="s%E4y=ni")
self.checkReqURI("http://127.0.0.1/spammity/spam", 0, self.checkReqURI("http://127.0.0.1/spammity/spam", 0,
SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni")
...@@ -342,7 +307,7 @@ class HeaderTests(TestCase): ...@@ -342,7 +307,7 @@ class HeaderTests(TestCase):
self.assertEqual(Headers(test[:]).keys(), ['x']) self.assertEqual(Headers(test[:]).keys(), ['x'])
self.assertEqual(Headers(test[:]).values(), ['y']) self.assertEqual(Headers(test[:]).values(), ['y'])
self.assertEqual(Headers(test[:]).items(), test) self.assertEqual(Headers(test[:]).items(), test)
self.assertFalse(Headers(test).items() is test) # must be copy! self.assertIsNot(Headers(test).items(), test) # must be copy!
h=Headers([]) h=Headers([])
del h['foo'] # should not raise an error del h['foo'] # should not raise an error
...@@ -411,15 +376,6 @@ class TestHandler(ErrorHandler): ...@@ -411,15 +376,6 @@ class TestHandler(ErrorHandler):
raise # for testing, we want to see what's happening raise # for testing, we want to see what's happening
class HandlerTests(TestCase): class HandlerTests(TestCase):
def checkEnvironAttrs(self, handler): def checkEnvironAttrs(self, handler):
...@@ -460,7 +416,6 @@ class HandlerTests(TestCase): ...@@ -460,7 +416,6 @@ class HandlerTests(TestCase):
h=TestHandler(); h.setup_environ() h=TestHandler(); h.setup_environ()
self.assertEqual(h.environ['wsgi.url_scheme'],'http') self.assertEqual(h.environ['wsgi.url_scheme'],'http')
def testAbstractMethods(self): def testAbstractMethods(self):
h = BaseHandler() h = BaseHandler()
for name in [ for name in [
...@@ -469,7 +424,6 @@ class HandlerTests(TestCase): ...@@ -469,7 +424,6 @@ class HandlerTests(TestCase):
self.assertRaises(NotImplementedError, getattr(h,name)) self.assertRaises(NotImplementedError, getattr(h,name))
self.assertRaises(NotImplementedError, h._write, "test") self.assertRaises(NotImplementedError, h._write, "test")
def testContentLength(self): def testContentLength(self):
# Demo one reason iteration is better than write()... ;) # Demo one reason iteration is better than write()... ;)
...@@ -549,7 +503,6 @@ class HandlerTests(TestCase): ...@@ -549,7 +503,6 @@ class HandlerTests(TestCase):
"\r\n"+MSG) "\r\n"+MSG)
self.assertNotEqual(h.stderr.getvalue().find("AssertionError"), -1) self.assertNotEqual(h.stderr.getvalue().find("AssertionError"), -1)
def testHeaderFormats(self): def testHeaderFormats(self):
def non_error_app(e,s): def non_error_app(e,s):
...@@ -591,40 +544,28 @@ class HandlerTests(TestCase): ...@@ -591,40 +544,28 @@ class HandlerTests(TestCase):
(stdpat%(version,sw), h.stdout.getvalue()) (stdpat%(version,sw), h.stdout.getvalue())
) )
# This epilogue is needed for compatibility with the Python 2.5 regrtest module def testCloseOnError(self):
side_effects = {'close_called': False}
MSG = b"Some output has been sent"
def error_app(e,s):
s("200 OK",[])(MSG)
class CrashyIterable(object):
def __iter__(self):
while True:
yield b'blah'
raise AssertionError("This should be caught by handler")
def close(self):
side_effects['close_called'] = True
return CrashyIterable()
h = ErrorHandler()
h.run(error_app)
self.assertEqual(side_effects['close_called'], True)
def test_main(): def test_main():
test_support.run_unittest(__name__) test_support.run_unittest(__name__)
if __name__ == "__main__": if __name__ == "__main__":
test_main() test_main()
# the above lines intentionally left blank
...@@ -74,6 +74,9 @@ def get_switch_expected(fullname): ...@@ -74,6 +74,9 @@ def get_switch_expected(fullname):
disabled_tests = [ disabled_tests = [
# The server side takes awhile to shut down
'test_httplib.HTTPSTest.test_local_bad_hostname',
'test_threading.ThreadTests.test_PyThreadState_SetAsyncExc', 'test_threading.ThreadTests.test_PyThreadState_SetAsyncExc',
# uses some internal C API of threads not available when threads are emulated with greenlets # uses some internal C API of threads not available when threads are emulated with greenlets
...@@ -148,6 +151,19 @@ disabled_tests = [ ...@@ -148,6 +151,19 @@ disabled_tests = [
'test_thread.ThreadRunningTests.test__count', 'test_thread.ThreadRunningTests.test__count',
'test_thread.TestForkInThread.test_forkinthread', 'test_thread.TestForkInThread.test_forkinthread',
# XXX needs investigating # XXX needs investigating
'test_subprocess.POSIXProcessTestCase.test_terminate_dead',
'test_subprocess.POSIXProcessTestCase.test_send_signal_dead',
'test_subprocess.POSIXProcessTestCase.test_kill_dead',
# Don't exist in the test suite until 2.7.4+; with our monkey patch in place,
# they fail because the process they're looking for has been allowed to exit.
# Our monkey patch waits for the process with a watcher and so detects
# the exit before the normal polling mechanism would
'test_subprocess.POSIXProcessTestCase.test_preexec_errpipe_does_not_double_close_pipes',
# Does not exist in the test suite until 2.7.4+. Subclasses Popen, and overrides
# _execute_child. But our version has a different parameter list than the
# version that comes with PyPy/CPython, so fails with a TypeError.
] ]
...@@ -173,18 +189,7 @@ if sys.platform == 'darwin': ...@@ -173,18 +189,7 @@ if sys.platform == 'darwin':
if hasattr(sys, 'pypy_version_info'): if hasattr(sys, 'pypy_version_info'):
disabled_tests += [ disabled_tests += [
'test_subprocess.POSIXProcessTestCase.test_terminate_dead',
'test_subprocess.POSIXProcessTestCase.test_send_signal_dead',
'test_subprocess.POSIXProcessTestCase.test_kill_dead',
# Don't exist in the CPython test suite; with our monkey patch in place,
# they fail because the process they're looking for has been allowed to exit.
# Our monkey patch waits for the process with a watcher and so detects
# the exit before the normal polling mechanism would
'test_subprocess.POSIXProcessTestCase.test_preexec_errpipe_does_not_double_close_pipes',
# Does not exist in the CPython test suite. Subclasses Popen, and overrides
# _execute_child. But our version has a different parameter list than the
# version that comes with PyPy, so fails with a TypeError.
'test_subprocess.ProcessTestCase.test_failed_child_execute_fd_leak', 'test_subprocess.ProcessTestCase.test_failed_child_execute_fd_leak',
# Does not exist in the CPython test suite, tests for a specific bug # Does not exist in the CPython test suite, tests for a specific bug
......
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