comparison bin/roundup-server @ 23:0eea7628adb2

More Grande Splite stuff
author Richard Jones <richard@users.sourceforge.net>
date Sun, 22 Jul 2001 11:15:45 +0000
parents
children
comparison
equal deleted inserted replaced
22:d64c32a499f9 23:0eea7628adb2
1 #!/usr/bin/python
2 """ HTTP Server that serves roundup.
3
4 Stolen from CGIHTTPServer
5
6 $Id: roundup-server,v 1.1 2001-07-22 11:15:45 richard Exp $
7
8 """
9 import sys
10 if int(sys.version[0]) < 2:
11 print "Content-Type: text/plain\n"
12 print "Roundup requires Python 2.0 or newer."
13
14 __version__ = "0.1"
15
16 __all__ = ["RoundupRequestHandler"]
17
18 import os, urllib, StringIO, traceback, cgi, binascii, string
19 import BaseHTTPServer
20 import SimpleHTTPServer
21
22 # Roundup modules of use here
23 from roundup import cgitb, cgi_client
24
25 # These are here temporarily until I get a real reload system in place
26 from roundup import date, hyperdb, hyper_bsddb, roundupdb, htmltemplate
27
28 #
29 ## Configuration
30 #
31
32 # This indicates where the Roundup instance lives
33 ROUNDUPS = {
34 'test': '/tmp/roundup_test',
35 }
36
37 # Where to log debugging information to. Use an instance of DevNull if you
38 # don't want to log anywhere.
39 # TODO: actually use this stuff
40 #class DevNull:
41 # def write(self, info):
42 # pass
43 #LOG = open('/var/log/roundup.cgi.log', 'a')
44 #LOG = DevNull()
45
46 #
47 ## end configuration
48 #
49
50
51 class RoundupRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
52 def send_head(self):
53 """Version of send_head that support CGI scripts"""
54 # TODO: actually do the HEAD ...
55 return self.run_cgi()
56
57 def run_cgi(self):
58 """ Execute the CGI command. Wrap an innner call in an error
59 handler so all errors can be caught.
60 """
61 save_stdin = sys.stdin
62 sys.stdin = self.rfile
63 try:
64 self.inner_run_cgi()
65 except cgi_client.Unauthorised:
66 self.wfile.write('Content-Type: text/html\n')
67 self.wfile.write('Status: 403\n')
68 self.wfile.write('Unauthorised')
69 except:
70 try:
71 reload(cgitb)
72 self.wfile.write("Content-Type: text/html\n\n")
73 self.wfile.write(cgitb.breaker())
74 self.wfile.write(cgitb.html())
75 except:
76 self.wfile.write("Content-Type: text/html\n\n")
77 self.wfile.write("<pre>")
78 s = StringIO.StringIO()
79 traceback.print_exc(None, s)
80 self.wfile.write(cgi.escape(s.getvalue()))
81 self.wfile.write("</pre>\n")
82 sys.stdin = save_stdin
83
84 def inner_run_cgi(self):
85 ''' This is the inner part of the CGI handling
86 '''
87
88 rest = self.path
89 i = rest.rfind('?')
90 if i >= 0:
91 rest, query = rest[:i], rest[i+1:]
92 else:
93 query = ''
94
95 # figure the instance
96 if rest == '/':
97 raise ValueError, 'No instance specified'
98 l_path = string.split(rest, '/')
99 instance = urllib.unquote(l_path[1])
100 if ROUNDUPS.has_key(instance):
101 instance_home = ROUNDUPS[instance]
102 module_path, instance = os.path.split(instance_home)
103 sys.path.insert(0, module_path)
104 try:
105 instance = __import__(instance)
106 finally:
107 del sys.path[0]
108 else:
109 raise ValueError, 'No such instance "%s"'%instance
110
111 # figure out what the rest of the path is
112 if len(l_path) > 2:
113 rest = '/'.join(l_path[2:])
114 else:
115 rest = '/'
116
117 # Set up the CGI environment
118 env = {}
119 env['REQUEST_METHOD'] = self.command
120 env['PATH_INFO'] = urllib.unquote(rest)
121 if query:
122 env['QUERY_STRING'] = query
123 host = self.address_string()
124 if self.headers.typeheader is None:
125 env['CONTENT_TYPE'] = self.headers.type
126 else:
127 env['CONTENT_TYPE'] = self.headers.typeheader
128 length = self.headers.getheader('content-length')
129 if length:
130 env['CONTENT_LENGTH'] = length
131 co = filter(None, self.headers.getheaders('cookie'))
132 if co:
133 env['HTTP_COOKIE'] = ', '.join(co)
134 env['SCRIPT_NAME'] = ''
135 env['SERVER_NAME'] = self.server.server_name
136 env['SERVER_PORT'] = str(self.server.server_port)
137
138 decoded_query = query.replace('+', ' ')
139
140 # if root, setuid to nobody
141 # TODO why isn't this done much earlier? - say, in main()?
142 if not os.getuid():
143 nobody = nobody_uid()
144 os.setuid(nobody)
145
146 # reload all modules
147 # TODO check for file timestamp changes and dependencies
148 reload(date)
149 reload(hyperdb)
150 reload(roundupdb)
151 reload(htmltemplate)
152 reload(cgi_client)
153 sys.path.insert(0, module_path)
154 try:
155 reload(instance)
156 finally:
157 del sys.path[0]
158
159 # initialise the roundupdb, check for auth
160 db = instance.open('admin')
161 message = 'Unauthorised'
162 auth = self.headers.getheader('authorization')
163 if auth:
164 l = binascii.a2b_base64(auth.split(' ')[1]).split(':')
165 user = l[0]
166 password = None
167 if len(l) > 1:
168 password = l[1]
169 try:
170 uid = db.user.lookup(user)
171 except KeyError:
172 auth = None
173 message = 'Username not recognised'
174 else:
175 if password != db.user.get(uid, 'password'):
176 message = 'Incorrect password'
177 auth = None
178 db.close()
179 del db
180 if not auth:
181 self.send_response(401)
182 self.send_header('Content-Type', 'text/html')
183 self.send_header('WWW-Authenticate', 'basic realm="Roundup"')
184 self.end_headers()
185 self.wfile.write(message)
186 return
187
188 self.send_response(200, "Script output follows")
189
190 # do the roundup thang
191 db = instance.open(user)
192 client = instance.Client(self.wfile, db, env, user)
193 client.main()
194 do_POST = run_cgi
195
196 nobody = None
197
198 def nobody_uid():
199 """Internal routine to get nobody's uid"""
200 global nobody
201 if nobody:
202 return nobody
203 try:
204 import pwd
205 except ImportError:
206 return -1
207 try:
208 nobody = pwd.getpwnam('nobody')[2]
209 except KeyError:
210 nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
211 return nobody
212
213 if __name__ == '__main__':
214 # TODO make this configurable again? command-line seems ok to me...
215 address = ('', 8080)
216 httpd = BaseHTTPServer.HTTPServer(address, RoundupRequestHandler)
217 print 'Roundup server started on', address
218 httpd.serve_forever()
219
220 #
221 # $Log: not supported by cvs2svn $
222 #
223

Roundup Issue Tracker: http://roundup-tracker.org/