views.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. import datetime
  2. import decimal
  3. import logging
  4. import sys
  5. from django.core.exceptions import (
  6. BadRequest, PermissionDenied, SuspiciousOperation,
  7. )
  8. from django.http import Http404, HttpResponse, JsonResponse
  9. from django.shortcuts import render
  10. from django.template import TemplateDoesNotExist
  11. from django.urls import get_resolver
  12. from django.views import View
  13. from django.views.debug import (
  14. ExceptionReporter, SafeExceptionReporterFilter, technical_500_response,
  15. )
  16. from django.views.decorators.debug import (
  17. sensitive_post_parameters, sensitive_variables,
  18. )
  19. def index_page(request):
  20. """Dummy index page"""
  21. return HttpResponse('<html><body>Dummy page</body></html>')
  22. def with_parameter(request, parameter):
  23. return HttpResponse('ok')
  24. def raises(request):
  25. # Make sure that a callable that raises an exception in the stack frame's
  26. # local vars won't hijack the technical 500 response (#15025).
  27. def callable():
  28. raise Exception
  29. try:
  30. raise Exception
  31. except Exception:
  32. return technical_500_response(request, *sys.exc_info())
  33. def raises500(request):
  34. # We need to inspect the HTML generated by the fancy 500 debug view but
  35. # the test client ignores it, so we send it explicitly.
  36. try:
  37. raise Exception
  38. except Exception:
  39. return technical_500_response(request, *sys.exc_info())
  40. def raises400(request):
  41. raise SuspiciousOperation
  42. def raises400_bad_request(request):
  43. raise BadRequest('Malformed request syntax')
  44. def raises403(request):
  45. raise PermissionDenied("Insufficient Permissions")
  46. def raises404(request):
  47. resolver = get_resolver(None)
  48. resolver.resolve('/not-in-urls')
  49. def technical404(request):
  50. raise Http404("Testing technical 404.")
  51. class Http404View(View):
  52. def get(self, request):
  53. raise Http404("Testing class-based technical 404.")
  54. def template_exception(request):
  55. return render(request, 'debug/template_exception.html')
  56. def jsi18n(request):
  57. return render(request, 'jsi18n.html')
  58. def jsi18n_multi_catalogs(request):
  59. return render(request, 'jsi18n-multi-catalogs.html')
  60. def raises_template_does_not_exist(request, path='i_dont_exist.html'):
  61. # We need to inspect the HTML generated by the fancy 500 debug view but
  62. # the test client ignores it, so we send it explicitly.
  63. try:
  64. return render(request, path)
  65. except TemplateDoesNotExist:
  66. return technical_500_response(request, *sys.exc_info())
  67. def render_no_template(request):
  68. # If we do not specify a template, we need to make sure the debug
  69. # view doesn't blow up.
  70. return render(request, [], {})
  71. def send_log(request, exc_info):
  72. logger = logging.getLogger('django')
  73. # The default logging config has a logging filter to ensure admin emails are
  74. # only sent with DEBUG=False, but since someone might choose to remove that
  75. # filter, we still want to be able to test the behavior of error emails
  76. # with DEBUG=True. So we need to remove the filter temporarily.
  77. admin_email_handler = [
  78. h for h in logger.handlers
  79. if h.__class__.__name__ == "AdminEmailHandler"
  80. ][0]
  81. orig_filters = admin_email_handler.filters
  82. admin_email_handler.filters = []
  83. admin_email_handler.include_html = True
  84. logger.error(
  85. 'Internal Server Error: %s', request.path,
  86. exc_info=exc_info,
  87. extra={'status_code': 500, 'request': request},
  88. )
  89. admin_email_handler.filters = orig_filters
  90. def non_sensitive_view(request):
  91. # Do not just use plain strings for the variables' values in the code
  92. # so that the tests don't return false positives when the function's source
  93. # is displayed in the exception report.
  94. cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA
  95. sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA
  96. try:
  97. raise Exception
  98. except Exception:
  99. exc_info = sys.exc_info()
  100. send_log(request, exc_info)
  101. return technical_500_response(request, *exc_info)
  102. @sensitive_variables('sauce')
  103. @sensitive_post_parameters('bacon-key', 'sausage-key')
  104. def sensitive_view(request):
  105. # Do not just use plain strings for the variables' values in the code
  106. # so that the tests don't return false positives when the function's source
  107. # is displayed in the exception report.
  108. cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA
  109. sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA
  110. try:
  111. raise Exception
  112. except Exception:
  113. exc_info = sys.exc_info()
  114. send_log(request, exc_info)
  115. return technical_500_response(request, *exc_info)
  116. @sensitive_variables()
  117. @sensitive_post_parameters()
  118. def paranoid_view(request):
  119. # Do not just use plain strings for the variables' values in the code
  120. # so that the tests don't return false positives when the function's source
  121. # is displayed in the exception report.
  122. cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA
  123. sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA
  124. try:
  125. raise Exception
  126. except Exception:
  127. exc_info = sys.exc_info()
  128. send_log(request, exc_info)
  129. return technical_500_response(request, *exc_info)
  130. def sensitive_args_function_caller(request):
  131. try:
  132. sensitive_args_function(''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']))
  133. except Exception:
  134. exc_info = sys.exc_info()
  135. send_log(request, exc_info)
  136. return technical_500_response(request, *exc_info)
  137. @sensitive_variables('sauce')
  138. def sensitive_args_function(sauce):
  139. # Do not just use plain strings for the variables' values in the code
  140. # so that the tests don't return false positives when the function's source
  141. # is displayed in the exception report.
  142. cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA
  143. raise Exception
  144. def sensitive_kwargs_function_caller(request):
  145. try:
  146. sensitive_kwargs_function(''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']))
  147. except Exception:
  148. exc_info = sys.exc_info()
  149. send_log(request, exc_info)
  150. return technical_500_response(request, *exc_info)
  151. @sensitive_variables('sauce')
  152. def sensitive_kwargs_function(sauce=None):
  153. # Do not just use plain strings for the variables' values in the code
  154. # so that the tests don't return false positives when the function's source
  155. # is displayed in the exception report.
  156. cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA
  157. raise Exception
  158. class UnsafeExceptionReporterFilter(SafeExceptionReporterFilter):
  159. """
  160. Ignores all the filtering done by its parent class.
  161. """
  162. def get_post_parameters(self, request):
  163. return request.POST
  164. def get_traceback_frame_variables(self, request, tb_frame):
  165. return tb_frame.f_locals.items()
  166. @sensitive_variables()
  167. @sensitive_post_parameters()
  168. def custom_exception_reporter_filter_view(request):
  169. # Do not just use plain strings for the variables' values in the code
  170. # so that the tests don't return false positives when the function's source
  171. # is displayed in the exception report.
  172. cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA
  173. sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA
  174. request.exception_reporter_filter = UnsafeExceptionReporterFilter()
  175. try:
  176. raise Exception
  177. except Exception:
  178. exc_info = sys.exc_info()
  179. send_log(request, exc_info)
  180. return technical_500_response(request, *exc_info)
  181. class CustomExceptionReporter(ExceptionReporter):
  182. custom_traceback_text = 'custom traceback text'
  183. def get_traceback_html(self):
  184. return self.custom_traceback_text
  185. def custom_reporter_class_view(request):
  186. request.exception_reporter_class = CustomExceptionReporter
  187. try:
  188. raise Exception
  189. except Exception:
  190. exc_info = sys.exc_info()
  191. return technical_500_response(request, *exc_info)
  192. class Klass:
  193. @sensitive_variables('sauce')
  194. def method(self, request):
  195. # Do not just use plain strings for the variables' values in the code
  196. # so that the tests don't return false positives when the function's
  197. # source is displayed in the exception report.
  198. cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA
  199. sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA
  200. try:
  201. raise Exception
  202. except Exception:
  203. exc_info = sys.exc_info()
  204. send_log(request, exc_info)
  205. return technical_500_response(request, *exc_info)
  206. def sensitive_method_view(request):
  207. return Klass().method(request)
  208. @sensitive_variables('sauce')
  209. @sensitive_post_parameters('bacon-key', 'sausage-key')
  210. def multivalue_dict_key_error(request):
  211. cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA
  212. sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA
  213. try:
  214. request.POST['bar']
  215. except Exception:
  216. exc_info = sys.exc_info()
  217. send_log(request, exc_info)
  218. return technical_500_response(request, *exc_info)
  219. def json_response_view(request):
  220. return JsonResponse({
  221. 'a': [1, 2, 3],
  222. 'foo': {'bar': 'baz'},
  223. # Make sure datetime and Decimal objects would be serialized properly
  224. 'timestamp': datetime.datetime(2013, 5, 19, 20),
  225. 'value': decimal.Decimal('3.14'),
  226. })