Changeset 2485 for package_branches/invirt-web/cherrypy/code/main.py
- Timestamp:
- Sep 28, 2009, 3:04:33 AM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
package_branches/invirt-web/cherrypy/code/main.py
r2484 r2485 11 11 import random 12 12 import sha 13 import simplejson14 13 import sys 15 14 import threading … … 18 17 import socket 19 18 import cherrypy 19 from cherrypy import _cperror 20 20 from StringIO import StringIO 21 22 def revertStandardError():23 """Move stderr to stdout, and return the contents of the old stderr."""24 errio = sys.stderr25 if not isinstance(errio, StringIO):26 return ''27 sys.stderr = sys.stdout28 errio.seek(0)29 return errio.read()30 21 31 22 def printError(): … … 38 29 atexit.register(printError) 39 30 40 import templates41 from Cheetah.Template import Template42 31 import validation 43 32 import cache_acls … … 51 40 import invirt.remctl 52 41 53 from view import View 42 from view import View, revertStandardError 54 43 import ajaxterm 55 44 … … 65 54 connect() 66 55 self._cp_config['tools.require_login.on'] = True 56 self._cp_config['tools.catch_stderr.on'] = True 67 57 self._cp_config['tools.mako.imports'] = ['from invirt.config import structs as config', 68 58 'from invirt import database'] 59 self._cp_config['request.error_response'] = self.handle_error 60 61 @cherrypy.expose 62 @cherrypy.tools.mako(filename="/invalid.mako") 63 def invalidInput(self): 64 """Print an error page when an InvalidInput exception occurs""" 65 err = cherrypy.request.prev.params["err"] 66 emsg = cherrypy.request.prev.params["emsg"] 67 d = dict(err_field=err.err_field, 68 err_value=str(err.err_value), stderr=emsg, 69 errorMessage=str(err)) 70 return d 71 72 @cherrypy.expose 73 @cherrypy.tools.mako(filename="/error.mako") 74 def error(self): 75 #op, username, fields, err, emsg, traceback): 76 """Print an error page when an exception occurs""" 77 op = cherrypy.request.prev.path_info 78 username = cherrypy.request.login 79 err = cherrypy.request.prev.params["err"] 80 emsg = cherrypy.request.prev.params["emsg"] 81 traceback = cherrypy.request.prev.params["traceback"] 82 d = dict(op = op, user=username, fields=cherrypy.request.prev.params, 83 errorMessage=str(err), stderr=emsg, traceback=traceback) 84 error_raw = cherrypy.tools.mako.callable.get_lookup(**cherrypy.tools.mako._merged_args()).get_template("/error_raw.mako") 85 details = error_raw.render(**d) 86 exclude = config.web.errormail_exclude 87 if username not in exclude and '*' not in exclude: 88 send_error_mail('xvm error on %s for %s: %s' % (op, cherrypy.request.login, err), 89 details) 90 d['details'] = details 91 return d 69 92 70 93 def __getattr__(self, name): … … 77 100 else: 78 101 return super(InvirtWeb, self).__getattr__(name) 102 103 def handle_error(self): 104 err = sys.exc_info()[1] 105 if isinstance(err, InvalidInput): 106 e = revertStandardError() 107 cherrypy.request.params['err'] = err 108 cherrypy.request.params['emsg'] = e 109 raise cherrypy.InternalRedirect('/invalidInput') 110 if not cherrypy.request.prev or 'err' not in cherrypy.request.prev.params: 111 e = revertStandardError() 112 cherrypy.request.params['err'] = err 113 cherrypy.request.params['emsg'] = e 114 cherrypy.request.params['traceback'] = _cperror.format_exc() 115 raise cherrypy.InternalRedirect('/error') 116 # fall back to cherrypy default error page 117 cherrypy.HTTPError(500).set_response() 79 118 80 119 @cherrypy.expose … … 207 246 def errortest(self): 208 247 """Throw an error, to test the error-tracing mechanisms.""" 248 print >>sys.stderr, "look ma, it's a stderr" 209 249 raise RuntimeError("test of the emergency broadcast system") 210 250 … … 309 349 raise 310 350 print >> sys.stderr, err 311 result = err351 result = str(err) 312 352 else: 313 353 result = 'Success!' … … 373 413 machine = MachineView() 374 414 375 def pathSplit(path):376 if path.startswith('/'):377 path = path[1:]378 i = path.find('/')379 if i == -1:380 i = len(path)381 return path[:i], path[i:]382 383 415 class Checkpoint: 384 416 def __init__(self): … … 395 427 396 428 checkpoint = Checkpoint() 397 398 def makeErrorPre(old, addition):399 if addition is None:400 return401 if old:402 return old[:-6] + '\n----\n' + str(addition) + '</pre>'403 else:404 return '<p>STDERR:</p><pre>' + str(addition) + '</pre>'405 406 Template.database = database407 Template.config = config408 Template.err = None409 410 class JsonDict:411 """Class to store a dictionary that will be converted to JSON"""412 def __init__(self, **kws):413 self.data = kws414 if 'err' in kws:415 err = kws['err']416 del kws['err']417 self.addError(err)418 419 def __str__(self):420 return simplejson.dumps(self.data)421 422 def addError(self, text):423 """Add stderr text to be displayed on the website."""424 self.data['err'] = \425 makeErrorPre(self.data.get('err'), text)426 429 427 430 class Defaults: … … 443 446 for key in kws: 444 447 setattr(self, key, kws[key]) 445 446 447 448 DEFAULT_HEADERS = {'Content-Type': 'text/html'}449 450 def invalidInput(op, username, fields, err, emsg):451 """Print an error page when an InvalidInput exception occurs"""452 d = dict(op=op, user=username, err_field=err.err_field,453 err_value=str(err.err_value), stderr=emsg,454 errorMessage=str(err))455 return templates.invalid(searchList=[d])456 448 457 449 def hasVnc(status): … … 623 615 return dict(machine=machine) 624 616 625 626 def badOperation(u, s, p, e):627 """Function called when accessing an unknown URI."""628 return ({'Status': '404 Not Found'}, 'Invalid operation.')629 630 617 def infoDict(username, state, machine): 631 618 """Get the variables used by info.tmpl.""" … … 716 703 return d 717 704 718 mapping = dict()719 720 def printHeaders(headers):721 """Print a dictionary as HTTP headers."""722 for key, value in headers.iteritems():723 print '%s: %s' % (key, value)724 print725 726 705 def send_error_mail(subject, body): 727 706 import subprocess … … 740 719 p.wait() 741 720 742 def show_error(op, username, fields, err, emsg, traceback): 743 """Print an error page when an exception occurs""" 744 d = dict(op=op, user=username, fields=fields, 745 errorMessage=str(err), stderr=emsg, traceback=traceback) 746 details = templates.error_raw(searchList=[d]) 747 exclude = config.web.errormail_exclude 748 if username not in exclude and '*' not in exclude: 749 send_error_mail('xvm error on %s for %s: %s' % (op, username, err), 750 details) 751 d['details'] = details 752 return templates.error(searchList=[d]) 753 754 def handler(username, state, path, fields): 755 operation, path = pathSplit(path) 756 if not operation: 757 operation = 'list' 758 print 'Starting', operation 759 fun = mapping.get(operation, badOperation) 760 return fun(username, state, path, fields) 761 762 class App: 763 def __init__(self, environ, start_response): 764 self.environ = environ 765 self.start = start_response 766 767 self.username = getUser(environ) 768 self.state = State(self.username) 769 self.state.environ = environ 770 771 random.seed() #sigh 772 773 def __iter__(self): 774 start_time = time.time() 775 database.clear_cache() 776 sys.stderr = StringIO() 777 fields = cgi.FieldStorage(fp=self.environ['wsgi.input'], environ=self.environ) 778 operation = self.environ.get('PATH_INFO', '') 779 if not operation: 780 self.start("301 Moved Permanently", [('Location', './')]) 781 return 782 if self.username is None: 783 operation = 'unauth' 784 785 try: 786 checkpoint.checkpoint('Before') 787 output = handler(self.username, self.state, operation, fields) 788 checkpoint.checkpoint('After') 789 790 headers = dict(DEFAULT_HEADERS) 791 if isinstance(output, tuple): 792 new_headers, output = output 793 headers.update(new_headers) 794 e = revertStandardError() 795 if e: 796 if hasattr(output, 'addError'): 797 output.addError(e) 798 else: 799 # This only happens on redirects, so it'd be a pain to get 800 # the message to the user. Maybe in the response is useful. 801 output = output + '\n\nstderr:\n' + e 802 output_string = str(output) 803 checkpoint.checkpoint('output as a string') 804 except Exception, err: 805 if not fields.has_key('js'): 806 if isinstance(err, InvalidInput): 807 self.start('200 OK', [('Content-Type', 'text/html')]) 808 e = revertStandardError() 809 yield str(invalidInput(operation, self.username, fields, 810 err, e)) 811 return 812 import traceback 813 self.start('500 Internal Server Error', 814 [('Content-Type', 'text/html')]) 815 e = revertStandardError() 816 s = show_error(operation, self.username, fields, 817 err, e, traceback.format_exc()) 818 yield str(s) 819 return 820 status = headers.setdefault('Status', '200 OK') 821 del headers['Status'] 822 self.start(status, headers.items()) 823 yield output_string 824 if fields.has_key('timedebug'): 825 yield '<pre>%s</pre>' % cgi.escape(str(checkpoint)) 826 827 def constructor(): 828 connect() 829 return App 830 831 def main(): 832 from flup.server.fcgi_fork import WSGIServer 833 WSGIServer(constructor()).run() 834 835 if __name__ == '__main__': 836 main() 721 random.seed()
Note: See TracChangeset
for help on using the changeset viewer.