1
from __future__ import unicode_literals
3
7
from django import http
8
from django.conf import settings
9
from django.core import exceptions
10
from django.core import urlresolvers
4
11
from django.core import signals
5
from django.utils.encoding import force_unicode
12
from django.utils.encoding import force_text
6
13
from django.utils.importlib import import_module
7
from django.utils.log import getLogger
14
from django.utils import six
15
from django.views import debug
9
logger = getLogger('django.request')
17
logger = logging.getLogger('django.request')
12
20
class BaseHandler(object):
29
37
Must be called after the environment is fixed (see __call__ in subclasses).
31
from django.conf import settings
32
from django.core import exceptions
33
39
self._view_middleware = []
34
40
self._template_response_middleware = []
35
41
self._response_middleware = []
43
49
raise exceptions.ImproperlyConfigured('%s isn\'t a middleware module' % middleware_path)
45
51
mod = import_module(mw_module)
46
except ImportError, e:
52
except ImportError as e:
47
53
raise exceptions.ImproperlyConfigured('Error importing middleware %s: "%s"' % (mw_module, e))
49
55
mw_class = getattr(mod, mw_classname)
72
78
def get_response(self, request):
73
79
"Returns an HttpResponse object for the given HttpRequest"
74
from django.core import exceptions, urlresolvers
75
from django.conf import settings
78
81
# Setup default url resolver for this thread, this code is outside
79
82
# the try/except so we don't get a spurious "unbound local
93
96
if response is None:
94
if hasattr(request, "urlconf"):
97
if hasattr(request, 'urlconf'):
95
98
# Reset url resolver with a custom urlconf.
96
99
urlconf = request.urlconf
97
100
urlresolvers.set_urlconf(urlconf)
98
101
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
100
callback, callback_args, callback_kwargs = resolver.resolve(
103
resolver_match = resolver.resolve(request.path_info)
104
callback, callback_args, callback_kwargs = resolver_match
105
request.resolver_match = resolver_match
103
107
# Apply view middleware
104
108
for middleware_method in self._view_middleware:
109
113
if response is None:
111
115
response = callback(request, *callback_args, **callback_kwargs)
116
except Exception as e:
113
117
# If the view raised an exception, run it through exception
114
118
# middleware, and if the exception middleware returns a
115
119
# response, use that. Otherwise, reraise the exception.
123
127
# Complain if the view returned None (a common error).
124
128
if response is None:
126
view_name = callback.func_name # If it's a function
127
except AttributeError:
128
view_name = callback.__class__.__name__ + '.__call__' # If it's a class
129
if isinstance(callback, types.FunctionType): # FBV
130
view_name = callback.__name__
132
view_name = callback.__class__.__name__ + '.__call__'
129
133
raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name))
131
135
# If the response supports deferred rendering, apply template
135
139
response = middleware_method(request, response)
136
140
response = response.render()
138
except http.Http404, e:
142
except http.Http404 as e:
139
143
logger.warning('Not Found: %s', request.path,
141
145
'status_code': 404,
142
146
'request': request
144
148
if settings.DEBUG:
145
from django.views import debug
146
149
response = debug.technical_404_response(request, e)
149
152
callback, param_dict = resolver.resolve404()
150
153
response = callback(request, **param_dict)
153
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
155
signals.got_request_exception.send(sender=self.__class__, request=request)
155
signals.got_request_exception.send(sender=self.__class__, request=request)
156
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
156
157
except exceptions.PermissionDenied:
158
159
'Forbidden (Permission denied): %s', request.path,
164
165
callback, param_dict = resolver.resolve403()
165
166
response = callback(request, **param_dict)
168
response = self.handle_uncaught_exception(request,
168
signals.got_request_exception.send(
169
sender=self.__class__, request=request)
170
response = self.handle_uncaught_exception(request,
169
171
resolver, sys.exc_info())
171
signals.got_request_exception.send(
172
sender=self.__class__, request=request)
173
172
except SystemExit:
174
173
# Allow sys.exit() to actually exit. See tickets #1023 and #4701
203
202
caused by anything, so assuming something like the database is always
204
203
available would be an error.
206
from django.conf import settings
208
205
if settings.DEBUG_PROPAGATE_EXCEPTIONS:
219
216
if settings.DEBUG:
220
from django.views import debug
221
217
return debug.technical_500_response(request, *exc_info)
223
219
# If Http500 handler is not installed, re-raise last exception
224
220
if resolver.urlconf_module is None:
225
raise exc_info[1], None, exc_info[2]
221
six.reraise(*exc_info)
226
222
# Return an HttpResponse that displays a friendly error message.
227
223
callback, param_dict = resolver.resolve500()
228
224
return callback(request, **param_dict)
237
233
response = func(request, response)
237
def get_path_info(environ):
239
Returns the HTTP request's PATH_INFO as a unicode string.
241
path_info = environ.get('PATH_INFO', str('/'))
242
# Under Python 3, strings in environ are decoded with ISO-8859-1;
243
# re-encode to recover the original bytestring provided by the webserver.
245
path_info = path_info.encode('iso-8859-1')
246
# It'd be better to implement URI-to-IRI decoding, see #19508.
247
return path_info.decode('utf-8')
240
250
def get_script_name(environ):
242
252
Returns the equivalent of the HTTP request's SCRIPT_NAME environment
245
255
from the client's perspective), unless the FORCE_SCRIPT_NAME setting is
246
256
set (to anything).
248
from django.conf import settings
249
258
if settings.FORCE_SCRIPT_NAME is not None:
250
return force_unicode(settings.FORCE_SCRIPT_NAME)
259
return force_text(settings.FORCE_SCRIPT_NAME)
252
261
# If Apache's mod_rewrite had a whack at the URL, Apache set either
253
262
# SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any
254
263
# rewrites. Unfortunately not every Web server (lighttpd!) passes this
255
264
# information through all the time, so FORCE_SCRIPT_NAME, above, is still
257
script_url = environ.get('SCRIPT_URL', u'')
259
script_url = environ.get('REDIRECT_URL', u'')
266
script_url = environ.get('SCRIPT_URL', environ.get('REDIRECT_URL', str('')))
261
return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))])
262
return force_unicode(environ.get('SCRIPT_NAME', u''))
268
script_name = script_url[:-len(environ.get('PATH_INFO', str('')))]
270
script_name = environ.get('SCRIPT_NAME', str(''))
271
# Under Python 3, strings in environ are decoded with ISO-8859-1;
272
# re-encode to recover the original bytestring provided by the webserver.
274
script_name = script_name.encode('iso-8859-1')
275
# It'd be better to implement URI-to-IRI decoding, see #19508.
276
return script_name.decode('utf-8')