OLD | NEW |
1 #!/usr/bin/python2.4 | 1 #!/usr/bin/python2.4 |
2 # Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """This is a simple HTTP server used for testing Chrome. | 6 """This is a simple HTTP server used for testing Chrome. |
7 | 7 |
8 It supports several test URLs, as specified by the handlers in TestPageHandler. | 8 It supports several test URLs, as specified by the handlers in TestPageHandler. |
9 It defaults to living on localhost:8888. | 9 It defaults to living on localhost:8888. |
10 It can use https if you specify the flag --https=CERT where CERT is the path | 10 It can use https if you specify the flag --https=CERT where CERT is the path |
11 to a pem file containing the certificate and private key that should be used. | 11 to a pem file containing the certificate and private key that should be used. |
12 """ | 12 """ |
13 | 13 |
14 import base64 | 14 import base64 |
15 import BaseHTTPServer | 15 import BaseHTTPServer |
16 import cgi | 16 import cgi |
17 import optparse | 17 import optparse |
18 import os | 18 import os |
19 import re | 19 import re |
20 import shutil | 20 import shutil |
21 import SocketServer | 21 import SocketServer |
22 import sys | 22 import sys |
23 import time | 23 import time |
24 import urllib2 | 24 import urlparse |
25 import warnings | 25 import warnings |
26 | 26 |
27 # Ignore deprecation warnings, they make our output more cluttered. | 27 # Ignore deprecation warnings, they make our output more cluttered. |
28 warnings.filterwarnings("ignore", category=DeprecationWarning) | 28 warnings.filterwarnings("ignore", category=DeprecationWarning) |
29 | 29 |
30 import pyftpdlib.ftpserver | 30 import pyftpdlib.ftpserver |
31 import tlslite | 31 import tlslite |
32 import tlslite.api | 32 import tlslite.api |
33 | 33 |
34 try: | 34 try: |
(...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
566 if not self._ShouldHandleRequest("/download-finish"): | 566 if not self._ShouldHandleRequest("/download-finish"): |
567 return False | 567 return False |
568 | 568 |
569 self.server.waitForDownload = False | 569 self.server.waitForDownload = False |
570 self.send_response(200) | 570 self.send_response(200) |
571 self.send_header('Content-type', 'text/html') | 571 self.send_header('Content-type', 'text/html') |
572 self.send_header('Cache-Control', 'max-age=0') | 572 self.send_header('Cache-Control', 'max-age=0') |
573 self.end_headers() | 573 self.end_headers() |
574 return True | 574 return True |
575 | 575 |
| 576 def _ReplaceFileData(self, data, query_parameters): |
| 577 """Replaces matching substrings in a file. |
| 578 |
| 579 If the 'replace_orig' and 'replace_new' URL query parameters are present, |
| 580 a new string is returned with all occasions of the 'replace_orig' value |
| 581 replaced by the 'replace_new' value. |
| 582 |
| 583 If the parameters are not present, |data| is returned. |
| 584 """ |
| 585 query_dict = cgi.parse_qs(query_parameters) |
| 586 orig_values = query_dict.get('replace_orig', []) |
| 587 new_values = query_dict.get('replace_new', []) |
| 588 if not orig_values or not new_values: |
| 589 return data |
| 590 orig_value = orig_values[0] |
| 591 new_value = new_values[0] |
| 592 return data.replace(orig_value, new_value) |
| 593 |
576 def FileHandler(self): | 594 def FileHandler(self): |
577 """This handler sends the contents of the requested file. Wow, it's like | 595 """This handler sends the contents of the requested file. Wow, it's like |
578 a real webserver!""" | 596 a real webserver!""" |
579 | 597 |
580 prefix = self.server.file_root_url | 598 prefix = self.server.file_root_url |
581 if not self.path.startswith(prefix): | 599 if not self.path.startswith(prefix): |
582 return False | 600 return False |
583 | 601 |
584 # Consume a request body if present. | 602 # Consume a request body if present. |
585 if self.command == 'POST' or self.command == 'PUT' : | 603 if self.command == 'POST' or self.command == 'PUT' : |
586 self.rfile.read(int(self.headers.getheader('content-length'))) | 604 self.rfile.read(int(self.headers.getheader('content-length'))) |
587 | 605 |
588 file = self.path[len(prefix):] | 606 _, _, url_path, _, query, _ = urlparse.urlparse(self.path) |
589 if file.find('?') > -1: | 607 sub_path = url_path[len(prefix):] |
590 # Ignore the query parameters entirely. | 608 entries = sub_path.split('/') |
591 url, querystring = file.split('?') | 609 file_path = os.path.join(self.server.data_dir, *entries) |
592 else: | 610 if os.path.isdir(file_path): |
593 url = file | 611 file_path = os.path.join(file_path, 'index.html') |
594 entries = url.split('/') | |
595 path = os.path.join(self.server.data_dir, *entries) | |
596 if os.path.isdir(path): | |
597 path = os.path.join(path, 'index.html') | |
598 | 612 |
599 if not os.path.isfile(path): | 613 if not os.path.isfile(file_path): |
600 print "File not found " + file + " full path:" + path | 614 print "File not found " + sub_path + " full path:" + file_path |
601 self.send_error(404) | 615 self.send_error(404) |
602 return True | 616 return True |
603 | 617 |
604 f = open(path, "rb") | 618 f = open(file_path, "rb") |
605 data = f.read() | 619 data = f.read() |
606 f.close() | 620 f.close() |
607 | 621 |
| 622 data = self._ReplaceFileData(data, query) |
| 623 |
608 # If file.mock-http-headers exists, it contains the headers we | 624 # If file.mock-http-headers exists, it contains the headers we |
609 # should send. Read them in and parse them. | 625 # should send. Read them in and parse them. |
610 headers_path = path + '.mock-http-headers' | 626 headers_path = file_path + '.mock-http-headers' |
611 if os.path.isfile(headers_path): | 627 if os.path.isfile(headers_path): |
612 f = open(headers_path, "r") | 628 f = open(headers_path, "r") |
613 | 629 |
614 # "HTTP/1.1 200 OK" | 630 # "HTTP/1.1 200 OK" |
615 response = f.readline() | 631 response = f.readline() |
616 status_code = re.findall('HTTP/\d+.\d+ (\d+)', response)[0] | 632 status_code = re.findall('HTTP/\d+.\d+ (\d+)', response)[0] |
617 self.send_response(int(status_code)) | 633 self.send_response(int(status_code)) |
618 | 634 |
619 for line in f: | 635 for line in f: |
620 header_values = re.findall('(\S+):\s*(.*)', line) | 636 header_values = re.findall('(\S+):\s*(.*)', line) |
621 if len(header_values) > 0: | 637 if len(header_values) > 0: |
622 # "name: value" | 638 # "name: value" |
623 name, value = header_values[0] | 639 name, value = header_values[0] |
624 self.send_header(name, value) | 640 self.send_header(name, value) |
625 f.close() | 641 f.close() |
626 else: | 642 else: |
627 # Could be more generic once we support mime-type sniffing, but for | 643 # Could be more generic once we support mime-type sniffing, but for |
628 # now we need to set it explicitly. | 644 # now we need to set it explicitly. |
629 self.send_response(200) | 645 self.send_response(200) |
630 self.send_header('Content-type', self.GetMIMETypeFromName(file)) | 646 self.send_header('Content-type', self.GetMIMETypeFromName(file_path)) |
631 self.send_header('Content-Length', len(data)) | 647 self.send_header('Content-Length', len(data)) |
632 self.end_headers() | 648 self.end_headers() |
633 | 649 |
634 self.wfile.write(data) | 650 self.wfile.write(data) |
635 | 651 |
636 return True | 652 return True |
637 | 653 |
638 def RealFileWithCommonHeaderHandler(self): | 654 def RealFileWithCommonHeaderHandler(self): |
639 """This handler sends the contents of the requested file without the pseudo | 655 """This handler sends the contents of the requested file without the pseudo |
640 http head!""" | 656 http head!""" |
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1258 'option may appear multiple times, indicating ' | 1274 'option may appear multiple times, indicating ' |
1259 'multiple algorithms should be enabled.'); | 1275 'multiple algorithms should be enabled.'); |
1260 option_parser.add_option('', '--file-root-url', default='/files/', | 1276 option_parser.add_option('', '--file-root-url', default='/files/', |
1261 help='Specify a root URL for files served.') | 1277 help='Specify a root URL for files served.') |
1262 option_parser.add_option('', '--startup-pipe', type='int', | 1278 option_parser.add_option('', '--startup-pipe', type='int', |
1263 dest='startup_pipe', | 1279 dest='startup_pipe', |
1264 help='File handle of pipe to parent process') | 1280 help='File handle of pipe to parent process') |
1265 options, args = option_parser.parse_args() | 1281 options, args = option_parser.parse_args() |
1266 | 1282 |
1267 sys.exit(main(options, args)) | 1283 sys.exit(main(options, args)) |
OLD | NEW |