blob: 403f6bf46c52c2220654dfc0731c6e0bebed1415 [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001# Test the support for SSL and sockets
2
3import sys
4import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00005from test import support
Thomas Woutersed03b412007-08-28 21:37:11 +00006import socket
Bill Janssen6e027db2007-11-15 22:23:56 +00007import select
Thomas Woutersed03b412007-08-28 21:37:11 +00008import errno
Thomas Woutersed03b412007-08-28 21:37:11 +00009import subprocess
10import time
Antoine Pitrou3b9b9ba2010-04-23 23:33:50 +000011import gc
Thomas Woutersed03b412007-08-28 21:37:11 +000012import os
Antoine Pitrou3b9b9ba2010-04-23 23:33:50 +000013import errno
Thomas Woutersed03b412007-08-28 21:37:11 +000014import pprint
Jeremy Hylton1afc1692008-06-18 20:49:58 +000015import urllib.parse, urllib.request
Thomas Woutersed03b412007-08-28 21:37:11 +000016import shutil
17import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000018import asyncore
Antoine Pitrou78f4a9a2010-04-23 23:12:22 +000019import weakref
Thomas Woutersed03b412007-08-28 21:37:11 +000020
Georg Brandl24420152008-05-26 16:32:26 +000021from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000022
Thomas Woutersed03b412007-08-28 21:37:11 +000023# Optionally test SSL support, if we have it in the tested platform
24skip_expected = False
25try:
26 import ssl
27except ImportError:
28 skip_expected = True
29
Benjamin Petersonee8712c2008-05-20 21:35:26 +000030HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000031CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000032SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000033
Thomas Woutersed03b412007-08-28 21:37:11 +000034def handle_error(prefix):
35 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000036 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000037 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000038
39
40class BasicTests(unittest.TestCase):
41
Georg Brandlfceab5a2008-01-19 20:08:23 +000042 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000043 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000044 return
45 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
46 cert_reqs=ssl.CERT_NONE)
47 s.connect(("svn.python.org", 443))
48 c = s.getpeercert()
49 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000050 raise support.TestFailed("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000051 s.close()
52
53 # this should fail because we have no verification certs
54 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
55 cert_reqs=ssl.CERT_REQUIRED)
56 try:
57 s.connect(("svn.python.org", 443))
58 except ssl.SSLError:
59 pass
60 finally:
61 s.close()
62
Thomas Wouters1b7f8912007-09-19 03:06:30 +000063 def testCrucialConstants(self):
64 ssl.PROTOCOL_SSLv2
65 ssl.PROTOCOL_SSLv23
66 ssl.PROTOCOL_SSLv3
67 ssl.PROTOCOL_TLSv1
68 ssl.CERT_NONE
69 ssl.CERT_OPTIONAL
70 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000071
Thomas Wouters1b7f8912007-09-19 03:06:30 +000072 def testRAND(self):
73 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000074 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000075 sys.stdout.write("\n RAND_status is %d (%s)\n"
76 % (v, (v and "sufficient randomness") or
77 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000078 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000079 ssl.RAND_egd(1)
80 except TypeError:
81 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000082 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000083 print("didn't raise TypeError")
84 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000085
Thomas Wouters1b7f8912007-09-19 03:06:30 +000086 def testParseCert(self):
87 # note that this uses an 'unofficial' function in _ssl.c,
88 # provided solely for this test, to exercise the certificate
89 # parsing code
90 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000091 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000092 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000093
Thomas Wouters1b7f8912007-09-19 03:06:30 +000094 def testDERtoPEM(self):
95
96 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
97 d1 = ssl.PEM_cert_to_DER_cert(pem)
98 p2 = ssl.DER_cert_to_PEM_cert(d1)
99 d2 = ssl.PEM_cert_to_DER_cert(p2)
100 if (d1 != d2):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000101 raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000102
Antoine Pitrou78f4a9a2010-04-23 23:12:22 +0000103 @support.cpython_only
104 def test_refcycle(self):
105 # Issue #7943: an SSL object doesn't create reference cycles with
106 # itself.
107 s = socket.socket(socket.AF_INET)
108 ss = ssl.wrap_socket(s)
109 wr = weakref.ref(ss)
110 del ss
111 self.assertEqual(wr(), None)
112
Antoine Pitrou3b9b9ba2010-04-23 23:33:50 +0000113
Bill Janssen6e027db2007-11-15 22:23:56 +0000114class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000115
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000116 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000117 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
118 cert_reqs=ssl.CERT_NONE)
119 s.connect(("svn.python.org", 443))
120 c = s.getpeercert()
121 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000122 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000123 s.close()
124
125 # this should fail because we have no verification certs
126 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
127 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000128 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000129 s.connect(("svn.python.org", 443))
130 except ssl.SSLError:
131 pass
132 finally:
133 s.close()
134
135 # this should succeed because we specify the root cert
136 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
137 cert_reqs=ssl.CERT_REQUIRED,
138 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
139 try:
140 s.connect(("svn.python.org", 443))
141 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000142 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000143 finally:
144 s.close()
145
Antoine Pitroufe0f1172010-04-24 11:17:37 +0000146 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
147 def test_makefile_close(self):
148 # Issue #5238: creating a file-like object with makefile() shouldn't
149 # delay closing the underlying "real socket" (here tested with its
150 # file descriptor, hence skipping the test under Windows).
151 ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
152 ss.connect(("svn.python.org", 443))
153 fd = ss.fileno()
154 f = ss.makefile()
155 f.close()
156 # The fd is still open
157 os.read(fd, 0)
158 # Closing the SSL socket should close the fd too
159 ss.close()
160 gc.collect()
161 try:
162 os.read(fd, 0)
163 except OSError as e:
164 self.assertEqual(e.errno, errno.EBADF)
165 else:
166 self.fail("OSError wasn't raised")
167
Bill Janssen6e027db2007-11-15 22:23:56 +0000168 def testNonBlockingHandshake(self):
169 s = socket.socket(socket.AF_INET)
170 s.connect(("svn.python.org", 443))
171 s.setblocking(False)
172 s = ssl.wrap_socket(s,
173 cert_reqs=ssl.CERT_NONE,
174 do_handshake_on_connect=False)
175 count = 0
176 while True:
177 try:
178 count += 1
179 s.do_handshake()
180 break
181 except ssl.SSLError as err:
182 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
183 select.select([s], [], [])
184 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
185 select.select([], [s], [])
186 else:
187 raise
188 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000189 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000190 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000191
Bill Janssen54cc54c2007-12-14 22:08:56 +0000192 def testFetchServerCert(self):
193
194 pem = ssl.get_server_certificate(("svn.python.org", 443))
195 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000196 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000197
198 return
199
200 try:
201 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
202 except ssl.SSLError as x:
203 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000204 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000205 sys.stdout.write("%s\n" % x)
206 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000207 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000208
209 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
210 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000211 raise support.TestFailed("No server certificate on svn.python.org:443!")
212 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000213 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
214
Antoine Pitrou754b98c2010-04-22 18:47:06 +0000215 # Test disabled: OPENSSL_VERSION* not available in Python 3.1
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000216 def test_algorithms(self):
Antoine Pitrouae92a722010-04-22 18:46:16 +0000217 if support.verbose:
218 sys.stdout.write("test_algorithms disabled, "
219 "as it fails on some old OpenSSL versions")
220 return
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000221 # Issue #8484: all algorithms should be available when verifying a
222 # certificate.
Antoine Pitrouae92a722010-04-22 18:46:16 +0000223 # SHA256 was added in OpenSSL 0.9.8
224 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
225 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000226 # NOTE: https://sha256.tbs-internet.com is another possible test host
227 remote = ("sha2.hboeck.de", 443)
228 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
229 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
230 cert_reqs=ssl.CERT_REQUIRED,
231 ca_certs=sha256_cert,)
232 with support.transient_internet():
233 try:
234 s.connect(remote)
235 if support.verbose:
236 sys.stdout.write("\nCipher with %r is %r\n" %
237 (remote, s.cipher()))
238 sys.stdout.write("Certificate is:\n%s\n" %
239 pprint.pformat(s.getpeercert()))
240 finally:
241 s.close()
242
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000243
244try:
245 import threading
246except ImportError:
247 _have_threads = False
248else:
249
250 _have_threads = True
251
252 class ThreadedEchoServer(threading.Thread):
253
254 class ConnectionHandler(threading.Thread):
255
256 """A mildly complicated class, because we want it to work both
257 with and without the SSL wrapper around the socket connection, so
258 that we can test the STARTTLS functionality."""
259
Bill Janssen6e027db2007-11-15 22:23:56 +0000260 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000261 self.server = server
262 self.running = False
263 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000264 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000265 self.sock.setblocking(1)
266 self.sslconn = None
267 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000268 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000269
270 def wrap_conn (self):
271 try:
272 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
273 certfile=self.server.certificate,
274 ssl_version=self.server.protocol,
275 ca_certs=self.server.cacerts,
276 cert_reqs=self.server.certreqs)
277 except:
278 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000279 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000280 if not self.server.expect_bad_connects:
281 # here, we want to stop the server, because this shouldn't
282 # happen in the context of our test case
283 self.running = False
284 # normally, we'd just stop here, but for the test
285 # harness, we want to stop the server
286 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000287 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000288 return False
289
290 else:
291 if self.server.certreqs == ssl.CERT_REQUIRED:
292 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000293 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000294 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
295 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000296 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000297 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
298 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000299 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000300 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
301 return True
302
303 def read(self):
304 if self.sslconn:
305 return self.sslconn.read()
306 else:
307 return self.sock.recv(1024)
308
309 def write(self, bytes):
310 if self.sslconn:
311 return self.sslconn.write(bytes)
312 else:
313 return self.sock.send(bytes)
314
315 def close(self):
316 if self.sslconn:
317 self.sslconn.close()
318 else:
319 self.sock.close()
320
321 def run (self):
322 self.running = True
323 if not self.server.starttls_server:
324 if not self.wrap_conn():
325 return
326 while self.running:
327 try:
328 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000329 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000330 if not msg:
331 # eof, so quit this handler
332 self.running = False
333 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000334 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000335 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000336 sys.stdout.write(" server: client closed connection\n")
337 self.close()
338 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000339 elif (self.server.starttls_server and
340 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000341 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000342 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000343 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000344 if not self.wrap_conn():
345 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000346 elif (self.server.starttls_server and self.sslconn
347 and amsg.strip() == 'ENDTLS'):
348 if support.verbose and self.server.connectionchatty:
349 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
350 self.write("OK\n".encode("ASCII", "strict"))
351 self.sock = self.sslconn.unwrap()
352 self.sslconn = None
353 if support.verbose and self.server.connectionchatty:
354 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000355 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000356 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000357 self.server.connectionchatty):
358 ctype = (self.sslconn and "encrypted") or "unencrypted"
359 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
360 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000361 self.write(amsg.lower().encode('ASCII', 'strict'))
362 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000363 if self.server.chatty:
364 handle_error("Test server failure:\n")
365 self.close()
366 self.running = False
367 # normally, we'd just stop here, but for the test
368 # harness, we want to stop the server
369 self.server.stop()
370 except:
371 handle_error('')
372
Trent Nelson78520002008-04-10 20:54:35 +0000373 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000374 certreqs=None, cacerts=None, expect_bad_connects=False,
375 chatty=True, connectionchatty=False, starttls_server=False):
376 if ssl_version is None:
377 ssl_version = ssl.PROTOCOL_TLSv1
378 if certreqs is None:
379 certreqs = ssl.CERT_NONE
380 self.certificate = certificate
381 self.protocol = ssl_version
382 self.certreqs = certreqs
383 self.cacerts = cacerts
384 self.expect_bad_connects = expect_bad_connects
385 self.chatty = chatty
386 self.connectionchatty = connectionchatty
387 self.starttls_server = starttls_server
388 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000389 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000390 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000391 self.active = False
392 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000393 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000394
395 def start (self, flag=None):
396 self.flag = flag
397 threading.Thread.start(self)
398
399 def run (self):
400 self.sock.settimeout(0.5)
401 self.sock.listen(5)
402 self.active = True
403 if self.flag:
404 # signal an event
405 self.flag.set()
406 while self.active:
407 try:
408 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000409 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000410 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000411 + repr(connaddr) + '\n')
412 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000413 handler.start()
414 except socket.timeout:
415 pass
416 except KeyboardInterrupt:
417 self.stop()
418 except:
419 if self.chatty:
420 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000421 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000422
423 def stop (self):
424 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000425
Bill Janssen54cc54c2007-12-14 22:08:56 +0000426 class OurHTTPSServer(threading.Thread):
427
428 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000429
430 class HTTPSServer(HTTPServer):
431
432 def __init__(self, server_address, RequestHandlerClass, certfile):
433
434 HTTPServer.__init__(self, server_address, RequestHandlerClass)
435 # we assume the certfile contains both private key and certificate
436 self.certfile = certfile
437 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000438 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000439 self.allow_reuse_address = True
440
Bill Janssen6e027db2007-11-15 22:23:56 +0000441 def __str__(self):
442 return ('<%s %s:%s>' %
443 (self.__class__.__name__,
444 self.server_name,
445 self.server_port))
446
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000447 def get_request (self):
448 # override this to wrap socket with SSL
449 sock, addr = self.socket.accept()
450 sslconn = ssl.wrap_socket(sock, server_side=True,
451 certfile=self.certfile)
452 return sslconn, addr
453
454 # The methods overridden below this are mainly so that we
455 # can run it in a thread and be able to stop it from another
456 # You probably wouldn't need them in other uses.
457
458 def server_activate(self):
459 # We want to run this in a thread for testing purposes,
460 # so we override this to set timeout, so that we get
461 # a chance to stop the server
462 self.socket.settimeout(0.5)
463 HTTPServer.server_activate(self)
464
465 def serve_forever(self):
466 # We want this to run in a thread, so we use a slightly
467 # modified version of "forever".
468 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000469 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000470 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000471 # We need to lock while handling the request.
472 # Another thread can close the socket after self.active
473 # has been checked and before the request is handled.
474 # This causes an exception when using the closed socket.
475 with self.active_lock:
476 if not self.active:
477 break
478 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000479 except socket.timeout:
480 pass
481 except KeyboardInterrupt:
482 self.server_close()
483 return
484 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000485 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
486 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000487 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000488
489 def server_close(self):
490 # Again, we want this to run in a thread, so we need to override
491 # close to clear the "active" flag, so that serve_forever() will
492 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000493 with self.active_lock:
494 HTTPServer.server_close(self)
495 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000496
497 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
498
499 # need to override translate_path to get a known root,
500 # instead of using os.curdir, since the test could be
501 # run from anywhere
502
503 server_version = "TestHTTPS/1.0"
504
505 root = None
506
507 def translate_path(self, path):
508 """Translate a /-separated PATH to the local filename syntax.
509
510 Components that mean special things to the local file system
511 (e.g. drive or directory names) are ignored. (XXX They should
512 probably be diagnosed.)
513
514 """
515 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000516 path = urllib.parse.urlparse(path)[2]
517 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000518 words = path.split('/')
519 words = filter(None, words)
520 path = self.root
521 for word in words:
522 drive, word = os.path.splitdrive(word)
523 head, word = os.path.split(word)
524 if word in self.root: continue
525 path = os.path.join(path, word)
526 return path
527
528 def log_message(self, format, *args):
529
530 # we override this to suppress logging unless "verbose"
531
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000532 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000533 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
534 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000535 self.server.server_port,
536 self.request.cipher(),
537 self.log_date_time_string(),
538 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000539
540
Trent Nelson78520002008-04-10 20:54:35 +0000541 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000542 self.flag = None
543 self.active = False
544 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000545 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000546 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000547 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000548 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000549 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000550
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000551 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000552 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000553
554 def start (self, flag=None):
555 self.flag = flag
556 threading.Thread.start(self)
557
Thomas Woutersed03b412007-08-28 21:37:11 +0000558 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000559 self.active = True
560 if self.flag:
561 self.flag.set()
562 self.server.serve_forever()
563 self.active = False
564
565 def stop (self):
566 self.active = False
567 self.server.server_close()
568
569
Bill Janssen54cc54c2007-12-14 22:08:56 +0000570 class AsyncoreEchoServer(threading.Thread):
571
572 # this one's based on asyncore.dispatcher
573
574 class EchoServer (asyncore.dispatcher):
575
576 class ConnectionHandler (asyncore.dispatcher_with_send):
577
578 def __init__(self, conn, certfile):
579 self.socket = ssl.wrap_socket(conn, server_side=True,
580 certfile=certfile,
581 do_handshake_on_connect=False)
582 asyncore.dispatcher_with_send.__init__(self, self.socket)
Antoine Pitrouec146182010-04-24 21:30:20 +0000583 self._ssl_accepting = True
584 self._do_ssl_handshake()
Bill Janssen54cc54c2007-12-14 22:08:56 +0000585
586 def readable(self):
587 if isinstance(self.socket, ssl.SSLSocket):
588 while self.socket.pending() > 0:
589 self.handle_read_event()
590 return True
591
Antoine Pitrouec146182010-04-24 21:30:20 +0000592 def _do_ssl_handshake(self):
593 try:
594 self.socket.do_handshake()
595 except ssl.SSLError as err:
596 if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
597 ssl.SSL_ERROR_WANT_WRITE):
598 return
599 elif err.args[0] == ssl.SSL_ERROR_EOF:
600 return self.handle_close()
601 raise
602 except socket.error as err:
603 if err.args[0] == errno.ECONNABORTED:
604 return self.handle_close()
Bill Janssen54cc54c2007-12-14 22:08:56 +0000605 else:
Antoine Pitrouec146182010-04-24 21:30:20 +0000606 self._ssl_accepting = False
607
608 def handle_read(self):
609 if self._ssl_accepting:
610 self._do_ssl_handshake()
611 else:
612 data = self.recv(1024)
613 if support.verbose:
614 sys.stdout.write(" server: read %s from client\n" % repr(data))
615 if not data:
616 self.close()
617 else:
618 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
Bill Janssen54cc54c2007-12-14 22:08:56 +0000619
620 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000621 self.close()
Antoine Pitrouec146182010-04-24 21:30:20 +0000622 if test_support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000623 sys.stdout.write(" server: closed connection %s\n" % self.socket)
624
625 def handle_error(self):
626 raise
627
628 def __init__(self, port, certfile):
629 self.port = port
630 self.certfile = certfile
631 asyncore.dispatcher.__init__(self)
632 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
633 self.bind(('', port))
634 self.listen(5)
635
636 def handle_accept(self):
637 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000638 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000639 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
640 self.ConnectionHandler(sock_obj, self.certfile)
641
642 def handle_error(self):
643 raise
644
Trent Nelson78520002008-04-10 20:54:35 +0000645 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000646 self.flag = None
647 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000648 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000649 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000650 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000651 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000652
653 def __str__(self):
654 return "<%s %s>" % (self.__class__.__name__, self.server)
655
656 def start (self, flag=None):
657 self.flag = flag
658 threading.Thread.start(self)
659
660 def run (self):
661 self.active = True
662 if self.flag:
663 self.flag.set()
664 while self.active:
665 try:
666 asyncore.loop(1)
667 except:
668 pass
669
670 def stop (self):
671 self.active = False
672 self.server.close()
673
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000674 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000675 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000676 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000677 cacerts=CERTFILE, chatty=False,
678 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000679 flag = threading.Event()
680 server.start(flag)
681 # wait for it to start
682 flag.wait()
683 # try to connect
684 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000685 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000686 s = ssl.wrap_socket(socket.socket(),
687 certfile=certfile,
688 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000689 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000690 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000691 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000692 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000693 except socket.error as x:
694 if support.verbose:
695 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000696 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000697 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000698 "Use of invalid cert should have failed!")
699 finally:
700 server.stop()
701 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000702
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000703 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000704 client_certfile, client_protocol=None,
705 indata="FOO\n",
706 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000707
Trent Nelson78520002008-04-10 20:54:35 +0000708 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000709 certreqs=certreqs,
710 ssl_version=protocol,
711 cacerts=cacertsfile,
712 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000713 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000714 flag = threading.Event()
715 server.start(flag)
716 # wait for it to start
717 flag.wait()
718 # try to connect
719 if client_protocol is None:
720 client_protocol = protocol
721 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000722 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000723 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000724 certfile=client_certfile,
725 ca_certs=cacertsfile,
726 cert_reqs=certreqs,
727 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000728 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000729 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000730 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000731 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000732 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000733 else:
734 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000735 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000736 sys.stdout.write(
737 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000738 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000739 outdata = s.read()
740 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000741 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000742 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000743 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000744 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000745 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000746 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000747 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
748 repr(indata[:min(len(indata),20)].lower()), len(indata)))
749 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000750 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000751 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000752 sys.stdout.write(" client: closing connection.\n")
753 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000754 finally:
755 server.stop()
756 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000757
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000758 def tryProtocolCombo (server_protocol,
759 client_protocol,
760 expectedToWork,
761 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000762
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000763 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000764 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000765
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000766 if certsreqs == ssl.CERT_NONE:
767 certtype = "CERT_NONE"
768 elif certsreqs == ssl.CERT_OPTIONAL:
769 certtype = "CERT_OPTIONAL"
770 elif certsreqs == ssl.CERT_REQUIRED:
771 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000772 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000773 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
774 sys.stdout.write(formatstr %
775 (ssl.get_protocol_name(client_protocol),
776 ssl.get_protocol_name(server_protocol),
777 certtype))
778 try:
779 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000780 CERTFILE, CERTFILE, client_protocol,
781 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000782 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000783 if expectedToWork:
784 raise
785 else:
786 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000787 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000788 "Client protocol %s succeeded with server protocol %s!"
789 % (ssl.get_protocol_name(client_protocol),
790 ssl.get_protocol_name(server_protocol)))
791
792
Bill Janssen6e027db2007-11-15 22:23:56 +0000793 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000794
Trent Nelson6b240cd2008-04-10 20:12:06 +0000795 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000796
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000797 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000798 sys.stdout.write("\n")
799 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
800 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
801 chatty=True, connectionchatty=True)
802
803 def testReadCert(self):
804
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000805 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000806 sys.stdout.write("\n")
807 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000808 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000809 certreqs=ssl.CERT_NONE,
810 ssl_version=ssl.PROTOCOL_SSLv23,
811 cacerts=CERTFILE,
812 chatty=False)
813 flag = threading.Event()
814 server.start(flag)
815 # wait for it to start
816 flag.wait()
817 # try to connect
818 try:
819 try:
820 s = ssl.wrap_socket(socket.socket(),
821 certfile=CERTFILE,
822 ca_certs=CERTFILE,
823 cert_reqs=ssl.CERT_REQUIRED,
824 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000825 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000826 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000827 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000828 "Unexpected SSL error: " + str(x))
829 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000830 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000831 "Unexpected exception: " + str(x))
832 else:
833 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000834 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000835 "Can't SSL-handshake with test server")
836 cert = s.getpeercert()
837 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000838 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000839 "Can't get peer certificate.")
840 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000841 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000842 sys.stdout.write(pprint.pformat(cert) + '\n')
843 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000844 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000845 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000846 "No subject field in certificate: %s." %
847 pprint.pformat(cert))
848 if ((('organizationName', 'Python Software Foundation'),)
849 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000850 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000851 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000852 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000853 s.close()
854 finally:
855 server.stop()
856 server.join()
857
858 def testNULLcert(self):
859 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
860 "nullcert.pem"))
861 def testMalformedCert(self):
862 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
863 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000864 def testWrongCert(self):
865 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
866 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000867 def testMalformedKey(self):
868 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
869 "badkey.pem"))
870
Trent Nelson6b240cd2008-04-10 20:12:06 +0000871 def testRudeShutdown(self):
872
873 listener_ready = threading.Event()
874 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000875 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000876
877 # `listener` runs in a thread. It opens a socket listening on
878 # PORT, and sits in an accept() until the main thread connects.
879 # Then it rudely closes the socket, and sets Event `listener_gone`
880 # to let the main thread know the socket is gone.
881 def listener():
882 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000883 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000884 s.listen(5)
885 listener_ready.set()
886 s.accept()
887 s = None # reclaim the socket object, which also closes it
888 listener_gone.set()
889
890 def connector():
891 listener_ready.wait()
892 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000893 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000894 listener_gone.wait()
895 try:
896 ssl_sock = ssl.wrap_socket(s)
897 except IOError:
898 pass
899 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000900 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000901 'connecting to closed SSL socket should have failed')
902
903 t = threading.Thread(target=listener)
904 t.start()
905 connector()
906 t.join()
907
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000908 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000909 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000910 sys.stdout.write("\n")
911 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
912 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
913 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
914 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
915 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
916 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
917
918 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000919 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000920 sys.stdout.write("\n")
921 try:
922 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000923 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000924 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000925 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000926 sys.stdout.write(
927 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
928 % str(x))
929 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
930 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
931 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
932
933 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
934 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
935 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
936
937 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
938 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
939 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
940
941 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000942 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000943 sys.stdout.write("\n")
944 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
945 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
946 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
947 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
948 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
949 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
950
951 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000952 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000953 sys.stdout.write("\n")
954 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
955 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
956 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
957 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
958 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
959 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
960
961 def testSTARTTLS (self):
962
Bill Janssen40a0f662008-08-12 16:56:25 +0000963 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000964
Trent Nelson78520002008-04-10 20:54:35 +0000965 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000966 ssl_version=ssl.PROTOCOL_TLSv1,
967 starttls_server=True,
968 chatty=True,
969 connectionchatty=True)
970 flag = threading.Event()
971 server.start(flag)
972 # wait for it to start
973 flag.wait()
974 # try to connect
975 wrapped = False
976 try:
977 try:
978 s = socket.socket()
979 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000980 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000981 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000982 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000983 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000984 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000985 sys.stdout.write("\n")
986 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000987 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000988 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000989 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000990 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000991 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000992 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000993 outdata = conn.read()
994 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000995 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000996 outdata = s.recv(1024)
997 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000998 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000999 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +00001000 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001001 sys.stdout.write(
1002 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +00001003 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001004 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001005 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +00001006 elif (indata == "ENDTLS" and
1007 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
1008 if support.verbose:
1009 msg = str(outdata, 'ASCII', 'replace')
1010 sys.stdout.write(
1011 " client: read %s from server, ending TLS...\n"
1012 % repr(msg))
1013 s = conn.unwrap()
1014 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001015 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001016 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +00001017 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001018 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +00001019 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001020 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001021 sys.stdout.write(" client: closing connection.\n")
1022 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +00001023 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001024 else:
Bill Janssen40a0f662008-08-12 16:56:25 +00001025 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +00001026 if wrapped:
1027 conn.close()
1028 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001029 s.close()
1030 finally:
1031 server.stop()
1032 server.join()
1033
Bill Janssen54cc54c2007-12-14 22:08:56 +00001034 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +00001035
Trent Nelson78520002008-04-10 20:54:35 +00001036 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001037 flag = threading.Event()
1038 server.start(flag)
1039 # wait for it to start
1040 flag.wait()
1041 # try to connect
1042 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001043 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001044 sys.stdout.write('\n')
1045 d1 = open(CERTFILE, 'rb').read()
1046 d2 = ''
1047 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001048 url = 'https://%s:%d/%s' % (
1049 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001050 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001051 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001052 if dlen and (int(dlen) > 0):
1053 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001054 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001055 sys.stdout.write(
1056 " client: read %d bytes from remote server '%s'\n"
1057 % (len(d2), server))
1058 f.close()
1059 except:
1060 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001061 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001062 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001063 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001064 else:
1065 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001066 print("d1 is", len(d1), repr(d1))
1067 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001068 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001069 "Couldn't fetch data from HTTPS server")
1070 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001071 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001072 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001073 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001074 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001075 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001076 server.join()
1077
Trent Nelson6b240cd2008-04-10 20:12:06 +00001078 def testAsyncoreServer(self):
1079
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001080 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001081 sys.stdout.write("\n")
1082
1083 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001084 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001085 flag = threading.Event()
1086 server.start(flag)
1087 # wait for it to start
1088 flag.wait()
1089 # try to connect
1090 try:
1091 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001092 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001093 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001094 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001095 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001096 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001097 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001098 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001099 sys.stdout.write(
1100 " client: sending %s...\n" % (repr(indata)))
1101 s.sendall(indata.encode('ASCII', 'strict'))
1102 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001103 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001104 sys.stdout.write(" client: read %s\n" % repr(outdata))
1105 outdata = str(outdata, 'ASCII', 'strict')
1106 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001107 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001108 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1109 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1110 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1111 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001112 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001113 sys.stdout.write(" client: closing connection.\n")
1114 s.close()
1115 finally:
1116 server.stop()
1117 server.join()
1118
Bill Janssen58afe4c2008-09-08 16:45:19 +00001119 def testAllRecvAndSendMethods(self):
1120
1121 if support.verbose:
1122 sys.stdout.write("\n")
1123
1124 server = ThreadedEchoServer(CERTFILE,
1125 certreqs=ssl.CERT_NONE,
1126 ssl_version=ssl.PROTOCOL_TLSv1,
1127 cacerts=CERTFILE,
1128 chatty=True,
1129 connectionchatty=False)
1130 flag = threading.Event()
1131 server.start(flag)
1132 # wait for it to start
1133 flag.wait()
1134 # try to connect
1135 try:
1136 s = ssl.wrap_socket(socket.socket(),
1137 server_side=False,
1138 certfile=CERTFILE,
1139 ca_certs=CERTFILE,
1140 cert_reqs=ssl.CERT_NONE,
1141 ssl_version=ssl.PROTOCOL_TLSv1)
1142 s.connect((HOST, server.port))
1143 except ssl.SSLError as x:
1144 raise support.TestFailed("Unexpected SSL error: " + str(x))
1145 except Exception as x:
1146 raise support.TestFailed("Unexpected exception: " + str(x))
1147 else:
1148 # helper methods for standardising recv* method signatures
1149 def _recv_into():
1150 b = bytearray(b"\0"*100)
1151 count = s.recv_into(b)
1152 return b[:count]
1153
1154 def _recvfrom_into():
1155 b = bytearray(b"\0"*100)
1156 count, addr = s.recvfrom_into(b)
1157 return b[:count]
1158
1159 # (name, method, whether to expect success, *args)
1160 send_methods = [
1161 ('send', s.send, True, []),
1162 ('sendto', s.sendto, False, ["some.address"]),
1163 ('sendall', s.sendall, True, []),
1164 ]
1165 recv_methods = [
1166 ('recv', s.recv, True, []),
1167 ('recvfrom', s.recvfrom, False, ["some.address"]),
1168 ('recv_into', _recv_into, True, []),
1169 ('recvfrom_into', _recvfrom_into, False, []),
1170 ]
1171 data_prefix = "PREFIX_"
1172
1173 for meth_name, send_meth, expect_success, args in send_methods:
1174 indata = data_prefix + meth_name
1175 try:
1176 send_meth(indata.encode('ASCII', 'strict'), *args)
1177 outdata = s.read()
1178 outdata = str(outdata, 'ASCII', 'strict')
1179 if outdata != indata.lower():
1180 raise support.TestFailed(
1181 "While sending with <<{name:s}>> bad data "
1182 "<<{outdata:s}>> ({nout:d}) received; "
1183 "expected <<{indata:s}>> ({nin:d})\n".format(
1184 name=meth_name, outdata=repr(outdata[:20]),
1185 nout=len(outdata),
1186 indata=repr(indata[:20]), nin=len(indata)
1187 )
1188 )
1189 except ValueError as e:
1190 if expect_success:
1191 raise support.TestFailed(
1192 "Failed to send with method <<{name:s}>>; "
1193 "expected to succeed.\n".format(name=meth_name)
1194 )
1195 if not str(e).startswith(meth_name):
1196 raise support.TestFailed(
1197 "Method <<{name:s}>> failed with unexpected "
1198 "exception message: {exp:s}\n".format(
1199 name=meth_name, exp=e
1200 )
1201 )
1202
1203 for meth_name, recv_meth, expect_success, args in recv_methods:
1204 indata = data_prefix + meth_name
1205 try:
1206 s.send(indata.encode('ASCII', 'strict'))
1207 outdata = recv_meth(*args)
1208 outdata = str(outdata, 'ASCII', 'strict')
1209 if outdata != indata.lower():
1210 raise support.TestFailed(
1211 "While receiving with <<{name:s}>> bad data "
1212 "<<{outdata:s}>> ({nout:d}) received; "
1213 "expected <<{indata:s}>> ({nin:d})\n".format(
1214 name=meth_name, outdata=repr(outdata[:20]),
1215 nout=len(outdata),
1216 indata=repr(indata[:20]), nin=len(indata)
1217 )
1218 )
1219 except ValueError as e:
1220 if expect_success:
1221 raise support.TestFailed(
1222 "Failed to receive with method <<{name:s}>>; "
1223 "expected to succeed.\n".format(name=meth_name)
1224 )
1225 if not str(e).startswith(meth_name):
1226 raise support.TestFailed(
1227 "Method <<{name:s}>> failed with unexpected "
1228 "exception message: {exp:s}\n".format(
1229 name=meth_name, exp=e
1230 )
1231 )
1232 # consume data
1233 s.read()
1234
1235 s.write("over\n".encode("ASCII", "strict"))
1236 s.close()
1237 finally:
1238 server.stop()
1239 server.join()
1240
Antoine Pitrouec146182010-04-24 21:30:20 +00001241 def test_handshake_timeout(self):
1242 # Issue #5103: SSL handshake must respect the socket timeout
1243 server = socket.socket(socket.AF_INET)
1244 host = "127.0.0.1"
1245 port = support.bind_port(server)
1246 started = threading.Event()
1247 finish = False
1248
1249 def serve():
1250 server.listen(5)
1251 started.set()
1252 conns = []
1253 while not finish:
1254 r, w, e = select.select([server], [], [], 0.1)
1255 if server in r:
1256 # Let the socket hang around rather than having
1257 # it closed by garbage collection.
1258 conns.append(server.accept()[0])
1259
1260 t = threading.Thread(target=serve)
1261 t.start()
1262 started.wait()
1263
1264 try:
1265 if 0:
1266 # Disabled until #8524 finds a solution
1267 try:
1268 c = socket.socket(socket.AF_INET)
1269 c.settimeout(1.0)
1270 c.connect((host, port))
1271 # Will attempt handshake and time out
1272 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1273 ssl.wrap_socket, c)
1274 finally:
1275 c.close()
1276 try:
1277 c = socket.socket(socket.AF_INET)
1278 c = ssl.wrap_socket(c)
1279 c.settimeout(0.2)
1280 # Will attempt handshake and time out
1281 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1282 c.connect, (host, port))
1283 finally:
1284 c.close()
1285 finally:
1286 finish = True
1287 t.join()
1288 server.close()
1289
Bill Janssen58afe4c2008-09-08 16:45:19 +00001290
Thomas Woutersed03b412007-08-28 21:37:11 +00001291def test_main(verbose=False):
1292 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001293 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001294
Trent Nelson78520002008-04-10 20:54:35 +00001295 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001296 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1297 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001298 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1299 os.path.dirname(__file__) or os.curdir,
1300 "https_svn_python_org_root.pem")
1301
1302 if (not os.path.exists(CERTFILE) or
1303 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001304 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001305
Thomas Woutersed03b412007-08-28 21:37:11 +00001306 tests = [BasicTests]
1307
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001308 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001309 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001310
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001311 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001312 thread_info = support.threading_setup()
1313 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001314 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001315
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001316 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001317
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001318 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001319 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001320
1321if __name__ == "__main__":
1322 test_main()