diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py
index 190a8b02c2..ba2e286721 100644
--- a/django/core/handlers/base.py
+++ b/django/core/handlers/base.py
@@ -86,14 +86,14 @@ class BaseHandler:
return response
except exceptions.Http404, e:
if DEBUG:
- return self.get_technical_error_response(is404=True, exception=e)
+ return self.get_technical_error_response(request, is404=True, exception=e)
else:
callback, param_dict = resolver.resolve404()
return callback(request, **param_dict)
except db.DatabaseError:
db.db.rollback()
if DEBUG:
- return self.get_technical_error_response()
+ return self.get_technical_error_response(request)
else:
subject = 'Database error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in INTERNAL_IPS and 'internal' or 'EXTERNAL'), getattr(request, 'path', ''))
message = "%s\n\n%s" % (self._get_traceback(), request)
@@ -103,7 +103,7 @@ class BaseHandler:
return httpwrappers.HttpResponseForbidden('
Permission denied
')
except: # Handle everything else, including SuspiciousOperation, etc.
if DEBUG:
- return self.get_technical_error_response()
+ return self.get_technical_error_response(request)
else:
subject = 'Coding error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in INTERNAL_IPS and 'internal' or 'EXTERNAL'), getattr(request, 'path', ''))
try:
@@ -123,35 +123,17 @@ class BaseHandler:
callback, param_dict = resolver.resolve500()
return callback(request, **param_dict)
- def get_technical_error_response(self, is404=False, exception=None):
+ def get_technical_error_response(self, request, is404=False, exception=None):
"""
Returns an HttpResponse that displays a TECHNICAL error message for a
fundamental database or coding error.
"""
+ import sys
+ from django.views import debug
if is404:
- from django.conf.settings import ROOT_URLCONF
- from django.utils.html import escape
- html = ['']
- html.append('Error 404')
- # Explicitly tell robots not to archive this, in case this slips
- # onto a production site.
- html.append('')
- html.append('Error 404
')
- try:
- tried = exception.args[0]['tried']
- except (IndexError, TypeError):
- if exception.args:
- html.append('%s
' % escape(exception.args[0]))
- else:
- html.append('Using the URLconf defined in %s
, Django tried these URL patterns, in this order:
' % ROOT_URLCONF)
- html.append('' % ''.join(['%s
' % escape(t).replace(' ', ' ') for t in tried]))
- html.append("The current URL, %r
, didn't match any of these.
" % exception.args[0]['path'])
- html.append("
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.
")
- html.append('')
- return httpwrappers.HttpResponseNotFound('\n'.join(html))
+ return debug.technical_404_response(request, exception)
else:
- output = "There's been an error:\n\n%s" % self._get_traceback()
- return httpwrappers.HttpResponseServerError(output, mimetype='text/plain')
+ return debug.technical_500_response(request, *sys.exc_info())
def _get_traceback(self):
"Helper function to return the traceback as a string"
diff --git a/django/views/debug.py b/django/views/debug.py
new file mode 100644
index 0000000000..2d3b7e9150
--- /dev/null
+++ b/django/views/debug.py
@@ -0,0 +1,438 @@
+import os
+import sys
+import inspect
+from django.conf import settings
+from os.path import dirname, join as pathjoin
+from django.core.template import Template, Context
+from django.utils.httpwrappers import HttpResponseServerError, HttpResponseNotFound
+
+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.
+ """
+ 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)
+ frames.append({
+ 'tb' : tb,
+ 'filename' : filename,
+ 'function' : function,
+ 'lineno' : lineno,
+ 'vars' : tb.tb_frame.f_locals,
+ 'id' : id(tb),
+ 'pre_context' : pre_context,
+ 'context_line' : context_line,
+ 'post_context' : post_context,
+ 'pre_context_lineno' : pre_context_lineno,
+ })
+ tb = tb.tb_next
+
+ t = Template(TECHNICAL_500_TEMPLATE)
+ c = Context({
+ 'exception_type' : exc_type.__name__,
+ 'exception_value' : exc_value,
+ 'frames' : frames,
+ 'lastframe' : frames[-1],
+ 'request' : request,
+ 'request_protocol' : os.environ.get("HTTPS") == "on" and "https" or "http",
+ 'settings' : dict([(k, getattr(settings, k)) for k in dir(settings) if k.isupper()]),
+
+ })
+ return HttpResponseServerError(t.render(c))
+
+def technical_404_response(request, exception):
+ """
+ Create a technical 404 error response. The exception should be the Http404
+ exception.
+ """
+ try:
+ tried = exception.args[0]['tried']
+ except (IndexError, TypeError):
+ tried = []
+
+ t = Template(TECHNICAL_404_TEMPLATE)
+ c = Context({
+ 'root_urlconf' : settings.ROOT_URLCONF,
+ 'urlpatterns' : tried,
+ 'reason' : str(exception),
+ 'request' : request,
+ 'request_protocol' : os.environ.get("HTTPS") == "on" and "https" or "http",
+ 'settings' : dict([(k, getattr(settings, k)) for k in dir(settings) if k.isupper()]),
+ })
+ return HttpResponseNotFound(t.render(c))
+
+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 }}
+
+
+
+
+
+
+
{{ exception_type }} at {{ request.path }}
+
{{ exception_value }}
+
+
+
+
+
Traceback (innermost last)
+
+ {% for frame in frames %}
+ -
+
{{ frame.filename }}
in {{ frame.function }}
+
+ {% if frame.context_line %}
+
+ {% if frame.pre_context %}
+
{% for line in frame.pre_context %}- {{ line|escape }}
{% endfor %}
+ {% endif %}
+
- {{ frame.context_line|escape }}
+ {% if frame.post_context %}
+
{% for line in frame.post_context %}- {{ line|escape }}
{% endfor %}
+ {% endif %}
+
+ {% endif %}
+
+ {% if frame.vars %}
+
+
+
+
+ Variable |
+ Value |
+
+
+
+ {% for var in frame.vars.items|dictsort:"0" %}
+
+ {{ var.0 }} |
+ {{ var.1|pprint|escape }} |
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% endfor %}
+
+
+
+
+
Request information
+
+
GET
+ {% if request.GET %}
+
+
+
+ Variable |
+ Value |
+
+
+
+ {% for var in request.GET.items %}
+
+ {{ var.0 }} |
+ {{ var.1|pprint|escape }} |
+
+ {% endfor %}
+
+
+ {% else %}
+
No GET data
+ {% endif %}
+
+
POST
+ {% if request.POST %}
+
+
+
+ Variable |
+ Value |
+
+
+
+ {% for var in request.POST.items %}
+
+ {{ var.0 }} |
+ {{ var.1|pprint|escape }} |
+
+ {% endfor %}
+
+
+ {% else %}
+
No POST data
+ {% endif %}
+
+
COOKIES
+ {% if request.COOKIES %}
+
+
+
+ Variable |
+ Value |
+
+
+
+ {% for var in request.COOKIES.items %}
+
+ {{ var.0 }} |
+ {{ var.1|pprint|escape }} |
+
+ {% endfor %}
+
+
+ {% else %}
+
No cookie data
+ {% endif %}
+
+
+
+
+
+ Variable |
+ Value |
+
+
+
+ {% for var in request.META.items|dictsort:"0" %}
+
+ {{ var.0 }} |
+ {{ var.1|pprint|escape }} |
+
+ {% endfor %}
+
+
+
+
Settings
+
Using settings module {{ settings.SETTINGS_MODULE }}
+
+
+
+ Setting |
+ Value |
+
+
+
+ {% for var in settings.items|dictsort:"0" %}
+
+ {{ var.0 }} |
+ {{ var.1|pprint|escape }} |
+
+ {% endfor %}
+
+
+
+
+
+
+
+ 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 }}
+
+
+
+
+
+
Page not found (404)
+
+
+
+ {% if urlpatterns %}
+
+ Using the URLconf defined in {{ settings.ROOT_URLCONF }}
,
+ Django tried these URL patterns, in this order:
+
+
+ {% for pattern in urlpatterns %}
+ - {{ pattern|escape }}
+ {% endfor %}
+
+
The current URL, {{ request.path }}
, 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.
+
+
+
+
+"""
\ No newline at end of file