blob: b05b17eece4b81bbed26b3ab5e554e40f929963b [file] [log] [blame]
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001# Test the support for SSL and sockets
2
3import sys
4import unittest
5from test import test_support
Bill Janssen934b16d2008-06-28 22:19:33 +00006import asyncore
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00007import socket
Bill Janssen934b16d2008-06-28 22:19:33 +00008import select
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00009import errno
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000010import subprocess
11import time
12import os
13import pprint
Bill Janssen296a59d2007-09-16 22:06:00 +000014import urllib, urlparse
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000015import shutil
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000016import traceback
17
Bill Janssen296a59d2007-09-16 22:06:00 +000018from BaseHTTPServer import HTTPServer
19from SimpleHTTPServer import SimpleHTTPRequestHandler
20
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000021# Optionally test SSL support, if we have it in the tested platform
22skip_expected = False
23try:
24 import ssl
25except ImportError:
26 skip_expected = True
27
Trent Nelsone41b0062008-04-08 23:47:30 +000028HOST = test_support.HOST
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000029CERTFILE = None
Bill Janssen296a59d2007-09-16 22:06:00 +000030SVN_PYTHON_ORG_ROOT_CERT = None
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000031
Neal Norwitz3e533c22007-08-27 01:03:18 +000032def handle_error(prefix):
33 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Bill Janssen98d19da2007-09-10 21:51:02 +000034 if test_support.verbose:
35 sys.stdout.write(prefix + exc_format)
Neal Norwitz3e533c22007-08-27 01:03:18 +000036
37
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000038class BasicTests(unittest.TestCase):
39
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000040 def testSSLconnect(self):
Christian Heimes6c29be52008-01-19 16:39:27 +000041 if not test_support.is_resource_enabled('network'):
42 return
Bill Janssen296a59d2007-09-16 22:06:00 +000043 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
44 cert_reqs=ssl.CERT_NONE)
45 s.connect(("svn.python.org", 443))
46 c = s.getpeercert()
47 if c:
48 raise test_support.TestFailed("Peer cert %s shouldn't be here!")
49 s.close()
50
51 # this should fail because we have no verification certs
52 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
53 cert_reqs=ssl.CERT_REQUIRED)
54 try:
55 s.connect(("svn.python.org", 443))
56 except ssl.SSLError:
57 pass
58 finally:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000059 s.close()
60
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000061
Bill Janssen98d19da2007-09-10 21:51:02 +000062 def testCrucialConstants(self):
63 ssl.PROTOCOL_SSLv2
64 ssl.PROTOCOL_SSLv23
65 ssl.PROTOCOL_SSLv3
66 ssl.PROTOCOL_TLSv1
67 ssl.CERT_NONE
68 ssl.CERT_OPTIONAL
69 ssl.CERT_REQUIRED
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000070
Bill Janssen98d19da2007-09-10 21:51:02 +000071 def testRAND(self):
72 v = ssl.RAND_status()
73 if test_support.verbose:
74 sys.stdout.write("\n RAND_status is %d (%s)\n"
75 % (v, (v and "sufficient randomness") or
76 "insufficient randomness"))
Guido van Rossume4729332007-08-26 19:35:09 +000077 try:
Bill Janssen98d19da2007-09-10 21:51:02 +000078 ssl.RAND_egd(1)
79 except TypeError:
80 pass
Guido van Rossume4729332007-08-26 19:35:09 +000081 else:
Bill Janssen98d19da2007-09-10 21:51:02 +000082 print "didn't raise TypeError"
83 ssl.RAND_add("this is a random string", 75.0)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000084
Bill Janssen98d19da2007-09-10 21:51:02 +000085 def testParseCert(self):
86 # note that this uses an 'unofficial' function in _ssl.c,
87 # provided solely for this test, to exercise the certificate
88 # parsing code
89 p = ssl._ssl._test_decode_cert(CERTFILE, False)
90 if test_support.verbose:
91 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000092
Bill Janssen296a59d2007-09-16 22:06:00 +000093 def testDERtoPEM(self):
94
95 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
96 d1 = ssl.PEM_cert_to_DER_cert(pem)
97 p2 = ssl.DER_cert_to_PEM_cert(d1)
98 d2 = ssl.PEM_cert_to_DER_cert(p2)
99 if (d1 != d2):
100 raise test_support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
101
Bill Janssen934b16d2008-06-28 22:19:33 +0000102class NetworkedTests(unittest.TestCase):
Bill Janssen296a59d2007-09-16 22:06:00 +0000103
104 def testConnect(self):
Bill Janssen296a59d2007-09-16 22:06:00 +0000105 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
106 cert_reqs=ssl.CERT_NONE)
107 s.connect(("svn.python.org", 443))
108 c = s.getpeercert()
109 if c:
110 raise test_support.TestFailed("Peer cert %s shouldn't be here!")
111 s.close()
112
113 # this should fail because we have no verification certs
114 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
115 cert_reqs=ssl.CERT_REQUIRED)
116 try:
117 s.connect(("svn.python.org", 443))
118 except ssl.SSLError:
119 pass
120 finally:
121 s.close()
122
123 # this should succeed because we specify the root cert
124 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
125 cert_reqs=ssl.CERT_REQUIRED,
126 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
127 try:
128 s.connect(("svn.python.org", 443))
129 except ssl.SSLError, x:
130 raise test_support.TestFailed("Unexpected exception %s" % x)
131 finally:
132 s.close()
133
Bill Janssen934b16d2008-06-28 22:19:33 +0000134
135 def testNonBlockingHandshake(self):
136 s = socket.socket(socket.AF_INET)
137 s.connect(("svn.python.org", 443))
138 s.setblocking(False)
139 s = ssl.wrap_socket(s,
140 cert_reqs=ssl.CERT_NONE,
141 do_handshake_on_connect=False)
142 count = 0
143 while True:
144 try:
145 count += 1
146 s.do_handshake()
147 break
148 except ssl.SSLError, err:
149 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
150 select.select([s], [], [])
151 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
152 select.select([], [s], [])
153 else:
154 raise
155 s.close()
156 if test_support.verbose:
157 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
158
Bill Janssen296a59d2007-09-16 22:06:00 +0000159 def testFetchServerCert(self):
160
161 pem = ssl.get_server_certificate(("svn.python.org", 443))
162 if not pem:
163 raise test_support.TestFailed("No server certificate on svn.python.org:443!")
164
165 try:
166 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
167 except ssl.SSLError:
168 #should fail
169 pass
170 else:
171 raise test_support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
172
173 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
174 if not pem:
175 raise test_support.TestFailed("No server certificate on svn.python.org:443!")
176 if test_support.verbose:
177 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
178
179
Bill Janssen98d19da2007-09-10 21:51:02 +0000180try:
181 import threading
182except ImportError:
183 _have_threads = False
184else:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000185
Bill Janssen98d19da2007-09-10 21:51:02 +0000186 _have_threads = True
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000187
Bill Janssen98d19da2007-09-10 21:51:02 +0000188 class ThreadedEchoServer(threading.Thread):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000189
Bill Janssen98d19da2007-09-10 21:51:02 +0000190 class ConnectionHandler(threading.Thread):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000191
Bill Janssen98d19da2007-09-10 21:51:02 +0000192 """A mildly complicated class, because we want it to work both
193 with and without the SSL wrapper around the socket connection, so
194 that we can test the STARTTLS functionality."""
195
196 def __init__(self, server, connsock):
197 self.server = server
198 self.running = False
199 self.sock = connsock
200 self.sock.setblocking(1)
201 self.sslconn = None
202 threading.Thread.__init__(self)
203 self.setDaemon(True)
204
Bill Janssen934b16d2008-06-28 22:19:33 +0000205 def show_conn_details(self):
206 if self.server.certreqs == ssl.CERT_REQUIRED:
207 cert = self.sslconn.getpeercert()
208 if test_support.verbose and self.server.chatty:
209 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
210 cert_binary = self.sslconn.getpeercert(True)
211 if test_support.verbose and self.server.chatty:
212 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
213 cipher = self.sslconn.cipher()
214 if test_support.verbose and self.server.chatty:
215 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
216
Bill Janssen98d19da2007-09-10 21:51:02 +0000217 def wrap_conn (self):
218 try:
219 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
220 certfile=self.server.certificate,
221 ssl_version=self.server.protocol,
222 ca_certs=self.server.cacerts,
223 cert_reqs=self.server.certreqs)
224 except:
225 if self.server.chatty:
226 handle_error("\n server: bad connection attempt from " +
227 str(self.sock.getpeername()) + ":\n")
Bill Janssen934b16d2008-06-28 22:19:33 +0000228 self.close()
Bill Janssen98d19da2007-09-10 21:51:02 +0000229 if not self.server.expect_bad_connects:
230 # here, we want to stop the server, because this shouldn't
231 # happen in the context of our test case
232 self.running = False
233 # normally, we'd just stop here, but for the test
234 # harness, we want to stop the server
235 self.server.stop()
236 return False
237
238 else:
Bill Janssen98d19da2007-09-10 21:51:02 +0000239 return True
240
241 def read(self):
242 if self.sslconn:
243 return self.sslconn.read()
244 else:
245 return self.sock.recv(1024)
246
247 def write(self, bytes):
248 if self.sslconn:
249 return self.sslconn.write(bytes)
250 else:
251 return self.sock.send(bytes)
252
253 def close(self):
254 if self.sslconn:
255 self.sslconn.close()
256 else:
Bill Janssen934b16d2008-06-28 22:19:33 +0000257 self.sock._sock.close()
Bill Janssen98d19da2007-09-10 21:51:02 +0000258
259 def run (self):
260 self.running = True
261 if not self.server.starttls_server:
Bill Janssen934b16d2008-06-28 22:19:33 +0000262 if isinstance(self.sock, ssl.SSLSocket):
263 self.sslconn = self.sock
264 elif not self.wrap_conn():
Bill Janssen98d19da2007-09-10 21:51:02 +0000265 return
Bill Janssen934b16d2008-06-28 22:19:33 +0000266 self.show_conn_details()
Bill Janssen98d19da2007-09-10 21:51:02 +0000267 while self.running:
268 try:
269 msg = self.read()
270 if not msg:
271 # eof, so quit this handler
272 self.running = False
273 self.close()
274 elif msg.strip() == 'over':
275 if test_support.verbose and self.server.connectionchatty:
276 sys.stdout.write(" server: client closed connection\n")
277 self.close()
278 return
279 elif self.server.starttls_server and msg.strip() == 'STARTTLS':
280 if test_support.verbose and self.server.connectionchatty:
281 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
282 self.write("OK\n")
283 if not self.wrap_conn():
284 return
285 else:
286 if (test_support.verbose and
287 self.server.connectionchatty):
288 ctype = (self.sslconn and "encrypted") or "unencrypted"
289 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
290 % (repr(msg), ctype, repr(msg.lower()), ctype))
291 self.write(msg.lower())
292 except ssl.SSLError:
293 if self.server.chatty:
294 handle_error("Test server failure:\n")
295 self.close()
296 self.running = False
297 # normally, we'd just stop here, but for the test
298 # harness, we want to stop the server
299 self.server.stop()
300 except:
301 handle_error('')
302
Trent Nelsone41b0062008-04-08 23:47:30 +0000303 def __init__(self, certificate, ssl_version=None,
Bill Janssen98d19da2007-09-10 21:51:02 +0000304 certreqs=None, cacerts=None, expect_bad_connects=False,
Bill Janssen934b16d2008-06-28 22:19:33 +0000305 chatty=True, connectionchatty=False, starttls_server=False,
306 wrap_accepting_socket=False):
307
Bill Janssen98d19da2007-09-10 21:51:02 +0000308 if ssl_version is None:
309 ssl_version = ssl.PROTOCOL_TLSv1
310 if certreqs is None:
311 certreqs = ssl.CERT_NONE
312 self.certificate = certificate
313 self.protocol = ssl_version
314 self.certreqs = certreqs
315 self.cacerts = cacerts
316 self.expect_bad_connects = expect_bad_connects
317 self.chatty = chatty
318 self.connectionchatty = connectionchatty
319 self.starttls_server = starttls_server
320 self.sock = socket.socket()
321 self.flag = None
Bill Janssen934b16d2008-06-28 22:19:33 +0000322 if wrap_accepting_socket:
323 self.sock = ssl.wrap_socket(self.sock, server_side=True,
324 certfile=self.certificate,
325 cert_reqs = self.certreqs,
326 ca_certs = self.cacerts,
327 ssl_version = self.protocol)
328 if test_support.verbose and self.chatty:
329 sys.stdout.write(' server: wrapped server socket as %s\n' % str(self.sock))
330 self.port = test_support.bind_port(self.sock)
Bill Janssen98d19da2007-09-10 21:51:02 +0000331 self.active = False
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000332 threading.Thread.__init__(self)
Bill Janssen98d19da2007-09-10 21:51:02 +0000333 self.setDaemon(False)
334
335 def start (self, flag=None):
336 self.flag = flag
337 threading.Thread.start(self)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000338
339 def run (self):
Bill Janssen98d19da2007-09-10 21:51:02 +0000340 self.sock.settimeout(0.5)
341 self.sock.listen(5)
342 self.active = True
343 if self.flag:
344 # signal an event
345 self.flag.set()
346 while self.active:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000347 try:
Bill Janssen98d19da2007-09-10 21:51:02 +0000348 newconn, connaddr = self.sock.accept()
349 if test_support.verbose and self.chatty:
350 sys.stdout.write(' server: new connection from '
351 + str(connaddr) + '\n')
352 handler = self.ConnectionHandler(self, newconn)
353 handler.start()
354 except socket.timeout:
355 pass
356 except KeyboardInterrupt:
357 self.stop()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000358 except:
Bill Janssen98d19da2007-09-10 21:51:02 +0000359 if self.chatty:
360 handle_error("Test server failure:\n")
Bill Janssen934b16d2008-06-28 22:19:33 +0000361 self.sock.close()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000362
Bill Janssen98d19da2007-09-10 21:51:02 +0000363 def stop (self):
364 self.active = False
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000365
Bill Janssen934b16d2008-06-28 22:19:33 +0000366 class AsyncoreEchoServer(threading.Thread):
Bill Janssen296a59d2007-09-16 22:06:00 +0000367
Bill Janssen934b16d2008-06-28 22:19:33 +0000368 class EchoServer (asyncore.dispatcher):
369
370 class ConnectionHandler (asyncore.dispatcher_with_send):
371
372 def __init__(self, conn, certfile):
373 asyncore.dispatcher_with_send.__init__(self, conn)
374 self.socket = ssl.wrap_socket(conn, server_side=True,
375 certfile=certfile,
376 do_handshake_on_connect=True)
377
378 def readable(self):
379 if isinstance(self.socket, ssl.SSLSocket):
380 while self.socket.pending() > 0:
381 self.handle_read_event()
382 return True
383
384 def handle_read(self):
385 data = self.recv(1024)
386 self.send(data.lower())
387
388 def handle_close(self):
Bill Janssende34d912008-06-28 23:00:39 +0000389 self.close()
Bill Janssen934b16d2008-06-28 22:19:33 +0000390 if test_support.verbose:
391 sys.stdout.write(" server: closed connection %s\n" % self.socket)
392
393 def handle_error(self):
394 raise
395
396 def __init__(self, certfile):
397 self.certfile = certfile
398 asyncore.dispatcher.__init__(self)
399 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
400 self.port = test_support.bind_port(self.socket)
401 self.listen(5)
402
403 def handle_accept(self):
404 sock_obj, addr = self.accept()
405 if test_support.verbose:
406 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
407 self.ConnectionHandler(sock_obj, self.certfile)
408
409 def handle_error(self):
410 raise
411
412 def __init__(self, certfile):
413 self.flag = None
414 self.active = False
415 self.server = self.EchoServer(certfile)
416 self.port = self.server.port
417 threading.Thread.__init__(self)
418 self.setDaemon(True)
419
420 def __str__(self):
421 return "<%s %s>" % (self.__class__.__name__, self.server)
422
423 def start (self, flag=None):
424 self.flag = flag
425 threading.Thread.start(self)
426
427 def run (self):
428 self.active = True
429 if self.flag:
430 self.flag.set()
431 while self.active:
432 try:
433 asyncore.loop(1)
434 except:
435 pass
436
437 def stop (self):
438 self.active = False
439 self.server.close()
440
441 class SocketServerHTTPSServer(threading.Thread):
Bill Janssen296a59d2007-09-16 22:06:00 +0000442
443 class HTTPSServer(HTTPServer):
444
445 def __init__(self, server_address, RequestHandlerClass, certfile):
446
447 HTTPServer.__init__(self, server_address, RequestHandlerClass)
448 # we assume the certfile contains both private key and certificate
449 self.certfile = certfile
450 self.active = False
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000451 self.active_lock = threading.Lock()
Bill Janssen296a59d2007-09-16 22:06:00 +0000452 self.allow_reuse_address = True
453
Bill Janssen934b16d2008-06-28 22:19:33 +0000454 def __str__(self):
455 return ('<%s %s:%s>' %
456 (self.__class__.__name__,
457 self.server_name,
458 self.server_port))
459
Bill Janssen296a59d2007-09-16 22:06:00 +0000460 def get_request (self):
461 # override this to wrap socket with SSL
462 sock, addr = self.socket.accept()
463 sslconn = ssl.wrap_socket(sock, server_side=True,
464 certfile=self.certfile)
465 return sslconn, addr
466
467 # The methods overridden below this are mainly so that we
468 # can run it in a thread and be able to stop it from another
469 # You probably wouldn't need them in other uses.
470
471 def server_activate(self):
472 # We want to run this in a thread for testing purposes,
473 # so we override this to set timeout, so that we get
474 # a chance to stop the server
475 self.socket.settimeout(0.5)
476 HTTPServer.server_activate(self)
477
478 def serve_forever(self):
479 # We want this to run in a thread, so we use a slightly
480 # modified version of "forever".
481 self.active = True
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000482 while 1:
Bill Janssen296a59d2007-09-16 22:06:00 +0000483 try:
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000484 # We need to lock while handling the request.
485 # Another thread can close the socket after self.active
486 # has been checked and before the request is handled.
487 # This causes an exception when using the closed socket.
488 with self.active_lock:
489 if not self.active:
490 break
491 self.handle_request()
Bill Janssen296a59d2007-09-16 22:06:00 +0000492 except socket.timeout:
493 pass
494 except KeyboardInterrupt:
495 self.server_close()
496 return
497 except:
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000498 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
499 break
Neal Norwitzd0a91af2008-04-02 05:54:27 +0000500 time.sleep(0.1)
Bill Janssen296a59d2007-09-16 22:06:00 +0000501
502 def server_close(self):
503 # Again, we want this to run in a thread, so we need to override
504 # close to clear the "active" flag, so that serve_forever() will
505 # terminate.
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000506 with self.active_lock:
507 HTTPServer.server_close(self)
508 self.active = False
Bill Janssen296a59d2007-09-16 22:06:00 +0000509
510 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
511
512 # need to override translate_path to get a known root,
513 # instead of using os.curdir, since the test could be
514 # run from anywhere
515
516 server_version = "TestHTTPS/1.0"
517
518 root = None
519
520 def translate_path(self, path):
521 """Translate a /-separated PATH to the local filename syntax.
522
523 Components that mean special things to the local file system
524 (e.g. drive or directory names) are ignored. (XXX They should
525 probably be diagnosed.)
526
527 """
528 # abandon query parameters
529 path = urlparse.urlparse(path)[2]
530 path = os.path.normpath(urllib.unquote(path))
531 words = path.split('/')
532 words = filter(None, words)
533 path = self.root
534 for word in words:
535 drive, word = os.path.splitdrive(word)
536 head, word = os.path.split(word)
537 if word in self.root: continue
538 path = os.path.join(path, word)
539 return path
540
541 def log_message(self, format, *args):
542
543 # we override this to suppress logging unless "verbose"
544
545 if test_support.verbose:
Bill Janssen934b16d2008-06-28 22:19:33 +0000546 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
547 (self.server.server_address,
Bill Janssen296a59d2007-09-16 22:06:00 +0000548 self.server.server_port,
549 self.request.cipher(),
550 self.log_date_time_string(),
551 format%args))
552
553
Trent Nelsone41b0062008-04-08 23:47:30 +0000554 def __init__(self, certfile):
Bill Janssen296a59d2007-09-16 22:06:00 +0000555 self.flag = None
556 self.active = False
557 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Trent Nelsone41b0062008-04-08 23:47:30 +0000558 self.port = test_support.find_unused_port()
Bill Janssen296a59d2007-09-16 22:06:00 +0000559 self.server = self.HTTPSServer(
Trent Nelsone41b0062008-04-08 23:47:30 +0000560 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Bill Janssen296a59d2007-09-16 22:06:00 +0000561 threading.Thread.__init__(self)
562 self.setDaemon(True)
563
564 def __str__(self):
Bill Janssen934b16d2008-06-28 22:19:33 +0000565 return "<%s %s>" % (self.__class__.__name__, self.server)
Bill Janssen296a59d2007-09-16 22:06:00 +0000566
567 def start (self, flag=None):
568 self.flag = flag
569 threading.Thread.start(self)
570
571 def run (self):
572 self.active = True
573 if self.flag:
574 self.flag.set()
575 self.server.serve_forever()
576 self.active = False
577
578 def stop (self):
579 self.active = False
580 self.server.server_close()
581
582
Bill Janssen98d19da2007-09-10 21:51:02 +0000583 def badCertTest (certfile):
Trent Nelsone41b0062008-04-08 23:47:30 +0000584 server = ThreadedEchoServer(CERTFILE,
Bill Janssen98d19da2007-09-10 21:51:02 +0000585 certreqs=ssl.CERT_REQUIRED,
586 cacerts=CERTFILE, chatty=False)
587 flag = threading.Event()
588 server.start(flag)
589 # wait for it to start
590 flag.wait()
591 # try to connect
592 try:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000593 try:
Bill Janssen98d19da2007-09-10 21:51:02 +0000594 s = ssl.wrap_socket(socket.socket(),
595 certfile=certfile,
596 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelsone41b0062008-04-08 23:47:30 +0000597 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000598 except ssl.SSLError, x:
Neal Norwitz9eb9b102007-08-27 01:15:33 +0000599 if test_support.verbose:
Bill Janssen98d19da2007-09-10 21:51:02 +0000600 sys.stdout.write("\nSSLError is %s\n" % x[1])
601 else:
602 raise test_support.TestFailed(
603 "Use of invalid cert should have failed!")
604 finally:
605 server.stop()
606 server.join()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000607
Bill Janssen98d19da2007-09-10 21:51:02 +0000608 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
609 client_certfile, client_protocol=None, indata="FOO\n",
Bill Janssen934b16d2008-06-28 22:19:33 +0000610 chatty=True, connectionchatty=False,
611 wrap_accepting_socket=False):
Bill Janssen98d19da2007-09-10 21:51:02 +0000612
Trent Nelsone41b0062008-04-08 23:47:30 +0000613 server = ThreadedEchoServer(certfile,
Bill Janssen98d19da2007-09-10 21:51:02 +0000614 certreqs=certreqs,
615 ssl_version=protocol,
616 cacerts=cacertsfile,
617 chatty=chatty,
Bill Janssen934b16d2008-06-28 22:19:33 +0000618 connectionchatty=connectionchatty,
619 wrap_accepting_socket=wrap_accepting_socket)
Bill Janssen98d19da2007-09-10 21:51:02 +0000620 flag = threading.Event()
621 server.start(flag)
622 # wait for it to start
623 flag.wait()
624 # try to connect
625 if client_protocol is None:
626 client_protocol = protocol
627 try:
628 try:
629 s = ssl.wrap_socket(socket.socket(),
630 certfile=client_certfile,
631 ca_certs=cacertsfile,
632 cert_reqs=certreqs,
633 ssl_version=client_protocol)
Trent Nelsone41b0062008-04-08 23:47:30 +0000634 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000635 except ssl.SSLError, x:
636 raise test_support.TestFailed("Unexpected SSL error: " + str(x))
637 except Exception, x:
638 raise test_support.TestFailed("Unexpected exception: " + str(x))
639 else:
640 if connectionchatty:
641 if test_support.verbose:
642 sys.stdout.write(
643 " client: sending %s...\n" % (repr(indata)))
644 s.write(indata)
645 outdata = s.read()
646 if connectionchatty:
647 if test_support.verbose:
648 sys.stdout.write(" client: read %s\n" % repr(outdata))
649 if outdata != indata.lower():
650 raise test_support.TestFailed(
651 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
652 % (outdata[:min(len(outdata),20)], len(outdata),
653 indata[:min(len(indata),20)].lower(), len(indata)))
654 s.write("over\n")
655 if connectionchatty:
656 if test_support.verbose:
657 sys.stdout.write(" client: closing connection.\n")
Bill Janssen98d19da2007-09-10 21:51:02 +0000658 s.close()
659 finally:
660 server.stop()
661 server.join()
662
663 def tryProtocolCombo (server_protocol,
664 client_protocol,
665 expectedToWork,
Bill Janssene3f1d7d2007-09-11 01:09:19 +0000666 certsreqs=None):
667
Benjamin Peterson5b63acd2008-03-29 15:24:25 +0000668 if certsreqs is None:
Bill Janssene3f1d7d2007-09-11 01:09:19 +0000669 certsreqs = ssl.CERT_NONE
Bill Janssen98d19da2007-09-10 21:51:02 +0000670
671 if certsreqs == ssl.CERT_NONE:
672 certtype = "CERT_NONE"
673 elif certsreqs == ssl.CERT_OPTIONAL:
674 certtype = "CERT_OPTIONAL"
675 elif certsreqs == ssl.CERT_REQUIRED:
676 certtype = "CERT_REQUIRED"
677 if test_support.verbose:
678 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
679 sys.stdout.write(formatstr %
680 (ssl.get_protocol_name(client_protocol),
681 ssl.get_protocol_name(server_protocol),
682 certtype))
683 try:
684 serverParamsTest(CERTFILE, server_protocol, certsreqs,
685 CERTFILE, CERTFILE, client_protocol, chatty=False)
686 except test_support.TestFailed:
687 if expectedToWork:
688 raise
689 else:
690 if not expectedToWork:
691 raise test_support.TestFailed(
692 "Client protocol %s succeeded with server protocol %s!"
693 % (ssl.get_protocol_name(client_protocol),
694 ssl.get_protocol_name(server_protocol)))
695
696
Bill Janssen934b16d2008-06-28 22:19:33 +0000697 class ThreadedTests(unittest.TestCase):
Bill Janssen98d19da2007-09-10 21:51:02 +0000698
699 def testRudeShutdown(self):
700
701 listener_ready = threading.Event()
702 listener_gone = threading.Event()
Trent Nelsone41b0062008-04-08 23:47:30 +0000703 port = test_support.find_unused_port()
Bill Janssen98d19da2007-09-10 21:51:02 +0000704
705 # `listener` runs in a thread. It opens a socket listening on
706 # PORT, and sits in an accept() until the main thread connects.
707 # Then it rudely closes the socket, and sets Event `listener_gone`
708 # to let the main thread know the socket is gone.
709 def listener():
710 s = socket.socket()
Trent Nelsone41b0062008-04-08 23:47:30 +0000711 s.bind((HOST, port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000712 s.listen(5)
713 listener_ready.set()
714 s.accept()
715 s = None # reclaim the socket object, which also closes it
716 listener_gone.set()
717
718 def connector():
719 listener_ready.wait()
720 s = socket.socket()
Trent Nelsone41b0062008-04-08 23:47:30 +0000721 s.connect((HOST, port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000722 listener_gone.wait()
723 try:
724 ssl_sock = ssl.wrap_socket(s)
Bill Janssen934b16d2008-06-28 22:19:33 +0000725 except IOError:
Bill Janssen98d19da2007-09-10 21:51:02 +0000726 pass
727 else:
728 raise test_support.TestFailed(
729 'connecting to closed SSL socket should have failed')
730
731 t = threading.Thread(target=listener)
732 t.start()
733 connector()
734 t.join()
735
736 def testEcho (self):
737
738 if test_support.verbose:
739 sys.stdout.write("\n")
740 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
741 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
742 chatty=True, connectionchatty=True)
743
744 def testReadCert(self):
745
746 if test_support.verbose:
747 sys.stdout.write("\n")
748 s2 = socket.socket()
Trent Nelsone41b0062008-04-08 23:47:30 +0000749 server = ThreadedEchoServer(CERTFILE,
Bill Janssen98d19da2007-09-10 21:51:02 +0000750 certreqs=ssl.CERT_NONE,
751 ssl_version=ssl.PROTOCOL_SSLv23,
752 cacerts=CERTFILE,
753 chatty=False)
754 flag = threading.Event()
755 server.start(flag)
756 # wait for it to start
757 flag.wait()
758 # try to connect
759 try:
760 try:
761 s = ssl.wrap_socket(socket.socket(),
762 certfile=CERTFILE,
763 ca_certs=CERTFILE,
764 cert_reqs=ssl.CERT_REQUIRED,
765 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelsone41b0062008-04-08 23:47:30 +0000766 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000767 except ssl.SSLError, x:
768 raise test_support.TestFailed(
769 "Unexpected SSL error: " + str(x))
770 except Exception, x:
771 raise test_support.TestFailed(
772 "Unexpected exception: " + str(x))
773 else:
774 if not s:
775 raise test_support.TestFailed(
776 "Can't SSL-handshake with test server")
777 cert = s.getpeercert()
778 if not cert:
779 raise test_support.TestFailed(
780 "Can't get peer certificate.")
781 cipher = s.cipher()
782 if test_support.verbose:
783 sys.stdout.write(pprint.pformat(cert) + '\n')
784 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
785 if not cert.has_key('subject'):
786 raise test_support.TestFailed(
787 "No subject field in certificate: %s." %
788 pprint.pformat(cert))
789 if ((('organizationName', 'Python Software Foundation'),)
790 not in cert['subject']):
791 raise test_support.TestFailed(
792 "Missing or invalid 'organizationName' field in certificate subject; "
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000793 "should be 'Python Software Foundation'.")
Bill Janssen98d19da2007-09-10 21:51:02 +0000794 s.close()
795 finally:
796 server.stop()
797 server.join()
798
799 def testNULLcert(self):
800 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
801 "nullcert.pem"))
802 def testMalformedCert(self):
803 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
804 "badcert.pem"))
Bill Janssen934b16d2008-06-28 22:19:33 +0000805 def testWrongCert(self):
806 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
807 "wrongcert.pem"))
Bill Janssen98d19da2007-09-10 21:51:02 +0000808 def testMalformedKey(self):
809 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
810 "badkey.pem"))
811
812 def testProtocolSSL2(self):
813 if test_support.verbose:
814 sys.stdout.write("\n")
815 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
816 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
817 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
818 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
819 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
820 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
821
822 def testProtocolSSL23(self):
823 if test_support.verbose:
824 sys.stdout.write("\n")
825 try:
826 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
827 except test_support.TestFailed, x:
828 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
829 if test_support.verbose:
830 sys.stdout.write(
831 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
832 % str(x))
833 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
834 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
835 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
836
837 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
838 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
839 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
840
841 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
842 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
843 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
844
845 def testProtocolSSL3(self):
846 if test_support.verbose:
847 sys.stdout.write("\n")
848 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
849 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
850 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
851 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
852 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
853 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
854
855 def testProtocolTLS1(self):
856 if test_support.verbose:
857 sys.stdout.write("\n")
858 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
859 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
860 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
861 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
862 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
863 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
864
865 def testSTARTTLS (self):
866
867 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4")
868
Trent Nelsone41b0062008-04-08 23:47:30 +0000869 server = ThreadedEchoServer(CERTFILE,
Bill Janssen98d19da2007-09-10 21:51:02 +0000870 ssl_version=ssl.PROTOCOL_TLSv1,
871 starttls_server=True,
872 chatty=True,
873 connectionchatty=True)
874 flag = threading.Event()
875 server.start(flag)
876 # wait for it to start
877 flag.wait()
878 # try to connect
879 wrapped = False
880 try:
881 try:
882 s = socket.socket()
883 s.setblocking(1)
Trent Nelsone41b0062008-04-08 23:47:30 +0000884 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000885 except Exception, x:
886 raise test_support.TestFailed("Unexpected exception: " + str(x))
887 else:
888 if test_support.verbose:
889 sys.stdout.write("\n")
890 for indata in msgs:
891 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000892 sys.stdout.write(
893 " client: sending %s...\n" % repr(indata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000894 if wrapped:
895 conn.write(indata)
896 outdata = conn.read()
897 else:
898 s.send(indata)
899 outdata = s.recv(1024)
Bill Janssen296a59d2007-09-16 22:06:00 +0000900 if (indata == "STARTTLS" and
901 outdata.strip().lower().startswith("ok")):
Bill Janssen98d19da2007-09-10 21:51:02 +0000902 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000903 sys.stdout.write(
904 " client: read %s from server, starting TLS...\n"
905 % repr(outdata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000906 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
907
908 wrapped = True
909 else:
910 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000911 sys.stdout.write(
912 " client: read %s from server\n" % repr(outdata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000913 if test_support.verbose:
914 sys.stdout.write(" client: closing connection.\n")
915 if wrapped:
916 conn.write("over\n")
Bill Janssen98d19da2007-09-10 21:51:02 +0000917 else:
918 s.send("over\n")
919 s.close()
920 finally:
921 server.stop()
922 server.join()
923
Bill Janssen934b16d2008-06-28 22:19:33 +0000924 def testSocketServer(self):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000925
Bill Janssen934b16d2008-06-28 22:19:33 +0000926 server = SocketServerHTTPSServer(CERTFILE)
Bill Janssen296a59d2007-09-16 22:06:00 +0000927 flag = threading.Event()
928 server.start(flag)
929 # wait for it to start
930 flag.wait()
931 # try to connect
932 try:
933 if test_support.verbose:
934 sys.stdout.write('\n')
Bill Janssenbf10c472007-09-16 23:16:46 +0000935 d1 = open(CERTFILE, 'rb').read()
Bill Janssen296a59d2007-09-16 22:06:00 +0000936 d2 = ''
937 # now fetch the same data from the HTTPS server
Bill Janssen934b16d2008-06-28 22:19:33 +0000938 url = 'https://127.0.0.1:%d/%s' % (
939 server.port, os.path.split(CERTFILE)[1])
Bill Janssen296a59d2007-09-16 22:06:00 +0000940 f = urllib.urlopen(url)
941 dlen = f.info().getheader("content-length")
942 if dlen and (int(dlen) > 0):
943 d2 = f.read(int(dlen))
944 if test_support.verbose:
945 sys.stdout.write(
946 " client: read %d bytes from remote server '%s'\n"
947 % (len(d2), server))
948 f.close()
949 except:
950 msg = ''.join(traceback.format_exception(*sys.exc_info()))
951 if test_support.verbose:
952 sys.stdout.write('\n' + msg)
953 raise test_support.TestFailed(msg)
954 else:
955 if not (d1 == d2):
956 raise test_support.TestFailed(
957 "Couldn't fetch data from HTTPS server")
958 finally:
959 server.stop()
960 server.join()
Neal Norwitz7fc8e292007-08-26 18:50:39 +0000961
Bill Janssen934b16d2008-06-28 22:19:33 +0000962 def testWrappedAccept (self):
963
964 if test_support.verbose:
965 sys.stdout.write("\n")
966 serverParamsTest(CERTFILE, ssl.PROTOCOL_SSLv23, ssl.CERT_REQUIRED,
967 CERTFILE, CERTFILE, ssl.PROTOCOL_SSLv23,
968 chatty=True, connectionchatty=True,
969 wrap_accepting_socket=True)
970
971
972 def testAsyncoreServer (self):
973
974 indata = "TEST MESSAGE of mixed case\n"
975
976 if test_support.verbose:
977 sys.stdout.write("\n")
978 server = AsyncoreEchoServer(CERTFILE)
979 flag = threading.Event()
980 server.start(flag)
981 # wait for it to start
982 flag.wait()
983 # try to connect
984 try:
985 try:
986 s = ssl.wrap_socket(socket.socket())
987 s.connect(('127.0.0.1', server.port))
988 except ssl.SSLError, x:
989 raise test_support.TestFailed("Unexpected SSL error: " + str(x))
990 except Exception, x:
991 raise test_support.TestFailed("Unexpected exception: " + str(x))
992 else:
993 if test_support.verbose:
994 sys.stdout.write(
995 " client: sending %s...\n" % (repr(indata)))
996 s.write(indata)
997 outdata = s.read()
998 if test_support.verbose:
999 sys.stdout.write(" client: read %s\n" % repr(outdata))
1000 if outdata != indata.lower():
1001 raise test_support.TestFailed(
1002 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1003 % (outdata[:min(len(outdata),20)], len(outdata),
1004 indata[:min(len(indata),20)].lower(), len(indata)))
1005 s.write("over\n")
1006 if test_support.verbose:
1007 sys.stdout.write(" client: closing connection.\n")
1008 s.close()
1009 finally:
1010 server.stop()
1011 # wait for server thread to end
1012 server.join()
1013
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001014
Neal Norwitz9eb9b102007-08-27 01:15:33 +00001015def test_main(verbose=False):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001016 if skip_expected:
Bill Janssenffe576d2007-09-05 00:46:27 +00001017 raise test_support.TestSkipped("No SSL support")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001018
Trent Nelsone41b0062008-04-08 23:47:30 +00001019 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Guido van Rossumba8c5652007-08-27 17:19:42 +00001020 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
Bill Janssen296a59d2007-09-16 22:06:00 +00001021 "keycert.pem")
1022 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1023 os.path.dirname(__file__) or os.curdir,
1024 "https_svn_python_org_root.pem")
1025
1026 if (not os.path.exists(CERTFILE) or
1027 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Bill Janssen98d19da2007-09-10 21:51:02 +00001028 raise test_support.TestFailed("Can't read certificate files!")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001029
Bill Janssen934b16d2008-06-28 22:19:33 +00001030 TESTPORT = test_support.find_unused_port()
1031 if not TESTPORT:
1032 raise test_support.TestFailed("Can't find open port to test servers on!")
1033
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001034 tests = [BasicTests]
1035
Bill Janssen296a59d2007-09-16 22:06:00 +00001036 if test_support.is_resource_enabled('network'):
Bill Janssen934b16d2008-06-28 22:19:33 +00001037 tests.append(NetworkedTests)
Bill Janssen296a59d2007-09-16 22:06:00 +00001038
Bill Janssen98d19da2007-09-10 21:51:02 +00001039 if _have_threads:
1040 thread_info = test_support.threading_setup()
Bill Janssen296a59d2007-09-16 22:06:00 +00001041 if thread_info and test_support.is_resource_enabled('network'):
Bill Janssen934b16d2008-06-28 22:19:33 +00001042 tests.append(ThreadedTests)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001043
Bill Janssen98d19da2007-09-10 21:51:02 +00001044 test_support.run_unittest(*tests)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001045
Bill Janssen98d19da2007-09-10 21:51:02 +00001046 if _have_threads:
1047 test_support.threading_cleanup(*thread_info)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001048
1049if __name__ == "__main__":
1050 test_main()