blob: d786154c809389e92153815d6373c4c82a555106 [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):
389 if test_support.verbose:
390 sys.stdout.write(" server: closed connection %s\n" % self.socket)
391
392 def handle_error(self):
393 raise
394
395 def __init__(self, certfile):
396 self.certfile = certfile
397 asyncore.dispatcher.__init__(self)
398 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
399 self.port = test_support.bind_port(self.socket)
400 self.listen(5)
401
402 def handle_accept(self):
403 sock_obj, addr = self.accept()
404 if test_support.verbose:
405 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
406 self.ConnectionHandler(sock_obj, self.certfile)
407
408 def handle_error(self):
409 raise
410
411 def __init__(self, certfile):
412 self.flag = None
413 self.active = False
414 self.server = self.EchoServer(certfile)
415 self.port = self.server.port
416 threading.Thread.__init__(self)
417 self.setDaemon(True)
418
419 def __str__(self):
420 return "<%s %s>" % (self.__class__.__name__, self.server)
421
422 def start (self, flag=None):
423 self.flag = flag
424 threading.Thread.start(self)
425
426 def run (self):
427 self.active = True
428 if self.flag:
429 self.flag.set()
430 while self.active:
431 try:
432 asyncore.loop(1)
433 except:
434 pass
435
436 def stop (self):
437 self.active = False
438 self.server.close()
439
440 class SocketServerHTTPSServer(threading.Thread):
Bill Janssen296a59d2007-09-16 22:06:00 +0000441
442 class HTTPSServer(HTTPServer):
443
444 def __init__(self, server_address, RequestHandlerClass, certfile):
445
446 HTTPServer.__init__(self, server_address, RequestHandlerClass)
447 # we assume the certfile contains both private key and certificate
448 self.certfile = certfile
449 self.active = False
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000450 self.active_lock = threading.Lock()
Bill Janssen296a59d2007-09-16 22:06:00 +0000451 self.allow_reuse_address = True
452
Bill Janssen934b16d2008-06-28 22:19:33 +0000453 def __str__(self):
454 return ('<%s %s:%s>' %
455 (self.__class__.__name__,
456 self.server_name,
457 self.server_port))
458
Bill Janssen296a59d2007-09-16 22:06:00 +0000459 def get_request (self):
460 # override this to wrap socket with SSL
461 sock, addr = self.socket.accept()
462 sslconn = ssl.wrap_socket(sock, server_side=True,
463 certfile=self.certfile)
464 return sslconn, addr
465
466 # The methods overridden below this are mainly so that we
467 # can run it in a thread and be able to stop it from another
468 # You probably wouldn't need them in other uses.
469
470 def server_activate(self):
471 # We want to run this in a thread for testing purposes,
472 # so we override this to set timeout, so that we get
473 # a chance to stop the server
474 self.socket.settimeout(0.5)
475 HTTPServer.server_activate(self)
476
477 def serve_forever(self):
478 # We want this to run in a thread, so we use a slightly
479 # modified version of "forever".
480 self.active = True
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000481 while 1:
Bill Janssen296a59d2007-09-16 22:06:00 +0000482 try:
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000483 # We need to lock while handling the request.
484 # Another thread can close the socket after self.active
485 # has been checked and before the request is handled.
486 # This causes an exception when using the closed socket.
487 with self.active_lock:
488 if not self.active:
489 break
490 self.handle_request()
Bill Janssen296a59d2007-09-16 22:06:00 +0000491 except socket.timeout:
492 pass
493 except KeyboardInterrupt:
494 self.server_close()
495 return
496 except:
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000497 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
498 break
Neal Norwitzd0a91af2008-04-02 05:54:27 +0000499 time.sleep(0.1)
Bill Janssen296a59d2007-09-16 22:06:00 +0000500
501 def server_close(self):
502 # Again, we want this to run in a thread, so we need to override
503 # close to clear the "active" flag, so that serve_forever() will
504 # terminate.
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000505 with self.active_lock:
506 HTTPServer.server_close(self)
507 self.active = False
Bill Janssen296a59d2007-09-16 22:06:00 +0000508
509 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
510
511 # need to override translate_path to get a known root,
512 # instead of using os.curdir, since the test could be
513 # run from anywhere
514
515 server_version = "TestHTTPS/1.0"
516
517 root = None
518
519 def translate_path(self, path):
520 """Translate a /-separated PATH to the local filename syntax.
521
522 Components that mean special things to the local file system
523 (e.g. drive or directory names) are ignored. (XXX They should
524 probably be diagnosed.)
525
526 """
527 # abandon query parameters
528 path = urlparse.urlparse(path)[2]
529 path = os.path.normpath(urllib.unquote(path))
530 words = path.split('/')
531 words = filter(None, words)
532 path = self.root
533 for word in words:
534 drive, word = os.path.splitdrive(word)
535 head, word = os.path.split(word)
536 if word in self.root: continue
537 path = os.path.join(path, word)
538 return path
539
540 def log_message(self, format, *args):
541
542 # we override this to suppress logging unless "verbose"
543
544 if test_support.verbose:
Bill Janssen934b16d2008-06-28 22:19:33 +0000545 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
546 (self.server.server_address,
Bill Janssen296a59d2007-09-16 22:06:00 +0000547 self.server.server_port,
548 self.request.cipher(),
549 self.log_date_time_string(),
550 format%args))
551
552
Trent Nelsone41b0062008-04-08 23:47:30 +0000553 def __init__(self, certfile):
Bill Janssen296a59d2007-09-16 22:06:00 +0000554 self.flag = None
555 self.active = False
556 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Trent Nelsone41b0062008-04-08 23:47:30 +0000557 self.port = test_support.find_unused_port()
Bill Janssen296a59d2007-09-16 22:06:00 +0000558 self.server = self.HTTPSServer(
Trent Nelsone41b0062008-04-08 23:47:30 +0000559 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Bill Janssen296a59d2007-09-16 22:06:00 +0000560 threading.Thread.__init__(self)
561 self.setDaemon(True)
562
563 def __str__(self):
Bill Janssen934b16d2008-06-28 22:19:33 +0000564 return "<%s %s>" % (self.__class__.__name__, self.server)
Bill Janssen296a59d2007-09-16 22:06:00 +0000565
566 def start (self, flag=None):
567 self.flag = flag
568 threading.Thread.start(self)
569
570 def run (self):
571 self.active = True
572 if self.flag:
573 self.flag.set()
574 self.server.serve_forever()
575 self.active = False
576
577 def stop (self):
578 self.active = False
579 self.server.server_close()
580
581
Bill Janssen98d19da2007-09-10 21:51:02 +0000582 def badCertTest (certfile):
Trent Nelsone41b0062008-04-08 23:47:30 +0000583 server = ThreadedEchoServer(CERTFILE,
Bill Janssen98d19da2007-09-10 21:51:02 +0000584 certreqs=ssl.CERT_REQUIRED,
585 cacerts=CERTFILE, chatty=False)
586 flag = threading.Event()
587 server.start(flag)
588 # wait for it to start
589 flag.wait()
590 # try to connect
591 try:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000592 try:
Bill Janssen98d19da2007-09-10 21:51:02 +0000593 s = ssl.wrap_socket(socket.socket(),
594 certfile=certfile,
595 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelsone41b0062008-04-08 23:47:30 +0000596 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000597 except ssl.SSLError, x:
Neal Norwitz9eb9b102007-08-27 01:15:33 +0000598 if test_support.verbose:
Bill Janssen98d19da2007-09-10 21:51:02 +0000599 sys.stdout.write("\nSSLError is %s\n" % x[1])
600 else:
601 raise test_support.TestFailed(
602 "Use of invalid cert should have failed!")
603 finally:
604 server.stop()
605 server.join()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000606
Bill Janssen98d19da2007-09-10 21:51:02 +0000607 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
608 client_certfile, client_protocol=None, indata="FOO\n",
Bill Janssen934b16d2008-06-28 22:19:33 +0000609 chatty=True, connectionchatty=False,
610 wrap_accepting_socket=False):
Bill Janssen98d19da2007-09-10 21:51:02 +0000611
Trent Nelsone41b0062008-04-08 23:47:30 +0000612 server = ThreadedEchoServer(certfile,
Bill Janssen98d19da2007-09-10 21:51:02 +0000613 certreqs=certreqs,
614 ssl_version=protocol,
615 cacerts=cacertsfile,
616 chatty=chatty,
Bill Janssen934b16d2008-06-28 22:19:33 +0000617 connectionchatty=connectionchatty,
618 wrap_accepting_socket=wrap_accepting_socket)
Bill Janssen98d19da2007-09-10 21:51:02 +0000619 flag = threading.Event()
620 server.start(flag)
621 # wait for it to start
622 flag.wait()
623 # try to connect
624 if client_protocol is None:
625 client_protocol = protocol
626 try:
627 try:
628 s = ssl.wrap_socket(socket.socket(),
629 certfile=client_certfile,
630 ca_certs=cacertsfile,
631 cert_reqs=certreqs,
632 ssl_version=client_protocol)
Trent Nelsone41b0062008-04-08 23:47:30 +0000633 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000634 except ssl.SSLError, x:
635 raise test_support.TestFailed("Unexpected SSL error: " + str(x))
636 except Exception, x:
637 raise test_support.TestFailed("Unexpected exception: " + str(x))
638 else:
639 if connectionchatty:
640 if test_support.verbose:
641 sys.stdout.write(
642 " client: sending %s...\n" % (repr(indata)))
643 s.write(indata)
644 outdata = s.read()
645 if connectionchatty:
646 if test_support.verbose:
647 sys.stdout.write(" client: read %s\n" % repr(outdata))
648 if outdata != indata.lower():
649 raise test_support.TestFailed(
650 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
651 % (outdata[:min(len(outdata),20)], len(outdata),
652 indata[:min(len(indata),20)].lower(), len(indata)))
653 s.write("over\n")
654 if connectionchatty:
655 if test_support.verbose:
656 sys.stdout.write(" client: closing connection.\n")
Bill Janssen98d19da2007-09-10 21:51:02 +0000657 s.close()
658 finally:
659 server.stop()
660 server.join()
661
662 def tryProtocolCombo (server_protocol,
663 client_protocol,
664 expectedToWork,
Bill Janssene3f1d7d2007-09-11 01:09:19 +0000665 certsreqs=None):
666
Benjamin Peterson5b63acd2008-03-29 15:24:25 +0000667 if certsreqs is None:
Bill Janssene3f1d7d2007-09-11 01:09:19 +0000668 certsreqs = ssl.CERT_NONE
Bill Janssen98d19da2007-09-10 21:51:02 +0000669
670 if certsreqs == ssl.CERT_NONE:
671 certtype = "CERT_NONE"
672 elif certsreqs == ssl.CERT_OPTIONAL:
673 certtype = "CERT_OPTIONAL"
674 elif certsreqs == ssl.CERT_REQUIRED:
675 certtype = "CERT_REQUIRED"
676 if test_support.verbose:
677 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
678 sys.stdout.write(formatstr %
679 (ssl.get_protocol_name(client_protocol),
680 ssl.get_protocol_name(server_protocol),
681 certtype))
682 try:
683 serverParamsTest(CERTFILE, server_protocol, certsreqs,
684 CERTFILE, CERTFILE, client_protocol, chatty=False)
685 except test_support.TestFailed:
686 if expectedToWork:
687 raise
688 else:
689 if not expectedToWork:
690 raise test_support.TestFailed(
691 "Client protocol %s succeeded with server protocol %s!"
692 % (ssl.get_protocol_name(client_protocol),
693 ssl.get_protocol_name(server_protocol)))
694
695
Bill Janssen934b16d2008-06-28 22:19:33 +0000696 class ThreadedTests(unittest.TestCase):
Bill Janssen98d19da2007-09-10 21:51:02 +0000697
698 def testRudeShutdown(self):
699
700 listener_ready = threading.Event()
701 listener_gone = threading.Event()
Trent Nelsone41b0062008-04-08 23:47:30 +0000702 port = test_support.find_unused_port()
Bill Janssen98d19da2007-09-10 21:51:02 +0000703
704 # `listener` runs in a thread. It opens a socket listening on
705 # PORT, and sits in an accept() until the main thread connects.
706 # Then it rudely closes the socket, and sets Event `listener_gone`
707 # to let the main thread know the socket is gone.
708 def listener():
709 s = socket.socket()
Trent Nelsone41b0062008-04-08 23:47:30 +0000710 s.bind((HOST, port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000711 s.listen(5)
712 listener_ready.set()
713 s.accept()
714 s = None # reclaim the socket object, which also closes it
715 listener_gone.set()
716
717 def connector():
718 listener_ready.wait()
719 s = socket.socket()
Trent Nelsone41b0062008-04-08 23:47:30 +0000720 s.connect((HOST, port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000721 listener_gone.wait()
722 try:
723 ssl_sock = ssl.wrap_socket(s)
Bill Janssen934b16d2008-06-28 22:19:33 +0000724 except IOError:
Bill Janssen98d19da2007-09-10 21:51:02 +0000725 pass
726 else:
727 raise test_support.TestFailed(
728 'connecting to closed SSL socket should have failed')
729
730 t = threading.Thread(target=listener)
731 t.start()
732 connector()
733 t.join()
734
735 def testEcho (self):
736
737 if test_support.verbose:
738 sys.stdout.write("\n")
739 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
740 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
741 chatty=True, connectionchatty=True)
742
743 def testReadCert(self):
744
745 if test_support.verbose:
746 sys.stdout.write("\n")
747 s2 = socket.socket()
Trent Nelsone41b0062008-04-08 23:47:30 +0000748 server = ThreadedEchoServer(CERTFILE,
Bill Janssen98d19da2007-09-10 21:51:02 +0000749 certreqs=ssl.CERT_NONE,
750 ssl_version=ssl.PROTOCOL_SSLv23,
751 cacerts=CERTFILE,
752 chatty=False)
753 flag = threading.Event()
754 server.start(flag)
755 # wait for it to start
756 flag.wait()
757 # try to connect
758 try:
759 try:
760 s = ssl.wrap_socket(socket.socket(),
761 certfile=CERTFILE,
762 ca_certs=CERTFILE,
763 cert_reqs=ssl.CERT_REQUIRED,
764 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelsone41b0062008-04-08 23:47:30 +0000765 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000766 except ssl.SSLError, x:
767 raise test_support.TestFailed(
768 "Unexpected SSL error: " + str(x))
769 except Exception, x:
770 raise test_support.TestFailed(
771 "Unexpected exception: " + str(x))
772 else:
773 if not s:
774 raise test_support.TestFailed(
775 "Can't SSL-handshake with test server")
776 cert = s.getpeercert()
777 if not cert:
778 raise test_support.TestFailed(
779 "Can't get peer certificate.")
780 cipher = s.cipher()
781 if test_support.verbose:
782 sys.stdout.write(pprint.pformat(cert) + '\n')
783 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
784 if not cert.has_key('subject'):
785 raise test_support.TestFailed(
786 "No subject field in certificate: %s." %
787 pprint.pformat(cert))
788 if ((('organizationName', 'Python Software Foundation'),)
789 not in cert['subject']):
790 raise test_support.TestFailed(
791 "Missing or invalid 'organizationName' field in certificate subject; "
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000792 "should be 'Python Software Foundation'.")
Bill Janssen98d19da2007-09-10 21:51:02 +0000793 s.close()
794 finally:
795 server.stop()
796 server.join()
797
798 def testNULLcert(self):
799 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
800 "nullcert.pem"))
801 def testMalformedCert(self):
802 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
803 "badcert.pem"))
Bill Janssen934b16d2008-06-28 22:19:33 +0000804 def testWrongCert(self):
805 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
806 "wrongcert.pem"))
Bill Janssen98d19da2007-09-10 21:51:02 +0000807 def testMalformedKey(self):
808 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
809 "badkey.pem"))
810
811 def testProtocolSSL2(self):
812 if test_support.verbose:
813 sys.stdout.write("\n")
814 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
815 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
816 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
817 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
818 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
819 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
820
821 def testProtocolSSL23(self):
822 if test_support.verbose:
823 sys.stdout.write("\n")
824 try:
825 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
826 except test_support.TestFailed, x:
827 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
828 if test_support.verbose:
829 sys.stdout.write(
830 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
831 % str(x))
832 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
833 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
834 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
835
836 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
837 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
838 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
839
840 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
841 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
842 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
843
844 def testProtocolSSL3(self):
845 if test_support.verbose:
846 sys.stdout.write("\n")
847 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
848 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
849 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
850 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
851 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
852 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
853
854 def testProtocolTLS1(self):
855 if test_support.verbose:
856 sys.stdout.write("\n")
857 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
858 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
859 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
860 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
861 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
862 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
863
864 def testSTARTTLS (self):
865
866 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4")
867
Trent Nelsone41b0062008-04-08 23:47:30 +0000868 server = ThreadedEchoServer(CERTFILE,
Bill Janssen98d19da2007-09-10 21:51:02 +0000869 ssl_version=ssl.PROTOCOL_TLSv1,
870 starttls_server=True,
871 chatty=True,
872 connectionchatty=True)
873 flag = threading.Event()
874 server.start(flag)
875 # wait for it to start
876 flag.wait()
877 # try to connect
878 wrapped = False
879 try:
880 try:
881 s = socket.socket()
882 s.setblocking(1)
Trent Nelsone41b0062008-04-08 23:47:30 +0000883 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000884 except Exception, x:
885 raise test_support.TestFailed("Unexpected exception: " + str(x))
886 else:
887 if test_support.verbose:
888 sys.stdout.write("\n")
889 for indata in msgs:
890 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000891 sys.stdout.write(
892 " client: sending %s...\n" % repr(indata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000893 if wrapped:
894 conn.write(indata)
895 outdata = conn.read()
896 else:
897 s.send(indata)
898 outdata = s.recv(1024)
Bill Janssen296a59d2007-09-16 22:06:00 +0000899 if (indata == "STARTTLS" and
900 outdata.strip().lower().startswith("ok")):
Bill Janssen98d19da2007-09-10 21:51:02 +0000901 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000902 sys.stdout.write(
903 " client: read %s from server, starting TLS...\n"
904 % repr(outdata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000905 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
906
907 wrapped = True
908 else:
909 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000910 sys.stdout.write(
911 " client: read %s from server\n" % repr(outdata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000912 if test_support.verbose:
913 sys.stdout.write(" client: closing connection.\n")
914 if wrapped:
915 conn.write("over\n")
Bill Janssen98d19da2007-09-10 21:51:02 +0000916 else:
917 s.send("over\n")
918 s.close()
919 finally:
920 server.stop()
921 server.join()
922
Bill Janssen934b16d2008-06-28 22:19:33 +0000923 def testSocketServer(self):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000924
Bill Janssen934b16d2008-06-28 22:19:33 +0000925 server = SocketServerHTTPSServer(CERTFILE)
Bill Janssen296a59d2007-09-16 22:06:00 +0000926 flag = threading.Event()
927 server.start(flag)
928 # wait for it to start
929 flag.wait()
930 # try to connect
931 try:
932 if test_support.verbose:
933 sys.stdout.write('\n')
Bill Janssenbf10c472007-09-16 23:16:46 +0000934 d1 = open(CERTFILE, 'rb').read()
Bill Janssen296a59d2007-09-16 22:06:00 +0000935 d2 = ''
936 # now fetch the same data from the HTTPS server
Bill Janssen934b16d2008-06-28 22:19:33 +0000937 url = 'https://127.0.0.1:%d/%s' % (
938 server.port, os.path.split(CERTFILE)[1])
Bill Janssen296a59d2007-09-16 22:06:00 +0000939 f = urllib.urlopen(url)
940 dlen = f.info().getheader("content-length")
941 if dlen and (int(dlen) > 0):
942 d2 = f.read(int(dlen))
943 if test_support.verbose:
944 sys.stdout.write(
945 " client: read %d bytes from remote server '%s'\n"
946 % (len(d2), server))
947 f.close()
948 except:
949 msg = ''.join(traceback.format_exception(*sys.exc_info()))
950 if test_support.verbose:
951 sys.stdout.write('\n' + msg)
952 raise test_support.TestFailed(msg)
953 else:
954 if not (d1 == d2):
955 raise test_support.TestFailed(
956 "Couldn't fetch data from HTTPS server")
957 finally:
958 server.stop()
959 server.join()
Neal Norwitz7fc8e292007-08-26 18:50:39 +0000960
Bill Janssen934b16d2008-06-28 22:19:33 +0000961 def testWrappedAccept (self):
962
963 if test_support.verbose:
964 sys.stdout.write("\n")
965 serverParamsTest(CERTFILE, ssl.PROTOCOL_SSLv23, ssl.CERT_REQUIRED,
966 CERTFILE, CERTFILE, ssl.PROTOCOL_SSLv23,
967 chatty=True, connectionchatty=True,
968 wrap_accepting_socket=True)
969
970
971 def testAsyncoreServer (self):
972
973 indata = "TEST MESSAGE of mixed case\n"
974
975 if test_support.verbose:
976 sys.stdout.write("\n")
977 server = AsyncoreEchoServer(CERTFILE)
978 flag = threading.Event()
979 server.start(flag)
980 # wait for it to start
981 flag.wait()
982 # try to connect
983 try:
984 try:
985 s = ssl.wrap_socket(socket.socket())
986 s.connect(('127.0.0.1', server.port))
987 except ssl.SSLError, x:
988 raise test_support.TestFailed("Unexpected SSL error: " + str(x))
989 except Exception, x:
990 raise test_support.TestFailed("Unexpected exception: " + str(x))
991 else:
992 if test_support.verbose:
993 sys.stdout.write(
994 " client: sending %s...\n" % (repr(indata)))
995 s.write(indata)
996 outdata = s.read()
997 if test_support.verbose:
998 sys.stdout.write(" client: read %s\n" % repr(outdata))
999 if outdata != indata.lower():
1000 raise test_support.TestFailed(
1001 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1002 % (outdata[:min(len(outdata),20)], len(outdata),
1003 indata[:min(len(indata),20)].lower(), len(indata)))
1004 s.write("over\n")
1005 if test_support.verbose:
1006 sys.stdout.write(" client: closing connection.\n")
1007 s.close()
1008 finally:
1009 server.stop()
1010 # wait for server thread to end
1011 server.join()
1012
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001013
Neal Norwitz9eb9b102007-08-27 01:15:33 +00001014def test_main(verbose=False):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001015 if skip_expected:
Bill Janssenffe576d2007-09-05 00:46:27 +00001016 raise test_support.TestSkipped("No SSL support")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001017
Trent Nelsone41b0062008-04-08 23:47:30 +00001018 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Guido van Rossumba8c5652007-08-27 17:19:42 +00001019 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
Bill Janssen296a59d2007-09-16 22:06:00 +00001020 "keycert.pem")
1021 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1022 os.path.dirname(__file__) or os.curdir,
1023 "https_svn_python_org_root.pem")
1024
1025 if (not os.path.exists(CERTFILE) or
1026 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Bill Janssen98d19da2007-09-10 21:51:02 +00001027 raise test_support.TestFailed("Can't read certificate files!")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001028
Bill Janssen934b16d2008-06-28 22:19:33 +00001029 TESTPORT = test_support.find_unused_port()
1030 if not TESTPORT:
1031 raise test_support.TestFailed("Can't find open port to test servers on!")
1032
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001033 tests = [BasicTests]
1034
Bill Janssen296a59d2007-09-16 22:06:00 +00001035 if test_support.is_resource_enabled('network'):
Bill Janssen934b16d2008-06-28 22:19:33 +00001036 tests.append(NetworkedTests)
Bill Janssen296a59d2007-09-16 22:06:00 +00001037
Bill Janssen98d19da2007-09-10 21:51:02 +00001038 if _have_threads:
1039 thread_info = test_support.threading_setup()
Bill Janssen296a59d2007-09-16 22:06:00 +00001040 if thread_info and test_support.is_resource_enabled('network'):
Bill Janssen934b16d2008-06-28 22:19:33 +00001041 tests.append(ThreadedTests)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001042
Bill Janssen98d19da2007-09-10 21:51:02 +00001043 test_support.run_unittest(*tests)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001044
Bill Janssen98d19da2007-09-10 21:51:02 +00001045 if _have_threads:
1046 test_support.threading_cleanup(*thread_info)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001047
1048if __name__ == "__main__":
1049 test_main()