1"""Unittests for the various HTTPServer modules. 2 3Written by Cody A.W. Somerville <cody-somerville@ubuntu.com>, 4Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest. 5""" 6 7import os 8import sys 9import re 10import base64 11import ntpath 12import shutil 13import urllib 14import httplib 15import tempfile 16import unittest 17import CGIHTTPServer 18 19 20from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 21from SimpleHTTPServer import SimpleHTTPRequestHandler 22from CGIHTTPServer import CGIHTTPRequestHandler 23from StringIO import StringIO 24from test import test_support 25 26 27threading = test_support.import_module('threading') 28 29 30class NoLogRequestHandler: 31 def log_message(self, *args): 32 # don't write log messages to stderr 33 pass 34 35class SocketlessRequestHandler(SimpleHTTPRequestHandler): 36 def __init__(self): 37 self.get_called = False 38 self.protocol_version = "HTTP/1.1" 39 40 def do_GET(self): 41 self.get_called = True 42 self.send_response(200) 43 self.send_header('Content-Type', 'text/html') 44 self.end_headers() 45 self.wfile.write(b'<html><body>Data</body></html>\r\n') 46 47 def log_message(self, fmt, *args): 48 pass 49 50 51class TestServerThread(threading.Thread): 52 def __init__(self, test_object, request_handler): 53 threading.Thread.__init__(self) 54 self.request_handler = request_handler 55 self.test_object = test_object 56 57 def run(self): 58 self.server = HTTPServer(('', 0), self.request_handler) 59 self.test_object.PORT = self.server.socket.getsockname()[1] 60 self.test_object.server_started.set() 61 self.test_object = None 62 try: 63 self.server.serve_forever(0.05) 64 finally: 65 self.server.server_close() 66 67 def stop(self): 68 self.server.shutdown() 69 self.join() 70 71 72class BaseTestCase(unittest.TestCase): 73 def setUp(self): 74 self._threads = test_support.threading_setup() 75 os.environ = test_support.EnvironmentVarGuard() 76 self.server_started = threading.Event() 77 self.thread = TestServerThread(self, self.request_handler) 78 self.thread.start() 79 self.server_started.wait() 80 81 def tearDown(self): 82 self.thread.stop() 83 os.environ.__exit__() 84 test_support.threading_cleanup(*self._threads) 85 86 def request(self, uri, method='GET', body=None, headers={}): 87 self.connection = httplib.HTTPConnection('localhost', self.PORT) 88 self.connection.request(method, uri, body, headers) 89 return self.connection.getresponse() 90 91class BaseHTTPRequestHandlerTestCase(unittest.TestCase): 92 """Test the functionality of the BaseHTTPServer focussing on 93 BaseHTTPRequestHandler. 94 """ 95 96 HTTPResponseMatch = re.compile('HTTP/1.[0-9]+ 200 OK') 97 98 def setUp (self): 99 self.handler = SocketlessRequestHandler() 100 101 def send_typical_request(self, message): 102 input_msg = StringIO(message) 103 output = StringIO() 104 self.handler.rfile = input_msg 105 self.handler.wfile = output 106 self.handler.handle_one_request() 107 output.seek(0) 108 return output.readlines() 109 110 def verify_get_called(self): 111 self.assertTrue(self.handler.get_called) 112 113 def verify_expected_headers(self, headers): 114 for fieldName in 'Server: ', 'Date: ', 'Content-Type: ': 115 self.assertEqual(sum(h.startswith(fieldName) for h in headers), 1) 116 117 def verify_http_server_response(self, response): 118 match = self.HTTPResponseMatch.search(response) 119 self.assertIsNotNone(match) 120 121 def test_http_1_1(self): 122 result = self.send_typical_request('GET / HTTP/1.1\r\n\r\n') 123 self.verify_http_server_response(result[0]) 124 self.verify_expected_headers(result[1:-1]) 125 self.verify_get_called() 126 self.assertEqual(result[-1], '<html><body>Data</body></html>\r\n') 127 128 def test_http_1_0(self): 129 result = self.send_typical_request('GET / HTTP/1.0\r\n\r\n') 130 self.verify_http_server_response(result[0]) 131 self.verify_expected_headers(result[1:-1]) 132 self.verify_get_called() 133 self.assertEqual(result[-1], '<html><body>Data</body></html>\r\n') 134 135 def test_http_0_9(self): 136 result = self.send_typical_request('GET / HTTP/0.9\r\n\r\n') 137 self.assertEqual(len(result), 1) 138 self.assertEqual(result[0], '<html><body>Data</body></html>\r\n') 139 self.verify_get_called() 140 141 def test_with_continue_1_0(self): 142 result = self.send_typical_request('GET / HTTP/1.0\r\nExpect: 100-continue\r\n\r\n') 143 self.verify_http_server_response(result[0]) 144 self.verify_expected_headers(result[1:-1]) 145 self.verify_get_called() 146 self.assertEqual(result[-1], '<html><body>Data</body></html>\r\n') 147 148 def test_request_length(self): 149 # Issue #10714: huge request lines are discarded, to avoid Denial 150 # of Service attacks. 151 result = self.send_typical_request(b'GET ' + b'x' * 65537) 152 self.assertEqual(result[0], b'HTTP/1.1 414 Request-URI Too Long\r\n') 153 self.assertFalse(self.handler.get_called) 154 155 156class BaseHTTPServerTestCase(BaseTestCase): 157 class request_handler(NoLogRequestHandler, BaseHTTPRequestHandler): 158 protocol_version = 'HTTP/1.1' 159 default_request_version = 'HTTP/1.1' 160 161 def do_TEST(self): 162 self.send_response(204) 163 self.send_header('Content-Type', 'text/html') 164 self.send_header('Connection', 'close') 165 self.end_headers() 166 167 def do_KEEP(self): 168 self.send_response(204) 169 self.send_header('Content-Type', 'text/html') 170 self.send_header('Connection', 'keep-alive') 171 self.end_headers() 172 173 def do_KEYERROR(self): 174 self.send_error(999) 175 176 def do_CUSTOM(self): 177 self.send_response(999) 178 self.send_header('Content-Type', 'text/html') 179 self.send_header('Connection', 'close') 180 self.end_headers() 181 182 def do_SEND_ERROR(self): 183 self.send_error(int(self.path[1:])) 184 185 def do_HEAD(self): 186 self.send_error(int(self.path[1:])) 187 188 def setUp(self): 189 BaseTestCase.setUp(self) 190 self.con = httplib.HTTPConnection('localhost', self.PORT) 191 self.con.connect() 192 193 def test_command(self): 194 self.con.request('GET', '/') 195 res = self.con.getresponse() 196 self.assertEqual(res.status, 501) 197 198 def test_request_line_trimming(self): 199 self.con._http_vsn_str = 'HTTP/1.1\n' 200 self.con.putrequest('XYZBOGUS', '/') 201 self.con.endheaders() 202 res = self.con.getresponse() 203 self.assertEqual(res.status, 501) 204 205 def test_version_bogus(self): 206 self.con._http_vsn_str = 'FUBAR' 207 self.con.putrequest('GET', '/') 208 self.con.endheaders() 209 res = self.con.getresponse() 210 self.assertEqual(res.status, 400) 211 212 def test_version_digits(self): 213 self.con._http_vsn_str = 'HTTP/9.9.9' 214 self.con.putrequest('GET', '/') 215 self.con.endheaders() 216 res = self.con.getresponse() 217 self.assertEqual(res.status, 400) 218 219 def test_version_none_get(self): 220 self.con._http_vsn_str = '' 221 self.con.putrequest('GET', '/') 222 self.con.endheaders() 223 res = self.con.getresponse() 224 self.assertEqual(res.status, 501) 225 226 def test_version_none(self): 227 # Test that a valid method is rejected when not HTTP/1.x 228 self.con._http_vsn_str = '' 229 self.con.putrequest('CUSTOM', '/') 230 self.con.endheaders() 231 res = self.con.getresponse() 232 self.assertEqual(res.status, 400) 233 234 def test_version_invalid(self): 235 self.con._http_vsn = 99 236 self.con._http_vsn_str = 'HTTP/9.9' 237 self.con.putrequest('GET', '/') 238 self.con.endheaders() 239 res = self.con.getresponse() 240 self.assertEqual(res.status, 505) 241 242 def test_send_blank(self): 243 self.con._http_vsn_str = '' 244 self.con.putrequest('', '') 245 self.con.endheaders() 246 res = self.con.getresponse() 247 self.assertEqual(res.status, 400) 248 249 def test_header_close(self): 250 self.con.putrequest('GET', '/') 251 self.con.putheader('Connection', 'close') 252 self.con.endheaders() 253 res = self.con.getresponse() 254 self.assertEqual(res.status, 501) 255 256 def test_head_keep_alive(self): 257 self.con._http_vsn_str = 'HTTP/1.1' 258 self.con.putrequest('GET', '/') 259 self.con.putheader('Connection', 'keep-alive') 260 self.con.endheaders() 261 res = self.con.getresponse() 262 self.assertEqual(res.status, 501) 263 264 def test_handler(self): 265 self.con.request('TEST', '/') 266 res = self.con.getresponse() 267 self.assertEqual(res.status, 204) 268 269 def test_return_header_keep_alive(self): 270 self.con.request('KEEP', '/') 271 res = self.con.getresponse() 272 self.assertEqual(res.getheader('Connection'), 'keep-alive') 273 self.con.request('TEST', '/') 274 self.addCleanup(self.con.close) 275 276 def test_internal_key_error(self): 277 self.con.request('KEYERROR', '/') 278 res = self.con.getresponse() 279 self.assertEqual(res.status, 999) 280 281 def test_return_custom_status(self): 282 self.con.request('CUSTOM', '/') 283 res = self.con.getresponse() 284 self.assertEqual(res.status, 999) 285 286 def test_send_error(self): 287 allow_transfer_encoding_codes = (205, 304) 288 for code in (101, 102, 204, 205, 304): 289 self.con.request('SEND_ERROR', '/{}'.format(code)) 290 res = self.con.getresponse() 291 self.assertEqual(code, res.status) 292 self.assertEqual(None, res.getheader('Content-Length')) 293 self.assertEqual(None, res.getheader('Content-Type')) 294 if code not in allow_transfer_encoding_codes: 295 self.assertEqual(None, res.getheader('Transfer-Encoding')) 296 297 data = res.read() 298 self.assertEqual(b'', data) 299 300 def test_head_via_send_error(self): 301 allow_transfer_encoding_codes = (205, 304) 302 for code in (101, 200, 204, 205, 304): 303 self.con.request('HEAD', '/{}'.format(code)) 304 res = self.con.getresponse() 305 self.assertEqual(code, res.status) 306 if code == 200: 307 self.assertEqual(None, res.getheader('Content-Length')) 308 self.assertIn('text/html', res.getheader('Content-Type')) 309 else: 310 self.assertEqual(None, res.getheader('Content-Length')) 311 self.assertEqual(None, res.getheader('Content-Type')) 312 if code not in allow_transfer_encoding_codes: 313 self.assertEqual(None, res.getheader('Transfer-Encoding')) 314 315 data = res.read() 316 self.assertEqual(b'', data) 317 318 319class SimpleHTTPServerTestCase(BaseTestCase): 320 class request_handler(NoLogRequestHandler, SimpleHTTPRequestHandler): 321 pass 322 323 def setUp(self): 324 BaseTestCase.setUp(self) 325 self.cwd = os.getcwd() 326 basetempdir = tempfile.gettempdir() 327 os.chdir(basetempdir) 328 self.data = 'We are the knights who say Ni!' 329 self.tempdir = tempfile.mkdtemp(dir=basetempdir) 330 self.tempdir_name = os.path.basename(self.tempdir) 331 self.base_url = '/' + self.tempdir_name 332 temp = open(os.path.join(self.tempdir, 'test'), 'wb') 333 temp.write(self.data) 334 temp.close() 335 336 def tearDown(self): 337 try: 338 os.chdir(self.cwd) 339 try: 340 shutil.rmtree(self.tempdir) 341 except OSError: 342 pass 343 finally: 344 BaseTestCase.tearDown(self) 345 346 def check_status_and_reason(self, response, status, data=None): 347 body = response.read() 348 self.assertTrue(response) 349 self.assertEqual(response.status, status) 350 self.assertIsNotNone(response.reason) 351 if data: 352 self.assertEqual(data, body) 353 354 def test_get(self): 355 #constructs the path relative to the root directory of the HTTPServer 356 response = self.request(self.base_url + '/test') 357 self.check_status_and_reason(response, 200, data=self.data) 358 # check for trailing "/" which should return 404. See Issue17324 359 response = self.request(self.base_url + '/test/') 360 self.check_status_and_reason(response, 404) 361 response = self.request(self.base_url + '/') 362 self.check_status_and_reason(response, 200) 363 response = self.request(self.base_url) 364 self.check_status_and_reason(response, 301) 365 response = self.request(self.base_url + '/?hi=2') 366 self.check_status_and_reason(response, 200) 367 response = self.request(self.base_url + '?hi=1') 368 self.check_status_and_reason(response, 301) 369 self.assertEqual(response.getheader("Location"), 370 self.base_url + "/?hi=1") 371 response = self.request('/ThisDoesNotExist') 372 self.check_status_and_reason(response, 404) 373 response = self.request('/' + 'ThisDoesNotExist' + '/') 374 self.check_status_and_reason(response, 404) 375 with open(os.path.join(self.tempdir_name, 'index.html'), 'w') as fp: 376 response = self.request(self.base_url + '/') 377 self.check_status_and_reason(response, 200) 378 # chmod() doesn't work as expected on Windows, and filesystem 379 # permissions are ignored by root on Unix. 380 if os.name == 'posix' and os.geteuid() != 0: 381 os.chmod(self.tempdir, 0) 382 response = self.request(self.base_url + '/') 383 self.check_status_and_reason(response, 404) 384 os.chmod(self.tempdir, 0755) 385 386 def test_head(self): 387 response = self.request( 388 self.base_url + '/test', method='HEAD') 389 self.check_status_and_reason(response, 200) 390 self.assertEqual(response.getheader('content-length'), 391 str(len(self.data))) 392 self.assertEqual(response.getheader('content-type'), 393 'application/octet-stream') 394 395 def test_invalid_requests(self): 396 response = self.request('/', method='FOO') 397 self.check_status_and_reason(response, 501) 398 # requests must be case sensitive,so this should fail too 399 response = self.request('/', method='custom') 400 self.check_status_and_reason(response, 501) 401 response = self.request('/', method='GETs') 402 self.check_status_and_reason(response, 501) 403 404 def test_path_without_leading_slash(self): 405 response = self.request(self.tempdir_name + '/test') 406 self.check_status_and_reason(response, 200, data=self.data) 407 response = self.request(self.tempdir_name + '/test/') 408 self.check_status_and_reason(response, 404) 409 response = self.request(self.tempdir_name + '/') 410 self.check_status_and_reason(response, 200) 411 response = self.request(self.tempdir_name) 412 self.check_status_and_reason(response, 301) 413 response = self.request(self.tempdir_name + '/?hi=2') 414 self.check_status_and_reason(response, 200) 415 response = self.request(self.tempdir_name + '?hi=1') 416 self.check_status_and_reason(response, 301) 417 self.assertEqual(response.getheader("Location"), 418 self.tempdir_name + "/?hi=1") 419 420 421cgi_file1 = """\ 422#!%s 423 424print "Content-type: text/html" 425print 426print "Hello World" 427""" 428 429cgi_file2 = """\ 430#!%s 431import cgi 432 433print "Content-type: text/html" 434print 435 436form = cgi.FieldStorage() 437print "%%s, %%s, %%s" %% (form.getfirst("spam"), form.getfirst("eggs"), 438 form.getfirst("bacon")) 439""" 440 441cgi_file4 = """\ 442#!%s 443import os 444 445print("Content-type: text/html") 446print("") 447 448print(os.environ["%s"]) 449""" 450 451 452@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0, 453 "This test can't be run reliably as root (issue #13308).") 454class CGIHTTPServerTestCase(BaseTestCase): 455 class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler): 456 pass 457 458 def setUp(self): 459 BaseTestCase.setUp(self) 460 self.parent_dir = tempfile.mkdtemp() 461 self.cgi_dir = os.path.join(self.parent_dir, 'cgi-bin') 462 self.cgi_child_dir = os.path.join(self.cgi_dir, 'child-dir') 463 os.mkdir(self.cgi_dir) 464 os.mkdir(self.cgi_child_dir) 465 466 # The shebang line should be pure ASCII: use symlink if possible. 467 # See issue #7668. 468 if hasattr(os, 'symlink'): 469 self.pythonexe = os.path.join(self.parent_dir, 'python') 470 os.symlink(sys.executable, self.pythonexe) 471 else: 472 self.pythonexe = sys.executable 473 474 self.nocgi_path = os.path.join(self.parent_dir, 'nocgi.py') 475 with open(self.nocgi_path, 'w') as fp: 476 fp.write(cgi_file1 % self.pythonexe) 477 os.chmod(self.nocgi_path, 0777) 478 479 self.file1_path = os.path.join(self.cgi_dir, 'file1.py') 480 with open(self.file1_path, 'w') as file1: 481 file1.write(cgi_file1 % self.pythonexe) 482 os.chmod(self.file1_path, 0777) 483 484 self.file2_path = os.path.join(self.cgi_dir, 'file2.py') 485 with open(self.file2_path, 'w') as file2: 486 file2.write(cgi_file2 % self.pythonexe) 487 os.chmod(self.file2_path, 0777) 488 489 self.file3_path = os.path.join(self.cgi_child_dir, 'file3.py') 490 with open(self.file3_path, 'w') as file3: 491 file3.write(cgi_file1 % self.pythonexe) 492 os.chmod(self.file3_path, 0777) 493 494 self.file4_path = os.path.join(self.cgi_dir, 'file4.py') 495 with open(self.file4_path, 'w') as file4: 496 file4.write(cgi_file4 % (self.pythonexe, 'QUERY_STRING')) 497 os.chmod(self.file4_path, 0o777) 498 499 self.cwd = os.getcwd() 500 os.chdir(self.parent_dir) 501 502 def tearDown(self): 503 try: 504 os.chdir(self.cwd) 505 if self.pythonexe != sys.executable: 506 os.remove(self.pythonexe) 507 os.remove(self.nocgi_path) 508 os.remove(self.file1_path) 509 os.remove(self.file2_path) 510 os.remove(self.file3_path) 511 os.remove(self.file4_path) 512 os.rmdir(self.cgi_child_dir) 513 os.rmdir(self.cgi_dir) 514 os.rmdir(self.parent_dir) 515 finally: 516 BaseTestCase.tearDown(self) 517 518 def test_url_collapse_path(self): 519 # verify tail is the last portion and head is the rest on proper urls 520 test_vectors = { 521 '': '//', 522 '..': IndexError, 523 '/.//..': IndexError, 524 '/': '//', 525 '//': '//', 526 '/\\': '//\\', 527 '/.//': '//', 528 'cgi-bin/file1.py': '/cgi-bin/file1.py', 529 '/cgi-bin/file1.py': '/cgi-bin/file1.py', 530 'a': '//a', 531 '/a': '//a', 532 '//a': '//a', 533 './a': '//a', 534 './C:/': '/C:/', 535 '/a/b': '/a/b', 536 '/a/b/': '/a/b/', 537 '/a/b/.': '/a/b/', 538 '/a/b/c/..': '/a/b/', 539 '/a/b/c/../d': '/a/b/d', 540 '/a/b/c/../d/e/../f': '/a/b/d/f', 541 '/a/b/c/../d/e/../../f': '/a/b/f', 542 '/a/b/c/../d/e/.././././..//f': '/a/b/f', 543 '../a/b/c/../d/e/.././././..//f': IndexError, 544 '/a/b/c/../d/e/../../../f': '/a/f', 545 '/a/b/c/../d/e/../../../../f': '//f', 546 '/a/b/c/../d/e/../../../../../f': IndexError, 547 '/a/b/c/../d/e/../../../../f/..': '//', 548 '/a/b/c/../d/e/../../../../f/../.': '//', 549 } 550 for path, expected in test_vectors.iteritems(): 551 if isinstance(expected, type) and issubclass(expected, Exception): 552 self.assertRaises(expected, 553 CGIHTTPServer._url_collapse_path, path) 554 else: 555 actual = CGIHTTPServer._url_collapse_path(path) 556 self.assertEqual(expected, actual, 557 msg='path = %r\nGot: %r\nWanted: %r' % 558 (path, actual, expected)) 559 560 def test_headers_and_content(self): 561 res = self.request('/cgi-bin/file1.py') 562 self.assertEqual(('Hello World\n', 'text/html', 200), 563 (res.read(), res.getheader('Content-type'), res.status)) 564 565 def test_issue19435(self): 566 res = self.request('///////////nocgi.py/../cgi-bin/nothere.sh') 567 self.assertEqual(res.status, 404) 568 569 def test_post(self): 570 params = urllib.urlencode({'spam' : 1, 'eggs' : 'python', 'bacon' : 123456}) 571 headers = {'Content-type' : 'application/x-www-form-urlencoded'} 572 res = self.request('/cgi-bin/file2.py', 'POST', params, headers) 573 574 self.assertEqual(res.read(), '1, python, 123456\n') 575 576 def test_invaliduri(self): 577 res = self.request('/cgi-bin/invalid') 578 res.read() 579 self.assertEqual(res.status, 404) 580 581 def test_authorization(self): 582 headers = {'Authorization' : 'Basic %s' % 583 base64.b64encode('username:pass')} 584 res = self.request('/cgi-bin/file1.py', 'GET', headers=headers) 585 self.assertEqual(('Hello World\n', 'text/html', 200), 586 (res.read(), res.getheader('Content-type'), res.status)) 587 588 def test_no_leading_slash(self): 589 # http://bugs.python.org/issue2254 590 res = self.request('cgi-bin/file1.py') 591 self.assertEqual(('Hello World\n', 'text/html', 200), 592 (res.read(), res.getheader('Content-type'), res.status)) 593 594 def test_os_environ_is_not_altered(self): 595 signature = "Test CGI Server" 596 os.environ['SERVER_SOFTWARE'] = signature 597 res = self.request('/cgi-bin/file1.py') 598 self.assertEqual((b'Hello World\n', 'text/html', 200), 599 (res.read(), res.getheader('Content-type'), res.status)) 600 self.assertEqual(os.environ['SERVER_SOFTWARE'], signature) 601 602 def test_urlquote_decoding_in_cgi_check(self): 603 res = self.request('/cgi-bin%2ffile1.py') 604 self.assertEqual((b'Hello World\n', 'text/html', 200), 605 (res.read(), res.getheader('Content-type'), res.status)) 606 607 def test_nested_cgi_path_issue21323(self): 608 res = self.request('/cgi-bin/child-dir/file3.py') 609 self.assertEqual((b'Hello World\n', 'text/html', 200), 610 (res.read(), res.getheader('Content-type'), res.status)) 611 612 def test_query_with_multiple_question_mark(self): 613 res = self.request('/cgi-bin/file4.py?a=b?c=d') 614 self.assertEqual( 615 (b'a=b?c=d\n', 'text/html', 200), 616 (res.read(), res.getheader('Content-type'), res.status)) 617 618 def test_query_with_continuous_slashes(self): 619 res = self.request('/cgi-bin/file4.py?k=aa%2F%2Fbb&//q//p//=//a//b//') 620 self.assertEqual( 621 (b'k=aa%2F%2Fbb&//q//p//=//a//b//\n', 622 'text/html', 200), 623 (res.read(), res.getheader('Content-type'), res.status)) 624 625 626class SimpleHTTPRequestHandlerTestCase(unittest.TestCase): 627 """ Test url parsing """ 628 def setUp(self): 629 self.translated = os.getcwd() 630 self.translated = os.path.join(self.translated, 'filename') 631 self.handler = SocketlessRequestHandler() 632 633 def test_query_arguments(self): 634 path = self.handler.translate_path('/filename') 635 self.assertEqual(path, self.translated) 636 path = self.handler.translate_path('/filename?foo=bar') 637 self.assertEqual(path, self.translated) 638 path = self.handler.translate_path('/filename?a=b&spam=eggs#zot') 639 self.assertEqual(path, self.translated) 640 641 def test_start_with_double_slash(self): 642 path = self.handler.translate_path('//filename') 643 self.assertEqual(path, self.translated) 644 path = self.handler.translate_path('//filename?foo=bar') 645 self.assertEqual(path, self.translated) 646 647 def test_windows_colon(self): 648 import SimpleHTTPServer 649 with test_support.swap_attr(SimpleHTTPServer.os, 'path', ntpath): 650 path = self.handler.translate_path('c:c:c:foo/filename') 651 path = path.replace(ntpath.sep, os.sep) 652 self.assertEqual(path, self.translated) 653 654 path = self.handler.translate_path('\\c:../filename') 655 path = path.replace(ntpath.sep, os.sep) 656 self.assertEqual(path, self.translated) 657 658 path = self.handler.translate_path('c:\\c:..\\foo/filename') 659 path = path.replace(ntpath.sep, os.sep) 660 self.assertEqual(path, self.translated) 661 662 path = self.handler.translate_path('c:c:foo\\c:c:bar/filename') 663 path = path.replace(ntpath.sep, os.sep) 664 self.assertEqual(path, self.translated) 665 666 667def test_main(verbose=None): 668 try: 669 cwd = os.getcwd() 670 test_support.run_unittest(BaseHTTPRequestHandlerTestCase, 671 SimpleHTTPRequestHandlerTestCase, 672 BaseHTTPServerTestCase, 673 SimpleHTTPServerTestCase, 674 CGIHTTPServerTestCase 675 ) 676 finally: 677 os.chdir(cwd) 678 679if __name__ == '__main__': 680 test_main() 681