Mercurial > p > roundup > code
diff roundup-server @ 27:e5e9ea306a09
moving the bin files to facilitate out-of-the-boxness
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Mon, 23 Jul 2001 03:46:48 +0000 |
| parents | |
| children | b475e7d3ce52 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/roundup-server Mon Jul 23 03:46:48 2001 +0000 @@ -0,0 +1,226 @@ +#!/usr/bin/python +""" HTTP Server that serves roundup. + +Stolen from CGIHTTPServer + +$Id: roundup-server,v 1.1 2001-07-23 03:46:48 richard Exp $ + +""" +import sys +if int(sys.version[0]) < 2: + print "Content-Type: text/plain\n" + print "Roundup requires Python 2.0 or newer." + +__version__ = "0.1" + +__all__ = ["RoundupRequestHandler"] + +import os, urllib, StringIO, traceback, cgi, binascii, string +import BaseHTTPServer +import SimpleHTTPServer + +# Roundup modules of use here +from roundup import cgitb, cgi_client + +# These are here temporarily until I get a real reload system in place +from roundup import date, hyperdb, hyper_bsddb, roundupdb, htmltemplate + +# +## Configuration +# + +# This indicates where the Roundup instance lives +ROUNDUPS = { + 'test': '/tmp/roundup_test', +} + +# Where to log debugging information to. Use an instance of DevNull if you +# don't want to log anywhere. +# TODO: actually use this stuff +#class DevNull: +# def write(self, info): +# pass +#LOG = open('/var/log/roundup.cgi.log', 'a') +#LOG = DevNull() + +# +## end configuration +# + + +class RoundupRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + def send_head(self): + """Version of send_head that support CGI scripts""" + # TODO: actually do the HEAD ... + return self.run_cgi() + + def run_cgi(self): + """ Execute the CGI command. Wrap an innner call in an error + handler so all errors can be caught. + """ + save_stdin = sys.stdin + sys.stdin = self.rfile + try: + self.inner_run_cgi() + except cgi_client.Unauthorised: + self.wfile.write('Content-Type: text/html\n') + self.wfile.write('Status: 403\n') + self.wfile.write('Unauthorised') + except: + try: + reload(cgitb) + self.wfile.write("Content-Type: text/html\n\n") + self.wfile.write(cgitb.breaker()) + self.wfile.write(cgitb.html()) + except: + self.wfile.write("Content-Type: text/html\n\n") + self.wfile.write("<pre>") + s = StringIO.StringIO() + traceback.print_exc(None, s) + self.wfile.write(cgi.escape(s.getvalue())) + self.wfile.write("</pre>\n") + sys.stdin = save_stdin + + def inner_run_cgi(self): + ''' This is the inner part of the CGI handling + ''' + + rest = self.path + i = rest.rfind('?') + if i >= 0: + rest, query = rest[:i], rest[i+1:] + else: + query = '' + + # figure the instance + if rest == '/': + raise ValueError, 'No instance specified' + l_path = string.split(rest, '/') + instance = urllib.unquote(l_path[1]) + if ROUNDUPS.has_key(instance): + instance_home = ROUNDUPS[instance] + module_path, instance = os.path.split(instance_home) + sys.path.insert(0, module_path) + try: + instance = __import__(instance) + finally: + del sys.path[0] + else: + raise ValueError, 'No such instance "%s"'%instance + + # figure out what the rest of the path is + if len(l_path) > 2: + rest = '/'.join(l_path[2:]) + else: + rest = '/' + + # Set up the CGI environment + env = {} + env['REQUEST_METHOD'] = self.command + env['PATH_INFO'] = urllib.unquote(rest) + if query: + env['QUERY_STRING'] = query + host = self.address_string() + if self.headers.typeheader is None: + env['CONTENT_TYPE'] = self.headers.type + else: + env['CONTENT_TYPE'] = self.headers.typeheader + length = self.headers.getheader('content-length') + if length: + env['CONTENT_LENGTH'] = length + co = filter(None, self.headers.getheaders('cookie')) + if co: + env['HTTP_COOKIE'] = ', '.join(co) + env['SCRIPT_NAME'] = '' + env['SERVER_NAME'] = self.server.server_name + env['SERVER_PORT'] = str(self.server.server_port) + + decoded_query = query.replace('+', ' ') + + # if root, setuid to nobody + # TODO why isn't this done much earlier? - say, in main()? + if not os.getuid(): + nobody = nobody_uid() + os.setuid(nobody) + + # reload all modules + # TODO check for file timestamp changes and dependencies + reload(date) + reload(hyperdb) + reload(roundupdb) + reload(htmltemplate) + reload(cgi_client) + sys.path.insert(0, module_path) + try: + reload(instance) + finally: + del sys.path[0] + + # initialise the roundupdb, check for auth + db = instance.open('admin') + message = 'Unauthorised' + auth = self.headers.getheader('authorization') + if auth: + l = binascii.a2b_base64(auth.split(' ')[1]).split(':') + user = l[0] + password = None + if len(l) > 1: + password = l[1] + try: + uid = db.user.lookup(user) + except KeyError: + auth = None + message = 'Username not recognised' + else: + if password != db.user.get(uid, 'password'): + message = 'Incorrect password' + auth = None + db.close() + del db + if not auth: + self.send_response(401) + self.send_header('Content-Type', 'text/html') + self.send_header('WWW-Authenticate', 'basic realm="Roundup"') + self.end_headers() + self.wfile.write(message) + return + + self.send_response(200, "Script output follows") + + # do the roundup thang + db = instance.open(user) + client = instance.Client(self.wfile, db, env, user) + client.main() + do_POST = run_cgi + +nobody = None + +def nobody_uid(): + """Internal routine to get nobody's uid""" + global nobody + if nobody: + return nobody + try: + import pwd + except ImportError: + return -1 + try: + nobody = pwd.getpwnam('nobody')[2] + except KeyError: + nobody = 1 + max(map(lambda x: x[2], pwd.getpwall())) + return nobody + +if __name__ == '__main__': + # TODO make this configurable again? command-line seems ok to me... + address = ('', 8080) + httpd = BaseHTTPServer.HTTPServer(address, RoundupRequestHandler) + print 'Roundup server started on', address + httpd.serve_forever() + +# +# $Log: not supported by cvs2svn $ +# Revision 1.1 2001/07/22 11:15:45 richard +# More Grande Splite stuff +# +# +
