OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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/FTP/SYNC/TCP/UDP/ server used for testing Chrome. | 6 """This is a simple HTTP/FTP/SYNC/TCP/UDP/ 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 By default, it listens on an ephemeral port and sends the port number back to | 9 By default, it listens on an ephemeral port and sends the port number back to |
10 the originating process over a pipe. The originating process can specify an | 10 the originating process over a pipe. The originating process can specify an |
11 explicit port if necessary. | 11 explicit port if necessary. |
12 It can use https if you specify the flag --https=CERT where CERT is the path | 12 It can use https if you specify the flag --https=CERT where CERT is the path |
13 to a pem file containing the certificate and private key that should be used. | 13 to a pem file containing the certificate and private key that should be used. |
14 """ | 14 """ |
15 | 15 |
16 import asyncore | 16 import asyncore |
17 import base64 | 17 import base64 |
18 import BaseHTTPServer | 18 import BaseHTTPServer |
19 import cgi | 19 import cgi |
20 import errno | 20 import errno |
21 import hashlib | |
21 import httplib | 22 import httplib |
23 import json | |
22 import minica | 24 import minica |
23 import optparse | 25 import optparse |
24 import os | 26 import os |
25 import random | 27 import random |
26 import re | 28 import re |
27 import select | 29 import select |
28 import socket | 30 import socket |
29 import SocketServer | 31 import SocketServer |
30 import struct | 32 import struct |
31 import sys | 33 import sys |
32 import threading | 34 import threading |
33 import time | 35 import time |
34 import urllib | 36 import urllib |
35 import urlparse | 37 import urlparse |
36 import warnings | 38 import warnings |
37 import zlib | 39 import zlib |
38 | 40 |
39 # Ignore deprecation warnings, they make our output more cluttered. | 41 # Ignore deprecation warnings, they make our output more cluttered. |
40 warnings.filterwarnings("ignore", category=DeprecationWarning) | 42 warnings.filterwarnings("ignore", category=DeprecationWarning) |
M-A Ruel
2012/09/14 23:16:08
Maybe it's not necessary anymore ?
mattm
2012/09/14 23:21:48
Seems like it.
I don't want to introduce extra va
| |
41 | 43 |
42 import echo_message | 44 import echo_message |
43 import pyftpdlib.ftpserver | 45 import pyftpdlib.ftpserver |
44 import tlslite | 46 import tlslite |
45 import tlslite.api | 47 import tlslite.api |
46 | 48 |
47 try: | |
48 import hashlib | |
49 _new_md5 = hashlib.md5 | |
50 except ImportError: | |
51 import md5 | |
52 _new_md5 = md5.new | |
53 | |
54 try: | |
55 import json | |
56 except ImportError: | |
57 import simplejson as json | |
58 | |
59 if sys.platform == 'win32': | 49 if sys.platform == 'win32': |
60 import msvcrt | 50 import msvcrt |
61 | 51 |
62 SERVER_HTTP = 0 | 52 SERVER_HTTP = 0 |
63 SERVER_FTP = 1 | 53 SERVER_FTP = 1 |
64 SERVER_SYNC = 2 | 54 SERVER_SYNC = 2 |
65 SERVER_TCP_ECHO = 3 | 55 SERVER_TCP_ECHO = 3 |
66 SERVER_UDP_ECHO = 4 | 56 SERVER_UDP_ECHO = 4 |
67 SERVER_BASIC_AUTH_PROXY = 5 | 57 SERVER_BASIC_AUTH_PROXY = 5 |
68 | 58 |
(...skipping 1242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1311 This is a fake implementation. A real implementation would only use a given | 1301 This is a fake implementation. A real implementation would only use a given |
1312 nonce a single time (hence the name n-once). However, for the purposes of | 1302 nonce a single time (hence the name n-once). However, for the purposes of |
1313 unittesting, we don't care about the security of the nonce. | 1303 unittesting, we don't care about the security of the nonce. |
1314 | 1304 |
1315 Args: | 1305 Args: |
1316 force_reset: Iff set, the nonce will be changed. Useful for testing the | 1306 force_reset: Iff set, the nonce will be changed. Useful for testing the |
1317 "stale" response. | 1307 "stale" response. |
1318 """ | 1308 """ |
1319 if force_reset or not self.server.nonce_time: | 1309 if force_reset or not self.server.nonce_time: |
1320 self.server.nonce_time = time.time() | 1310 self.server.nonce_time = time.time() |
1321 return _new_md5('privatekey%s%d' % | 1311 return hashlib.md5('privatekey%s%d' % |
1322 (self.path, self.server.nonce_time)).hexdigest() | 1312 (self.path, self.server.nonce_time)).hexdigest() |
1323 | 1313 |
1324 def AuthDigestHandler(self): | 1314 def AuthDigestHandler(self): |
1325 """This handler tests 'Digest' authentication. | 1315 """This handler tests 'Digest' authentication. |
1326 | 1316 |
1327 It just sends a page with title 'user/pass' if you succeed. | 1317 It just sends a page with title 'user/pass' if you succeed. |
1328 | 1318 |
1329 A stale response is sent iff "stale" is present in the request path. | 1319 A stale response is sent iff "stale" is present in the request path. |
1330 """ | 1320 """ |
1331 if not self._ShouldHandleRequest("/auth-digest"): | 1321 if not self._ShouldHandleRequest("/auth-digest"): |
1332 return False | 1322 return False |
1333 | 1323 |
1334 stale = 'stale' in self.path | 1324 stale = 'stale' in self.path |
1335 nonce = self.GetNonce(force_reset=stale) | 1325 nonce = self.GetNonce(force_reset=stale) |
1336 opaque = _new_md5('opaque').hexdigest() | 1326 opaque = hashlib.md5('opaque').hexdigest() |
1337 password = 'secret' | 1327 password = 'secret' |
1338 realm = 'testrealm' | 1328 realm = 'testrealm' |
1339 | 1329 |
1340 auth = self.headers.getheader('authorization') | 1330 auth = self.headers.getheader('authorization') |
1341 pairs = {} | 1331 pairs = {} |
1342 try: | 1332 try: |
1343 if not auth: | 1333 if not auth: |
1344 raise Exception('no auth') | 1334 raise Exception('no auth') |
1345 if not auth.startswith('Digest'): | 1335 if not auth.startswith('Digest'): |
1346 raise Exception('not digest') | 1336 raise Exception('not digest') |
1347 # Pull out all the name="value" pairs as a dictionary. | 1337 # Pull out all the name="value" pairs as a dictionary. |
1348 pairs = dict(re.findall(r'(\b[^ ,=]+)="?([^",]+)"?', auth)) | 1338 pairs = dict(re.findall(r'(\b[^ ,=]+)="?([^",]+)"?', auth)) |
1349 | 1339 |
1350 # Make sure it's all valid. | 1340 # Make sure it's all valid. |
1351 if pairs['nonce'] != nonce: | 1341 if pairs['nonce'] != nonce: |
1352 raise Exception('wrong nonce') | 1342 raise Exception('wrong nonce') |
1353 if pairs['opaque'] != opaque: | 1343 if pairs['opaque'] != opaque: |
1354 raise Exception('wrong opaque') | 1344 raise Exception('wrong opaque') |
1355 | 1345 |
1356 # Check the 'response' value and make sure it matches our magic hash. | 1346 # Check the 'response' value and make sure it matches our magic hash. |
1357 # See http://www.ietf.org/rfc/rfc2617.txt | 1347 # See http://www.ietf.org/rfc/rfc2617.txt |
1358 hash_a1 = _new_md5( | 1348 hash_a1 = hashlib.md5( |
1359 ':'.join([pairs['username'], realm, password])).hexdigest() | 1349 ':'.join([pairs['username'], realm, password])).hexdigest() |
1360 hash_a2 = _new_md5(':'.join([self.command, pairs['uri']])).hexdigest() | 1350 hash_a2 = hashlib.md5(':'.join([self.command, pairs['uri']])).hexdigest() |
1361 if 'qop' in pairs and 'nc' in pairs and 'cnonce' in pairs: | 1351 if 'qop' in pairs and 'nc' in pairs and 'cnonce' in pairs: |
1362 response = _new_md5(':'.join([hash_a1, nonce, pairs['nc'], | 1352 response = hashlib.md5(':'.join([hash_a1, nonce, pairs['nc'], |
1363 pairs['cnonce'], pairs['qop'], hash_a2])).hexdigest() | 1353 pairs['cnonce'], pairs['qop'], hash_a2])).hexdigest() |
1364 else: | 1354 else: |
1365 response = _new_md5(':'.join([hash_a1, nonce, hash_a2])).hexdigest() | 1355 response = hashlib.md5(':'.join([hash_a1, nonce, hash_a2])).hexdigest() |
1366 | 1356 |
1367 if pairs['response'] != response: | 1357 if pairs['response'] != response: |
1368 raise Exception('wrong password') | 1358 raise Exception('wrong password') |
1369 except Exception, e: | 1359 except Exception, e: |
1370 # Authentication failed. | 1360 # Authentication failed. |
1371 self.send_response(401) | 1361 self.send_response(401) |
1372 hdr = ('Digest ' | 1362 hdr = ('Digest ' |
1373 'realm="%s", ' | 1363 'realm="%s", ' |
1374 'domain="/", ' | 1364 'domain="/", ' |
1375 'qop="auth", ' | 1365 'qop="auth", ' |
(...skipping 1029 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2405 dest='host', | 2395 dest='host', |
2406 help='Hostname or IP upon which the server will ' | 2396 help='Hostname or IP upon which the server will ' |
2407 'listen. Client connections will also only be ' | 2397 'listen. Client connections will also only be ' |
2408 'allowed from this address.') | 2398 'allowed from this address.') |
2409 option_parser.add_option('', '--auth-token', dest='auth_token', | 2399 option_parser.add_option('', '--auth-token', dest='auth_token', |
2410 help='Specify the auth token which should be used' | 2400 help='Specify the auth token which should be used' |
2411 'in the authorization header for GData.') | 2401 'in the authorization header for GData.') |
2412 options, args = option_parser.parse_args() | 2402 options, args = option_parser.parse_args() |
2413 | 2403 |
2414 sys.exit(main(options, args)) | 2404 sys.exit(main(options, args)) |
OLD | NEW |