Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Constrained Network Server. Serves files with supplied network constraints. | 6 """Constrained Network Server. Serves files with supplied network constraints. |
| 7 | 7 |
| 8 The CNS exposes a web based API allowing network constraints to be imposed on | 8 The CNS exposes a web based API allowing network constraints to be imposed on |
| 9 file serving. | 9 file serving. |
| 10 | 10 |
| 11 TODO(dalecurtis): Add some more docs here. | 11 TODO(dalecurtis): Add some more docs here. |
| 12 | 12 |
| 13 """ | 13 """ |
| 14 | 14 |
| 15 import logging | |
| 15 import mimetypes | 16 import mimetypes |
| 16 import optparse | 17 import optparse |
| 17 import os | 18 import os |
| 18 import signal | 19 import signal |
| 19 import sys | 20 import sys |
| 20 import threading | 21 import threading |
| 21 import time | 22 import time |
| 22 import traffic_control | 23 import traffic_control |
| 23 | 24 |
| 24 try: | 25 try: |
| 25 import cherrypy | 26 import cherrypy |
| 26 except ImportError: | 27 except ImportError: |
| 27 print ('CNS requires CherryPy v3 or higher to be installed. Please install\n' | 28 print ('CNS requires CherryPy v3 or higher to be installed. Please install\n' |
| 28 'and try again. On Linux: sudo apt-get install python-cherrypy3\n') | 29 'and try again. On Linux: sudo apt-get install python-cherrypy3\n') |
| 29 sys.exit(1) | 30 sys.exit(1) |
| 30 | 31 |
| 31 # Add webm file types to mimetypes map since cherrypy's default type is text. | 32 # Add webm file types to mimetypes map since cherrypy's default type is text. |
| 32 mimetypes.types_map['.webm'] = 'video/webm' | 33 mimetypes.types_map['.webm'] = 'video/webm' |
| 33 | 34 |
| 35 # Default logging is ERROR. Use --verbose to enable DEBUG logging. | |
| 36 _DEFAULT_LOG_LEVEL = logging.ERROR | |
| 37 | |
| 34 # Default port to serve the CNS on. | 38 # Default port to serve the CNS on. |
| 35 _DEFAULT_SERVING_PORT = 9000 | 39 _DEFAULT_SERVING_PORT = 9000 |
| 36 | 40 |
| 37 # Default port range for constrained use. | 41 # Default port range for constrained use. |
| 38 _DEFAULT_CNS_PORT_RANGE = (50000, 51000) | 42 _DEFAULT_CNS_PORT_RANGE = (50000, 51000) |
| 39 | 43 |
| 40 # Default number of seconds before a port can be torn down. | 44 # Default number of seconds before a port can be torn down. |
| 41 _DEFAULT_PORT_EXPIRY_TIME_SECS = 5 * 60 | 45 _DEFAULT_PORT_EXPIRY_TIME_SECS = 5 * 60 |
| 42 | 46 |
| 43 | 47 |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 280 parser.add_option('--interface', default='eth0', | 284 parser.add_option('--interface', default='eth0', |
| 281 help=('Interface to setup constraints on. Use lo for a ' | 285 help=('Interface to setup constraints on. Use lo for a ' |
| 282 'local client. Default: %default')) | 286 'local client. Default: %default')) |
| 283 parser.add_option('--threads', type='int', | 287 parser.add_option('--threads', type='int', |
| 284 default=cherrypy._cpserver.Server.thread_pool, | 288 default=cherrypy._cpserver.Server.thread_pool, |
| 285 help=('Number of threads in the thread pool. Default: ' | 289 help=('Number of threads in the thread pool. Default: ' |
| 286 '%default')) | 290 '%default')) |
| 287 parser.add_option('--www-root', default=os.getcwd(), | 291 parser.add_option('--www-root', default=os.getcwd(), |
| 288 help=('Directory root to serve files from. Defaults to the ' | 292 help=('Directory root to serve files from. Defaults to the ' |
| 289 'current directory: %default')) | 293 'current directory: %default')) |
| 294 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', | |
| 295 default=False, help='Turn on verbose output.') | |
| 290 | 296 |
| 291 options = parser.parse_args()[0] | 297 options = parser.parse_args()[0] |
| 292 | 298 |
| 293 # Convert port range into the desired tuple format. | 299 # Convert port range into the desired tuple format. |
| 294 try: | 300 try: |
| 295 if isinstance(options.port_range, str): | 301 if isinstance(options.port_range, str): |
| 296 options.port_range = [int(port) for port in options.port_range.split(',')] | 302 options.port_range = [int(port) for port in options.port_range.split(',')] |
| 297 except ValueError: | 303 except ValueError: |
| 298 parser.error('Invalid port range specified.') | 304 parser.error('Invalid port range specified.') |
| 299 | 305 |
| 300 # Convert the path to an absolute to remove any . or .. | 306 # Convert the path to an absolute to remove any . or .. |
| 301 options.www_root = os.path.abspath(options.www_root) | 307 options.www_root = os.path.abspath(options.www_root) |
| 302 | 308 |
| 309 # Required so that cherrypy logs do not get propagated to root logger causing | |
| 310 # the logs to be printed twice. | |
| 311 cherrypy.log.error_log.propagate = False | |
| 312 | |
| 313 _SetLogger(options.verbose) | |
| 314 | |
| 303 return options | 315 return options |
| 304 | 316 |
| 305 | 317 |
| 318 def _SetLogger(verbose): | |
| 319 # Logging is used for traffic_control debug statements. | |
| 320 log_level = _DEFAULT_LOG_LEVEL | |
| 321 if verbose: | |
| 322 log_level = logging.DEBUG | |
| 323 logging.basicConfig(level=log_level, format='%(message)s') | |
|
DaleCurtis
2012/01/06 23:19:42
Need a more descriptive message here. One that is
shadi
2012/01/07 04:56:19
cherrypy.log only shows date. I added thread numbe
DaleCurtis
2012/01/09 19:21:19
Ah, I'm thinking of cherrypy.request.log() I think
| |
| 324 | |
| 325 | |
| 326 def _CheckRootAccess(): | |
|
DaleCurtis
2012/01/06 23:19:42
This is not complete and should instead be in the
shadi
2012/01/07 04:56:19
Check http://codereview.chromium.org/9125022/
On 2
| |
| 327 if os.geteuid() != 0: | |
| 328 sys.exit('Need root access to run a constrained server.') | |
| 329 | |
| 330 | |
| 306 def Main(): | 331 def Main(): |
| 307 """Configure and start the ConstrainedNetworkServer.""" | 332 """Configure and start the ConstrainedNetworkServer.""" |
| 308 options = ParseArgs() | 333 options = ParseArgs() |
| 334 _CheckRootAccess() | |
| 309 | 335 |
| 310 cherrypy.config.update( | 336 cherrypy.config.update( |
| 311 {'server.socket_host': '::', 'server.socket_port': options.port}) | 337 {'server.socket_host': '::', 'server.socket_port': options.port}) |
| 312 | 338 |
| 313 if options.threads: | 339 if options.threads: |
| 314 cherrypy.config.update({'server.thread_pool': options.threads}) | 340 cherrypy.config.update({'server.thread_pool': options.threads}) |
| 315 | 341 |
| 316 # Setup port allocator here so we can call cleanup on failures/exit. | 342 # Setup port allocator here so we can call cleanup on failures/exit. |
| 317 pa = PortAllocator(options.port_range, expiry_time_secs=options.expiry_time) | 343 pa = PortAllocator(options.port_range, expiry_time_secs=options.expiry_time) |
| 318 | 344 |
| 319 try: | 345 try: |
| 320 cherrypy.quickstart(ConstrainedNetworkServer(options, pa)) | 346 cherrypy.quickstart(ConstrainedNetworkServer(options, pa)) |
| 321 finally: | 347 finally: |
| 322 # Disable Ctrl-C handler to prevent interruption of cleanup. | 348 # Disable Ctrl-C handler to prevent interruption of cleanup. |
| 323 signal.signal(signal.SIGINT, lambda signal, frame: None) | 349 signal.signal(signal.SIGINT, lambda signal, frame: None) |
| 324 pa.Cleanup(options.interface, all_ports=True) | 350 pa.Cleanup(options.interface, all_ports=True) |
| 325 | 351 |
| 326 | 352 |
| 327 if __name__ == '__main__': | 353 if __name__ == '__main__': |
| 328 Main() | 354 Main() |
| OLD | NEW |