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