Changeset 2693
- Timestamp:
- Dec 20, 2009, 9:45:52 PM (15 years ago)
- Location:
- package_branches/invirt-web/cherrypy-rebased
- Files:
-
- 2 added
- 2 deleted
- 4 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
package_branches/invirt-web/cherrypy-rebased/code/main.py
r2692 r2693 9 9 import random 10 10 import sha 11 import simplejson12 11 import sys 13 12 import time … … 15 14 import socket 16 15 import cherrypy 16 from cherrypy import _cperror 17 17 from StringIO import StringIO 18 def revertStandardError():19 """Move stderr to stdout, and return the contents of the old stderr."""20 errio = sys.stderr21 if not isinstance(errio, StringIO):22 return ''23 sys.stderr = sys.stdout24 errio.seek(0)25 return errio.read()26 18 27 19 def printError(): … … 34 26 atexit.register(printError) 35 27 36 import templates37 from Cheetah.Template import Template38 28 import validation 39 29 import cache_acls … … 46 36 from invirt.common import InvalidInput, CodeError 47 37 48 from view import View 38 from view import View, revertStandardError 49 39 50 40 class InvirtUnauthWeb(View): … … 59 49 connect() 60 50 self._cp_config['tools.require_login.on'] = True 51 self._cp_config['tools.catch_stderr.on'] = True 61 52 self._cp_config['tools.mako.imports'] = ['from invirt.config import structs as config', 62 53 'from invirt import database'] 54 self._cp_config['request.error_response'] = self.handle_error 55 56 @cherrypy.expose 57 @cherrypy.tools.mako(filename="/invalid.mako") 58 def invalidInput(self): 59 """Print an error page when an InvalidInput exception occurs""" 60 err = cherrypy.request.prev.params["err"] 61 emsg = cherrypy.request.prev.params["emsg"] 62 d = dict(err_field=err.err_field, 63 err_value=str(err.err_value), stderr=emsg, 64 errorMessage=str(err)) 65 return d 66 67 @cherrypy.expose 68 @cherrypy.tools.mako(filename="/error.mako") 69 def error(self): 70 #op, username, fields, err, emsg, traceback): 71 """Print an error page when an exception occurs""" 72 op = cherrypy.request.prev.path_info 73 username = cherrypy.request.login 74 err = cherrypy.request.prev.params["err"] 75 emsg = cherrypy.request.prev.params["emsg"] 76 traceback = cherrypy.request.prev.params["traceback"] 77 d = dict(op = op, user=username, fields=cherrypy.request.prev.params, 78 errorMessage=str(err), stderr=emsg, traceback=traceback) 79 error_raw = cherrypy.tools.mako.callable.get_lookup(**cherrypy.tools.mako._merged_args()).get_template("/error_raw.mako") 80 details = error_raw.render(**d) 81 exclude = config.web.errormail_exclude 82 if username not in exclude and '*' not in exclude: 83 send_error_mail('xvm error on %s for %s: %s' % (op, cherrypy.request.login, err), 84 details) 85 d['details'] = details 86 return d 63 87 64 88 def __getattr__(self, name): … … 71 95 else: 72 96 return super(InvirtWeb, self).__getattr__(name) 97 98 def handle_error(self): 99 err = sys.exc_info()[1] 100 if isinstance(err, InvalidInput): 101 e = revertStandardError() 102 cherrypy.request.params['err'] = err 103 cherrypy.request.params['emsg'] = e 104 raise cherrypy.InternalRedirect('/invalidInput') 105 if not cherrypy.request.prev or 'err' not in cherrypy.request.prev.params: 106 e = revertStandardError() 107 cherrypy.request.params['err'] = err 108 cherrypy.request.params['emsg'] = e 109 cherrypy.request.params['traceback'] = _cperror.format_exc() 110 raise cherrypy.InternalRedirect('/error') 111 # fall back to cherrypy default error page 112 cherrypy.HTTPError(500).set_response() 73 113 74 114 @cherrypy.expose … … 201 241 def errortest(self): 202 242 """Throw an error, to test the error-tracing mechanisms.""" 243 print >>sys.stderr, "look ma, it's a stderr" 203 244 raise RuntimeError("test of the emergency broadcast system") 204 245 … … 303 344 raise 304 345 print >> sys.stderr, err 305 result = err346 result = str(err) 306 347 else: 307 348 result = 'Success!' … … 318 359 machine = MachineView() 319 360 320 def pathSplit(path):321 if path.startswith('/'):322 path = path[1:]323 i = path.find('/')324 if i == -1:325 i = len(path)326 return path[:i], path[i:]327 328 361 class Checkpoint: 329 362 def __init__(self): … … 340 373 341 374 checkpoint = Checkpoint() 342 343 def makeErrorPre(old, addition):344 if addition is None:345 return346 if old:347 return old[:-6] + '\n----\n' + str(addition) + '</pre>'348 else:349 return '<p>STDERR:</p><pre>' + str(addition) + '</pre>'350 351 Template.database = database352 Template.config = config353 Template.err = None354 355 class JsonDict:356 """Class to store a dictionary that will be converted to JSON"""357 def __init__(self, **kws):358 self.data = kws359 if 'err' in kws:360 err = kws['err']361 del kws['err']362 self.addError(err)363 364 def __str__(self):365 return simplejson.dumps(self.data)366 367 def addError(self, text):368 """Add stderr text to be displayed on the website."""369 self.data['err'] = \370 makeErrorPre(self.data.get('err'), text)371 375 372 376 class Defaults: … … 388 392 for key in kws: 389 393 setattr(self, key, kws[key]) 390 391 392 393 DEFAULT_HEADERS = {'Content-Type': 'text/html'}394 395 def invalidInput(op, username, fields, err, emsg):396 """Print an error page when an InvalidInput exception occurs"""397 d = dict(op=op, user=username, err_field=err.err_field,398 err_value=str(err.err_value), stderr=emsg,399 errorMessage=str(err))400 return templates.invalid(searchList=[d])401 394 402 395 def hasVnc(status): … … 568 561 return dict(machine=machine) 569 562 570 571 def badOperation(u, s, p, e):572 """Function called when accessing an unknown URI."""573 return ({'Status': '404 Not Found'}, 'Invalid operation.')574 575 563 def infoDict(username, state, machine): 576 564 """Get the variables used by info.tmpl.""" … … 661 649 return d 662 650 663 mapping = dict()664 665 def printHeaders(headers):666 """Print a dictionary as HTTP headers."""667 for key, value in headers.iteritems():668 print '%s: %s' % (key, value)669 print670 671 651 def send_error_mail(subject, body): 672 652 import subprocess … … 685 665 p.wait() 686 666 687 def show_error(op, username, fields, err, emsg, traceback): 688 """Print an error page when an exception occurs""" 689 d = dict(op=op, user=username, fields=fields, 690 errorMessage=str(err), stderr=emsg, traceback=traceback) 691 details = templates.error_raw(searchList=[d]) 692 exclude = config.web.errormail_exclude 693 if username not in exclude and '*' not in exclude: 694 send_error_mail('xvm error on %s for %s: %s' % (op, username, err), 695 details) 696 d['details'] = details 697 return templates.error(searchList=[d]) 698 699 def handler(username, state, path, fields): 700 operation, path = pathSplit(path) 701 if not operation: 702 operation = 'list' 703 print 'Starting', operation 704 fun = mapping.get(operation, badOperation) 705 return fun(username, state, path, fields) 706 707 class App: 708 def __init__(self, environ, start_response): 709 self.environ = environ 710 self.start = start_response 711 712 self.username = getUser(environ) 713 self.state = State(self.username) 714 self.state.environ = environ 715 716 random.seed() #sigh 717 718 def __iter__(self): 719 start_time = time.time() 720 database.clear_cache() 721 sys.stderr = StringIO() 722 fields = cgi.FieldStorage(fp=self.environ['wsgi.input'], environ=self.environ) 723 operation = self.environ.get('PATH_INFO', '') 724 if not operation: 725 self.start("301 Moved Permanently", [('Location', './')]) 726 return 727 if self.username is None: 728 operation = 'unauth' 729 730 try: 731 checkpoint.checkpoint('Before') 732 output = handler(self.username, self.state, operation, fields) 733 checkpoint.checkpoint('After') 734 735 headers = dict(DEFAULT_HEADERS) 736 if isinstance(output, tuple): 737 new_headers, output = output 738 headers.update(new_headers) 739 e = revertStandardError() 740 if e: 741 if hasattr(output, 'addError'): 742 output.addError(e) 743 else: 744 # This only happens on redirects, so it'd be a pain to get 745 # the message to the user. Maybe in the response is useful. 746 output = output + '\n\nstderr:\n' + e 747 output_string = str(output) 748 checkpoint.checkpoint('output as a string') 749 except Exception, err: 750 if not fields.has_key('js'): 751 if isinstance(err, InvalidInput): 752 self.start('200 OK', [('Content-Type', 'text/html')]) 753 e = revertStandardError() 754 yield str(invalidInput(operation, self.username, fields, 755 err, e)) 756 return 757 import traceback 758 self.start('500 Internal Server Error', 759 [('Content-Type', 'text/html')]) 760 e = revertStandardError() 761 s = show_error(operation, self.username, fields, 762 err, e, traceback.format_exc()) 763 yield str(s) 764 return 765 status = headers.setdefault('Status', '200 OK') 766 del headers['Status'] 767 self.start(status, headers.items()) 768 yield output_string 769 if fields.has_key('timedebug'): 770 yield '<pre>%s</pre>' % cgi.escape(str(checkpoint)) 771 772 def constructor(): 773 connect() 774 return App 775 776 def main(): 777 from flup.server.fcgi_fork import WSGIServer 778 WSGIServer(constructor()).run() 779 780 if __name__ == '__main__': 781 main() 667 random.seed() -
package_branches/invirt-web/cherrypy-rebased/code/templates/error.mako
r2692 r2693 1 #from skeleton import skeleton 2 #extends skeleton 1 <%page expression_filter="h"/> 2 <%inherit file="skeleton.mako" /> 3 3 4 #def title 4 <%def name="title()"> 5 5 ERROR! 6 #end def 6 </%def> 7 7 8 #def body9 8 <p>Uh-oh! We experienced an error. Sorry about that. We've gotten 10 9 mail about it.</p> … … 16 15 17 16 <pre> 18 $ details17 ${details} 19 18 </pre> 20 #end def -
package_branches/invirt-web/cherrypy-rebased/code/view.py
r2690 r2693 1 import os 1 import os, sys 2 2 3 3 import cherrypy … … 6 6 import simplejson 7 7 import datetime, decimal 8 from StringIO import StringIO 8 9 from invirt.config import structs as config 9 10 from webcommon import State … … 28 29 def __init__(self): 29 30 self.lookups = {} 30 31 def __call__(self, filename, directories, module_directory=None, 32 collection_size=-1, content_type='text/html; charset=utf-8', 33 imports=[]): 31 32 def get_lookup(self, directories, module_directory=None, 33 collection_size=-1, imports=[], **kwargs): 34 34 # Find the appropriate template lookup. 35 35 key = (tuple(directories), module_directory) … … 46 46 ) 47 47 self.lookups[key] = lookup 48 cherrypy.request.lookup = lookup 48 return lookup 49 50 def __call__(self, filename, directories, module_directory=None, 51 collection_size=-1, content_type='text/html; charset=utf-8', 52 imports=[]): 53 cherrypy.request.lookup = lookup = self.get_lookup(directories, module_directory, 54 collection_size, imports) 49 55 50 56 # Replace the current handler. … … 54 60 main = MakoLoader() 55 61 cherrypy.tools.mako = cherrypy.Tool('on_start_resource', main) 62 63 def revertStandardError(): 64 """Move stderr to stdout, and return the contents of the old stderr.""" 65 errio = sys.stderr 66 if not isinstance(errio, StringIO): 67 return '' 68 sys.stderr = sys.stdout 69 errio.seek(0) 70 return errio.read() 71 72 def catchStderr(): 73 old_handler = cherrypy.request.handler 74 def wrapper(*args, **kwargs): 75 sys.stderr = StringIO() 76 ret = old_handler(*args, **kwargs) 77 e = revertStandardError() 78 if e: 79 if isinstance(ret, dict): 80 ret["error_text"] = e 81 return ret 82 if old_handler: 83 cherrypy.request.handler = wrapper 84 85 cherrypy.tools.catch_stderr = cherrypy.Tool('before_handler', catchStderr) 56 86 57 87 class JSONEncoder(simplejson.JSONEncoder): -
package_branches/invirt-web/cherrypy-rebased/debian/changelog
r2658 r2693 3 3 * Depend on python-cherrypy3 and python-mako in preparation of migrating the 4 4 web site. 5 6 -- Quentin Smith <quentin@mit.edu> Sat, 02 May 2009 22:32:53 -0400 5 * Remove dependency on python-cheetah 6 7 -- Quentin Smith <quentin@mit.edu> Mon, 28 Sep 2009 01:26:06 -0400 7 8 8 9 invirt-web (0.0.24) unstable; urgency=low -
package_branches/invirt-web/cherrypy-rebased/debian/control
r2658 r2693 17 17 debathena-ssl-certificates, 18 18 # python libraries 19 python-flup, python- cheetah, python-simplejson,19 python-flup, python-simplejson, 20 20 python-dns, python-dnspython, python-cherrypy3, 21 21 python-mako,
Note: See TracChangeset
for help on using the changeset viewer.