comparison tincan.py @ 70:a78c74c73d98 draft

Get rid of bogus "None" messages in the standard error pages.
author David Barts <n5jrn@me.com>
date Mon, 15 Jul 2019 13:13:46 -0700
parents c168aad7a731
children
comparison
equal deleted inserted replaced
69:c168aad7a731 70:a78c74c73d98
219 chameleon_template = functools.partial(bottle.template, template_adapter=ChameleonTemplate) 219 chameleon_template = functools.partial(bottle.template, template_adapter=ChameleonTemplate)
220 chameleon_view = functools.partial(bottle.view, template_adapter=ChameleonTemplate) 220 chameleon_view = functools.partial(bottle.view, template_adapter=ChameleonTemplate)
221 221
222 # U t i l i t i e s 222 # U t i l i t i e s
223 223
224 def _hterror(**kwargs):
225 """
226 Make a suitable bottle.HttpError object, with a message that is
227 always meaningful.
228 """
229 if "status" not in kwargs:
230 raise ValueError("status argument is mandatory")
231 if "body" not in kwargs:
232 kwargs["body"] = "No further details available."
233 return bottle.HTTPError(**kwargs)
234
224 def _normpath(base, unsplit): 235 def _normpath(base, unsplit):
225 """ 236 """
226 Split, normalize and ensure a possibly relative path is absolute. First 237 Split, normalize and ensure a possibly relative path is absolute. First
227 argument is a list of directory names, defining a base. Second 238 argument is a list of directory names, defining a base. Second
228 argument is a string, which may either be relative to that base, or 239 argument is a string, which may either be relative to that base, or
480 try: 491 try:
481 with open(self._fspath, "rb") as fp: 492 with open(self._fspath, "rb") as fp:
482 mtime = os.fstat(fp.fileno()).st_mtime 493 mtime = os.fstat(fp.fileno()).st_mtime
483 bytes = fp.read() 494 bytes = fp.read()
484 except FileNotFoundError as e: 495 except FileNotFoundError as e:
485 return bottle.HTTPError(status=404, exception=e) 496 return _hterror(status=404, exception=e)
486 except PermissionError as e: 497 except PermissionError as e:
487 return bottle.HTTPError(status=403, exception=e) 498 return _hterror(status=403, exception=e)
488 except OSError as e: 499 except OSError as e:
489 self.logger.exception("unexpected exception reading %r", self._fspath) 500 self.logger.exception("unexpected exception reading %r", self._fspath)
490 return bottle.HTTPError(status=500, exception=e) 501 return _hterror(status=500, exception=e)
491 # Establish preliminary standard headers. 502 # Establish preliminary standard headers.
492 headers = { 503 headers = {
493 "Content-Type": self._type, 504 "Content-Type": self._type,
494 "Last-Modified": time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(mtime)), 505 "Last-Modified": time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(mtime)),
495 } 506 }
537 # Bottle doesn't allow error handlers to themselves cause 548 # Bottle doesn't allow error handlers to themselves cause
538 # errors, most likely as a measure to prevent looping. So 549 # errors, most likely as a measure to prevent looping. So
539 # this will cause a "Critical error while processing request" 550 # this will cause a "Critical error while processing request"
540 # page to be displayed, and any installed error pages to be 551 # page to be displayed, and any installed error pages to be
541 # ignored. 552 # ignored.
542 raise bottle.HTTPError(status=500, exception=e) 553 raise _hterror(status=500, exception=e)
543 554
544 class _TinCanRoute(_TinCanBaseRoute): 555 class _TinCanRoute(_TinCanBaseRoute):
545 """ 556 """
546 A route created by the TinCan launcher. 557 A route created by the TinCan launcher.
547 """ 558 """
789 target = fwd.target 800 target = fwd.target
790 except bottle.HTTPResponse as e: 801 except bottle.HTTPResponse as e:
791 return e 802 return e
792 except Exception as e: 803 except Exception as e:
793 self.logger.exception("%s: unexpected exception", self._urlpath) 804 self.logger.exception("%s: unexpected exception", self._urlpath)
794 raise bottle.HTTPError(status=500, exception=e) 805 raise _hterror(status=500, exception=e)
795 if target is None: 806 if target is None:
796 self.logger.error("%s: unexpected null target", self._urlpath) 807 message = "{0}: unexpected null target".format(self._urlpath)
797 raise bottle.HTTPError(status=500, exception=TinCanError(message)) 808 self.logger.error(message)
809 raise _hterror(status=500, exception=TinCanError(message))
798 # We get here if we are doing a server-side programmatic 810 # We get here if we are doing a server-side programmatic
799 # forward. 811 # forward.
800 environ = bottle.request.environ 812 environ = bottle.request.environ
801 if _FORIG not in environ: 813 if _FORIG not in environ:
802 environ[_FORIG] = self._urlpath 814 environ[_FORIG] = self._urlpath
803 if _FLOOP not in environ: 815 if _FLOOP not in environ:
804 environ[_FLOOP] = set([self._urlpath]) 816 environ[_FLOOP] = set([self._urlpath])
805 elif target in environ[_FLOOP]: 817 elif target in environ[_FLOOP]:
806 self.logger.error("%s: forward loop detected", environ[_FORIG]) 818 message = "{0}: forward loop detected".format(environ[_FORIG])
807 raise bottle.HTTPError(status=500, exception=TinCanError(message)) 819 self.logger.error(message)
820 raise _hterror(status=500, exception=TinCanError(message))
808 environ[_FLOOP].add(target) 821 environ[_FLOOP].add(target)
809 environ['bottle.raw_path'] = target 822 environ['bottle.raw_path'] = target
810 environ['PATH_INFO'] = urllib.parse.quote(target) 823 environ['PATH_INFO'] = urllib.parse.quote(target)
811 route, args = self._app.router.match(environ) 824 route, args = self._app.router.match(environ)
812 environ['route.handle'] = environ['bottle.route'] = route 825 environ['route.handle'] = environ['bottle.route'] = route