133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck#!/usr/bin/env python 233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Copyright 2010 Google Inc. All Rights Reserved. 333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# 433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Licensed under the Apache License, Version 2.0 (the "License"); 533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# you may not use this file except in compliance with the License. 633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# You may obtain a copy of the License at 733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# 833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# http://www.apache.org/licenses/LICENSE-2.0 933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# 1033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Unless required by applicable law or agreed to in writing, software 1133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# distributed under the License is distributed on an "AS IS" BASIS, 1233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# See the License for the specific language governing permissions and 1433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# limitations under the License. 1533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 1633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck"""Replays web pages under simulated network conditions. 1733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 1833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckMust be run as administrator (sudo). 1933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckTo record web pages: 2133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 1. Start the program in record mode. 2233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck $ sudo ./replay.py --record archive.wpr 2333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2. Load the web pages you want to record in a web browser. It is important to 2433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck clear browser caches before this so that all subresources are requested 2533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck from the network. 2633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 3. Kill the process to stop recording. 2733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckTo replay web pages: 2933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 1. Start the program in replay mode with a previously recorded archive. 3033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck $ sudo ./replay.py archive.wpr 3133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 2. Load recorded pages in a web browser. A 404 will be served for any pages or 3233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck resources not in the recorded archive. 3333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 3433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckNetwork simulation examples: 3533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 128KByte/s uplink bandwidth, 4Mbps/s downlink bandwidth with 100ms RTT time 3633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck $ sudo ./replay.py --up 128KByte/s --down 4Mbit/s --delay_ms=100 archive.wpr 3733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 3833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # 1% packet loss rate 3933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck $ sudo ./replay.py --packet_loss_rate=0.01 archive.wpr 4033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck""" 4133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 4233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport argparse 4333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport json 4433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport logging 4533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport os 4633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport socket 4733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport sys 4833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport traceback 4933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 5033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport customhandlers 5133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport dnsproxy 5233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport httparchive 5333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport httpclient 5433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport httpproxy 5533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport net_configs 5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport platformsettings 5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport rules_parser 5833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport script_injector 5933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport servermanager 6033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport trafficshaper 6133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 6233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckif sys.version < '2.6': 6333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck print 'Need Python 2.6 or greater.' 6433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck sys.exit(1) 6533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 6633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 6733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef configure_logging(log_level_name, log_file_name=None): 6833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Configure logging level and format. 6933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 7033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck Args: 7133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck log_level_name: 'debug', 'info', 'warning', 'error', or 'critical'. 7233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck log_file_name: a file name 7333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """ 7433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if logging.root.handlers: 7533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.critical('A logging method (e.g. "logging.warn(...)")' 7633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ' was called before logging was configured.') 7733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck log_level = getattr(logging, log_level_name.upper()) 7833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck log_format = ( 7933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck '(%(levelname)s) %(asctime)s %(module)s.%(funcName)s:%(lineno)d ' 8033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck '%(message)s') 8133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 8233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 8333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.basicConfig(level=log_level, format=log_format) 8433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logger = logging.getLogger() 8533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if log_file_name: 8633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck fh = logging.FileHandler(log_file_name) 8733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck fh.setLevel(log_level) 8833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck fh.setFormatter(logging.Formatter(log_format)) 8933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logger.addHandler(fh) 9033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck system_handler = platformsettings.get_system_logging_handler() 9133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if system_handler: 9233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logger.addHandler(system_handler) 9333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 9433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 9533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef AddDnsForward(server_manager, host): 9633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Forward DNS traffic.""" 9733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.Append(platformsettings.set_temporary_primary_nameserver, host) 9833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 9933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 10033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef AddDnsProxy(server_manager, options, host, port, real_dns_lookup, 10133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck http_archive): 10233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dns_filters = [] 10333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.dns_private_passthrough: 10433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck private_filter = dnsproxy.PrivateIpFilter(real_dns_lookup, http_archive) 10533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dns_filters.append(private_filter) 10633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.AppendRecordCallback(private_filter.InitializeArchiveHosts) 10733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.AppendReplayCallback(private_filter.InitializeArchiveHosts) 10833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.shaping_dns: 10933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck delay_filter = dnsproxy.DelayFilter(options.record, **options.shaping_dns) 11033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dns_filters.append(delay_filter) 11133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.AppendRecordCallback(delay_filter.SetRecordMode) 11233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.AppendReplayCallback(delay_filter.SetReplayMode) 11333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.Append(dnsproxy.DnsProxyServer, host, port, 11433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dns_lookup=dnsproxy.ReplayDnsLookup(host, dns_filters)) 11533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 11633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 11733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef AddWebProxy(server_manager, options, host, real_dns_lookup, http_archive): 11833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.rules_path: 11933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck with open(options.rules_path) as file_obj: 12033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck allowed_imports = [ 12133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck name.strip() for name in options.allowed_rule_imports.split(',')] 12233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck rules = rules_parser.Rules(file_obj, allowed_imports) 12333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.info('Parsed %s rules:\n%s', options.rules_path, rules) 12433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck else: 12533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck rules = rules_parser.Rules() 12633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck injector = script_injector.GetScriptInjector(options.inject_scripts) 12733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck custom_handlers = customhandlers.CustomHandlers(options, http_archive) 12833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck custom_handlers.add_server_manager_handler(server_manager) 12933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck archive_fetch = httpclient.ControllableHttpArchiveFetch( 13033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck http_archive, real_dns_lookup, 13133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck injector, 13233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck options.diff_unknown_requests, options.record, 13333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck use_closest_match=options.use_closest_match, 13433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck scramble_images=options.scramble_images) 13533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.AppendRecordCallback(archive_fetch.SetRecordMode) 13633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.AppendReplayCallback(archive_fetch.SetReplayMode) 13733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck allow_generate_304 = not options.record 13833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.Append( 13933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck httpproxy.HttpProxyServer, 14033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck archive_fetch, custom_handlers, rules, 14133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck host=host, port=options.port, use_delays=options.use_server_delay, 14233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck allow_generate_304=allow_generate_304, 14333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck **options.shaping_http) 14433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.ssl: 14533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.should_generate_certs: 14633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.Append( 14733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck httpproxy.HttpsProxyServer, archive_fetch, custom_handlers, rules, 14833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck options.https_root_ca_cert_path, host=host, port=options.ssl_port, 14933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck allow_generate_304=allow_generate_304, 15033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck use_delays=options.use_server_delay, **options.shaping_http) 15133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck else: 15233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.Append( 15333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck httpproxy.SingleCertHttpsProxyServer, archive_fetch, 15433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck custom_handlers, rules, options.https_root_ca_cert_path, host=host, 15533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck port=options.ssl_port, use_delays=options.use_server_delay, 15633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck allow_generate_304=allow_generate_304, 15733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck **options.shaping_http) 15833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.http_to_https_port: 15933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.Append( 16033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck httpproxy.HttpToHttpsProxyServer, 16133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck archive_fetch, custom_handlers, rules, 16233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck host=host, port=options.http_to_https_port, 16333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck use_delays=options.use_server_delay, 16433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck allow_generate_304=allow_generate_304, 16533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck **options.shaping_http) 16633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 16733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 16833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef AddTrafficShaper(server_manager, options, host): 16933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.shaping_dummynet: 17033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.AppendTrafficShaper( 17133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck trafficshaper.TrafficShaper, host=host, 17233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck use_loopback=not options.server_mode and host == '127.0.0.1', 17333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck **options.shaping_dummynet) 17433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 17533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 17633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass OptionsWrapper(object): 17733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Add checks, updates, and methods to option values. 17833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 17933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck Example: 18033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck options, args = arg_parser.parse_args() 18133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck options = OptionsWrapper(options, arg_parser) # run checks and updates 18233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.record and options.HasTrafficShaping(): 18333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck [...] 18433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """ 18533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck _TRAFFICSHAPING_OPTIONS = { 18633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'down', 'up', 'delay_ms', 'packet_loss_rate', 'init_cwnd', 'net'} 18733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck _CONFLICTING_OPTIONS = ( 18833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ('record', ('down', 'up', 'delay_ms', 'packet_loss_rate', 'net', 18933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'spdy', 'use_server_delay')), 19033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ('append', ('down', 'up', 'delay_ms', 'packet_loss_rate', 'net', 19133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'use_server_delay')), # same as --record 19233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ('net', ('down', 'up', 'delay_ms')), 19333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ('server', ('server_mode',)), 19433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ) 19533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 19633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def __init__(self, options, parser): 19733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._options = options 19833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._parser = parser 19933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._nondefaults = set([ 20033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action.dest for action in parser._optionals._actions 20133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if getattr(options, action.dest, action.default) is not action.default]) 20233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._CheckConflicts() 20333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._CheckValidIp('host') 20433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._CheckFeatureSupport() 20533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._MassageValues() 20633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 20733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def _CheckConflicts(self): 20833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Give an error if mutually exclusive options are used.""" 20933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck for option, bad_options in self._CONFLICTING_OPTIONS: 21033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if option in self._nondefaults: 21133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck for bad_option in bad_options: 21233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if bad_option in self._nondefaults: 21333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._parser.error('Option --%s cannot be used with --%s.' % 21433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck (bad_option, option)) 21533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 21633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def _CheckValidIp(self, name): 21733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Give an error if option |name| is not a valid IPv4 address.""" 21833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck value = getattr(self._options, name) 21933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if value: 22033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck try: 22133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck socket.inet_aton(value) 22233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck except Exception: 22333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._parser.error('Option --%s must be a valid IPv4 address.' % name) 22433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 22533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def _CheckFeatureSupport(self): 22633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if (self._options.should_generate_certs and 22733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck not platformsettings.HasSniSupport()): 22833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._parser.error('Option --should_generate_certs requires pyOpenSSL ' 22933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck '0.13 or greater for SNI support.') 23033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 23133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def _ShapingKeywordArgs(self, shaping_key): 23233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Return the shaping keyword args for |shaping_key|. 23333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 23433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck Args: 23533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck shaping_key: one of 'dummynet', 'dns', 'http'. 23633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck Returns: 23733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck {} # if shaping_key does not apply, or options have default values. 23833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck {k: v, ...} 23933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """ 24033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck kwargs = {} 24133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def AddItemIfSet(d, kw_key, opt_key=None): 24233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck opt_key = opt_key or kw_key 24333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if opt_key in self._nondefaults: 24433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck d[kw_key] = getattr(self, opt_key) 24533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if ((self.shaping_type == 'proxy' and shaping_key in ('dns', 'http')) or 24633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.shaping_type == shaping_key): 24733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck AddItemIfSet(kwargs, 'delay_ms') 24833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if shaping_key in ('dummynet', 'http'): 24933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck AddItemIfSet(kwargs, 'down_bandwidth', opt_key='down') 25033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck AddItemIfSet(kwargs, 'up_bandwidth', opt_key='up') 25133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if shaping_key == 'dummynet': 25233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck AddItemIfSet(kwargs, 'packet_loss_rate') 25333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck AddItemIfSet(kwargs, 'init_cwnd') 25433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck elif self.shaping_type != 'none': 25533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if 'packet_loss_rate' in self._nondefaults: 25633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.warn('Shaping type, %s, ignores --packet_loss_rate=%s', 25733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.shaping_type, self.packet_loss_rate) 25833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if 'init_cwnd' in self._nondefaults: 25933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.warn('Shaping type, %s, ignores --init_cwnd=%s', 26033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.shaping_type, self.init_cwnd) 26133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return kwargs 26233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 26333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def _MassageValues(self): 26433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Set options that depend on the values of other options.""" 26533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if self.append and not self.record: 26633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._options.record = True 26733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if self.net: 26833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._options.down, self._options.up, self._options.delay_ms = \ 26933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck net_configs.GetNetConfig(self.net) 27033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._nondefaults.update(['down', 'up', 'delay_ms']) 27133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if not self.ssl: 27233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self._options.https_root_ca_cert_path = None 27333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.shaping_dns = self._ShapingKeywordArgs('dns') 27433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.shaping_http = self._ShapingKeywordArgs('http') 27533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck self.shaping_dummynet = self._ShapingKeywordArgs('dummynet') 27633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 27733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def __getattr__(self, name): 27833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Make the original option values available.""" 27933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return getattr(self._options, name) 28033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 28133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def __repr__(self): 28233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Return a json representation of the original options dictionary.""" 28333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return json.dumps(self._options.__dict__) 28433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 28533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def IsRootRequired(self): 28633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Returns True iff the options require whole program root access.""" 28733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if self.server: 28833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return True 28933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 29033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def IsPrivilegedPort(port): 29133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return port and port < 1024 29233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 29333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if IsPrivilegedPort(self.port) or (self.ssl and 29433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck IsPrivilegedPort(self.ssl_port)): 29533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return True 29633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 29733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if self.dns_forwarding: 29833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if IsPrivilegedPort(self.dns_port): 29933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return True 30033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if not self.server_mode and self.host == '127.0.0.1': 30133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return True 30233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 30333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return False 30433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 30533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 30633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef replay(options, replay_filename): 30733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.record and sys.version_info < (2, 7, 9): 30833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck print ('Need Python 2.7.9 or greater for recording mode.\n' 30933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'For instructions on how to upgrade Python on Ubuntu 14.04, see:\n' 31033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'http://mbless.de/blog/2016/01/09/upgrade-to-python-2711-on-ubuntu-1404-lts.html\n') 31133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.admin_check and options.IsRootRequired(): 31233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck platformsettings.rerun_as_administrator() 31333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck configure_logging(options.log_level, options.log_file) 31433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager = servermanager.ServerManager(options.record) 31533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.server: 31633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck AddDnsForward(server_manager, options.server) 31733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck else: 31833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.record: 31933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck httparchive.HttpArchive.AssertWritable(replay_filename) 32033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.append and os.path.exists(replay_filename): 32133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck http_archive = httparchive.HttpArchive.Load(replay_filename) 32233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.info('Appending to %s (loaded %d existing responses)', 32333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck replay_filename, len(http_archive)) 32433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck else: 32533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck http_archive = httparchive.HttpArchive() 32633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck else: 32733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck http_archive = httparchive.HttpArchive.Load(replay_filename) 32833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.info('Loaded %d responses from %s', 32933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck len(http_archive), replay_filename) 33033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.AppendRecordCallback(http_archive.clear) 33133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 33233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ipfw_dns_host = None 33333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.dns_forwarding or options.shaping_dummynet: 33433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # compute the ip/host used for the DNS server and traffic shaping 33533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ipfw_dns_host = options.host 33633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if not ipfw_dns_host: 33733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ipfw_dns_host = platformsettings.get_server_ip_address( 33833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck options.server_mode) 33933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 340a0e5c0de428e9dea6d07dd57c5594fb1f1c17c20Chris Craik real_dns_lookup = dnsproxy.RealDnsLookup( 341a0e5c0de428e9dea6d07dd57c5594fb1f1c17c20Chris Craik name_servers=[platformsettings.get_original_primary_nameserver()], 342a0e5c0de428e9dea6d07dd57c5594fb1f1c17c20Chris Craik dns_forwarding=options.dns_forwarding, 343a0e5c0de428e9dea6d07dd57c5594fb1f1c17c20Chris Craik proxy_host=ipfw_dns_host, 344a0e5c0de428e9dea6d07dd57c5594fb1f1c17c20Chris Craik proxy_port=options.dns_port) 345a0e5c0de428e9dea6d07dd57c5594fb1f1c17c20Chris Craik server_manager.AppendRecordCallback(real_dns_lookup.ClearCache) 346a0e5c0de428e9dea6d07dd57c5594fb1f1c17c20Chris Craik 34733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.dns_forwarding: 34833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if not options.server_mode and ipfw_dns_host == '127.0.0.1': 34933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck AddDnsForward(server_manager, ipfw_dns_host) 35033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck AddDnsProxy(server_manager, options, ipfw_dns_host, options.dns_port, 35133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck real_dns_lookup, http_archive) 35233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.ssl and options.https_root_ca_cert_path is None: 35333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck options.https_root_ca_cert_path = os.path.join(os.path.dirname(__file__), 35433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'wpr_cert.pem') 35533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck http_proxy_address = options.host 35633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if not http_proxy_address: 35733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck http_proxy_address = platformsettings.get_httpproxy_ip_address( 35833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck options.server_mode) 35933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck AddWebProxy(server_manager, options, http_proxy_address, real_dns_lookup, 36033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck http_archive) 36133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck AddTrafficShaper(server_manager, options, ipfw_dns_host) 36233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 36333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck exit_status = 0 36433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck try: 36533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck server_manager.Run() 36633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck except KeyboardInterrupt: 36733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.info('Shutting down.') 36833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck except (dnsproxy.DnsProxyException, 36933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck trafficshaper.TrafficShaperException, 37033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck platformsettings.NotAdministratorError, 37133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck platformsettings.DnsUpdateError) as e: 37233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.critical('%s: %s', e.__class__.__name__, e) 37333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck exit_status = 1 37433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck except Exception: 37533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.critical(traceback.format_exc()) 37633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck exit_status = 2 37733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 37833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.record: 37933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck http_archive.Persist(replay_filename) 38033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck logging.info('Saved %d responses to %s', len(http_archive), replay_filename) 38133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return exit_status 38233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 38333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 38433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef GetParser(): 38533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck arg_parser = argparse.ArgumentParser( 38633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck usage='%(prog)s [options] replay_file', 38733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck description=__doc__, 38833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck formatter_class=argparse.RawDescriptionHelpFormatter, 38933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck epilog='http://code.google.com/p/web-page-replay/') 39033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 39133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck arg_parser.add_argument('replay_filename', type=str, help='Replay file', 39233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck nargs='?') 39333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 39433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck arg_parser.add_argument('-r', '--record', default=False, 39533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_true', 39633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Download real responses and record them to replay_file') 39733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck arg_parser.add_argument('--append', default=False, 39833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_true', 39933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Append responses to replay_file.') 40033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck arg_parser.add_argument('-l', '--log_level', default='debug', 40133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 40233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 40333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck choices=('debug', 'info', 'warning', 'error', 'critical'), 40433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Minimum verbosity level to log') 40533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck arg_parser.add_argument('-f', '--log_file', default=None, 40633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 40733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 40833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Log file to use in addition to writting logs to stderr.') 40933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 41033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck network_group = arg_parser.add_argument_group( 41133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck title='Network Simulation Options', 41233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck description=('These options configure the network simulation in ' 41333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'replay mode')) 41433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck network_group.add_argument('-u', '--up', default='0', 41533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 41633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 41733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Upload Bandwidth in [K|M]{bit/s|Byte/s}. Zero means unlimited.') 41833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck network_group.add_argument('-d', '--down', default='0', 41933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 42033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 42133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Download Bandwidth in [K|M]{bit/s|Byte/s}. Zero means unlimited.') 42233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck network_group.add_argument('-m', '--delay_ms', default='0', 42333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 42433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 42533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Propagation delay (latency) in milliseconds. Zero means no delay.') 42633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck network_group.add_argument('-p', '--packet_loss_rate', default='0', 42733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 42833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 42933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Packet loss rate in range [0..1]. Zero means no loss.') 43033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck network_group.add_argument('-w', '--init_cwnd', default='0', 43133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 43233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 43333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Set initial cwnd (linux only, requires kernel patch)') 43433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck network_group.add_argument('--net', default=None, 43533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 43633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 43733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck choices=net_configs.NET_CONFIG_NAMES, 43833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Select a set of network options: %s.' % ', '.join( 43933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck net_configs.NET_CONFIG_NAMES)) 44033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck network_group.add_argument('--shaping_type', default='dummynet', 44133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 44233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck choices=('dummynet', 'proxy'), 44333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='When shaping is configured (i.e. --up, --down, etc.) decides ' 44433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'whether to use |dummynet| (default), or |proxy| servers.') 44533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 44633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group = arg_parser.add_argument_group( 44733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck title='Replay Harness Options', 44833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck description=('These advanced options configure various aspects ' 44933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'of the replay harness')) 45033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-S', '--server', default=None, 45133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 45233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 45333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='IP address of host running "replay.py --server_mode". ' 45433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'This only changes the primary DNS nameserver to use the given IP.') 45533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-M', '--server_mode', default=False, 45633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_true', 45733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Run replay DNS & http proxies, and trafficshaping on --port ' 45833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'without changing the primary DNS nameserver. ' 45933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'Other hosts may connect to this using "replay.py --server" ' 46033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'or by pointing their DNS to this server.') 46133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-i', '--inject_scripts', default='deterministic.js', 46233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 46333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dest='inject_scripts', 46433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='A comma separated list of JavaScript sources to inject in all ' 46533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'pages. By default a script is injected that eliminates sources ' 46633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'of entropy such as Date() and Math.random() deterministic. ' 46733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'CAUTION: Without deterministic.js, many pages will not replay.') 46833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-D', '--no-diff_unknown_requests', default=True, 46933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_false', 47033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dest='diff_unknown_requests', 47133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='During replay, do not show a diff of unknown requests against ' 47233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'their nearest match in the archive.') 47333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-C', '--use_closest_match', default=False, 47433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_true', 47533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dest='use_closest_match', 47633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='During replay, if a request is not found, serve the closest match' 47733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'in the archive instead of giving a 404.') 47833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-U', '--use_server_delay', default=False, 47933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_true', 48033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dest='use_server_delay', 48133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='During replay, simulate server delay by delaying response time to' 48233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'requests.') 48333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-I', '--screenshot_dir', default=None, 48433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 48533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 48633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Save PNG images of the loaded page in the given directory.') 48733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-P', '--no-dns_private_passthrough', default=True, 48833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_false', 48933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dest='dns_private_passthrough', 49033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Don\'t forward DNS requests that resolve to private network ' 49133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'addresses. CAUTION: With this option important services like ' 49233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'Kerberos will resolve to the HTTP proxy address.') 49333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-x', '--no-dns_forwarding', default=True, 49433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_false', 49533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dest='dns_forwarding', 49633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Don\'t forward DNS requests to the local replay server. ' 49733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'CAUTION: With this option an external mechanism must be used to ' 49833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'forward traffic to the replay server.') 49933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('--host', default=None, 50033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 50133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 50233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='The IP address to bind all servers to. Defaults to 0.0.0.0 or ' 50333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck '127.0.0.1, depending on --server_mode and platform.') 50433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-o', '--port', default=80, 50533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 50633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=int, 50733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Port number to listen on.') 50833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('--ssl_port', default=443, 50933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 51033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=int, 51133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='SSL port number to listen on.') 51233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('--http_to_https_port', default=None, 51333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 51433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=int, 51533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Port on which WPR will listen for HTTP requests that it will send ' 51633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 'along as HTTPS requests.') 51733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('--dns_port', default=53, 51833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 51933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=int, 52033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='DNS port number to listen on.') 52133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('-c', '--https_root_ca_cert_path', default=None, 52233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 52333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck type=str, 52433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Certificate file to use with SSL (gets auto-generated if needed).') 52533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('--no-ssl', default=True, 52633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_false', 52733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dest='ssl', 52833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Do not setup an SSL proxy.') 52933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('--should_generate_certs', default=False, 53033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_true', 53133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Use OpenSSL to generate certificate files for requested hosts.') 53233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('--no-admin-check', default=True, 53333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_false', 53433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dest='admin_check', 53533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Do not check if administrator access is needed.') 53633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('--scramble_images', default=False, 53733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store_true', 53833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck dest='scramble_images', 53933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Scramble image responses.') 54033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('--rules_path', default=None, 54133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 54233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='Path of file containing Python rules.') 54333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck harness_group.add_argument('--allowed_rule_imports', default='rules', 54433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck action='store', 54533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck help='A comma-separate list of allowed rule imports, or \'*\' to allow' 54633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck ' all packages. Defaults to %(default)s.') 54733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return arg_parser 54833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 54933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 55033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef main(): 55133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck arg_parser = GetParser() 55233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck options = arg_parser.parse_args() 55333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck options = OptionsWrapper(options, arg_parser) 55433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 55533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if options.server: 55633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck options.replay_filename = None 55733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck elif options.replay_filename is None: 55833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck arg_parser.error('Must specify a replay_file') 55933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return replay(options, options.replay_filename) 56033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 56133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 56233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckif __name__ == '__main__': 56333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck sys.exit(main()) 564