1 import sys |
1 import sys |
2 |
2 |
3 from django import http |
3 from django import http |
4 from django.core import signals |
4 from django.core import signals |
5 from django.dispatch import dispatcher |
5 from django.utils.encoding import force_unicode |
6 |
6 |
7 class BaseHandler(object): |
7 class BaseHandler(object): |
8 # Changes that are always applied to a response (in this order). |
8 # Changes that are always applied to a response (in this order). |
9 response_fixes = [http.fix_location_header, |
9 response_fixes = [ |
10 http.conditional_content_removal] |
10 http.fix_location_header, |
|
11 http.conditional_content_removal, |
|
12 http.fix_IE_for_attach, |
|
13 http.fix_IE_for_vary, |
|
14 ] |
11 |
15 |
12 def __init__(self): |
16 def __init__(self): |
13 self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None |
17 self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None |
14 |
18 |
15 def load_middleware(self): |
19 def load_middleware(self): |
54 self._exception_middleware.insert(0, mw_instance.process_exception) |
58 self._exception_middleware.insert(0, mw_instance.process_exception) |
55 |
59 |
56 def get_response(self, request): |
60 def get_response(self, request): |
57 "Returns an HttpResponse object for the given HttpRequest" |
61 "Returns an HttpResponse object for the given HttpRequest" |
58 from django.core import exceptions, urlresolvers |
62 from django.core import exceptions, urlresolvers |
59 from django.core.mail import mail_admins |
|
60 from django.conf import settings |
63 from django.conf import settings |
61 |
64 |
62 # Apply request middleware |
65 # Apply request middleware |
63 for middleware_method in self._request_middleware: |
66 for middleware_method in self._request_middleware: |
64 response = middleware_method(request) |
67 response = middleware_method(request) |
68 # Get urlconf from request object, if available. Otherwise use default. |
71 # Get urlconf from request object, if available. Otherwise use default. |
69 urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF) |
72 urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF) |
70 |
73 |
71 resolver = urlresolvers.RegexURLResolver(r'^/', urlconf) |
74 resolver = urlresolvers.RegexURLResolver(r'^/', urlconf) |
72 try: |
75 try: |
73 callback, callback_args, callback_kwargs = resolver.resolve(request.path) |
76 callback, callback_args, callback_kwargs = resolver.resolve( |
|
77 request.path_info) |
74 |
78 |
75 # Apply view middleware |
79 # Apply view middleware |
76 for middleware_method in self._view_middleware: |
80 for middleware_method in self._view_middleware: |
77 response = middleware_method(request, callback, callback_args, callback_kwargs) |
81 response = middleware_method(request, callback, callback_args, callback_kwargs) |
78 if response: |
82 if response: |
102 except http.Http404, e: |
106 except http.Http404, e: |
103 if settings.DEBUG: |
107 if settings.DEBUG: |
104 from django.views import debug |
108 from django.views import debug |
105 return debug.technical_404_response(request, e) |
109 return debug.technical_404_response(request, e) |
106 else: |
110 else: |
107 callback, param_dict = resolver.resolve404() |
111 try: |
108 return callback(request, **param_dict) |
112 callback, param_dict = resolver.resolve404() |
|
113 return callback(request, **param_dict) |
|
114 except: |
|
115 try: |
|
116 return self.handle_uncaught_exception(request, resolver, sys.exc_info()) |
|
117 finally: |
|
118 receivers = signals.got_request_exception.send(sender=self.__class__, request=request) |
109 except exceptions.PermissionDenied: |
119 except exceptions.PermissionDenied: |
110 return http.HttpResponseForbidden('<h1>Permission denied</h1>') |
120 return http.HttpResponseForbidden('<h1>Permission denied</h1>') |
111 except SystemExit: |
121 except SystemExit: |
112 # Allow sys.exit() to actually exit. See tickets #1023 and #4701 |
122 # Allow sys.exit() to actually exit. See tickets #1023 and #4701 |
113 raise |
123 raise |
114 except: # Handle everything else, including SuspiciousOperation, etc. |
124 except: # Handle everything else, including SuspiciousOperation, etc. |
115 # Get the exception info now, in case another exception is thrown later. |
125 # Get the exception info now, in case another exception is thrown later. |
116 exc_info = sys.exc_info() |
126 exc_info = sys.exc_info() |
117 receivers = dispatcher.send(signal=signals.got_request_exception, request=request) |
127 receivers = signals.got_request_exception.send(sender=self.__class__, request=request) |
118 |
128 return self.handle_uncaught_exception(request, resolver, exc_info) |
119 if settings.DEBUG_PROPAGATE_EXCEPTIONS: |
129 |
120 raise |
130 def handle_uncaught_exception(self, request, resolver, exc_info): |
121 elif settings.DEBUG: |
131 """ |
122 from django.views import debug |
132 Processing for any otherwise uncaught exceptions (those that will |
123 return debug.technical_500_response(request, *exc_info) |
133 generate HTTP 500 responses). Can be overridden by subclasses who want |
124 else: |
134 customised 500 handling. |
125 # When DEBUG is False, send an error message to the admins. |
135 |
126 subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path) |
136 Be *very* careful when overriding this because the error could be |
127 try: |
137 caused by anything, so assuming something like the database is always |
128 request_repr = repr(request) |
138 available would be an error. |
129 except: |
139 """ |
130 request_repr = "Request repr() unavailable" |
140 from django.conf import settings |
131 message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr) |
141 from django.core.mail import mail_admins |
132 mail_admins(subject, message, fail_silently=True) |
142 |
133 # Return an HttpResponse that displays a friendly error message. |
143 if settings.DEBUG_PROPAGATE_EXCEPTIONS: |
134 callback, param_dict = resolver.resolve500() |
144 raise |
135 return callback(request, **param_dict) |
145 |
|
146 if settings.DEBUG: |
|
147 from django.views import debug |
|
148 return debug.technical_500_response(request, *exc_info) |
|
149 |
|
150 # When DEBUG is False, send an error message to the admins. |
|
151 subject = 'Error (%s IP): %s' % ((request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS and 'internal' or 'EXTERNAL'), request.path) |
|
152 try: |
|
153 request_repr = repr(request) |
|
154 except: |
|
155 request_repr = "Request repr() unavailable" |
|
156 message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr) |
|
157 mail_admins(subject, message, fail_silently=True) |
|
158 # Return an HttpResponse that displays a friendly error message. |
|
159 callback, param_dict = resolver.resolve500() |
|
160 return callback(request, **param_dict) |
136 |
161 |
137 def _get_traceback(self, exc_info=None): |
162 def _get_traceback(self, exc_info=None): |
138 "Helper function to return the traceback as a string" |
163 "Helper function to return the traceback as a string" |
139 import traceback |
164 import traceback |
140 return '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info()))) |
165 return '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info()))) |
147 """ |
172 """ |
148 for func in self.response_fixes: |
173 for func in self.response_fixes: |
149 response = func(request, response) |
174 response = func(request, response) |
150 return response |
175 return response |
151 |
176 |
|
177 def get_script_name(environ): |
|
178 """ |
|
179 Returns the equivalent of the HTTP request's SCRIPT_NAME environment |
|
180 variable. If Apache mod_rewrite has been used, returns what would have been |
|
181 the script name prior to any rewriting (so it's the script name as seen |
|
182 from the client's perspective), unless DJANGO_USE_POST_REWRITE is set (to |
|
183 anything). |
|
184 """ |
|
185 from django.conf import settings |
|
186 if settings.FORCE_SCRIPT_NAME is not None: |
|
187 return force_unicode(settings.FORCE_SCRIPT_NAME) |
|
188 |
|
189 # If Apache's mod_rewrite had a whack at the URL, Apache set either |
|
190 # SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any |
|
191 # rewrites. Unfortunately not every webserver (lighttpd!) passes this |
|
192 # information through all the time, so FORCE_SCRIPT_NAME, above, is still |
|
193 # needed. |
|
194 script_url = environ.get('SCRIPT_URL', u'') |
|
195 if not script_url: |
|
196 script_url = environ.get('REDIRECT_URL', u'') |
|
197 if script_url: |
|
198 return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))]) |
|
199 return force_unicode(environ.get('SCRIPT_NAME', u'')) |
|
200 |