| OLD | NEW |
| 1 #!/usr/bin/python2.4 | 1 #!/usr/bin/python2.4 |
| 2 # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2008 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 To shut it down properly, visit localhost:8888/kill. | 12 To shut it down properly, visit localhost:8888/kill. |
| 13 """ | 13 """ |
| 14 | 14 |
| 15 import base64 | 15 import base64 |
| 16 import BaseHTTPServer | 16 import BaseHTTPServer |
| 17 import cgi | 17 import cgi |
| 18 import md5 | |
| 19 import optparse | 18 import optparse |
| 20 import os | 19 import os |
| 21 import re | 20 import re |
| 22 import shutil | 21 import shutil |
| 23 import SocketServer | 22 import SocketServer |
| 24 import sys | 23 import sys |
| 25 import time | 24 import time |
| 26 import tlslite | 25 import tlslite |
| 27 import tlslite.api | 26 import tlslite.api |
| 28 import pyftpdlib.ftpserver | 27 import pyftpdlib.ftpserver |
| 29 | 28 |
| 29 try: |
| 30 import hashlib |
| 31 _new_md5 = hashlib.md5 |
| 32 except ImportError: |
| 33 import md5 |
| 34 _new_md5 = md5.new |
| 35 |
| 30 SERVER_HTTP = 0 | 36 SERVER_HTTP = 0 |
| 31 SERVER_FTP = 1 | 37 SERVER_FTP = 1 |
| 32 | 38 |
| 33 debug_output = sys.stderr | 39 debug_output = sys.stderr |
| 34 def debug(str): | 40 def debug(str): |
| 35 debug_output.write(str + "\n") | 41 debug_output.write(str + "\n") |
| 36 debug_output.flush() | 42 debug_output.flush() |
| 37 | 43 |
| 38 class StoppableHTTPServer(BaseHTTPServer.HTTPServer): | 44 class StoppableHTTPServer(BaseHTTPServer.HTTPServer): |
| 39 """This is a specialization of of BaseHTTPServer to allow it | 45 """This is a specialization of of BaseHTTPServer to allow it |
| (...skipping 682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 722 | 728 |
| 723 # Periodically generate a new nonce. Technically we should incorporate | 729 # Periodically generate a new nonce. Technically we should incorporate |
| 724 # the request URL into this, but we don't care for testing. | 730 # the request URL into this, but we don't care for testing. |
| 725 nonce_life = 10 | 731 nonce_life = 10 |
| 726 stale = False | 732 stale = False |
| 727 if not self.server.nonce or (time.time() - self.server.nonce_time > nonce_li
fe): | 733 if not self.server.nonce or (time.time() - self.server.nonce_time > nonce_li
fe): |
| 728 if self.server.nonce: | 734 if self.server.nonce: |
| 729 stale = True | 735 stale = True |
| 730 self.server.nonce_time = time.time() | 736 self.server.nonce_time = time.time() |
| 731 self.server.nonce = \ | 737 self.server.nonce = \ |
| 732 md5.new(time.ctime(self.server.nonce_time) + 'privatekey').hexdigest() | 738 _new_md5(time.ctime(self.server.nonce_time) + 'privatekey').hexdigest(
) |
| 733 | 739 |
| 734 nonce = self.server.nonce | 740 nonce = self.server.nonce |
| 735 opaque = md5.new('opaque').hexdigest() | 741 opaque = _new_md5('opaque').hexdigest() |
| 736 password = 'secret' | 742 password = 'secret' |
| 737 realm = 'testrealm' | 743 realm = 'testrealm' |
| 738 | 744 |
| 739 auth = self.headers.getheader('authorization') | 745 auth = self.headers.getheader('authorization') |
| 740 pairs = {} | 746 pairs = {} |
| 741 try: | 747 try: |
| 742 if not auth: | 748 if not auth: |
| 743 raise Exception('no auth') | 749 raise Exception('no auth') |
| 744 if not auth.startswith('Digest'): | 750 if not auth.startswith('Digest'): |
| 745 raise Exception('not digest') | 751 raise Exception('not digest') |
| 746 # Pull out all the name="value" pairs as a dictionary. | 752 # Pull out all the name="value" pairs as a dictionary. |
| 747 pairs = dict(re.findall(r'(\b[^ ,=]+)="?([^",]+)"?', auth)) | 753 pairs = dict(re.findall(r'(\b[^ ,=]+)="?([^",]+)"?', auth)) |
| 748 | 754 |
| 749 # Make sure it's all valid. | 755 # Make sure it's all valid. |
| 750 if pairs['nonce'] != nonce: | 756 if pairs['nonce'] != nonce: |
| 751 raise Exception('wrong nonce') | 757 raise Exception('wrong nonce') |
| 752 if pairs['opaque'] != opaque: | 758 if pairs['opaque'] != opaque: |
| 753 raise Exception('wrong opaque') | 759 raise Exception('wrong opaque') |
| 754 | 760 |
| 755 # Check the 'response' value and make sure it matches our magic hash. | 761 # Check the 'response' value and make sure it matches our magic hash. |
| 756 # See http://www.ietf.org/rfc/rfc2617.txt | 762 # See http://www.ietf.org/rfc/rfc2617.txt |
| 757 hash_a1 = md5.new(':'.join([pairs['username'], realm, password])).hexdiges
t() | 763 hash_a1 = _new_md5(':'.join([pairs['username'], realm, password])).hexdige
st() |
| 758 hash_a2 = md5.new(':'.join([self.command, pairs['uri']])).hexdigest() | 764 hash_a2 = _new_md5(':'.join([self.command, pairs['uri']])).hexdigest() |
| 759 if 'qop' in pairs and 'nc' in pairs and 'cnonce' in pairs: | 765 if 'qop' in pairs and 'nc' in pairs and 'cnonce' in pairs: |
| 760 response = md5.new(':'.join([hash_a1, nonce, pairs['nc'], | 766 response = _new_md5(':'.join([hash_a1, nonce, pairs['nc'], |
| 761 pairs['cnonce'], pairs['qop'], hash_a2])).hexdigest() | 767 pairs['cnonce'], pairs['qop'], hash_a2])).hexdigest() |
| 762 else: | 768 else: |
| 763 response = md5.new(':'.join([hash_a1, nonce, hash_a2])).hexdigest() | 769 response = _new_md5(':'.join([hash_a1, nonce, hash_a2])).hexdigest() |
| 764 | 770 |
| 765 if pairs['response'] != response: | 771 if pairs['response'] != response: |
| 766 raise Exception('wrong password') | 772 raise Exception('wrong password') |
| 767 except Exception, e: | 773 except Exception, e: |
| 768 # Authentication failed. | 774 # Authentication failed. |
| 769 self.send_response(401) | 775 self.send_response(401) |
| 770 hdr = ('Digest ' | 776 hdr = ('Digest ' |
| 771 'realm="%s", ' | 777 'realm="%s", ' |
| 772 'domain="/", ' | 778 'domain="/", ' |
| 773 'qop="auth", ' | 779 'qop="auth", ' |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1063 option_parser.add_option('', '--data-dir', dest='data_dir', | 1069 option_parser.add_option('', '--data-dir', dest='data_dir', |
| 1064 help='Directory from which to read the files') | 1070 help='Directory from which to read the files') |
| 1065 option_parser.add_option('', '--https', dest='cert', | 1071 option_parser.add_option('', '--https', dest='cert', |
| 1066 help='Specify that https should be used, specify ' | 1072 help='Specify that https should be used, specify ' |
| 1067 'the path to the cert containing the private key ' | 1073 'the path to the cert containing the private key ' |
| 1068 'the server should use') | 1074 'the server should use') |
| 1069 options, args = option_parser.parse_args() | 1075 options, args = option_parser.parse_args() |
| 1070 | 1076 |
| 1071 sys.exit(main(options, args)) | 1077 sys.exit(main(options, args)) |
| 1072 | 1078 |
| OLD | NEW |