/circuits/web/main.py
Python | 245 lines | 219 code | 20 blank | 6 comment | 0 complexity | c8b07e6c286e26914dd3c161a3a6ca53 MD5 | raw file
1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4 5"""Main 6 7circutis.web Web Server and Testing Tool. 8""" 9 10 11import os 12from sys import stderr 13from hashlib import md5 14from optparse import OptionParser 15from wsgiref.validate import validator 16from wsgiref.simple_server import make_server 17 18try: 19 import hotshot 20 import hotshot.stats 21except ImportError: 22 hostshot = None 23 24 25import circuits 26from circuits import handler, Component, Manager, Debugger 27 28from circuits.core.pollers import Select 29from circuits.tools import inspect, graph 30 31from circuits.web.wsgi import Application 32from circuits.web.tools import check_auth, digest_auth 33from circuits.web import BaseServer, Controller, Logger, Server, Static 34 35try: 36 from circuits.core.pollers import Poll 37except ImportError: 38 Poll = None # NOQA 39 40try: 41 from circuits.core.pollers import EPoll 42except ImportError: 43 EPoll = None # NOQA 44 45 46USAGE = "%prog [options] [docroot]" 47VERSION = "%prog v" + circuits.__version__ 48 49 50def parse_options(): 51 parser = OptionParser(usage=USAGE, version=VERSION) 52 53 parser.add_option( 54 "-b", "--bind", 55 action="store", type="string", default="0.0.0.0:8000", dest="bind", 56 help="Bind to address:[port]" 57 ) 58 59 parser.add_option( 60 "-l", "--logging", 61 action="store_true", default=False, dest="logging", 62 help="Enable logging of requests" 63 ) 64 65 parser.add_option( 66 "-p", "--passwd", 67 action="store", default=None, dest="passwd", 68 help="Location to passwd file for Digest Auth" 69 ) 70 71 parser.add_option( 72 "-j", "--jobs", 73 action="store", type="int", default=0, dest="jobs", 74 help="Specify no. of jobs/processes to start" 75 ) 76 77 parser.add_option( 78 "", "--poller", 79 action="store", type="string", default="select", dest="poller", 80 help="Specify type of poller to use" 81 ) 82 83 parser.add_option( 84 "", "--server", 85 action="store", type="string", default="server", dest="server", 86 help="Specify server to use" 87 ) 88 89 parser.add_option( 90 "", "--profile", 91 action="store_true", default=False, dest="profile", 92 help="Enable execution profiling support" 93 ) 94 95 parser.add_option( 96 "", "--debug", 97 action="store_true", default=False, dest="debug", 98 help="Enable debug mode" 99 ) 100 101 parser.add_option( 102 "", "--validate", 103 action="store_true", default=False, dest="validate", 104 help="Enable WSGI validation mode" 105 ) 106 107 opts, args = parser.parse_args() 108 109 return opts, args 110 111 112class Authentication(Component): 113 114 channel = "web" 115 116 realm = "Secure Area" 117 users = {"admin": md5("admin").hexdigest()} 118 119 def __init__(self, channel=channel, realm=None, passwd=None): 120 super(Authentication, self).__init__(self, channel=channel) 121 122 if realm is not None: 123 self.realm = realm 124 125 if passwd is not None: 126 with open(passwd, "r") as f: 127 lines = (line.strip() for line in f) 128 self.users = dict((line.split(":", 1) for line in lines)) 129 130 @handler("request", priority=10) 131 def request(self, event, request, response): 132 if not check_auth(request, response, self.realm, self.users): 133 event.stop() 134 return digest_auth(request, response, self.realm, self.users) 135 136 137class HelloWorld(Component): 138 139 channel = "web" 140 141 def request(self, request, response): 142 return "Hello World!" 143 144 145class Root(Controller): 146 147 def hello(self): 148 return "Hello World!" 149 150 151def select_poller(poller): 152 if poller == "poll": 153 if Poll is None: 154 stderr.write( 155 "No poll support available - defaulting to Select..." 156 ) 157 Poller = Select 158 else: 159 Poller = Poll 160 elif poller == "epoll": 161 if EPoll is None: 162 stderr.write( 163 "No epoll support available - defaulting to Select..." 164 ) 165 Poller = Select 166 else: 167 Poller = EPoll 168 else: 169 Poller = Select 170 171 return Poller 172 173 174def parse_bind(bind): 175 if ":" in bind: 176 address, port = bind.split(":") 177 port = int(port) 178 else: 179 address, port = bind, 8000 180 181 return (address, port) 182 183 184def main(): 185 opts, args = parse_options() 186 187 bind = parse_bind(opts.bind) 188 189 if opts.validate: 190 application = (Application() + Root()) 191 app = validator(application) 192 193 httpd = make_server(bind[0], bind[1], app) 194 httpd.serve_forever() 195 196 raise SystemExit(0) 197 198 manager = Manager() 199 200 opts.debug and Debugger().register(manager) 201 202 Poller = select_poller(opts.poller.lower()) 203 Poller().register(manager) 204 205 if opts.server.lower() == "base": 206 BaseServer(bind).register(manager) 207 HelloWorld().register(manager) 208 else: 209 Server(bind).register(manager) 210 Root().register(manager) 211 212 docroot = os.getcwd() if not args else args[0] 213 214 Static(docroot=docroot, dirlisting=True).register(manager) 215 216 opts.passwd and Authentication(passwd=opts.passwd).register(manager) 217 218 opts.logging and Logger().register(manager) 219 220 if opts.profile and hotshot: 221 profiler = hotshot.Profile(".profile") 222 profiler.start() 223 224 if opts.debug: 225 print(graph(manager, name="circuits.web")) 226 print() 227 print(inspect(manager)) 228 229 for i in range(opts.jobs): 230 manager.start(process=True) 231 232 manager.run() 233 234 if opts.profile and hotshot: 235 profiler.stop() 236 profiler.close() 237 238 stats = hotshot.stats.load(".profile") 239 stats.strip_dirs() 240 stats.sort_stats("time", "calls") 241 stats.print_stats(20) 242 243 244if __name__ == "__main__": 245 main()