from django.conf import settings from django.template import Template, Context, TemplateDoesNotExist from django.utils.html import escape from django.http import HttpResponseServerError, HttpResponseNotFound import os, re HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST') def linebreak_iter(template_source): yield 0 p = template_source.find('\n') while p >= 0: yield p+1 p = template_source.find('\n', p+1) yield len(template_source) + 1 def get_template_exception_info(exc_type, exc_value, tb): origin, (start, end) = exc_value.source template_source = origin.reload() context_lines = 10 line = 0 upto = 0 source_lines = [] before = during = after = "" for num, next in enumerate(linebreak_iter(template_source)): if start >= upto and end <= next: line = num before = escape(template_source[upto:start]) during = escape(template_source[start:end]) after = escape(template_source[end:next]) source_lines.append( (num, escape(template_source[upto:next])) ) upto = next total = len(source_lines) top = max(1, line - context_lines) bottom = min(total, line + 1 + context_lines) template_info = { 'message': exc_value.args[0], 'source_lines': source_lines[top:bottom], 'before': before, 'during': during, 'after': after, 'top': top, 'bottom': bottom, 'total': total, 'line': line, 'name': origin.name, } exc_info = hasattr(exc_value, 'exc_info') and exc_value.exc_info or (exc_type, exc_value, tb) return exc_info + (template_info,) def get_safe_settings(): "Returns a dictionary of the settings module, with sensitive settings blurred out." settings_dict = {} for k in dir(settings): if k.isupper(): if HIDDEN_SETTINGS.search(k): settings_dict[k] = '********************' else: settings_dict[k] = getattr(settings, k) return settings_dict def technical_500_response(request, exc_type, exc_value, tb): """ Create a technical server error response. The last three arguments are the values returned from sys.exc_info() and friends. """ template_info = None template_does_not_exist = False loader_debug_info = None if issubclass(exc_type, TemplateDoesNotExist): from django.template.loader import template_source_loaders template_does_not_exist = True loader_debug_info = [] for loader in template_source_loaders: try: source_list_func = getattr(__import__(loader.__module__, '', '', ['get_template_sources']), 'get_template_sources') # NOTE: This assumes exc_value is the name of the template that # the loader attempted to load. template_list = [{'name': t, 'exists': os.path.exists(t)} \ for t in source_list_func(str(exc_value))] except (ImportError, AttributeError): template_list = [] loader_debug_info.append({ 'loader': loader.__module__ + '.' + loader.__name__, 'templates': template_list, }) if settings.TEMPLATE_DEBUG and hasattr(exc_value, 'source'): exc_type, exc_value, tb, template_info = get_template_exception_info(exc_type, exc_value, tb) frames = [] while tb is not None: filename = tb.tb_frame.f_code.co_filename function = tb.tb_frame.f_code.co_name lineno = tb.tb_lineno - 1 pre_context_lineno, pre_context, context_line, post_context = _get_lines_from_file(filename, lineno, 7) if pre_context_lineno: frames.append({ 'tb': tb, 'filename': filename, 'function': function, 'lineno': lineno + 1, 'vars': tb.tb_frame.f_locals.items(), 'id': id(tb), 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, 'pre_context_lineno': pre_context_lineno + 1, }) tb = tb.tb_next if not frames: frames = [{ 'filename': '<unknown>', 'function': '?', 'lineno': '?', }] t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template') c = Context({ 'exception_type': exc_type.__name__, 'exception_value': exc_value, 'frames': frames, 'lastframe': frames[-1], 'request': request, 'request_protocol': request.is_secure() and "https" or "http", 'settings': get_safe_settings(), 'template_info': template_info, 'template_does_not_exist': template_does_not_exist, 'loader_debug_info': loader_debug_info, }) return HttpResponseServerError(t.render(c), mimetype='text/html') def technical_404_response(request, exception): "Create a technical 404 error response. The exception should be the Http404." try: tried = exception.args[0]['tried'] except (IndexError, TypeError): tried = [] else: if not tried: # tried exists but is an empty list. The URLconf must've been empty. return empty_urlconf(request) t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template') c = Context({ 'root_urlconf': settings.ROOT_URLCONF, 'urlpatterns': tried, 'reason': str(exception), 'request': request, 'request_protocol': request.is_secure() and "https" or "http", 'settings': get_safe_settings(), }) return HttpResponseNotFound(t.render(c), mimetype='text/html') def empty_urlconf(request): "Create an empty URLconf 404 error response." t = Template(EMPTY_URLCONF_TEMPLATE, name='Empty URLConf template') c = Context({ 'project_name': settings.SETTINGS_MODULE.split('.')[0] }) return HttpResponseNotFound(t.render(c), mimetype='text/html') def _get_lines_from_file(filename, lineno, context_lines): """ Returns context_lines before and after lineno from file. Returns (pre_context_lineno, pre_context, context_line, post_context). """ try: source = open(filename).readlines() lower_bound = max(0, lineno - context_lines) upper_bound = lineno + context_lines pre_context = [line.strip('\n') for line in source[lower_bound:lineno]] context_line = source[lineno].strip('\n') post_context = [line.strip('\n') for line in source[lineno+1:upper_bound]] return lower_bound, pre_context, context_line, post_context except (OSError, IOError): return None, [], None, [] # # Templates are embedded in the file so that we know the error handler will # always work even if the template loader is broken. # TECHNICAL_500_TEMPLATE = """ {{ exception_type }} at {{ request.path|escape }}

