Mercurial > p > roundup > code
comparison roundup/scripts/roundup_server.py @ 592:326388b8604a
Moved scripts from top-level dir to roundup.scripts subpackage
| author | Jürgen Hermann <jhermann@users.sourceforge.net> |
|---|---|
| date | Tue, 29 Jan 2002 19:53:08 +0000 |
| parents | |
| children | 2256f81293c1 |
comparison
equal
deleted
inserted
replaced
| 591:4d509f01d336 | 592:326388b8604a |
|---|---|
| 1 #!/usr/bin/python | |
| 2 # | |
| 3 # Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/) | |
| 4 # This module is free software, and you may redistribute it and/or modify | |
| 5 # under the same terms as Python, so long as this copyright message and | |
| 6 # disclaimer are retained in their original form. | |
| 7 # | |
| 8 # IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR | |
| 9 # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING | |
| 10 # OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE | |
| 11 # POSSIBILITY OF SUCH DAMAGE. | |
| 12 # | |
| 13 # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |
| 14 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 15 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" | |
| 16 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, | |
| 17 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |
| 18 # | |
| 19 """ HTTP Server that serves roundup. | |
| 20 | |
| 21 $Id: roundup_server.py,v 1.1 2002-01-29 19:53:08 jhermann Exp $ | |
| 22 """ | |
| 23 | |
| 24 # python version check | |
| 25 from roundup import version_check | |
| 26 | |
| 27 import sys, os, urllib, StringIO, traceback, cgi, binascii, getopt, imp | |
| 28 import BaseHTTPServer | |
| 29 | |
| 30 # Roundup modules of use here | |
| 31 from roundup import cgitb, cgi_client | |
| 32 import roundup.instance | |
| 33 from roundup.i18n import _ | |
| 34 | |
| 35 # | |
| 36 ## Configuration | |
| 37 # | |
| 38 | |
| 39 # This indicates where the Roundup instance lives | |
| 40 ROUNDUP_INSTANCE_HOMES = { | |
| 41 'bar': '/tmp/bar', | |
| 42 } | |
| 43 | |
| 44 ROUNDUP_USER = None | |
| 45 | |
| 46 | |
| 47 # Where to log debugging information to. Use an instance of DevNull if you | |
| 48 # don't want to log anywhere. | |
| 49 # TODO: actually use this stuff | |
| 50 #class DevNull: | |
| 51 # def write(self, info): | |
| 52 # pass | |
| 53 #LOG = open('/var/log/roundup.cgi.log', 'a') | |
| 54 #LOG = DevNull() | |
| 55 | |
| 56 # | |
| 57 ## end configuration | |
| 58 # | |
| 59 | |
| 60 | |
| 61 class RoundupRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |
| 62 ROUNDUP_INSTANCE_HOMES = ROUNDUP_INSTANCE_HOMES | |
| 63 ROUNDUP_USER = ROUNDUP_USER | |
| 64 | |
| 65 def run_cgi(self): | |
| 66 """ Execute the CGI command. Wrap an innner call in an error | |
| 67 handler so all errors can be caught. | |
| 68 """ | |
| 69 save_stdin = sys.stdin | |
| 70 sys.stdin = self.rfile | |
| 71 try: | |
| 72 self.inner_run_cgi() | |
| 73 except cgi_client.NotFound: | |
| 74 self.send_error(404, self.path) | |
| 75 except cgi_client.Unauthorised: | |
| 76 self.send_error(403, self.path) | |
| 77 except: | |
| 78 # it'd be nice to be able to detect if these are going to have | |
| 79 # any effect... | |
| 80 self.send_response(400) | |
| 81 self.send_header('Content-Type', 'text/html') | |
| 82 self.end_headers() | |
| 83 try: | |
| 84 reload(cgitb) | |
| 85 self.wfile.write(cgitb.breaker()) | |
| 86 self.wfile.write(cgitb.html()) | |
| 87 except: | |
| 88 self.wfile.write("<pre>") | |
| 89 s = StringIO.StringIO() | |
| 90 traceback.print_exc(None, s) | |
| 91 self.wfile.write(cgi.escape(s.getvalue())) | |
| 92 self.wfile.write("</pre>\n") | |
| 93 sys.stdin = save_stdin | |
| 94 | |
| 95 do_GET = do_POST = do_HEAD = send_head = run_cgi | |
| 96 | |
| 97 def index(self): | |
| 98 ''' Print up an index of the available instances | |
| 99 ''' | |
| 100 self.send_response(200) | |
| 101 self.send_header('Content-Type', 'text/html') | |
| 102 self.end_headers() | |
| 103 w = self.wfile.write | |
| 104 w(_('<html><head><title>Roundup instances index</title></head>\n')) | |
| 105 w(_('<body><h1>Roundup instances index</h1><ol>\n')) | |
| 106 for instance in self.ROUNDUP_INSTANCE_HOMES.keys(): | |
| 107 w(_('<li><a href="%(instance_url)s/index">%(instance_name)s</a>\n')%{ | |
| 108 'instance_url': urllib.quote(instance), | |
| 109 'instance_name': cgi.escape(instance)}) | |
| 110 w(_('</ol></body></html>')) | |
| 111 | |
| 112 def inner_run_cgi(self): | |
| 113 ''' This is the inner part of the CGI handling | |
| 114 ''' | |
| 115 | |
| 116 rest = self.path | |
| 117 i = rest.rfind('?') | |
| 118 if i >= 0: | |
| 119 rest, query = rest[:i], rest[i+1:] | |
| 120 else: | |
| 121 query = '' | |
| 122 | |
| 123 # figure the instance | |
| 124 if rest == '/': | |
| 125 return self.index() | |
| 126 l_path = rest.split('/') | |
| 127 instance_name = urllib.unquote(l_path[1]) | |
| 128 if self.ROUNDUP_INSTANCE_HOMES.has_key(instance_name): | |
| 129 instance_home = self.ROUNDUP_INSTANCE_HOMES[instance_name] | |
| 130 instance = roundup.instance.open(instance_home) | |
| 131 else: | |
| 132 raise cgi_client.NotFound | |
| 133 | |
| 134 # figure out what the rest of the path is | |
| 135 if len(l_path) > 2: | |
| 136 rest = '/'.join(l_path[2:]) | |
| 137 else: | |
| 138 rest = '/' | |
| 139 | |
| 140 # Set up the CGI environment | |
| 141 env = {} | |
| 142 env['INSTANCE_NAME'] = instance_name | |
| 143 env['REQUEST_METHOD'] = self.command | |
| 144 env['PATH_INFO'] = urllib.unquote(rest) | |
| 145 if query: | |
| 146 env['QUERY_STRING'] = query | |
| 147 host = self.address_string() | |
| 148 if self.headers.typeheader is None: | |
| 149 env['CONTENT_TYPE'] = self.headers.type | |
| 150 else: | |
| 151 env['CONTENT_TYPE'] = self.headers.typeheader | |
| 152 length = self.headers.getheader('content-length') | |
| 153 if length: | |
| 154 env['CONTENT_LENGTH'] = length | |
| 155 co = filter(None, self.headers.getheaders('cookie')) | |
| 156 if co: | |
| 157 env['HTTP_COOKIE'] = ', '.join(co) | |
| 158 env['SCRIPT_NAME'] = '' | |
| 159 env['SERVER_NAME'] = self.server.server_name | |
| 160 env['SERVER_PORT'] = str(self.server.server_port) | |
| 161 | |
| 162 decoded_query = query.replace('+', ' ') | |
| 163 | |
| 164 # do the roundup thang | |
| 165 client = instance.Client(instance, self, env) | |
| 166 client.main() | |
| 167 | |
| 168 def usage(message=''): | |
| 169 if message: | |
| 170 message = _('Error: %(error)s\n\n')%{'error': message} | |
| 171 print _('''%(message)sUsage: | |
| 172 roundup-server [-n hostname] [-p port] [name=instance home]* | |
| 173 | |
| 174 -n: sets the host name | |
| 175 -p: sets the port to listen on | |
| 176 | |
| 177 name=instance home | |
| 178 Sets the instance home(s) to use. The name is how the instance is | |
| 179 identified in the URL (it's the first part of the URL path). The | |
| 180 instance home is the directory that was identified when you did | |
| 181 "roundup-admin init". You may specify any number of these name=home | |
| 182 pairs on the command-line. For convenience, you may edit the | |
| 183 ROUNDUP_INSTANCE_HOMES variable in the roundup-server file instead. | |
| 184 ''')%locals() | |
| 185 sys.exit(0) | |
| 186 | |
| 187 def main(): | |
| 188 hostname = '' | |
| 189 port = 8080 | |
| 190 try: | |
| 191 # handle the command-line args | |
| 192 try: | |
| 193 optlist, args = getopt.getopt(sys.argv[1:], 'n:p:u:') | |
| 194 except getopt.GetoptError, e: | |
| 195 usage(str(e)) | |
| 196 | |
| 197 user = ROUNDUP_USER | |
| 198 for (opt, arg) in optlist: | |
| 199 if opt == '-n': hostname = arg | |
| 200 elif opt == '-p': port = int(arg) | |
| 201 elif opt == '-u': user = arg | |
| 202 elif opt == '-h': usage() | |
| 203 | |
| 204 if hasattr(os, 'getuid'): | |
| 205 # if root, setuid to the running user | |
| 206 if not os.getuid() and user is not None: | |
| 207 try: | |
| 208 import pwd | |
| 209 except ImportError: | |
| 210 raise ValueError, _("Can't change users - no pwd module") | |
| 211 try: | |
| 212 uid = pwd.getpwnam(user)[2] | |
| 213 except KeyError: | |
| 214 raise ValueError, _("User %(user)s doesn't exist")%locals() | |
| 215 os.setuid(uid) | |
| 216 elif os.getuid() and user is not None: | |
| 217 print _('WARNING: ignoring "-u" argument, not root') | |
| 218 | |
| 219 # People can remove this check if they're really determined | |
| 220 if not os.getuid() and user is None: | |
| 221 raise ValueError, _("Can't run as root!") | |
| 222 | |
| 223 # handle instance specs | |
| 224 if args: | |
| 225 d = {} | |
| 226 for arg in args: | |
| 227 try: | |
| 228 name, home = arg.split('=') | |
| 229 except ValueError: | |
| 230 raise ValueError, _("Instances must be name=home") | |
| 231 d[name] = home | |
| 232 RoundupRequestHandler.ROUNDUP_INSTANCE_HOMES = d | |
| 233 except SystemExit: | |
| 234 raise | |
| 235 except: | |
| 236 exc_type, exc_value = sys.exc_info()[:2] | |
| 237 usage('%s: %s'%(exc_type, exc_value)) | |
| 238 | |
| 239 # we don't want the cgi module interpreting the command-line args ;) | |
| 240 sys.argv = sys.argv[:1] | |
| 241 address = (hostname, port) | |
| 242 httpd = BaseHTTPServer.HTTPServer(address, RoundupRequestHandler) | |
| 243 print _('Roundup server started on %(address)s')%locals() | |
| 244 httpd.serve_forever() | |
| 245 | |
| 246 if __name__ == '__main__': | |
| 247 main() | |
| 248 | |
| 249 # | |
| 250 # $Log: not supported by cvs2svn $ | |
| 251 # Revision 1.25 2002/01/05 02:21:21 richard | |
| 252 # fixes | |
| 253 # | |
| 254 # Revision 1.24 2002/01/05 02:19:03 richard | |
| 255 # i18n'ification | |
| 256 # | |
| 257 # Revision 1.23 2001/12/15 23:47:07 richard | |
| 258 # sys module went away... | |
| 259 # | |
| 260 # Revision 1.22 2001/12/13 00:20:01 richard | |
| 261 # . Centralised the python version check code, bumped version to 2.1.1 (really | |
| 262 # needs to be 2.1.2, but that isn't released yet :) | |
| 263 # | |
| 264 # Revision 1.21 2001/12/02 05:06:16 richard | |
| 265 # . We now use weakrefs in the Classes to keep the database reference, so | |
| 266 # the close() method on the database is no longer needed. | |
| 267 # I bumped the minimum python requirement up to 2.1 accordingly. | |
| 268 # . #487480 ] roundup-server | |
| 269 # . #487476 ] INSTALL.txt | |
| 270 # | |
| 271 # I also cleaned up the change message / post-edit stuff in the cgi client. | |
| 272 # There's now a clearly marked "TODO: append the change note" where I believe | |
| 273 # the change note should be added there. The "changes" list will obviously | |
| 274 # have to be modified to be a dict of the changes, or somesuch. | |
| 275 # | |
| 276 # More testing needed. | |
| 277 # | |
| 278 # Revision 1.20 2001/11/26 22:55:56 richard | |
| 279 # Feature: | |
| 280 # . Added INSTANCE_NAME to configuration - used in web and email to identify | |
| 281 # the instance. | |
| 282 # . Added EMAIL_SIGNATURE_POSITION to indicate where to place the roundup | |
| 283 # signature info in e-mails. | |
| 284 # . Some more flexibility in the mail gateway and more error handling. | |
| 285 # . Login now takes you to the page you back to the were denied access to. | |
| 286 # | |
| 287 # Fixed: | |
| 288 # . Lots of bugs, thanks Roché and others on the devel mailing list! | |
| 289 # | |
| 290 # Revision 1.19 2001/11/12 22:51:04 jhermann | |
| 291 # Fixed option & associated error handling | |
| 292 # | |
| 293 # Revision 1.18 2001/11/01 22:04:37 richard | |
| 294 # Started work on supporting a pop3-fetching server | |
| 295 # Fixed bugs: | |
| 296 # . bug #477104 ] HTML tag error in roundup-server | |
| 297 # . bug #477107 ] HTTP header problem | |
| 298 # | |
| 299 # Revision 1.17 2001/10/29 23:55:44 richard | |
| 300 # Fix to CGI top-level index (thanks Juergen Hermann) | |
| 301 # | |
| 302 # Revision 1.16 2001/10/27 00:12:21 richard | |
| 303 # Fixed roundup-server for windows, thanks Juergen Hermann. | |
| 304 # | |
| 305 # Revision 1.15 2001/10/12 02:23:26 richard | |
| 306 # Didn't clean up after myself :) | |
| 307 # | |
| 308 # Revision 1.14 2001/10/12 02:20:32 richard | |
| 309 # server now handles setuid'ing much better | |
| 310 # | |
| 311 # Revision 1.13 2001/10/05 02:23:24 richard | |
| 312 # . roundup-admin create now prompts for property info if none is supplied | |
| 313 # on the command-line. | |
| 314 # . hyperdb Class getprops() method may now return only the mutable | |
| 315 # properties. | |
| 316 # . Login now uses cookies, which makes it a whole lot more flexible. We can | |
| 317 # now support anonymous user access (read-only, unless there's an | |
| 318 # "anonymous" user, in which case write access is permitted). Login | |
| 319 # handling has been moved into cgi_client.Client.main() | |
| 320 # . The "extended" schema is now the default in roundup init. | |
| 321 # . The schemas have had their page headings modified to cope with the new | |
| 322 # login handling. Existing installations should copy the interfaces.py | |
| 323 # file from the roundup lib directory to their instance home. | |
| 324 # . Incorrectly had a Bizar Software copyright on the cgitb.py module from | |
| 325 # Ping - has been removed. | |
| 326 # . Fixed a whole bunch of places in the CGI interface where we should have | |
| 327 # been returning Not Found instead of throwing an exception. | |
| 328 # . Fixed a deviation from the spec: trying to modify the 'id' property of | |
| 329 # an item now throws an exception. | |
| 330 # | |
| 331 # Revision 1.12 2001/09/29 13:27:00 richard | |
| 332 # CGI interfaces now spit up a top-level index of all the instances they can | |
| 333 # serve. | |
| 334 # | |
| 335 # Revision 1.11 2001/08/07 00:24:42 richard | |
| 336 # stupid typo | |
| 337 # | |
| 338 # Revision 1.10 2001/08/07 00:15:51 richard | |
| 339 # Added the copyright/license notice to (nearly) all files at request of | |
| 340 # Bizar Software. | |
| 341 # | |
| 342 # Revision 1.9 2001/08/05 07:44:36 richard | |
| 343 # Instances are now opened by a special function that generates a unique | |
| 344 # module name for the instances on import time. | |
| 345 # | |
| 346 # Revision 1.8 2001/08/03 01:28:33 richard | |
| 347 # Used the much nicer load_package, pointed out by Steve Majewski. | |
| 348 # | |
| 349 # Revision 1.7 2001/08/03 00:59:34 richard | |
| 350 # Instance import now imports the instance using imp.load_module so that | |
| 351 # we can have instance homes of "roundup" or other existing python package | |
| 352 # names. | |
| 353 # | |
| 354 # Revision 1.6 2001/07/29 07:01:39 richard | |
| 355 # Added vim command to all source so that we don't get no steenkin' tabs :) | |
| 356 # | |
| 357 # Revision 1.5 2001/07/24 01:07:59 richard | |
| 358 # Added command-line arg handling to roundup-server so it's more useful | |
| 359 # out-of-the-box. | |
| 360 # | |
| 361 # Revision 1.4 2001/07/23 10:31:45 richard | |
| 362 # disabled the reloading until it can be done properly | |
| 363 # | |
| 364 # Revision 1.3 2001/07/23 08:53:44 richard | |
| 365 # Fixed the ROUNDUPS decl in roundup-server | |
| 366 # Move the installation notes to INSTALL | |
| 367 # | |
| 368 # Revision 1.2 2001/07/23 04:05:05 anthonybaxter | |
| 369 # actually quit if python version wrong | |
| 370 # | |
| 371 # Revision 1.1 2001/07/23 03:46:48 richard | |
| 372 # moving the bin files to facilitate out-of-the-boxness | |
| 373 # | |
| 374 # Revision 1.1 2001/07/22 11:15:45 richard | |
| 375 # More Grande Splite stuff | |
| 376 # | |
| 377 # | |
| 378 # vim: set filetype=python ts=4 sw=4 et si |
