Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Side by Side Diff: net/tools/testserver/testserver.py

Issue 10073033: Run safebrowsing_service_test through the net testserver code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: updates for comments 10 & 11 Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
22 import minica 23 import minica
23 import optparse
24 import os 24 import os
25 import random 25 import random
26 import re 26 import re
27 import select 27 import select
28 import socket 28 import socket
29 import SocketServer 29 import SocketServer
30 import struct
31 import sys 30 import sys
32 import threading 31 import threading
33 import time 32 import time
34 import urllib 33 import urllib
35 import urlparse 34 import urlparse
36 import warnings
37 import zlib 35 import zlib
38 36
39 # Ignore deprecation warnings, they make our output more cluttered.
40 warnings.filterwarnings("ignore", category=DeprecationWarning)
41
42 import echo_message 37 import echo_message
43 import pyftpdlib.ftpserver 38 import pyftpdlib.ftpserver
39 import testserver_base
44 import tlslite 40 import tlslite
45 import tlslite.api 41 import tlslite.api
46 42
47 try:
48 import hashlib
49 _new_md5 = hashlib.md5
50 except ImportError:
51 import md5
52 _new_md5 = md5.new
53 43
54 try: 44 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
55 import json
56 except ImportError:
57 import simplejson as json
58
59 if sys.platform == 'win32':
60 import msvcrt
61 45
62 SERVER_HTTP = 0 46 SERVER_HTTP = 0
63 SERVER_FTP = 1 47 SERVER_FTP = 1
64 SERVER_SYNC = 2 48 SERVER_SYNC = 2
65 SERVER_TCP_ECHO = 3 49 SERVER_TCP_ECHO = 3
66 SERVER_UDP_ECHO = 4 50 SERVER_UDP_ECHO = 4
67 51
52
68 # Using debug() seems to cause hangs on XP: see http://crbug.com/64515 . 53 # Using debug() seems to cause hangs on XP: see http://crbug.com/64515 .
69 debug_output = sys.stderr 54 debug_output = sys.stderr
70 def debug(str): 55 def debug(str):
71 debug_output.write(str + "\n") 56 debug_output.write(str + "\n")
72 debug_output.flush() 57 debug_output.flush()
73 58
59
74 class RecordingSSLSessionCache(object): 60 class RecordingSSLSessionCache(object):
75 """RecordingSSLSessionCache acts as a TLS session cache and maintains a log of 61 """RecordingSSLSessionCache acts as a TLS session cache and maintains a log of
76 lookups and inserts in order to test session cache behaviours.""" 62 lookups and inserts in order to test session cache behaviours."""
77 63
78 def __init__(self): 64 def __init__(self):
79 self.log = [] 65 self.log = []
80 66
81 def __getitem__(self, sessionID): 67 def __getitem__(self, sessionID):
82 self.log.append(('lookup', sessionID)) 68 self.log.append(('lookup', sessionID))
83 raise KeyError() 69 raise KeyError()
84 70
85 def __setitem__(self, sessionID, session): 71 def __setitem__(self, sessionID, session):
86 self.log.append(('insert', sessionID)) 72 self.log.append(('insert', sessionID))
87 73
88 74
89 class ClientRestrictingServerMixIn: 75 class ClientRestrictingServerMixIn(object):
90 """Implements verify_request to limit connections to our configured IP 76 """Implements verify_request to limit connections to our configured IP
91 address.""" 77 address."""
92 78
93 def verify_request(self, request, client_address): 79 def verify_request(self, request, client_address):
94 return client_address[0] == self.server_address[0] 80 return client_address[0] == self.server_address[0]
95 81
96 82
97 class StoppableHTTPServer(BaseHTTPServer.HTTPServer): 83 class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
98 """This is a specialization of BaseHTTPServer to allow it 84 """This is a specialization of BaseHTTPServer to allow it
99 to be exited cleanly (by setting its "stop" member to True).""" 85 to be exited cleanly (by setting its "stop" member to True)."""
(...skipping 18 matching lines...) Expand all
118 104
119 def serve_forever_on_thread(self): 105 def serve_forever_on_thread(self):
120 self.thread = threading.Thread(target = self.serve_forever, 106 self.thread = threading.Thread(target = self.serve_forever,
121 name = "OCSPServerThread") 107 name = "OCSPServerThread")
122 self.thread.start() 108 self.thread.start()
123 109
124 def stop_serving(self): 110 def stop_serving(self):
125 self.shutdown() 111 self.shutdown()
126 self.thread.join() 112 self.thread.join()
127 113
114
128 class HTTPSServer(tlslite.api.TLSSocketServerMixIn, 115 class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
129 ClientRestrictingServerMixIn, 116 ClientRestrictingServerMixIn,
130 StoppableHTTPServer): 117 StoppableHTTPServer):
131 """This is a specialization of StoppableHTTPServer that add https support and 118 """This is a specialization of StoppableHTTPServer that add https support and
132 client verification.""" 119 client verification."""
133 120
134 def __init__(self, server_address, request_hander_class, pem_cert_and_key, 121 def __init__(self, server_address, request_hander_class, pem_cert_and_key,
135 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, 122 ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers,
136 record_resume_info, tls_intolerant): 123 record_resume_info, tls_intolerant):
137 self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key) 124 self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key)
(...skipping 1172 matching lines...) Expand 10 before | Expand all | Expand 10 after
1310 This is a fake implementation. A real implementation would only use a given 1297 This is a fake implementation. A real implementation would only use a given
1311 nonce a single time (hence the name n-once). However, for the purposes of 1298 nonce a single time (hence the name n-once). However, for the purposes of
1312 unittesting, we don't care about the security of the nonce. 1299 unittesting, we don't care about the security of the nonce.
1313 1300
1314 Args: 1301 Args:
1315 force_reset: Iff set, the nonce will be changed. Useful for testing the 1302 force_reset: Iff set, the nonce will be changed. Useful for testing the
1316 "stale" response. 1303 "stale" response.
1317 """ 1304 """
1318 if force_reset or not self.server.nonce_time: 1305 if force_reset or not self.server.nonce_time:
1319 self.server.nonce_time = time.time() 1306 self.server.nonce_time = time.time()
1320 return _new_md5('privatekey%s%d' % 1307 return hashlib.md5('privatekey%s%d' %
1321 (self.path, self.server.nonce_time)).hexdigest() 1308 (self.path, self.server.nonce_time)).hexdigest()
1322 1309
1323 def AuthDigestHandler(self): 1310 def AuthDigestHandler(self):
1324 """This handler tests 'Digest' authentication. 1311 """This handler tests 'Digest' authentication.
1325 1312
1326 It just sends a page with title 'user/pass' if you succeed. 1313 It just sends a page with title 'user/pass' if you succeed.
1327 1314
1328 A stale response is sent iff "stale" is present in the request path. 1315 A stale response is sent iff "stale" is present in the request path.
1329 """ 1316 """
1330 if not self._ShouldHandleRequest("/auth-digest"): 1317 if not self._ShouldHandleRequest("/auth-digest"):
1331 return False 1318 return False
1332 1319
1333 stale = 'stale' in self.path 1320 stale = 'stale' in self.path
1334 nonce = self.GetNonce(force_reset=stale) 1321 nonce = self.GetNonce(force_reset=stale)
1335 opaque = _new_md5('opaque').hexdigest() 1322 opaque = hashlib.md5('opaque').hexdigest()
1336 password = 'secret' 1323 password = 'secret'
1337 realm = 'testrealm' 1324 realm = 'testrealm'
1338 1325
1339 auth = self.headers.getheader('authorization') 1326 auth = self.headers.getheader('authorization')
1340 pairs = {} 1327 pairs = {}
1341 try: 1328 try:
1342 if not auth: 1329 if not auth:
1343 raise Exception('no auth') 1330 raise Exception('no auth')
1344 if not auth.startswith('Digest'): 1331 if not auth.startswith('Digest'):
1345 raise Exception('not digest') 1332 raise Exception('not digest')
1346 # Pull out all the name="value" pairs as a dictionary. 1333 # Pull out all the name="value" pairs as a dictionary.
1347 pairs = dict(re.findall(r'(\b[^ ,=]+)="?([^",]+)"?', auth)) 1334 pairs = dict(re.findall(r'(\b[^ ,=]+)="?([^",]+)"?', auth))
1348 1335
1349 # Make sure it's all valid. 1336 # Make sure it's all valid.
1350 if pairs['nonce'] != nonce: 1337 if pairs['nonce'] != nonce:
1351 raise Exception('wrong nonce') 1338 raise Exception('wrong nonce')
1352 if pairs['opaque'] != opaque: 1339 if pairs['opaque'] != opaque:
1353 raise Exception('wrong opaque') 1340 raise Exception('wrong opaque')
1354 1341
1355 # Check the 'response' value and make sure it matches our magic hash. 1342 # Check the 'response' value and make sure it matches our magic hash.
1356 # See http://www.ietf.org/rfc/rfc2617.txt 1343 # See http://www.ietf.org/rfc/rfc2617.txt
1357 hash_a1 = _new_md5( 1344 hash_a1 = hashlib.md5(
1358 ':'.join([pairs['username'], realm, password])).hexdigest() 1345 ':'.join([pairs['username'], realm, password])).hexdigest()
1359 hash_a2 = _new_md5(':'.join([self.command, pairs['uri']])).hexdigest() 1346 hash_a2 = hashlib.md5(':'.join([self.command, pairs['uri']])).hexdigest()
1360 if 'qop' in pairs and 'nc' in pairs and 'cnonce' in pairs: 1347 if 'qop' in pairs and 'nc' in pairs and 'cnonce' in pairs:
1361 response = _new_md5(':'.join([hash_a1, nonce, pairs['nc'], 1348 response = hashlib.md5(':'.join([hash_a1, nonce, pairs['nc'],
1362 pairs['cnonce'], pairs['qop'], hash_a2])).hexdigest() 1349 pairs['cnonce'], pairs['qop'], hash_a2])).hexdigest()
1363 else: 1350 else:
1364 response = _new_md5(':'.join([hash_a1, nonce, hash_a2])).hexdigest() 1351 response = hashlib.md5(':'.join([hash_a1, nonce, hash_a2])).hexdigest()
1365 1352
1366 if pairs['response'] != response: 1353 if pairs['response'] != response:
1367 raise Exception('wrong password') 1354 raise Exception('wrong password')
1368 except Exception, e: 1355 except Exception, e:
1369 # Authentication failed. 1356 # Authentication failed.
1370 self.send_response(401) 1357 self.send_response(401)
1371 hdr = ('Digest ' 1358 hdr = ('Digest '
1372 'realm="%s", ' 1359 'realm="%s", '
1373 'domain="/", ' 1360 'domain="/", '
1374 'qop="auth", ' 1361 'qop="auth", '
(...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after
1934 return False 1921 return False
1935 result, raw_reply = self.server._sync_handler.HandleCreateSyncedBookmarks() 1922 result, raw_reply = self.server._sync_handler.HandleCreateSyncedBookmarks()
1936 self.send_response(result) 1923 self.send_response(result)
1937 self.send_header('Content-Type', 'text/html') 1924 self.send_header('Content-Type', 'text/html')
1938 self.send_header('Content-Length', len(raw_reply)) 1925 self.send_header('Content-Length', len(raw_reply))
1939 self.end_headers() 1926 self.end_headers()
1940 self.wfile.write(raw_reply) 1927 self.wfile.write(raw_reply)
1941 return True; 1928 return True;
1942 1929
1943 1930
1944 def MakeDataDir():
1945 if options.data_dir:
1946 if not os.path.isdir(options.data_dir):
1947 print 'specified data dir not found: ' + options.data_dir + ' exiting...'
1948 return None
1949 my_data_dir = options.data_dir
1950 else:
1951 # Create the default path to our data dir, relative to the exe dir.
1952 my_data_dir = os.path.dirname(sys.argv[0])
1953 my_data_dir = os.path.join(my_data_dir, "..", "..", "..", "..",
1954 "test", "data")
1955
1956 #TODO(ibrar): Must use Find* funtion defined in google\tools
1957 #i.e my_data_dir = FindUpward(my_data_dir, "test", "data")
1958
1959 return my_data_dir
1960
1961 class OCSPHandler(BasePageHandler): 1931 class OCSPHandler(BasePageHandler):
1962 def __init__(self, request, client_address, socket_server): 1932 def __init__(self, request, client_address, socket_server):
1963 handlers = [self.OCSPResponse] 1933 handlers = [self.OCSPResponse]
1964 self.ocsp_response = socket_server.ocsp_response 1934 self.ocsp_response = socket_server.ocsp_response
1965 BasePageHandler.__init__(self, request, client_address, socket_server, 1935 BasePageHandler.__init__(self, request, client_address, socket_server,
1966 [], handlers, [], handlers, []) 1936 [], handlers, [], handlers, [])
1967 1937
1968 def OCSPResponse(self): 1938 def OCSPResponse(self):
1969 self.send_response(200) 1939 self.send_response(200)
1970 self.send_header('Content-Type', 'application/ocsp-response') 1940 self.send_header('Content-Type', 'application/ocsp-response')
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
2012 # "echo response" message if "echo request" message is valid. 1982 # "echo response" message if "echo request" message is valid.
2013 try: 1983 try:
2014 return_data = echo_message.GetEchoResponseData(data) 1984 return_data = echo_message.GetEchoResponseData(data)
2015 if not return_data: 1985 if not return_data:
2016 return 1986 return
2017 except ValueError: 1987 except ValueError:
2018 return 1988 return
2019 socket.sendto(return_data, self.client_address) 1989 socket.sendto(return_data, self.client_address)
2020 1990
2021 1991
2022 class FileMultiplexer: 1992 class ServerRunner(testserver_base.TestServerRunner):
2023 def __init__(self, fd1, fd2) : 1993 def __init__(self):
2024 self.__fd1 = fd1 1994 super(ServerRunner, self).__init__()
2025 self.__fd2 = fd2 1995 self.__ocsp_server = None
2026 1996
2027 def __del__(self) : 1997 def __make_data_dir(self):
2028 if self.__fd1 != sys.stdout and self.__fd1 != sys.stderr: 1998 if self.options.data_dir:
2029 self.__fd1.close() 1999 if not os.path.isdir(self.options.data_dir):
2030 if self.__fd2 != sys.stdout and self.__fd2 != sys.stderr: 2000 raise testserver_base.OptionError('specified data dir not found: ' +
2031 self.__fd2.close() 2001 self.options.data_dir + ' exiting...')
2032 2002 my_data_dir = self.options.data_dir
2033 def write(self, text) : 2003 else:
2034 self.__fd1.write(text) 2004 # Create the default path to our data dir, relative to the exe dir.
2035 self.__fd2.write(text) 2005 my_data_dir = os.path.join(BASE_DIR, "..", "..", "..", "..",
2036 2006 "test", "data")
2037 def flush(self) : 2007
2038 self.__fd1.flush() 2008 #TODO(ibrar): Must use Find* funtion defined in google\tools
2039 self.__fd2.flush() 2009 #i.e my_data_dir = FindUpward(my_data_dir, "test", "data")
2040 2010
2041 def main(options, args): 2011 return my_data_dir
2042 logfile = open('testserver.log', 'w') 2012
2043 sys.stderr = FileMultiplexer(sys.stderr, logfile) 2013 def create_server(self, server_data):
2044 if options.log_to_console: 2014 port = self.options.port
2045 sys.stdout = FileMultiplexer(sys.stdout, logfile) 2015 host = self.options.host
2046 else: 2016
2047 sys.stdout = logfile 2017 if self.options.server_type == SERVER_HTTP:
2048 2018 if self.options.https:
2049 port = options.port 2019 pem_cert_and_key = None
2050 host = options.host 2020 if self.options.cert_and_key_file:
2051 2021 if not os.path.isfile(self.options.cert_and_key_file):
2052 server_data = {} 2022 raise testserver_base.OptionError(
2053 server_data['host'] = host 2023 'specified server cert file not found: ' +
2054 2024 self.options.cert_and_key_file + ' exiting...')
2055 ocsp_server = None 2025 pem_cert_and_key = file(self.options.cert_and_key_file, 'r').read()
2056 2026 else:
2057 if options.server_type == SERVER_HTTP: 2027 # generate a new certificate and run an OCSP server for it.
2058 if options.https: 2028 self.__ocsp_server = OCSPServer((host, 0), OCSPHandler)
2059 pem_cert_and_key = None 2029 print ('OCSP server started on %s:%d...' %
2060 if options.cert_and_key_file: 2030 (host, self.__ocsp_server.server_port))
2061 if not os.path.isfile(options.cert_and_key_file): 2031
2062 print ('specified server cert file not found: ' + 2032 ocsp_der = None
2063 options.cert_and_key_file + ' exiting...') 2033 ocsp_state = None
2064 return 2034
2065 pem_cert_and_key = file(options.cert_and_key_file, 'r').read() 2035 if self.options.ocsp == 'ok':
2036 ocsp_state = minica.OCSP_STATE_GOOD
2037 elif self.options.ocsp == 'revoked':
2038 ocsp_state = minica.OCSP_STATE_REVOKED
2039 elif self.options.ocsp == 'invalid':
2040 ocsp_state = minica.OCSP_STATE_INVALID
2041 elif self.options.ocsp == 'unauthorized':
2042 ocsp_state = minica.OCSP_STATE_UNAUTHORIZED
2043 elif self.options.ocsp == 'unknown':
2044 ocsp_state = minica.OCSP_STATE_UNKNOWN
2045 else:
2046 raise testserver_base.OptionError('unknown OCSP status: ' +
2047 self.options.ocsp_status)
2048
2049 (pem_cert_and_key, ocsp_der) = minica.GenerateCertKeyAndOCSP(
2050 subject = "127.0.0.1",
2051 ocsp_url = ("http://%s:%d/ocsp" %
2052 (host, self.__ocsp_server.server_port)),
2053 ocsp_state = ocsp_state)
2054
2055 self.__ocsp_server.ocsp_response = ocsp_der
2056
2057 for ca_cert in self.options.ssl_client_ca:
2058 if not os.path.isfile(ca_cert):
2059 raise testserver_base.OptionError(
2060 'specified trusted client CA file not found: ' + ca_cert +
2061 ' exiting...')
2062 server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key,
2063 self.options.ssl_client_auth,
2064 self.options.ssl_client_ca,
2065 self.options.ssl_bulk_cipher,
2066 self.options.record_resume,
2067 self.options.tls_intolerant)
2068 print 'HTTPS server started on %s:%d...' % (host, server.server_port)
2066 else: 2069 else:
2067 # generate a new certificate and run an OCSP server for it. 2070 server = HTTPServer((host, port), TestPageHandler)
2068 ocsp_server = OCSPServer((host, 0), OCSPHandler) 2071 print 'HTTP server started on %s:%d...' % (host, server.server_port)
2069 print ('OCSP server started on %s:%d...' % 2072
2070 (host, ocsp_server.server_port)) 2073 server.data_dir = self.__make_data_dir()
2071 2074 server.file_root_url = self.options.file_root_url
2072 ocsp_der = None 2075 server_data['port'] = server.server_port
2073 ocsp_state = None 2076 server._device_management_handler = None
2074 2077 server.policy_keys = self.options.policy_keys
2075 if options.ocsp == 'ok': 2078 server.policy_user = self.options.policy_user
2076 ocsp_state = minica.OCSP_STATE_GOOD 2079 server.gdata_auth_token = self.options.auth_token
2077 elif options.ocsp == 'revoked': 2080 elif self.options.server_type == SERVER_SYNC:
2078 ocsp_state = minica.OCSP_STATE_REVOKED 2081 xmpp_port = self.options.xmpp_port
2079 elif options.ocsp == 'invalid': 2082 server = SyncHTTPServer((host, port), xmpp_port, SyncPageHandler)
2080 ocsp_state = minica.OCSP_STATE_INVALID 2083 print 'Sync HTTP server started on port %d...' % server.server_port
2081 elif options.ocsp == 'unauthorized': 2084 print 'Sync XMPP server started on port %d...' % server.xmpp_port
2082 ocsp_state = minica.OCSP_STATE_UNAUTHORIZED 2085 server_data['port'] = server.server_port
2083 elif options.ocsp == 'unknown': 2086 server_data['xmpp_port'] = server.xmpp_port
2084 ocsp_state = minica.OCSP_STATE_UNKNOWN 2087 elif self.options.server_type == SERVER_TCP_ECHO:
2085 else: 2088 # Used for generating the key (randomly) that encodes the "echo request"
2086 print 'unknown OCSP status: ' + options.ocsp_status 2089 # message.
2087 return 2090 random.seed()
2088 2091 server = TCPEchoServer((host, port), TCPEchoHandler)
2089 (pem_cert_and_key, ocsp_der) = \ 2092 print 'Echo TCP server started on port %d...' % server.server_port
2090 minica.GenerateCertKeyAndOCSP( 2093 server_data['port'] = server.server_port
2091 subject = "127.0.0.1", 2094 elif self.options.server_type == SERVER_UDP_ECHO:
2092 ocsp_url = ("http://%s:%d/ocsp" % 2095 # Used for generating the key (randomly) that encodes the "echo request"
2093 (host, ocsp_server.server_port)), 2096 # message.
2094 ocsp_state = ocsp_state) 2097 random.seed()
2095 2098 server = UDPEchoServer((host, port), UDPEchoHandler)
2096 ocsp_server.ocsp_response = ocsp_der 2099 print 'Echo UDP server started on port %d...' % server.server_port
2097 2100 server_data['port'] = server.server_port
2098 for ca_cert in options.ssl_client_ca: 2101 elif self.options.server_type == SERVER_FTP:
2099 if not os.path.isfile(ca_cert): 2102 my_data_dir = self.__make_data_dir()
2100 print 'specified trusted client CA file not found: ' + ca_cert + \ 2103
2101 ' exiting...' 2104 # Instantiate a dummy authorizer for managing 'virtual' users
2102 return 2105 authorizer = pyftpdlib.ftpserver.DummyAuthorizer()
2103 server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key, 2106
2104 options.ssl_client_auth, options.ssl_client_ca, 2107 # Define a new user having full r/w permissions and a read-only
2105 options.ssl_bulk_cipher, options.record_resume, 2108 # anonymous user
2106 options.tls_intolerant) 2109 authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw')
2107 print 'HTTPS server started on %s:%d...' % (host, server.server_port) 2110
2111 authorizer.add_anonymous(my_data_dir)
2112
2113 # Instantiate FTP handler class
2114 ftp_handler = pyftpdlib.ftpserver.FTPHandler
2115 ftp_handler.authorizer = authorizer
2116
2117 # Define a customized banner (string returned when client connects)
2118 ftp_handler.banner = ("pyftpdlib %s based ftpd ready." %
2119 pyftpdlib.ftpserver.__ver__)
2120
2121 # Instantiate FTP server class and listen to address:port
2122 server = pyftpdlib.ftpserver.FTPServer((host, port), ftp_handler)
2123 server_data['port'] = server.socket.getsockname()[1]
2124 print 'FTP server started on port %d...' % server_data['port']
2108 else: 2125 else:
2109 server = HTTPServer((host, port), TestPageHandler) 2126 raise testserver_base.OptionError('unknown server type' +
2110 print 'HTTP server started on %s:%d...' % (host, server.server_port) 2127 self.options.server_type)
2111 2128
2112 server.data_dir = MakeDataDir() 2129 return server
2113 server.file_root_url = options.file_root_url 2130
2114 server_data['port'] = server.server_port 2131 def run_server(self):
2115 server._device_management_handler = None 2132 if self.__ocsp_server:
2116 server.policy_keys = options.policy_keys 2133 self.__ocsp_server.serve_forever_on_thread()
2117 server.policy_user = options.policy_user 2134
2118 server.gdata_auth_token = options.auth_token 2135 testserver_base.TestServerRunner.run_server(self)
2119 elif options.server_type == SERVER_SYNC: 2136
2120 xmpp_port = options.xmpp_port 2137 if self.__ocsp_server:
2121 server = SyncHTTPServer((host, port), xmpp_port, SyncPageHandler) 2138 self.__ocsp_server.stop_serving()
2122 print 'Sync HTTP server started on port %d...' % server.server_port 2139
2123 print 'Sync XMPP server started on port %d...' % server.xmpp_port 2140 def add_options(self):
2124 server_data['port'] = server.server_port 2141 testserver_base.TestServerRunner.add_options(self)
2125 server_data['xmpp_port'] = server.xmpp_port 2142 self.option_parser.add_option('-f', '--ftp', action='store_const',
2126 elif options.server_type == SERVER_TCP_ECHO: 2143 const=SERVER_FTP, default=SERVER_HTTP,
2127 # Used for generating the key (randomly) that encodes the "echo request" 2144 dest='server_type',
2128 # message. 2145 help='start up an FTP server.')
2129 random.seed() 2146 self.option_parser.add_option('--sync', action='store_const',
2130 server = TCPEchoServer((host, port), TCPEchoHandler) 2147 const=SERVER_SYNC, default=SERVER_HTTP,
2131 print 'Echo TCP server started on port %d...' % server.server_port 2148 dest='server_type',
2132 server_data['port'] = server.server_port 2149 help='start up a sync server.')
2133 elif options.server_type == SERVER_UDP_ECHO: 2150 self.option_parser.add_option('--tcp-echo', action='store_const',
2134 # Used for generating the key (randomly) that encodes the "echo request" 2151 const=SERVER_TCP_ECHO, default=SERVER_HTTP,
2135 # message. 2152 dest='server_type',
2136 random.seed() 2153 help='start up a tcp echo server.')
2137 server = UDPEchoServer((host, port), UDPEchoHandler) 2154 self.option_parser.add_option('--udp-echo', action='store_const',
2138 print 'Echo UDP server started on port %d...' % server.server_port 2155 const=SERVER_UDP_ECHO, default=SERVER_HTTP,
2139 server_data['port'] = server.server_port 2156 dest='server_type',
2140 # means FTP Server 2157 help='start up a udp echo server.')
2141 else: 2158 self.option_parser.add_option('--xmpp-port', default='0', type='int',
2142 my_data_dir = MakeDataDir() 2159 help='Port used by the XMPP server. If '
2143 2160 'unspecified, the XMPP server will listen on '
2144 # Instantiate a dummy authorizer for managing 'virtual' users 2161 'an ephemeral port.')
2145 authorizer = pyftpdlib.ftpserver.DummyAuthorizer() 2162 self.option_parser.add_option('--data-dir', dest='data_dir',
2146 2163 help='Directory from which to read the '
2147 # Define a new user having full r/w permissions and a read-only 2164 'files.')
2148 # anonymous user 2165 self.option_parser.add_option('--https', action='store_true',
2149 authorizer.add_user('chrome', 'chrome', my_data_dir, perm='elradfmw') 2166 dest='https', help='Specify that https '
2150 2167 'should be used.')
2151 authorizer.add_anonymous(my_data_dir) 2168 self.option_parser.add_option('--cert-and-key-file',
2152 2169 dest='cert_and_key_file', help='specify the '
2153 # Instantiate FTP handler class 2170 'path to the file containing the certificate '
2154 ftp_handler = pyftpdlib.ftpserver.FTPHandler 2171 'and private key for the server in PEM '
2155 ftp_handler.authorizer = authorizer 2172 'format')
2156 2173 self.option_parser.add_option('--ocsp', dest='ocsp', default='ok',
2157 # Define a customized banner (string returned when client connects) 2174 help='The type of OCSP response generated '
2158 ftp_handler.banner = ("pyftpdlib %s based ftpd ready." % 2175 'for the automatically generated '
2159 pyftpdlib.ftpserver.__ver__) 2176 'certificate. One of [ok,revoked,invalid]')
2160 2177 self.option_parser.add_option('--tls-intolerant', dest='tls_intolerant',
2161 # Instantiate FTP server class and listen to address:port 2178 default='0', type='int',
2162 server = pyftpdlib.ftpserver.FTPServer((host, port), ftp_handler) 2179 help='If nonzero, certain TLS connections '
2163 server_data['port'] = server.socket.getsockname()[1] 2180 'will be aborted in order to test version '
2164 print 'FTP server started on port %d...' % server_data['port'] 2181 'fallback. 1 means all TLS versions will be '
2165 2182 'aborted. 2 means TLS 1.1 or higher will be '
2166 # Notify the parent that we've started. (BaseServer subclasses 2183 'aborted. 3 means TLS 1.2 or higher will be '
2167 # bind their sockets on construction.) 2184 'aborted.')
2168 if options.startup_pipe is not None: 2185 self.option_parser.add_option('--https-record-resume',
2169 server_data_json = json.dumps(server_data) 2186 dest='record_resume', const=True,
2170 server_data_len = len(server_data_json) 2187 default=False, action='store_const',
2171 print 'sending server_data: %s (%d bytes)' % ( 2188 help='Record resumption cache events rather '
2172 server_data_json, server_data_len) 2189 'than resuming as normal. Allows the use of '
2173 if sys.platform == 'win32': 2190 'the /ssl-session-cache request')
2174 fd = msvcrt.open_osfhandle(options.startup_pipe, 0) 2191 self.option_parser.add_option('--ssl-client-auth', action='store_true',
2175 else: 2192 help='Require SSL client auth on every '
2176 fd = options.startup_pipe 2193 'connection.')
2177 startup_pipe = os.fdopen(fd, "w") 2194 self.option_parser.add_option('--ssl-client-ca', action='append',
2178 # First write the data length as an unsigned 4-byte value. This 2195 default=[], help='Specify that the client '
2179 # is _not_ using network byte ordering since the other end of the 2196 'certificate request should include the CA '
2180 # pipe is on the same machine. 2197 'named in the subject of the DER-encoded '
2181 startup_pipe.write(struct.pack('=L', server_data_len)) 2198 'certificate contained in the specified '
2182 startup_pipe.write(server_data_json) 2199 'file. This option may appear multiple '
2183 startup_pipe.close() 2200 'times, indicating multiple CA names should '
2184 2201 'be sent in the request.')
2185 if ocsp_server is not None: 2202 self.option_parser.add_option('--ssl-bulk-cipher', action='append',
2186 ocsp_server.serve_forever_on_thread() 2203 help='Specify the bulk encryption '
2187 2204 'algorithm(s) that will be accepted by the '
2188 try: 2205 'SSL server. Valid values are "aes256", '
2189 server.serve_forever() 2206 '"aes128", "3des", "rc4". If omitted, all '
2190 except KeyboardInterrupt: 2207 'algorithms will be used. This option may '
2191 print 'shutting down server' 2208 'appear multiple times, indicating '
2192 if ocsp_server is not None: 2209 'multiple algorithms should be enabled.');
2193 ocsp_server.stop_serving() 2210 self.option_parser.add_option('--file-root-url', default='/files/',
2194 server.stop = True 2211 help='Specify a root URL for files served.')
2212 self.option_parser.add_option('--policy-key', action='append',
2213 dest='policy_keys',
2214 help='Specify a path to a PEM-encoded '
2215 'private key to use for policy signing. May '
2216 'be specified multiple times in order to '
2217 'load multipe keys into the server. If the '
2218 'server has multiple keys, it will rotate '
2219 'through them in at each request a '
2220 'round-robin fashion. The server will '
2221 'generate a random key if none is specified '
2222 'on the command line.')
2223 self.option_parser.add_option('--policy-user',
2224 default='user@example.com',
2225 dest='policy_user',
2226 help='Specify the user name the server '
2227 'should report back to the client as the '
2228 'user owning the token used for making the '
2229 'policy request.')
2230 self.option_parser.add_option('--auth-token', dest='auth_token',
2231 help='Specify the auth token which should be '
2232 'used in the authorization header for GData.')
2233
2195 2234
2196 if __name__ == '__main__': 2235 if __name__ == '__main__':
2197 option_parser = optparse.OptionParser() 2236 sys.exit(ServerRunner().main())
2198 option_parser.add_option("-f", '--ftp', action='store_const',
2199 const=SERVER_FTP, default=SERVER_HTTP,
2200 dest='server_type',
2201 help='start up an FTP server.')
2202 option_parser.add_option('', '--sync', action='store_const',
2203 const=SERVER_SYNC, default=SERVER_HTTP,
2204 dest='server_type',
2205 help='start up a sync server.')
2206 option_parser.add_option('', '--tcp-echo', action='store_const',
2207 const=SERVER_TCP_ECHO, default=SERVER_HTTP,
2208 dest='server_type',
2209 help='start up a tcp echo server.')
2210 option_parser.add_option('', '--udp-echo', action='store_const',
2211 const=SERVER_UDP_ECHO, default=SERVER_HTTP,
2212 dest='server_type',
2213 help='start up a udp echo server.')
2214 option_parser.add_option('', '--log-to-console', action='store_const',
2215 const=True, default=False,
2216 dest='log_to_console',
2217 help='Enables or disables sys.stdout logging to '
2218 'the console.')
2219 option_parser.add_option('', '--port', default='0', type='int',
2220 help='Port used by the server. If unspecified, the '
2221 'server will listen on an ephemeral port.')
2222 option_parser.add_option('', '--xmpp-port', default='0', type='int',
2223 help='Port used by the XMPP server. If unspecified, '
2224 'the XMPP server will listen on an ephemeral port.')
2225 option_parser.add_option('', '--data-dir', dest='data_dir',
2226 help='Directory from which to read the files.')
2227 option_parser.add_option('', '--https', action='store_true', dest='https',
2228 help='Specify that https should be used.')
2229 option_parser.add_option('', '--cert-and-key-file', dest='cert_and_key_file',
2230 help='specify the path to the file containing the '
2231 'certificate and private key for the server in PEM '
2232 'format')
2233 option_parser.add_option('', '--ocsp', dest='ocsp', default='ok',
2234 help='The type of OCSP response generated for the '
2235 'automatically generated certificate. One of '
2236 '[ok,revoked,invalid]')
2237 option_parser.add_option('', '--tls-intolerant', dest='tls_intolerant',
2238 default='0', type='int',
2239 help='If nonzero, certain TLS connections will be'
2240 ' aborted in order to test version fallback. 1'
2241 ' means all TLS versions will be aborted. 2 means'
2242 ' TLS 1.1 or higher will be aborted. 3 means TLS'
2243 ' 1.2 or higher will be aborted.')
2244 option_parser.add_option('', '--https-record-resume', dest='record_resume',
2245 const=True, default=False, action='store_const',
2246 help='Record resumption cache events rather than'
2247 ' resuming as normal. Allows the use of the'
2248 ' /ssl-session-cache request')
2249 option_parser.add_option('', '--ssl-client-auth', action='store_true',
2250 help='Require SSL client auth on every connection.')
2251 option_parser.add_option('', '--ssl-client-ca', action='append', default=[],
2252 help='Specify that the client certificate request '
2253 'should include the CA named in the subject of '
2254 'the DER-encoded certificate contained in the '
2255 'specified file. This option may appear multiple '
2256 'times, indicating multiple CA names should be '
2257 'sent in the request.')
2258 option_parser.add_option('', '--ssl-bulk-cipher', action='append',
2259 help='Specify the bulk encryption algorithm(s)'
2260 'that will be accepted by the SSL server. Valid '
2261 'values are "aes256", "aes128", "3des", "rc4". If '
2262 'omitted, all algorithms will be used. This '
2263 'option may appear multiple times, indicating '
2264 'multiple algorithms should be enabled.');
2265 option_parser.add_option('', '--file-root-url', default='/files/',
2266 help='Specify a root URL for files served.')
2267 option_parser.add_option('', '--startup-pipe', type='int',
2268 dest='startup_pipe',
2269 help='File handle of pipe to parent process')
2270 option_parser.add_option('', '--policy-key', action='append',
2271 dest='policy_keys',
2272 help='Specify a path to a PEM-encoded private key '
2273 'to use for policy signing. May be specified '
2274 'multiple times in order to load multipe keys into '
2275 'the server. If ther server has multiple keys, it '
2276 'will rotate through them in at each request a '
2277 'round-robin fashion. The server will generate a '
2278 'random key if none is specified on the command '
2279 'line.')
2280 option_parser.add_option('', '--policy-user', default='user@example.com',
2281 dest='policy_user',
2282 help='Specify the user name the server should '
2283 'report back to the client as the user owning the '
2284 'token used for making the policy request.')
2285 option_parser.add_option('', '--host', default='127.0.0.1',
2286 dest='host',
2287 help='Hostname or IP upon which the server will '
2288 'listen. Client connections will also only be '
2289 'allowed from this address.')
2290 option_parser.add_option('', '--auth-token', dest='auth_token',
2291 help='Specify the auth token which should be used'
2292 'in the authorization header for GData.')
2293 options, args = option_parser.parse_args()
2294
2295 sys.exit(main(options, args))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698