{{ exception_type }} at {{ request.path|escape }}

{{ exception_value|escape }}

Request Method: {{ request.META.REQUEST_METHOD }}
Request URL: {{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path|escape }}
Exception Type: {{ exception_type }}
Exception Value: {{ exception_value|escape }}
Exception Location: {{ lastframe.filename }} in {{ lastframe.function }}, line {{ lastframe.lineno }}
{% if template_does_not_exist %}

Template-loader postmortem

{% if loader_debug_info %}

Django tried loading these templates, in this order:

{% else %}

Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty!

{% endif %}
{% endif %} {% if template_info %}

Template error

In template {{ template_info.name }}, error at line {{ template_info.line }}

{{ template_info.message|escape }}

{% for source_line in template_info.source_lines %} {% ifequal source_line.0 template_info.line %} {% else %} {% endifequal %} {% endfor %}
{{ source_line.0 }} {{ template_info.before }}{{ template_info.during }}{{ template_info.after }}
{{ source_line.0 }} {{ source_line.1 }}
{% endif %}

Traceback (innermost last)

Switch to copy-and-paste view

Traceback (most recent call last):
{% for frame in frames %} File "{{ frame.filename }}" in {{ frame.function }}
{% if frame.context_line %}   {{ frame.lineno }}. {{ frame.context_line|escape }}
{% endif %} {% endfor %}
  {{ exception_type }} at {{ request.path|escape }}
  {{ exception_value|escape }}

Request information

GET

{% if request.GET %} {% for var in request.GET.items %} {% endfor %}
Variable Value
{{ var.0 }}
{{ var.1|pprint|escape }}
{% else %}

No GET data

{% endif %}

POST

{% if request.POST %} {% for var in request.POST.items %} {% endfor %}
Variable Value
{{ var.0 }}
{{ var.1|pprint|escape }}
{% else %}

No POST data

{% endif %} {% if request.COOKIES %} {% for var in request.COOKIES.items %} {% endfor %}
Variable Value
{{ var.0 }}
{{ var.1|pprint|escape }}
{% else %}

No cookie data

{% endif %}

META

{% for var in request.META.items|dictsort:"0" %} {% endfor %}
Variable Value
{{ var.0 }}
{{ var.1|pprint|escape }}

Settings

Using settings module {{ settings.SETTINGS_MODULE }}

{% for var in settings.items|dictsort:"0" %} {% endfor %}
Setting Value
{{ var.0 }}
{{ var.1|pprint|escape }}

You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 500 page.

""" TECHNICAL_404_TEMPLATE = """ Page not found at {{ request.path|escape }}

Page not found (404)

Request Method: {{ request.META.REQUEST_METHOD }}
Request URL: {{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path|escape }}
{% if urlpatterns %}

Using the URLconf defined in {{ settings.ROOT_URLCONF }}, Django tried these URL patterns, in this order:

    {% for pattern in urlpatterns %}
  1. {{ pattern|escape }}
  2. {% endfor %}

The current URL, {{ request.path|escape }}, didn't match any of these.

{% else %}

{{ reason|escape }}

{% endif %}

You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.

""" EMPTY_URLCONF_TEMPLATE = """ Welcome to Django

It worked!

Congratulations on your first Django-powered page.

Of course, you haven't actually done any work yet. Here's what to do next:

You're seeing this message because you have DEBUG = True in your Django settings file and you haven't configured any URLs. Get to work!

"""