/pyramid_debugtoolbar/views.py

https://bitbucket.org/biideal/pyramid_debugtoolbar · Python · 195 lines · 164 code · 29 blank · 2 comment · 24 complexity · 926ac76c4c9e968ccb7e53961a9a1161 MD5 · raw file

  1. import hashlib
  2. from pyramid.httpexceptions import HTTPBadRequest
  3. from pyramid.security import NO_PERMISSION_REQUIRED
  4. from pyramid.response import Response
  5. from pyramid.view import view_config
  6. from pyramid_debugtoolbar.compat import json
  7. from pyramid_debugtoolbar.compat import bytes_
  8. from pyramid_debugtoolbar.compat import url_quote
  9. from pyramid_debugtoolbar.console import _ConsoleFrame
  10. from pyramid_debugtoolbar.utils import STATIC_PATH
  11. from pyramid_debugtoolbar.utils import ROOT_ROUTE_NAME
  12. from pyramid_debugtoolbar.utils import format_sql
  13. from pyramid_debugtoolbar.utils import get_setting
  14. from pyramid_debugtoolbar.utils import addr_in
  15. from pyramid_debugtoolbar.utils import last_proxy
  16. from pyramid_debugtoolbar.toolbar import IRequestAuthorization
  17. def valid_host(info, request):
  18. hosts = get_setting(request.registry.settings, 'hosts')
  19. if request.remote_addr is None:
  20. return False
  21. last_proxy_addr = last_proxy(request.remote_addr)
  22. return addr_in(last_proxy_addr, hosts)
  23. def valid_request(info, request):
  24. auth_check = request.registry.queryUtility(IRequestAuthorization)
  25. return auth_check(request) if auth_check else True
  26. class ExceptionDebugView(object):
  27. def __init__(self, request):
  28. self.request = request
  29. exc_history = request.exc_history
  30. if exc_history is None:
  31. raise HTTPBadRequest('No exception history')
  32. self.exc_history = exc_history
  33. token = self.request.params.get('token')
  34. if not token:
  35. raise HTTPBadRequest('No token in request')
  36. if not token == self.exc_history.token:
  37. raise HTTPBadRequest('Bad token in request')
  38. frm = self.request.params.get('frm')
  39. if frm is not None:
  40. frm = int(frm)
  41. self.frame = frm
  42. cmd = self.request.params.get('cmd')
  43. self.cmd = cmd
  44. tb = self.request.params.get('tb')
  45. if tb is not None:
  46. tb = int(tb)
  47. self.tb = tb
  48. @view_config(
  49. route_name='debugtoolbar.exception',
  50. permission=NO_PERMISSION_REQUIRED,
  51. custom_predicates=(valid_host, valid_request)
  52. )
  53. def exception(self):
  54. tb = self.exc_history.tracebacks[self.tb]
  55. body = tb.render_full(self.request).encode('utf-8', 'replace')
  56. response = Response(body, status=500)
  57. return response
  58. @view_config(
  59. route_name='debugtoolbar.source',
  60. permission=NO_PERMISSION_REQUIRED,
  61. custom_predicates=(valid_host, valid_request)
  62. )
  63. def source(self):
  64. exc_history = self.exc_history
  65. if self.frame is not None:
  66. frame = exc_history.frames.get(self.frame)
  67. if frame is not None:
  68. return Response(frame.render_source(), content_type='text/html')
  69. return HTTPBadRequest()
  70. @view_config(
  71. route_name='debugtoolbar.execute',
  72. permission=NO_PERMISSION_REQUIRED,
  73. custom_predicates=(valid_host, valid_request)
  74. )
  75. def execute(self):
  76. if self.request.exc_history.eval_exc:
  77. exc_history = self.exc_history
  78. if self.frame is not None and self.cmd is not None:
  79. frame = exc_history.frames.get(self.frame)
  80. if frame is not None:
  81. result = frame.console.eval(self.cmd)
  82. return Response(result, content_type='text/html')
  83. return HTTPBadRequest()
  84. @view_config(
  85. route_name='debugtoolbar.console',
  86. renderer='pyramid_debugtoolbar:templates/console.dbtmako',
  87. custom_predicates=(valid_host, valid_request)
  88. )
  89. def console(self):
  90. static_path = self.request.static_url(STATIC_PATH)
  91. toolbar_root_path = self.request.route_url(ROOT_ROUTE_NAME)
  92. exc_history = self.exc_history
  93. vars = {
  94. 'evalex': exc_history.eval_exc and 'true' or 'false',
  95. 'console': 'true',
  96. 'title': 'Console',
  97. 'traceback_id': self.tb or -1,
  98. 'root_path': toolbar_root_path,
  99. 'static_path': static_path,
  100. 'token': exc_history.token,
  101. }
  102. if 0 not in exc_history.frames:
  103. exc_history.frames[0] = _ConsoleFrame({})
  104. return vars
  105. class SQLAlchemyViews(object):
  106. def __init__(self, request):
  107. self.request = request
  108. def validate(self):
  109. stmt = self.request.params['sql']
  110. params = self.request.params['params']
  111. # Validate hash
  112. need = self.request.exc_history.token + stmt + url_quote(params)
  113. hash = hashlib.sha1(bytes_(need)).hexdigest()
  114. if hash != self.request.params['hash']:
  115. raise HTTPBadRequest('Bad token in request')
  116. return stmt, params
  117. @view_config(
  118. route_name='debugtoolbar.sql_select',
  119. renderer='pyramid_debugtoolbar.panels:templates/sqlalchemy_select.dbtmako',
  120. permission=NO_PERMISSION_REQUIRED,
  121. custom_predicates=(valid_host, valid_request)
  122. )
  123. def sql_select(self):
  124. stmt, params = self.validate()
  125. engine_id = self.request.params['engine_id']
  126. # Make sure it is a select statement
  127. if not stmt.lower().strip().startswith('select'):
  128. raise HTTPBadRequest('Not a SELECT SQL statement')
  129. if not engine_id:
  130. raise HTTPBadRequest('No valid database engine')
  131. engine = getattr(self.request.registry, 'pdtb_sqla_engines')\
  132. [int(engine_id)]()
  133. params = [json.loads(params)]
  134. result = engine.execute(stmt, params)
  135. return {
  136. 'result': result.fetchall(),
  137. 'headers': result.keys(),
  138. 'sql': format_sql(stmt),
  139. 'duration': float(self.request.params['duration']),
  140. }
  141. @view_config(
  142. route_name='debugtoolbar.sql_explain',
  143. renderer='pyramid_debugtoolbar.panels:templates/sqlalchemy_explain.dbtmako',
  144. permission=NO_PERMISSION_REQUIRED,
  145. custom_predicates=(valid_host, valid_request)
  146. )
  147. def sql_explain(self):
  148. stmt, params = self.validate()
  149. engine_id = self.request.params['engine_id']
  150. if not engine_id:
  151. raise HTTPBadRequest('No valid database engine')
  152. engine = getattr(self.request.registry, 'pdtb_sqla_engines')\
  153. [int(engine_id)]()
  154. params = json.loads(params)
  155. if engine.name.startswith('sqlite'):
  156. query = 'EXPLAIN QUERY PLAN %s' % stmt
  157. else:
  158. query = 'EXPLAIN %s' % stmt
  159. result = engine.execute(query, params)
  160. return {
  161. 'result': result.fetchall(),
  162. 'headers': result.keys(),
  163. 'sql': format_sql(stmt),
  164. 'str': str,
  165. 'duration': float(self.request.params['duration']),
  166. }