| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2010 Google Inc. All Rights Reserved. | 2 # Copyright 2010 Google Inc. All Rights Reserved. |
| 3 # | 3 # |
| 4 # Licensed under the Apache License, Version 2.0 (the "License"); | 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 # you may not use this file except in compliance with the License. | 5 # you may not use this file except in compliance with the License. |
| 6 # You may obtain a copy of the License at | 6 # You may obtain a copy of the License at |
| 7 # | 7 # |
| 8 # http://www.apache.org/licenses/LICENSE-2.0 | 8 # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 # | 9 # |
| 10 # Unless required by applicable law or agreed to in writing, software | 10 # Unless required by applicable law or agreed to in writing, software |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 $ sudo ./replay.py --up 128KByte/s --down 4Mbit/s --delay_ms=100 archive.wpr | 36 $ sudo ./replay.py --up 128KByte/s --down 4Mbit/s --delay_ms=100 archive.wpr |
| 37 | 37 |
| 38 # 1% packet loss rate | 38 # 1% packet loss rate |
| 39 $ sudo ./replay.py --packet_loss_rate=0.01 archive.wpr | 39 $ sudo ./replay.py --packet_loss_rate=0.01 archive.wpr |
| 40 """ | 40 """ |
| 41 | 41 |
| 42 import json | 42 import json |
| 43 import logging | 43 import logging |
| 44 import optparse | 44 import optparse |
| 45 import os | 45 import os |
| 46 import socket |
| 46 import sys | 47 import sys |
| 47 import traceback | 48 import traceback |
| 48 | 49 |
| 49 import cachemissarchive | 50 import cachemissarchive |
| 50 import customhandlers | 51 import customhandlers |
| 51 import dnsproxy | 52 import dnsproxy |
| 52 import httparchive | 53 import httparchive |
| 53 import httpclient | 54 import httpclient |
| 54 import httpproxy | 55 import httpproxy |
| 55 import platformsettings | 56 import platformsettings |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 httpproxy.HttpsProxyServer, | 142 httpproxy.HttpsProxyServer, |
| 142 archive_fetch, custom_handlers, options.certfile, | 143 archive_fetch, custom_handlers, options.certfile, |
| 143 host=host, port=options.ssl_port, **options.shaping_http) | 144 host=host, port=options.ssl_port, **options.shaping_http) |
| 144 | 145 |
| 145 | 146 |
| 146 def AddTrafficShaper(server_manager, options, host): | 147 def AddTrafficShaper(server_manager, options, host): |
| 147 if options.shaping_dummynet: | 148 if options.shaping_dummynet: |
| 148 ssl_port = options.ssl_shaping_port if options.ssl else None | 149 ssl_port = options.ssl_shaping_port if options.ssl else None |
| 149 kwargs = dict( | 150 kwargs = dict( |
| 150 host=host, port=options.shaping_port, ssl_port=ssl_port, | 151 host=host, port=options.shaping_port, ssl_port=ssl_port, |
| 151 use_loopback=not options.server_mode, **options.shaping_dummynet) | 152 use_loopback=not options.server_mode and host == '127.0.0.1', |
| 153 **options.shaping_dummynet) |
| 152 if not options.dns_forwarding: | 154 if not options.dns_forwarding: |
| 153 kwargs['dns_port'] = None | 155 kwargs['dns_port'] = None |
| 154 server_manager.Append(trafficshaper.TrafficShaper, **kwargs) | 156 server_manager.Append(trafficshaper.TrafficShaper, **kwargs) |
| 155 | 157 |
| 156 | 158 |
| 157 class OptionsWrapper(object): | 159 class OptionsWrapper(object): |
| 158 """Add checks, updates, and methods to option values. | 160 """Add checks, updates, and methods to option values. |
| 159 | 161 |
| 160 Example: | 162 Example: |
| 161 options, args = option_parser.parse_args() | 163 options, args = option_parser.parse_args() |
| (...skipping 21 matching lines...) Expand all Loading... |
| 183 ) | 185 ) |
| 184 NET_CHOICES = [key for key, values in _NET_CONFIGS] | 186 NET_CHOICES = [key for key, values in _NET_CONFIGS] |
| 185 | 187 |
| 186 def __init__(self, options, parser): | 188 def __init__(self, options, parser): |
| 187 self._options = options | 189 self._options = options |
| 188 self._parser = parser | 190 self._parser = parser |
| 189 self._nondefaults = set([ | 191 self._nondefaults = set([ |
| 190 name for name, value in parser.defaults.items() | 192 name for name, value in parser.defaults.items() |
| 191 if getattr(options, name) != value]) | 193 if getattr(options, name) != value]) |
| 192 self._CheckConflicts() | 194 self._CheckConflicts() |
| 195 self._CheckValidIp('host') |
| 193 self._MassageValues() | 196 self._MassageValues() |
| 194 | 197 |
| 195 def _CheckConflicts(self): | 198 def _CheckConflicts(self): |
| 196 """Give an error if mutually exclusive options are used.""" | 199 """Give an error if mutually exclusive options are used.""" |
| 197 for option, bad_options in self._CONFLICTING_OPTIONS: | 200 for option, bad_options in self._CONFLICTING_OPTIONS: |
| 198 if option in self._nondefaults: | 201 if option in self._nondefaults: |
| 199 for bad_option in bad_options: | 202 for bad_option in bad_options: |
| 200 if bad_option in self._nondefaults: | 203 if bad_option in self._nondefaults: |
| 201 self._parser.error('Option --%s cannot be used with --%s.' % | 204 self._parser.error('Option --%s cannot be used with --%s.' % |
| 202 (bad_option, option)) | 205 (bad_option, option)) |
| 203 | 206 |
| 207 def _CheckValidIp(self, name): |
| 208 """Give an error if option |name| is not a valid IPv4 address.""" |
| 209 value = getattr(self._options, name) |
| 210 if value: |
| 211 try: |
| 212 socket.inet_aton(value) |
| 213 except: |
| 214 self._parser.error('Option --%s must be a valid IPv4 address.' % name) |
| 215 |
| 204 def _ShapingKeywordArgs(self, shaping_key): | 216 def _ShapingKeywordArgs(self, shaping_key): |
| 205 """Return the shaping keyword args for |shaping_key|. | 217 """Return the shaping keyword args for |shaping_key|. |
| 206 | 218 |
| 207 Args: | 219 Args: |
| 208 shaping_key: one of 'dummynet', 'dns', 'http'. | 220 shaping_key: one of 'dummynet', 'dns', 'http'. |
| 209 Returns: | 221 Returns: |
| 210 {} # if shaping_key does not apply, or options have default values. | 222 {} # if shaping_key does not apply, or options have default values. |
| 211 {k: v, ...} | 223 {k: v, ...} |
| 212 """ | 224 """ |
| 213 kwargs = {} | 225 kwargs = {} |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 'replay will load and append entries to archive file', | 291 'replay will load and append entries to archive file', |
| 280 options.cache_miss_file) | 292 options.cache_miss_file) |
| 281 cache_misses = cachemissarchive.CacheMissArchive.Load( | 293 cache_misses = cachemissarchive.CacheMissArchive.Load( |
| 282 options.cache_miss_file) | 294 options.cache_miss_file) |
| 283 else: | 295 else: |
| 284 cache_misses = cachemissarchive.CacheMissArchive( | 296 cache_misses = cachemissarchive.CacheMissArchive( |
| 285 options.cache_miss_file) | 297 options.cache_miss_file) |
| 286 if options.server: | 298 if options.server: |
| 287 AddDnsForward(server_manager, options.server) | 299 AddDnsForward(server_manager, options.server) |
| 288 else: | 300 else: |
| 289 host = platformsettings.get_server_ip_address(options.server_mode) | 301 host = options.host |
| 302 if not host: |
| 303 host = platformsettings.get_server_ip_address(options.server_mode) |
| 290 real_dns_lookup = dnsproxy.RealDnsLookup( | 304 real_dns_lookup = dnsproxy.RealDnsLookup( |
| 291 name_servers=[platformsettings.get_original_primary_nameserver()]) | 305 name_servers=[platformsettings.get_original_primary_nameserver()]) |
| 292 if options.record: | 306 if options.record: |
| 293 httparchive.HttpArchive.AssertWritable(replay_filename) | 307 httparchive.HttpArchive.AssertWritable(replay_filename) |
| 294 if options.append and os.path.exists(replay_filename): | 308 if options.append and os.path.exists(replay_filename): |
| 295 http_archive = httparchive.HttpArchive.Load(replay_filename) | 309 http_archive = httparchive.HttpArchive.Load(replay_filename) |
| 296 logging.info('Appending to %s (loaded %d existing responses)', | 310 logging.info('Appending to %s (loaded %d existing responses)', |
| 297 replay_filename, len(http_archive)) | 311 replay_filename, len(http_archive)) |
| 298 else: | 312 else: |
| 299 http_archive = httparchive.HttpArchive() | 313 http_archive = httparchive.HttpArchive() |
| 300 else: | 314 else: |
| 301 http_archive = httparchive.HttpArchive.Load(replay_filename) | 315 http_archive = httparchive.HttpArchive.Load(replay_filename) |
| 302 logging.info('Loaded %d responses from %s', | 316 logging.info('Loaded %d responses from %s', |
| 303 len(http_archive), replay_filename) | 317 len(http_archive), replay_filename) |
| 304 server_manager.AppendRecordCallback(real_dns_lookup.ClearCache) | 318 server_manager.AppendRecordCallback(real_dns_lookup.ClearCache) |
| 305 server_manager.AppendRecordCallback(http_archive.clear) | 319 server_manager.AppendRecordCallback(http_archive.clear) |
| 306 | 320 |
| 307 if options.dns_forwarding: | 321 if options.dns_forwarding: |
| 308 if not options.server_mode: | 322 if not options.server_mode and host == '127.0.0.1': |
| 309 AddDnsForward(server_manager, host) | 323 AddDnsForward(server_manager, host) |
| 310 AddDnsProxy(server_manager, options, host, real_dns_lookup, http_archive) | 324 AddDnsProxy(server_manager, options, host, real_dns_lookup, http_archive) |
| 311 if options.ssl and options.certfile is None: | 325 if options.ssl and options.certfile is None: |
| 312 options.certfile = os.path.join(os.path.dirname(__file__), 'wpr_cert.pem') | 326 options.certfile = os.path.join(os.path.dirname(__file__), 'wpr_cert.pem') |
| 313 http_proxy_address = platformsettings.get_httpproxy_ip_address( | 327 http_proxy_address = options.host |
| 314 options.server_mode) | 328 if not http_proxy_address: |
| 329 http_proxy_address = platformsettings.get_httpproxy_ip_address( |
| 330 options.server_mode) |
| 315 AddWebProxy(server_manager, options, http_proxy_address, real_dns_lookup, | 331 AddWebProxy(server_manager, options, http_proxy_address, real_dns_lookup, |
| 316 http_archive, cache_misses) | 332 http_archive, cache_misses) |
| 317 AddTrafficShaper(server_manager, options, host) | 333 AddTrafficShaper(server_manager, options, host) |
| 318 | 334 |
| 319 exit_status = 0 | 335 exit_status = 0 |
| 320 try: | 336 try: |
| 321 server_manager.Run() | 337 server_manager.Run() |
| 322 except KeyboardInterrupt: | 338 except KeyboardInterrupt: |
| 323 logging.info('Shutting down.') | 339 logging.info('Shutting down.') |
| 324 except (dnsproxy.DnsProxyException, | 340 except (dnsproxy.DnsProxyException, |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 dest='dns_private_passthrough', | 478 dest='dns_private_passthrough', |
| 463 help='Don\'t forward DNS requests that resolve to private network ' | 479 help='Don\'t forward DNS requests that resolve to private network ' |
| 464 'addresses. CAUTION: With this option important services like ' | 480 'addresses. CAUTION: With this option important services like ' |
| 465 'Kerberos will resolve to the HTTP proxy address.') | 481 'Kerberos will resolve to the HTTP proxy address.') |
| 466 harness_group.add_option('-x', '--no-dns_forwarding', default=True, | 482 harness_group.add_option('-x', '--no-dns_forwarding', default=True, |
| 467 action='store_false', | 483 action='store_false', |
| 468 dest='dns_forwarding', | 484 dest='dns_forwarding', |
| 469 help='Don\'t forward DNS requests to the local replay server. ' | 485 help='Don\'t forward DNS requests to the local replay server. ' |
| 470 'CAUTION: With this option an external mechanism must be used to ' | 486 'CAUTION: With this option an external mechanism must be used to ' |
| 471 'forward traffic to the replay server.') | 487 'forward traffic to the replay server.') |
| 488 harness_group.add_option('--host', default=None, |
| 489 action='store', |
| 490 type='str', |
| 491 help='The IP address to bind all servers to. Defaults to 0.0.0.0 or ' |
| 492 '127.0.0.1, depending on --server_mode and platform.') |
| 472 harness_group.add_option('-o', '--port', default=80, | 493 harness_group.add_option('-o', '--port', default=80, |
| 473 action='store', | 494 action='store', |
| 474 type='int', | 495 type='int', |
| 475 help='Port number to listen on.') | 496 help='Port number to listen on.') |
| 476 harness_group.add_option('--ssl_port', default=443, | 497 harness_group.add_option('--ssl_port', default=443, |
| 477 action='store', | 498 action='store', |
| 478 type='int', | 499 type='int', |
| 479 help='SSL port number to listen on.') | 500 help='SSL port number to listen on.') |
| 480 harness_group.add_option('--shaping_port', default=None, | 501 harness_group.add_option('--shaping_port', default=None, |
| 481 action='store', | 502 action='store', |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 513 elif len(args) != 1: | 534 elif len(args) != 1: |
| 514 option_parser.error('Must specify a replay_file') | 535 option_parser.error('Must specify a replay_file') |
| 515 else: | 536 else: |
| 516 replay_filename = args[0] | 537 replay_filename = args[0] |
| 517 | 538 |
| 518 return replay(options, replay_filename) | 539 return replay(options, replay_filename) |
| 519 | 540 |
| 520 | 541 |
| 521 if __name__ == '__main__': | 542 if __name__ == '__main__': |
| 522 sys.exit(main()) | 543 sys.exit(main()) |
| OLD | NEW |