PageRenderTime 63ms CodeModel.GetById 21ms app.highlight 37ms RepoModel.GetById 1ms app.codeStats 0ms

/circuits/web/main.py

https://bitbucket.org/prologic/circuits/
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()