Fixed #26601 -- Improved middleware per DEP 0005.

Thanks Tim Graham for polishing the patch, updating the tests, and
writing documentation. Thanks Carl Meyer for shepherding the DEP.
This commit is contained in:
Florian Apolloner 2015-11-07 16:12:37 +01:00 committed by Tim Graham
parent 05c888ffb8
commit 9baf692a58
81 changed files with 900 additions and 1414 deletions

View File

@ -433,14 +433,16 @@ SECURE_PROXY_SSL_HEADER = None
# MIDDLEWARE # # MIDDLEWARE #
############## ##############
# List of middleware classes to use. Order is important; in the request phase, # List of middleware to use. Order is important; in the request phase, these
# this middleware classes will be applied in the order given, and in the # middleware will be applied in the order given, and in the response
# response phase the middleware will be applied in reverse order. # phase the middleware will be applied in reverse order.
MIDDLEWARE_CLASSES = [ MIDDLEWARE_CLASSES = [
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
] ]
MIDDLEWARE = None
############ ############
# SESSIONS # # SESSIONS #
############ ############

View File

@ -39,7 +39,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles', 'django.contrib.staticfiles',
] ]
MIDDLEWARE_CLASSES = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',

View File

@ -1,19 +1,18 @@
from django.contrib.staticfiles.testing import StaticLiveServerTestCase from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.test import modify_settings from django.test import modify_settings
from django.test.selenium import SeleniumTestCase from django.test.selenium import SeleniumTestCase
from django.utils.deprecation import MiddlewareMixin
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
class CSPMiddleware(object): class CSPMiddleware(MiddlewareMixin):
"""The admin's JavaScript should be compatible with CSP.""" """The admin's JavaScript should be compatible with CSP."""
def process_response(self, request, response): def process_response(self, request, response):
response['Content-Security-Policy'] = "default-src 'self'" response['Content-Security-Policy'] = "default-src 'self'"
return response return response
@modify_settings( @modify_settings(MIDDLEWARE={'append': 'django.contrib.admin.tests.CSPMiddleware'})
MIDDLEWARE_CLASSES={'append': 'django.contrib.admin.tests.CSPMiddleware'},
)
class AdminSeleniumTestCase(SeleniumTestCase, StaticLiveServerTestCase): class AdminSeleniumTestCase(SeleniumTestCase, StaticLiveServerTestCase):
available_apps = [ available_apps = [

View File

@ -1,8 +1,9 @@
from django import http from django import http
from django.conf import settings from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
class XViewMiddleware(object): class XViewMiddleware(MiddlewareMixin):
""" """
Adds an X-View header to internal HEAD requests -- used by the documentation system. Adds an X-View header to internal HEAD requests -- used by the documentation system.
""" """
@ -15,8 +16,11 @@ class XViewMiddleware(object):
""" """
assert hasattr(request, 'user'), ( assert hasattr(request, 'user'), (
"The XView middleware requires authentication middleware to be " "The XView middleware requires authentication middleware to be "
"installed. Edit your MIDDLEWARE_CLASSES setting to insert " "installed. Edit your MIDDLEWARE%s setting to insert "
"'django.contrib.auth.middleware.AuthenticationMiddleware'.") "'django.contrib.auth.middleware.AuthenticationMiddleware'." % (
"_CLASSES" if settings.MIDDLEWARE is None else ""
)
)
if request.method == 'HEAD' and (request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or if request.method == 'HEAD' and (request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or
(request.user.is_active and request.user.is_staff)): (request.user.is_active and request.user.is_staff)):
response = http.HttpResponse() response = http.HttpResponse()

View File

@ -1,7 +1,9 @@
from django.conf import settings
from django.contrib import auth from django.contrib import auth
from django.contrib.auth import load_backend from django.contrib.auth import load_backend
from django.contrib.auth.backends import RemoteUserBackend from django.contrib.auth.backends import RemoteUserBackend
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils.deprecation import MiddlewareMixin
from django.utils.functional import SimpleLazyObject from django.utils.functional import SimpleLazyObject
@ -11,18 +13,18 @@ def get_user(request):
return request._cached_user return request._cached_user
class AuthenticationMiddleware(object): class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request): def process_request(self, request):
assert hasattr(request, 'session'), ( assert hasattr(request, 'session'), (
"The Django authentication middleware requires session middleware " "The Django authentication middleware requires session middleware "
"to be installed. Edit your MIDDLEWARE_CLASSES setting to insert " "to be installed. Edit your MIDDLEWARE%s setting to insert "
"'django.contrib.sessions.middleware.SessionMiddleware' before " "'django.contrib.sessions.middleware.SessionMiddleware' before "
"'django.contrib.auth.middleware.AuthenticationMiddleware'." "'django.contrib.auth.middleware.AuthenticationMiddleware'."
) ) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
request.user = SimpleLazyObject(lambda: get_user(request)) request.user = SimpleLazyObject(lambda: get_user(request))
class SessionAuthenticationMiddleware(object): class SessionAuthenticationMiddleware(MiddlewareMixin):
""" """
Formerly, a middleware for invalidating a user's sessions that don't Formerly, a middleware for invalidating a user's sessions that don't
correspond to the user's current session authentication hash. However, it correspond to the user's current session authentication hash. However, it
@ -35,7 +37,7 @@ class SessionAuthenticationMiddleware(object):
pass pass
class RemoteUserMiddleware(object): class RemoteUserMiddleware(MiddlewareMixin):
""" """
Middleware for utilizing Web-server-provided authentication. Middleware for utilizing Web-server-provided authentication.
@ -61,7 +63,7 @@ class RemoteUserMiddleware(object):
raise ImproperlyConfigured( raise ImproperlyConfigured(
"The Django remote user auth middleware requires the" "The Django remote user auth middleware requires the"
" authentication middleware to be installed. Edit your" " authentication middleware to be installed. Edit your"
" MIDDLEWARE_CLASSES setting to insert" " MIDDLEWARE setting to insert"
" 'django.contrib.auth.middleware.AuthenticationMiddleware'" " 'django.contrib.auth.middleware.AuthenticationMiddleware'"
" before the RemoteUserMiddleware class.") " before the RemoteUserMiddleware class.")
try: try:

View File

@ -29,8 +29,9 @@ class FlatpageForm(forms.ModelForm):
ugettext("URL is missing a leading slash."), ugettext("URL is missing a leading slash."),
code='missing_leading_slash', code='missing_leading_slash',
) )
if (settings.APPEND_SLASH and if (settings.APPEND_SLASH and (
'django.middleware.common.CommonMiddleware' in settings.MIDDLEWARE_CLASSES and (settings.MIDDLEWARE and 'django.middleware.common.CommonMiddleware' in settings.MIDDLEWARE) or
'django.middleware.common.CommonMiddleware' in settings.MIDDLEWARE_CLASSES) and
not url.endswith('/')): not url.endswith('/')):
raise forms.ValidationError( raise forms.ValidationError(
ugettext("URL is missing a trailing slash."), ugettext("URL is missing a trailing slash."),

View File

@ -1,9 +1,20 @@
from django.conf import settings from django.conf import settings
from django.contrib.flatpages.views import flatpage from django.contrib.flatpages.views import flatpage
from django.http import Http404 from django.http import Http404
from django.middleware.exception import ExceptionMiddleware
class FlatpageFallbackMiddleware(object): class FlatpageFallbackMiddleware(ExceptionMiddleware):
def __init__(self, get_response=None):
# This override makes get_response optional during the
# MIDDLEWARE_CLASSES deprecation.
super(FlatpageFallbackMiddleware, self).__init__(get_response)
def __call__(self, request):
response = super(FlatpageFallbackMiddleware, self).__call__(request)
return self.process_response(request, response)
def process_response(self, request, response): def process_response(self, request, response):
if response.status_code != 404: if response.status_code != 404:
return response # No need to check for a flatpage for non-404 responses. return response # No need to check for a flatpage for non-404 responses.

View File

@ -1,8 +1,9 @@
from django.conf import settings from django.conf import settings
from django.contrib.messages.storage import default_storage from django.contrib.messages.storage import default_storage
from django.utils.deprecation import MiddlewareMixin
class MessageMiddleware(object): class MessageMiddleware(MiddlewareMixin):
""" """
Middleware that handles temporary messages. Middleware that handles temporary messages.
""" """

View File

@ -1,5 +1,6 @@
import json import json
from django.conf import settings
from django.contrib.messages.storage.base import BaseStorage from django.contrib.messages.storage.base import BaseStorage
from django.contrib.messages.storage.cookie import ( from django.contrib.messages.storage.cookie import (
MessageDecoder, MessageEncoder, MessageDecoder, MessageEncoder,
@ -17,7 +18,7 @@ class SessionStorage(BaseStorage):
assert hasattr(request, 'session'), "The session-based temporary "\ assert hasattr(request, 'session'), "The session-based temporary "\
"message storage requires session middleware to be installed, "\ "message storage requires session middleware to be installed, "\
"and come before the message middleware in the "\ "and come before the message middleware in the "\
"MIDDLEWARE_CLASSES list." "MIDDLEWARE%s list." % ("_CLASSES" if settings.MIDDLEWARE is None else "")
super(SessionStorage, self).__init__(request, *args, **kwargs) super(SessionStorage, self).__init__(request, *args, **kwargs)
def _get(self, *args, **kwargs): def _get(self, *args, **kwargs):

View File

@ -6,20 +6,26 @@ from django.conf import settings
from django.contrib.redirects.models import Redirect from django.contrib.redirects.models import Redirect
from django.contrib.sites.shortcuts import get_current_site from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.middleware.exception import ExceptionMiddleware
class RedirectFallbackMiddleware(object): class RedirectFallbackMiddleware(ExceptionMiddleware):
# Defined as class-level attributes to be subclassing-friendly. # Defined as class-level attributes to be subclassing-friendly.
response_gone_class = http.HttpResponseGone response_gone_class = http.HttpResponseGone
response_redirect_class = http.HttpResponsePermanentRedirect response_redirect_class = http.HttpResponsePermanentRedirect
def __init__(self): def __init__(self, get_response=None):
if not apps.is_installed('django.contrib.sites'): if not apps.is_installed('django.contrib.sites'):
raise ImproperlyConfigured( raise ImproperlyConfigured(
"You cannot use RedirectFallbackMiddleware when " "You cannot use RedirectFallbackMiddleware when "
"django.contrib.sites is not installed." "django.contrib.sites is not installed."
) )
super(RedirectFallbackMiddleware, self).__init__(get_response)
def __call__(self, request):
response = super(RedirectFallbackMiddleware, self).__call__(request)
return self.process_response(request, response)
def process_response(self, request, response): def process_response(self, request, response):
# No need to check for a redirect for non-404 responses. # No need to check for a redirect for non-404 responses.

View File

@ -5,11 +5,13 @@ from django.conf import settings
from django.contrib.sessions.backends.base import UpdateError from django.contrib.sessions.backends.base import UpdateError
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
from django.utils.deprecation import MiddlewareMixin
from django.utils.http import cookie_date from django.utils.http import cookie_date
class SessionMiddleware(object): class SessionMiddleware(MiddlewareMixin):
def __init__(self): def __init__(self, get_response=None):
self.get_response = get_response
engine = import_module(settings.SESSION_ENGINE) engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore self.SessionStore = engine.SessionStore

View File

@ -1,13 +1,14 @@
from django.conf import settings from django.conf import settings
from .. import Tags, Warning, register from .. import Tags, Warning, register
from ..utils import patch_middleware_message
SECRET_KEY_MIN_LENGTH = 50 SECRET_KEY_MIN_LENGTH = 50
SECRET_KEY_MIN_UNIQUE_CHARACTERS = 5 SECRET_KEY_MIN_UNIQUE_CHARACTERS = 5
W001 = Warning( W001 = Warning(
"You do not have 'django.middleware.security.SecurityMiddleware' " "You do not have 'django.middleware.security.SecurityMiddleware' "
"in your MIDDLEWARE_CLASSES so the SECURE_HSTS_SECONDS, " "in your MIDDLEWARE so the SECURE_HSTS_SECONDS, "
"SECURE_CONTENT_TYPE_NOSNIFF, " "SECURE_CONTENT_TYPE_NOSNIFF, "
"SECURE_BROWSER_XSS_FILTER, and SECURE_SSL_REDIRECT settings " "SECURE_BROWSER_XSS_FILTER, and SECURE_SSL_REDIRECT settings "
"will have no effect.", "will have no effect.",
@ -17,7 +18,7 @@ W001 = Warning(
W002 = Warning( W002 = Warning(
"You do not have " "You do not have "
"'django.middleware.clickjacking.XFrameOptionsMiddleware' in your " "'django.middleware.clickjacking.XFrameOptionsMiddleware' in your "
"MIDDLEWARE_CLASSES, so your pages will not be served with an " "MIDDLEWARE, so your pages will not be served with an "
"'x-frame-options' header. Unless there is a good reason for your " "'x-frame-options' header. Unless there is a good reason for your "
"site to be served in a frame, you should consider enabling this " "site to be served in a frame, you should consider enabling this "
"header to help prevent clickjacking attacks.", "header to help prevent clickjacking attacks.",
@ -88,7 +89,7 @@ W018 = Warning(
W019 = Warning( W019 = Warning(
"You have " "You have "
"'django.middleware.clickjacking.XFrameOptionsMiddleware' in your " "'django.middleware.clickjacking.XFrameOptionsMiddleware' in your "
"MIDDLEWARE_CLASSES, but X_FRAME_OPTIONS is not set to 'DENY'. " "MIDDLEWARE, but X_FRAME_OPTIONS is not set to 'DENY'. "
"The default is 'SAMEORIGIN', but unless there is a good reason for " "The default is 'SAMEORIGIN', but unless there is a good reason for "
"your site to serve other parts of itself in a frame, you should " "your site to serve other parts of itself in a frame, you should "
"change it to 'DENY'.", "change it to 'DENY'.",
@ -102,23 +103,25 @@ W020 = Warning(
def _security_middleware(): def _security_middleware():
return "django.middleware.security.SecurityMiddleware" in settings.MIDDLEWARE_CLASSES return ("django.middleware.security.SecurityMiddleware" in settings.MIDDLEWARE_CLASSES or
settings.MIDDLEWARE and "django.middleware.security.SecurityMiddleware" in settings.MIDDLEWARE)
def _xframe_middleware(): def _xframe_middleware():
return "django.middleware.clickjacking.XFrameOptionsMiddleware" in settings.MIDDLEWARE_CLASSES return ("django.middleware.clickjacking.XFrameOptionsMiddleware" in settings.MIDDLEWARE_CLASSES or
settings.MIDDLEWARE and "django.middleware.clickjacking.XFrameOptionsMiddleware" in settings.MIDDLEWARE)
@register(Tags.security, deploy=True) @register(Tags.security, deploy=True)
def check_security_middleware(app_configs, **kwargs): def check_security_middleware(app_configs, **kwargs):
passed_check = _security_middleware() passed_check = _security_middleware()
return [] if passed_check else [W001] return [] if passed_check else [patch_middleware_message(W001)]
@register(Tags.security, deploy=True) @register(Tags.security, deploy=True)
def check_xframe_options_middleware(app_configs, **kwargs): def check_xframe_options_middleware(app_configs, **kwargs):
passed_check = _xframe_middleware() passed_check = _xframe_middleware()
return [] if passed_check else [W002] return [] if passed_check else [patch_middleware_message(W002)]
@register(Tags.security, deploy=True) @register(Tags.security, deploy=True)
@ -186,7 +189,7 @@ def check_xframe_deny(app_configs, **kwargs):
not _xframe_middleware() or not _xframe_middleware() or
settings.X_FRAME_OPTIONS == 'DENY' settings.X_FRAME_OPTIONS == 'DENY'
) )
return [] if passed_check else [W019] return [] if passed_check else [patch_middleware_message(W019)]
@register(Tags.security, deploy=True) @register(Tags.security, deploy=True)

View File

@ -1,19 +1,20 @@
from django.conf import settings from django.conf import settings
from .. import Tags, Warning, register from .. import Tags, Warning, register
from ..utils import patch_middleware_message
W003 = Warning( W003 = Warning(
"You don't appear to be using Django's built-in " "You don't appear to be using Django's built-in "
"cross-site request forgery protection via the middleware " "cross-site request forgery protection via the middleware "
"('django.middleware.csrf.CsrfViewMiddleware' is not in your " "('django.middleware.csrf.CsrfViewMiddleware' is not in your "
"MIDDLEWARE_CLASSES). Enabling the middleware is the safest approach " "MIDDLEWARE). Enabling the middleware is the safest approach "
"to ensure you don't leave any holes.", "to ensure you don't leave any holes.",
id='security.W003', id='security.W003',
) )
W016 = Warning( W016 = Warning(
"You have 'django.middleware.csrf.CsrfViewMiddleware' in your " "You have 'django.middleware.csrf.CsrfViewMiddleware' in your "
"MIDDLEWARE_CLASSES, but you have not set CSRF_COOKIE_SECURE to True. " "MIDDLEWARE, but you have not set CSRF_COOKIE_SECURE to True. "
"Using a secure-only CSRF cookie makes it more difficult for network " "Using a secure-only CSRF cookie makes it more difficult for network "
"traffic sniffers to steal the CSRF token.", "traffic sniffers to steal the CSRF token.",
id='security.W016', id='security.W016',
@ -21,7 +22,7 @@ W016 = Warning(
W017 = Warning( W017 = Warning(
"You have 'django.middleware.csrf.CsrfViewMiddleware' in your " "You have 'django.middleware.csrf.CsrfViewMiddleware' in your "
"MIDDLEWARE_CLASSES, but you have not set CSRF_COOKIE_HTTPONLY to True. " "MIDDLEWARE, but you have not set CSRF_COOKIE_HTTPONLY to True. "
"Using an HttpOnly CSRF cookie makes it more difficult for cross-site " "Using an HttpOnly CSRF cookie makes it more difficult for cross-site "
"scripting attacks to steal the CSRF token.", "scripting attacks to steal the CSRF token.",
id='security.W017', id='security.W017',
@ -29,13 +30,14 @@ W017 = Warning(
def _csrf_middleware(): def _csrf_middleware():
return "django.middleware.csrf.CsrfViewMiddleware" in settings.MIDDLEWARE_CLASSES return ("django.middleware.csrf.CsrfViewMiddleware" in settings.MIDDLEWARE_CLASSES or
settings.MIDDLEWARE and "django.middleware.csrf.CsrfViewMiddleware" in settings.MIDDLEWARE)
@register(Tags.security, deploy=True) @register(Tags.security, deploy=True)
def check_csrf_middleware(app_configs, **kwargs): def check_csrf_middleware(app_configs, **kwargs):
passed_check = _csrf_middleware() passed_check = _csrf_middleware()
return [] if passed_check else [W003] return [] if passed_check else [patch_middleware_message(W003)]
@register(Tags.security, deploy=True) @register(Tags.security, deploy=True)
@ -44,7 +46,7 @@ def check_csrf_cookie_secure(app_configs, **kwargs):
not _csrf_middleware() or not _csrf_middleware() or
settings.CSRF_COOKIE_SECURE settings.CSRF_COOKIE_SECURE
) )
return [] if passed_check else [W016] return [] if passed_check else [patch_middleware_message(W016)]
@register(Tags.security, deploy=True) @register(Tags.security, deploy=True)
@ -53,4 +55,4 @@ def check_csrf_cookie_httponly(app_configs, **kwargs):
not _csrf_middleware() or not _csrf_middleware() or
settings.CSRF_COOKIE_HTTPONLY settings.CSRF_COOKIE_HTTPONLY
) )
return [] if passed_check else [W017] return [] if passed_check else [patch_middleware_message(W017)]

View File

@ -1,6 +1,7 @@
from django.conf import settings from django.conf import settings
from .. import Tags, Warning, register from .. import Tags, Warning, register
from ..utils import patch_middleware_message
def add_session_cookie_message(message): def add_session_cookie_message(message):
@ -20,7 +21,7 @@ W010 = Warning(
W011 = Warning( W011 = Warning(
add_session_cookie_message( add_session_cookie_message(
"You have 'django.contrib.sessions.middleware.SessionMiddleware' " "You have 'django.contrib.sessions.middleware.SessionMiddleware' "
"in your MIDDLEWARE_CLASSES, but you have not set " "in your MIDDLEWARE, but you have not set "
"SESSION_COOKIE_SECURE to True." "SESSION_COOKIE_SECURE to True."
), ),
id='security.W011', id='security.W011',
@ -50,7 +51,7 @@ W013 = Warning(
W014 = Warning( W014 = Warning(
add_httponly_message( add_httponly_message(
"You have 'django.contrib.sessions.middleware.SessionMiddleware' " "You have 'django.contrib.sessions.middleware.SessionMiddleware' "
"in your MIDDLEWARE_CLASSES, but you have not set " "in your MIDDLEWARE, but you have not set "
"SESSION_COOKIE_HTTPONLY to True." "SESSION_COOKIE_HTTPONLY to True."
), ),
id='security.W014', id='security.W014',
@ -69,7 +70,7 @@ def check_session_cookie_secure(app_configs, **kwargs):
if _session_app(): if _session_app():
errors.append(W010) errors.append(W010)
if _session_middleware(): if _session_middleware():
errors.append(W011) errors.append(patch_middleware_message(W011))
if len(errors) > 1: if len(errors) > 1:
errors = [W012] errors = [W012]
return errors return errors
@ -82,15 +83,15 @@ def check_session_cookie_httponly(app_configs, **kwargs):
if _session_app(): if _session_app():
errors.append(W013) errors.append(W013)
if _session_middleware(): if _session_middleware():
errors.append(W014) errors.append(patch_middleware_message(W014))
if len(errors) > 1: if len(errors) > 1:
errors = [W015] errors = [W015]
return errors return errors
def _session_middleware(): def _session_middleware():
return ("django.contrib.sessions.middleware.SessionMiddleware" in return ("django.contrib.sessions.middleware.SessionMiddleware" in settings.MIDDLEWARE_CLASSES or
settings.MIDDLEWARE_CLASSES) settings.MIDDLEWARE and "django.contrib.sessions.middleware.SessionMiddleware" in settings.MIDDLEWARE)
def _session_app(): def _session_app():

View File

@ -0,0 +1,10 @@
import copy
from django.conf import settings
def patch_middleware_message(error):
if settings.MIDDLEWARE is None:
error = copy.copy(error)
error.msg = error.msg.replace('MIDDLEWARE', 'MIDDLEWARE_CLASSES')
return error

View File

@ -7,7 +7,7 @@ import warnings
from django.conf import settings from django.conf import settings
from django.core import signals from django.core import signals
from django.core.exceptions import MiddlewareNotUsed from django.core.exceptions import ImproperlyConfigured, MiddlewareNotUsed
from django.db import connections, transaction from django.db import connections, transaction
from django.middleware.exception import ExceptionMiddleware from django.middleware.exception import ExceptionMiddleware
from django.urls import get_resolver, get_urlconf, set_urlconf from django.urls import get_resolver, get_urlconf, set_urlconf
@ -31,7 +31,8 @@ class BaseHandler(object):
def load_middleware(self): def load_middleware(self):
""" """
Populate middleware lists from settings.MIDDLEWARE_CLASSES. Populate middleware lists from settings.MIDDLEWARE (or the deprecated
MIDDLEWARE_CLASSES).
Must be called after the environment is fixed (see __call__ in subclasses). Must be called after the environment is fixed (see __call__ in subclasses).
""" """
@ -41,29 +42,55 @@ class BaseHandler(object):
self._response_middleware = [] self._response_middleware = []
self._exception_middleware = [] self._exception_middleware = []
handler = self._legacy_get_response if settings.MIDDLEWARE is None:
for middleware_path in settings.MIDDLEWARE_CLASSES: handler = self._legacy_get_response
mw_class = import_string(middleware_path) for middleware_path in settings.MIDDLEWARE_CLASSES:
try: mw_class = import_string(middleware_path)
mw_instance = mw_class() try:
except MiddlewareNotUsed as exc: mw_instance = mw_class()
if settings.DEBUG: except MiddlewareNotUsed as exc:
if six.text_type(exc): if settings.DEBUG:
logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc) if six.text_type(exc):
else: logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
logger.debug('MiddlewareNotUsed: %r', middleware_path) else:
continue logger.debug('MiddlewareNotUsed: %r', middleware_path)
continue
if hasattr(mw_instance, 'process_request'): if hasattr(mw_instance, 'process_request'):
self._request_middleware.append(mw_instance.process_request) self._request_middleware.append(mw_instance.process_request)
if hasattr(mw_instance, 'process_view'): if hasattr(mw_instance, 'process_view'):
self._view_middleware.append(mw_instance.process_view) self._view_middleware.append(mw_instance.process_view)
if hasattr(mw_instance, 'process_template_response'): if hasattr(mw_instance, 'process_template_response'):
self._template_response_middleware.insert(0, mw_instance.process_template_response) self._template_response_middleware.insert(0, mw_instance.process_template_response)
if hasattr(mw_instance, 'process_response'): if hasattr(mw_instance, 'process_response'):
self._response_middleware.insert(0, mw_instance.process_response) self._response_middleware.insert(0, mw_instance.process_response)
if hasattr(mw_instance, 'process_exception'): if hasattr(mw_instance, 'process_exception'):
self._exception_middleware.insert(0, mw_instance.process_exception) self._exception_middleware.insert(0, mw_instance.process_exception)
else:
handler = self._get_response
for middleware_path in reversed(settings.MIDDLEWARE):
middleware = import_string(middleware_path)
try:
mw_instance = middleware(handler)
except MiddlewareNotUsed as exc:
if settings.DEBUG:
if six.text_type(exc):
logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
else:
logger.debug('MiddlewareNotUsed: %r', middleware_path)
continue
if mw_instance is None:
raise ImproperlyConfigured(
'Middleware factory %s returned None.' % middleware_path
)
if hasattr(mw_instance, 'process_view'):
self._view_middleware.insert(0, mw_instance.process_view)
if hasattr(mw_instance, 'process_template_response'):
self._template_response_middleware.append(mw_instance.process_template_response)
handler = mw_instance
handler = ExceptionMiddleware(handler, self) handler = ExceptionMiddleware(handler, self)

View File

@ -4,7 +4,7 @@ URL. The canonical way to enable cache middleware is to set
``UpdateCacheMiddleware`` as your first piece of middleware, and ``UpdateCacheMiddleware`` as your first piece of middleware, and
``FetchFromCacheMiddleware`` as the last:: ``FetchFromCacheMiddleware`` as the last::
MIDDLEWARE_CLASSES = [ MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.cache.UpdateCacheMiddleware',
... ...
'django.middleware.cache.FetchFromCacheMiddleware' 'django.middleware.cache.FetchFromCacheMiddleware'
@ -49,22 +49,24 @@ from django.utils.cache import (
get_cache_key, get_max_age, has_vary_header, learn_cache_key, get_cache_key, get_max_age, has_vary_header, learn_cache_key,
patch_response_headers, patch_response_headers,
) )
from django.utils.deprecation import MiddlewareMixin
class UpdateCacheMiddleware(object): class UpdateCacheMiddleware(MiddlewareMixin):
""" """
Response-phase cache middleware that updates the cache if the response is Response-phase cache middleware that updates the cache if the response is
cacheable. cacheable.
Must be used as part of the two-part update/fetch cache middleware. Must be used as part of the two-part update/fetch cache middleware.
UpdateCacheMiddleware must be the first piece of middleware in UpdateCacheMiddleware must be the first piece of middleware in MIDDLEWARE
MIDDLEWARE_CLASSES so that it'll get called last during the response phase. so that it'll get called last during the response phase.
""" """
def __init__(self): def __init__(self, get_response=None):
self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
self.cache = caches[self.cache_alias] self.cache = caches[self.cache_alias]
self.get_response = get_response
def _should_update_cache(self, request, response): def _should_update_cache(self, request, response):
return hasattr(request, '_cache_update_cache') and request._cache_update_cache return hasattr(request, '_cache_update_cache') and request._cache_update_cache
@ -104,18 +106,19 @@ class UpdateCacheMiddleware(object):
return response return response
class FetchFromCacheMiddleware(object): class FetchFromCacheMiddleware(MiddlewareMixin):
""" """
Request-phase cache middleware that fetches a page from the cache. Request-phase cache middleware that fetches a page from the cache.
Must be used as part of the two-part update/fetch cache middleware. Must be used as part of the two-part update/fetch cache middleware.
FetchFromCacheMiddleware must be the last piece of middleware in FetchFromCacheMiddleware must be the last piece of middleware in MIDDLEWARE
MIDDLEWARE_CLASSES so that it'll get called last during the request phase. so that it'll get called last during the request phase.
""" """
def __init__(self): def __init__(self, get_response=None):
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
self.cache = caches[self.cache_alias] self.cache = caches[self.cache_alias]
self.get_response = get_response
def process_request(self, request): def process_request(self, request):
""" """
@ -153,7 +156,8 @@ class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware):
Also used as the hook point for the cache decorator, which is generated Also used as the hook point for the cache decorator, which is generated
using the decorator-from-middleware utility. using the decorator-from-middleware utility.
""" """
def __init__(self, cache_timeout=None, **kwargs): def __init__(self, get_response=None, cache_timeout=None, **kwargs):
self.get_response = get_response
# We need to differentiate between "provided, but using default value", # We need to differentiate between "provided, but using default value",
# and "not provided". If the value is provided using a default, then # and "not provided". If the value is provided using a default, then
# we fall back to system defaults. If it is not provided at all, # we fall back to system defaults. If it is not provided at all,

View File

@ -6,9 +6,10 @@ malicious site loading resources from your site in a hidden frame.
""" """
from django.conf import settings from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
class XFrameOptionsMiddleware(object): class XFrameOptionsMiddleware(MiddlewareMixin):
""" """
Middleware that sets the X-Frame-Options HTTP header in HTTP responses. Middleware that sets the X-Frame-Options HTTP header in HTTP responses.

View File

@ -7,6 +7,7 @@ from django.core.exceptions import PermissionDenied
from django.core.mail import mail_managers from django.core.mail import mail_managers
from django.urls import is_valid_path from django.urls import is_valid_path
from django.utils.cache import get_conditional_response, set_response_etag from django.utils.cache import get_conditional_response, set_response_etag
from django.utils.deprecation import MiddlewareMixin
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.http import unquote_etag from django.utils.http import unquote_etag
from django.utils.six.moves.urllib.parse import urlparse from django.utils.six.moves.urllib.parse import urlparse
@ -14,7 +15,7 @@ from django.utils.six.moves.urllib.parse import urlparse
logger = logging.getLogger('django.request') logger = logging.getLogger('django.request')
class CommonMiddleware(object): class CommonMiddleware(MiddlewareMixin):
""" """
"Common" middleware for taking care of some basic operations: "Common" middleware for taking care of some basic operations:
@ -129,7 +130,7 @@ class CommonMiddleware(object):
return response return response
class BrokenLinkEmailsMiddleware(object): class BrokenLinkEmailsMiddleware(MiddlewareMixin):
def process_response(self, request, response): def process_response(self, request, response):
""" """

View File

@ -13,6 +13,7 @@ from django.conf import settings
from django.urls import get_callable from django.urls import get_callable
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
from django.utils.crypto import constant_time_compare, get_random_string from django.utils.crypto import constant_time_compare, get_random_string
from django.utils.deprecation import MiddlewareMixin
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.http import is_same_domain from django.utils.http import is_same_domain
from django.utils.six.moves.urllib.parse import urlparse from django.utils.six.moves.urllib.parse import urlparse
@ -78,7 +79,7 @@ def _sanitize_token(token):
return token return token
class CsrfViewMiddleware(object): class CsrfViewMiddleware(MiddlewareMixin):
""" """
Middleware that requires a present and correct csrfmiddlewaretoken Middleware that requires a present and correct csrfmiddlewaretoken
for POST requests that have a CSRF cookie, and sets an outgoing for POST requests that have a CSRF cookie, and sets an outgoing

View File

@ -1,12 +1,13 @@
import re import re
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
from django.utils.deprecation import MiddlewareMixin
from django.utils.text import compress_sequence, compress_string from django.utils.text import compress_sequence, compress_string
re_accepts_gzip = re.compile(r'\bgzip\b') re_accepts_gzip = re.compile(r'\bgzip\b')
class GZipMiddleware(object): class GZipMiddleware(MiddlewareMixin):
""" """
This middleware compresses content if the browser allows gzip compression. This middleware compresses content if the browser allows gzip compression.
It sets the Vary header accordingly, so that caches will base their storage It sets the Vary header accordingly, so that caches will base their storage

View File

@ -1,8 +1,9 @@
from django.utils.cache import get_conditional_response from django.utils.cache import get_conditional_response
from django.utils.deprecation import MiddlewareMixin
from django.utils.http import http_date, parse_http_date_safe, unquote_etag from django.utils.http import http_date, parse_http_date_safe, unquote_etag
class ConditionalGetMiddleware(object): class ConditionalGetMiddleware(MiddlewareMixin):
""" """
Handles conditional GET operations. If the response has an ETag or Handles conditional GET operations. If the response has an ETag or
Last-Modified header, and the request has If-None-Match or Last-Modified header, and the request has If-None-Match or

View File

@ -3,12 +3,13 @@
from django.conf import settings from django.conf import settings
from django.conf.urls.i18n import is_language_prefix_patterns_used from django.conf.urls.i18n import is_language_prefix_patterns_used
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.middleware.exception import ExceptionMiddleware
from django.urls import get_script_prefix, is_valid_path from django.urls import get_script_prefix, is_valid_path
from django.utils import translation from django.utils import translation
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
class LocaleMiddleware(object): class LocaleMiddleware(ExceptionMiddleware):
""" """
This is a very simple middleware that parses a request This is a very simple middleware that parses a request
and decides what translation object to install in the current and decides what translation object to install in the current
@ -18,6 +19,17 @@ class LocaleMiddleware(object):
""" """
response_redirect_class = HttpResponseRedirect response_redirect_class = HttpResponseRedirect
def __init__(self, get_response=None):
# This override makes get_response optional during the
# MIDDLEWARE_CLASSES deprecation.
super(LocaleMiddleware, self).__init__(get_response)
def __call__(self, request):
response = self.process_request(request)
if not response:
response = super(LocaleMiddleware, self).__call__(request)
return self.process_response(request, response)
def process_request(self, request): def process_request(self, request):
urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF) urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF)
i18n_patterns_used, prefixed_default_language = is_language_prefix_patterns_used(urlconf) i18n_patterns_used, prefixed_default_language = is_language_prefix_patterns_used(urlconf)

View File

@ -2,10 +2,11 @@ import re
from django.conf import settings from django.conf import settings
from django.http import HttpResponsePermanentRedirect from django.http import HttpResponsePermanentRedirect
from django.utils.deprecation import MiddlewareMixin
class SecurityMiddleware(object): class SecurityMiddleware(MiddlewareMixin):
def __init__(self): def __init__(self, get_response=None):
self.sts_seconds = settings.SECURE_HSTS_SECONDS self.sts_seconds = settings.SECURE_HSTS_SECONDS
self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS
self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF
@ -13,6 +14,7 @@ class SecurityMiddleware(object):
self.redirect = settings.SECURE_SSL_REDIRECT self.redirect = settings.SECURE_SSL_REDIRECT
self.redirect_host = settings.SECURE_SSL_HOST self.redirect_host = settings.SECURE_SSL_HOST
self.redirect_exempt = [re.compile(r) for r in settings.SECURE_REDIRECT_EXEMPT] self.redirect_exempt = [re.compile(r) for r in settings.SECURE_REDIRECT_EXEMPT]
self.get_response = get_response
def process_request(self, request): def process_request(self, request):
path = request.path.lstrip("/") path = request.path.lstrip("/")

View File

@ -125,7 +125,7 @@ class ClientHandler(BaseHandler):
def __call__(self, environ): def __call__(self, environ):
# Set up middleware if needed. We couldn't do this earlier, because # Set up middleware if needed. We couldn't do this earlier, because
# settings weren't available. # settings weren't available.
if self._request_middleware is None: if self._middleware_chain is None:
self.load_middleware() self.load_middleware()
request_started.disconnect(close_old_connections) request_started.disconnect(close_old_connections)

View File

@ -109,3 +109,25 @@ class CallableBool:
CallableFalse = CallableBool(False) CallableFalse = CallableBool(False)
CallableTrue = CallableBool(True) CallableTrue = CallableBool(True)
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__()
def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
try:
response = self.get_response(request)
except Exception as e:
if hasattr(self, 'process_exception'):
return self.process_exception(request, e)
else:
raise
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response

View File

@ -852,7 +852,8 @@ Python Version: {{ sys_version_info }}
Installed Applications: Installed Applications:
{{ settings.INSTALLED_APPS|pprint }} {{ settings.INSTALLED_APPS|pprint }}
Installed Middleware: Installed Middleware:
{{ settings.MIDDLEWARE_CLASSES|pprint }} {% if settings.MIDDLEWARE is not None %}{{ settings.MIDDLEWARE|pprint }}"""
"""{% else %}{{ settings.MIDDLEWARE_CLASSES|pprint }}{% endif %}
{% if template_does_not_exist %}Template loader postmortem {% if template_does_not_exist %}Template loader postmortem
{% if postmortem %}Django tried loading these templates, in this order: {% if postmortem %}Django tried loading these templates, in this order:
@ -1059,7 +1060,8 @@ Server time: {{server_time|date:"r"}}
Installed Applications: Installed Applications:
{{ settings.INSTALLED_APPS|pprint }} {{ settings.INSTALLED_APPS|pprint }}
Installed Middleware: Installed Middleware:
{{ settings.MIDDLEWARE_CLASSES|pprint }} {% if settings.MIDDLEWARE is not None %}{{ settings.MIDDLEWARE|pprint }}"""
"""{% else %}{{ settings.MIDDLEWARE_CLASSES|pprint }}{% endif %}
{% if template_does_not_exist %}Template loader postmortem {% if template_does_not_exist %}Template loader postmortem
{% if postmortem %}Django tried loading these templates, in this order: {% if postmortem %}Django tried loading these templates, in this order:
{% for entry in postmortem %} {% for entry in postmortem %}

View File

@ -29,10 +29,10 @@ Configuration
First, you must add the First, you must add the
:class:`django.contrib.auth.middleware.RemoteUserMiddleware` to the :class:`django.contrib.auth.middleware.RemoteUserMiddleware` to the
:setting:`MIDDLEWARE_CLASSES` setting **after** the :setting:`MIDDLEWARE` setting **after** the
:class:`django.contrib.auth.middleware.AuthenticationMiddleware`:: :class:`django.contrib.auth.middleware.AuthenticationMiddleware`::
MIDDLEWARE_CLASSES = [ MIDDLEWARE = [
'...', '...',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware', 'django.contrib.auth.middleware.RemoteUserMiddleware',

View File

@ -57,7 +57,7 @@ not found" errors). Django sends emails about 404 errors when:
* :setting:`DEBUG` is ``False``; * :setting:`DEBUG` is ``False``;
* Your :setting:`MIDDLEWARE_CLASSES` setting includes * Your :setting:`MIDDLEWARE` setting includes
:class:`django.middleware.common.BrokenLinkEmailsMiddleware`. :class:`django.middleware.common.BrokenLinkEmailsMiddleware`.
If those conditions are met, Django will email the users listed in the If those conditions are met, Django will email the users listed in the
@ -78,7 +78,7 @@ behavior is from broken Web bots too.
before other middleware that intercepts 404 errors, such as before other middleware that intercepts 404 errors, such as
:class:`~django.middleware.locale.LocaleMiddleware` or :class:`~django.middleware.locale.LocaleMiddleware` or
:class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`. :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`.
Put it towards the top of your :setting:`MIDDLEWARE_CLASSES` setting. Put it towards the top of your :setting:`MIDDLEWARE` setting.
You can tell Django to stop reporting particular 404s by tweaking the You can tell Django to stop reporting particular 404s by tweaking the
:setting:`IGNORABLE_404_URLS` setting. It should be a list of compiled :setting:`IGNORABLE_404_URLS` setting. It should be a list of compiled

View File

@ -37,8 +37,8 @@ projects.
Applications include some combination of models, views, templates, template Applications include some combination of models, views, templates, template
tags, static files, URLs, middleware, etc. They're generally wired into tags, static files, URLs, middleware, etc. They're generally wired into
projects with the :setting:`INSTALLED_APPS` setting and optionally with other projects with the :setting:`INSTALLED_APPS` setting and optionally with other
mechanisms such as URLconfs, the :setting:`MIDDLEWARE_CLASSES` setting, or mechanisms such as URLconfs, the :setting:`MIDDLEWARE` setting, or template
template inheritance. inheritance.
It is important to understand that a Django application is just a set of code It is important to understand that a Django application is just a set of code
that interacts with various parts of the framework. There's no such thing as that interacts with various parts of the framework. There's no such thing as

View File

@ -491,19 +491,19 @@ The following checks are run if you use the :option:`check --deploy` option:
* **security.W001**: You do not have * **security.W001**: You do not have
:class:`django.middleware.security.SecurityMiddleware` in your :class:`django.middleware.security.SecurityMiddleware` in your
:setting:`MIDDLEWARE_CLASSES` so the :setting:`SECURE_HSTS_SECONDS`, :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES` so the :setting:`SECURE_HSTS_SECONDS`,
:setting:`SECURE_CONTENT_TYPE_NOSNIFF`, :setting:`SECURE_BROWSER_XSS_FILTER`, :setting:`SECURE_CONTENT_TYPE_NOSNIFF`, :setting:`SECURE_BROWSER_XSS_FILTER`,
and :setting:`SECURE_SSL_REDIRECT` settings will have no effect. and :setting:`SECURE_SSL_REDIRECT` settings will have no effect.
* **security.W002**: You do not have * **security.W002**: You do not have
:class:`django.middleware.clickjacking.XFrameOptionsMiddleware` in your :class:`django.middleware.clickjacking.XFrameOptionsMiddleware` in your
:setting:`MIDDLEWARE_CLASSES`, so your pages will not be served with an :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, so your pages will not be served with an
``'x-frame-options'`` header. Unless there is a good reason for your ``'x-frame-options'`` header. Unless there is a good reason for your
site to be served in a frame, you should consider enabling this site to be served in a frame, you should consider enabling this
header to help prevent clickjacking attacks. header to help prevent clickjacking attacks.
* **security.W003**: You don't appear to be using Django's built-in cross-site * **security.W003**: You don't appear to be using Django's built-in cross-site
request forgery protection via the middleware request forgery protection via the middleware
(:class:`django.middleware.csrf.CsrfViewMiddleware` is not in your (:class:`django.middleware.csrf.CsrfViewMiddleware` is not in your
:setting:`MIDDLEWARE_CLASSES`). Enabling the middleware is the safest :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`). Enabling the middleware is the safest
approach to ensure you don't leave any holes. approach to ensure you don't leave any holes.
* **security.W004**: You have not set a value for the * **security.W004**: You have not set a value for the
:setting:`SECURE_HSTS_SECONDS` setting. If your entire site is served only :setting:`SECURE_HSTS_SECONDS` setting. If your entire site is served only
@ -540,7 +540,7 @@ The following checks are run if you use the :option:`check --deploy` option:
sessions. sessions.
* **security.W011**: You have * **security.W011**: You have
:class:`django.contrib.sessions.middleware.SessionMiddleware` in your :class:`django.contrib.sessions.middleware.SessionMiddleware` in your
:setting:`MIDDLEWARE_CLASSES`, but you have not set :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, but you have not set
:setting:`SESSION_COOKIE_SECURE` to ``True``. Using a secure-only session :setting:`SESSION_COOKIE_SECURE` to ``True``. Using a secure-only session
cookie makes it more difficult for network traffic sniffers to hijack user cookie makes it more difficult for network traffic sniffers to hijack user
sessions. sessions.
@ -554,7 +554,7 @@ The following checks are run if you use the :option:`check --deploy` option:
sessions. sessions.
* **security.W014**: You have * **security.W014**: You have
:class:`django.contrib.sessions.middleware.SessionMiddleware` in your :class:`django.contrib.sessions.middleware.SessionMiddleware` in your
:setting:`MIDDLEWARE_CLASSES`, but you have not set :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, but you have not set
:setting:`SESSION_COOKIE_HTTPONLY` to ``True``. Using an ``HttpOnly`` session :setting:`SESSION_COOKIE_HTTPONLY` to ``True``. Using an ``HttpOnly`` session
cookie makes it more difficult for cross-site scripting attacks to hijack user cookie makes it more difficult for cross-site scripting attacks to hijack user
sessions. sessions.
@ -571,7 +571,7 @@ The following checks are run if you use the :option:`check --deploy` option:
deployment. deployment.
* **security.W019**: You have * **security.W019**: You have
:class:`django.middleware.clickjacking.XFrameOptionsMiddleware` in your :class:`django.middleware.clickjacking.XFrameOptionsMiddleware` in your
:setting:`MIDDLEWARE_CLASSES`, but :setting:`X_FRAME_OPTIONS` is not set to :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, but :setting:`X_FRAME_OPTIONS` is not set to
``'DENY'``. The default is ``'SAMEORIGIN'``, but unless there is a good reason ``'DENY'``. The default is ``'SAMEORIGIN'``, but unless there is a good reason
for your site to serve other parts of itself in a frame, you should change for your site to serve other parts of itself in a frame, you should change
it to ``'DENY'``. it to ``'DENY'``.

View File

@ -56,9 +56,9 @@ Setting ``X-Frame-Options`` for all responses
To set the same ``X-Frame-Options`` value for all responses in your site, put To set the same ``X-Frame-Options`` value for all responses in your site, put
``'django.middleware.clickjacking.XFrameOptionsMiddleware'`` to ``'django.middleware.clickjacking.XFrameOptionsMiddleware'`` to
:setting:`MIDDLEWARE_CLASSES`:: :setting:`MIDDLEWARE`::
MIDDLEWARE_CLASSES = [ MIDDLEWARE = [
... ...
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
... ...

View File

@ -41,8 +41,8 @@ For reference, here are the requirements:
defined in your :setting:`TEMPLATES` as well as defined in your :setting:`TEMPLATES` as well as
:class:`django.contrib.auth.middleware.AuthenticationMiddleware` and :class:`django.contrib.auth.middleware.AuthenticationMiddleware` and
:class:`django.contrib.messages.middleware.MessageMiddleware` to :class:`django.contrib.messages.middleware.MessageMiddleware` to
:setting:`MIDDLEWARE_CLASSES`. (These are all active by default, so :setting:`MIDDLEWARE`. These are all active by default, so you only need to
you only need to do this if you've manually tweaked the settings.) do this if you've manually tweaked the settings.
4. Determine which of your application's models should be editable in the 4. Determine which of your application's models should be editable in the
admin interface. admin interface.

View File

@ -53,7 +53,7 @@ Then either:
or: or:
3. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'`` 3. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'``
to your :setting:`MIDDLEWARE_CLASSES` setting. to your :setting:`MIDDLEWARE` setting.
4. Run the command :djadmin:`manage.py migrate <migrate>`. 4. Run the command :djadmin:`manage.py migrate <migrate>`.
@ -144,8 +144,7 @@ can do all of the work.
methods. Only requests which are successfully routed to a view via methods. Only requests which are successfully routed to a view via
normal URL resolution apply view middleware. normal URL resolution apply view middleware.
Note that the order of :setting:`MIDDLEWARE_CLASSES` matters. Generally, you Note that the order of :setting:`MIDDLEWARE` matters. Generally, you can put
can put
:class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware` at the :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware` at the
end of the list. This means it will run first when processing the response, and end of the list. This means it will run first when processing the response, and
ensures that any other response-processing middlewares see the real flatpage ensures that any other response-processing middlewares see the real flatpage

View File

@ -27,14 +27,14 @@ already contains all the settings required to enable message functionality:
* ``'django.contrib.messages'`` is in :setting:`INSTALLED_APPS`. * ``'django.contrib.messages'`` is in :setting:`INSTALLED_APPS`.
* :setting:`MIDDLEWARE_CLASSES` contains * :setting:`MIDDLEWARE` contains
``'django.contrib.sessions.middleware.SessionMiddleware'`` and ``'django.contrib.sessions.middleware.SessionMiddleware'`` and
``'django.contrib.messages.middleware.MessageMiddleware'``. ``'django.contrib.messages.middleware.MessageMiddleware'``.
The default :ref:`storage backend <message-storage-backends>` relies on The default :ref:`storage backend <message-storage-backends>` relies on
:doc:`sessions </topics/http/sessions>`. That's why ``SessionMiddleware`` :doc:`sessions </topics/http/sessions>`. That's why ``SessionMiddleware``
must be enabled and appear before ``MessageMiddleware`` in must be enabled and appear before ``MessageMiddleware`` in
:setting:`MIDDLEWARE_CLASSES`. :setting:`MIDDLEWARE`.
* The ``'context_processors'`` option of the ``DjangoTemplates`` backend * The ``'context_processors'`` option of the ``DjangoTemplates`` backend
defined in your :setting:`TEMPLATES` setting contains defined in your :setting:`TEMPLATES` setting contains
@ -42,8 +42,8 @@ already contains all the settings required to enable message functionality:
If you don't want to use messages, you can remove If you don't want to use messages, you can remove
``'django.contrib.messages'`` from your :setting:`INSTALLED_APPS`, the ``'django.contrib.messages'`` from your :setting:`INSTALLED_APPS`, the
``MessageMiddleware`` line from :setting:`MIDDLEWARE_CLASSES`, and the ``MessageMiddleware`` line from :setting:`MIDDLEWARE`, and the ``messages``
``messages`` context processor from :setting:`TEMPLATES`. context processor from :setting:`TEMPLATES`.
Configuring the message engine Configuring the message engine
============================== ==============================

View File

@ -18,7 +18,7 @@ To install the redirects app, follow these steps:
:ref:`is installed <enabling-the-sites-framework>`. :ref:`is installed <enabling-the-sites-framework>`.
2. Add ``'django.contrib.redirects'`` to your :setting:`INSTALLED_APPS` setting. 2. Add ``'django.contrib.redirects'`` to your :setting:`INSTALLED_APPS` setting.
3. Add ``'django.contrib.redirects.middleware.RedirectFallbackMiddleware'`` 3. Add ``'django.contrib.redirects.middleware.RedirectFallbackMiddleware'``
to your :setting:`MIDDLEWARE_CLASSES` setting. to your :setting:`MIDDLEWARE` setting.
4. Run the command :djadmin:`manage.py migrate <migrate>`. 4. Run the command :djadmin:`manage.py migrate <migrate>`.
How it works How it works
@ -49,9 +49,9 @@ given ``old_path`` with a site ID that corresponds to the
The middleware only gets activated for 404s -- not for 500s or responses of any The middleware only gets activated for 404s -- not for 500s or responses of any
other status code. other status code.
Note that the order of :setting:`MIDDLEWARE_CLASSES` matters. Generally, you Note that the order of :setting:`MIDDLEWARE` matters. Generally, you can put
can put :class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware` :class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware` at the
at the end of the list, because it's a last resort. end of the list, because it's a last resort.
For more on middleware, read the :doc:`middleware docs For more on middleware, read the :doc:`middleware docs
</topics/http/middleware>`. </topics/http/middleware>`.

View File

@ -405,8 +405,8 @@ If you often use this pattern::
there is simple way to avoid repetitions. Add there is simple way to avoid repetitions. Add
:class:`django.contrib.sites.middleware.CurrentSiteMiddleware` to :class:`django.contrib.sites.middleware.CurrentSiteMiddleware` to
:setting:`MIDDLEWARE_CLASSES`. The middleware sets the ``site`` attribute on :setting:`MIDDLEWARE`. The middleware sets the ``site`` attribute on every
every request object, so you can use ``request.site`` to get the current site. request object, so you can use ``request.site`` to get the current site.
How Django uses the sites framework How Django uses the sites framework
=================================== ===================================

View File

@ -27,10 +27,10 @@ How to use it
To take advantage of CSRF protection in your views, follow these steps: To take advantage of CSRF protection in your views, follow these steps:
1. The CSRF middleware is activated by default in the 1. The CSRF middleware is activated by default in the :setting:`MIDDLEWARE`
:setting:`MIDDLEWARE_CLASSES` setting. If you override that setting, remember setting. If you override that setting, remember that
that ``'django.middleware.csrf.CsrfViewMiddleware'`` should come before any ``'django.middleware.csrf.CsrfViewMiddleware'`` should come before any view
view middleware that assume that CSRF attacks have been dealt with. middleware that assume that CSRF attacks have been dealt with.
If you disabled it, which is not recommended, you can use If you disabled it, which is not recommended, you can use
:func:`~django.views.decorators.csrf.csrf_protect` on particular views :func:`~django.views.decorators.csrf.csrf_protect` on particular views

View File

@ -77,6 +77,36 @@ issued by the middleware.
* Sends broken link notification emails to :setting:`MANAGERS` (see * Sends broken link notification emails to :setting:`MANAGERS` (see
:doc:`/howto/error-reporting`). :doc:`/howto/error-reporting`).
Exception middleware
--------------------
.. module:: django.middleware.exception
:synopsis: Middleware to return responses for exceptions.
.. class:: ExceptionMiddleware
.. versionadded:: 1.10
Catches exceptions raised during the request/response cycle and returns the
appropriate response.
* :class:`~django.http.Http404` is processed by
:data:`~django.conf.urls.handler404` (or a more friendly debug page if
:setting:`DEBUG=True <DEBUG>`).
* :class:`~django.core.exceptions.PermissionDenied` is processed
by :data:`~django.conf.urls.handler403`.
* ``MultiPartParserError`` is processed by :data:`~django.conf.urls.handler400`.
* :class:`~django.core.exceptions.SuspiciousOperation` is processed by
:data:`~django.conf.urls.handler400` (or a more friendly debug page if
:setting:`DEBUG=True <DEBUG>`).
* Any other exception is processed by :data:`~django.conf.urls.handler500`
(or a more friendly debug page if :setting:`DEBUG=True <DEBUG>`).
Django uses this middleware regardless of whether or not you include it in
:setting:`MIDDLEWARE`, however, you may want to subclass if your own middleware
needs to transform any of these exceptions into the appropriate responses.
:class:`~django.middleware.locale.LocaleMiddleware` does this, for example.
GZip middleware GZip middleware
--------------- ---------------

View File

@ -176,9 +176,9 @@ All attributes should be considered read-only, unless stated otherwise.
An instance of :class:`~django.urls.ResolverMatch` representing the An instance of :class:`~django.urls.ResolverMatch` representing the
resolved URL. This attribute is only set after URL resolving took place, resolved URL. This attribute is only set after URL resolving took place,
which means it's available in all views but not in middleware methods which means it's available in all views but not in middleware which are
which are executed before URL resolving takes place (like executed before URL resolving takes place (you can use it in
``process_request()``, you can use ``process_view()`` instead). :meth:`process_view` though).
Attributes set by application code Attributes set by application code
---------------------------------- ----------------------------------
@ -210,7 +210,7 @@ Attributes set by middleware
Some of the middleware included in Django's contrib apps set attributes on the Some of the middleware included in Django's contrib apps set attributes on the
request. If you don't see the attribute on a request, be sure the appropriate request. If you don't see the attribute on a request, be sure the appropriate
middleware class is listed in :setting:`MIDDLEWARE_CLASSES`. middleware class is listed in :setting:`MIDDLEWARE`.
.. attribute:: HttpRequest.session .. attribute:: HttpRequest.session
@ -257,7 +257,9 @@ Methods
behind multiple proxies. One solution is to use middleware to rewrite behind multiple proxies. One solution is to use middleware to rewrite
the proxy headers, as in the following example:: the proxy headers, as in the following example::
class MultipleProxyMiddleware(object): from django.django.utils.deprecation import MiddlewareMixin
class MultipleProxyMiddleware(MiddlewareMixin):
FORWARDED_FOR_FIELDS = [ FORWARDED_FOR_FIELDS = [
'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED_HOST', 'HTTP_X_FORWARDED_HOST',

View File

@ -77,7 +77,7 @@ can be used as a subdomain wildcard: ``'.example.com'`` will match
``example.com``. A value of ``'*'`` will match anything; in this case you are ``example.com``. A value of ``'*'`` will match anything; in this case you are
responsible to provide your own validation of the ``Host`` header (perhaps in a responsible to provide your own validation of the ``Host`` header (perhaps in a
middleware; if so this middleware must be listed first in middleware; if so this middleware must be listed first in
:setting:`MIDDLEWARE_CLASSES`). :setting:`MIDDLEWARE`).
Django also allows the `fully qualified domain name (FQDN)`_ of any entries. Django also allows the `fully qualified domain name (FQDN)`_ of any entries.
Some browsers include a trailing dot in the ``Host`` header which Django Some browsers include a trailing dot in the ``Host`` header which Django
@ -1844,6 +1844,17 @@ Example: ``"http://media.example.com/"``
:setting:`MEDIA_URL` and :setting:`STATIC_URL` must have different :setting:`MEDIA_URL` and :setting:`STATIC_URL` must have different
values. See :setting:`MEDIA_ROOT` for more details. values. See :setting:`MEDIA_ROOT` for more details.
.. setting:: MIDDLEWARE
``MIDDLEWARE``
--------------
.. versionadded:: 1.10
Default:: ``None``
A list of middleware to use. See :doc:`/topics/http/middleware`.
.. setting:: MIDDLEWARE_CLASSES .. setting:: MIDDLEWARE_CLASSES
``MIDDLEWARE_CLASSES`` ``MIDDLEWARE_CLASSES``
@ -1856,7 +1867,11 @@ Default::
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
] ]
A list of middleware classes to use. See :doc:`/topics/http/middleware`. A list of middleware classes to use. This was the default setting used in
Django 1.9 and earlier. Django 1.10 introduced a new style of middleware. If
you have an older project using this setting you should :ref:`update any
middleware you've written yourself <upgrading-middleware>` to the new style
and then use the :setting:`MIDDLEWARE` setting.
.. setting:: MIGRATION_MODULES .. setting:: MIGRATION_MODULES
@ -3312,6 +3327,7 @@ HTTP
* :setting:`DISALLOWED_USER_AGENTS` * :setting:`DISALLOWED_USER_AGENTS`
* :setting:`FORCE_SCRIPT_NAME` * :setting:`FORCE_SCRIPT_NAME`
* :setting:`INTERNAL_IPS` * :setting:`INTERNAL_IPS`
* :setting:`MIDDLEWARE`
* :setting:`MIDDLEWARE_CLASSES` * :setting:`MIDDLEWARE_CLASSES`
* Security * Security

View File

@ -173,6 +173,10 @@ The functions defined in this module share the following properties:
middleware functionality on a per-view basis. The middleware is created middleware functionality on a per-view basis. The middleware is created
with no params passed. with no params passed.
It assumes middleware that's compatible with the old style of Django 1.9
and earlier (having methods like ``process_request()``,
``process_exception()``, and ``process_response()``).
.. function:: decorator_from_middleware_with_args(middleware_class) .. function:: decorator_from_middleware_with_args(middleware_class)
Like ``decorator_from_middleware``, but returns a function Like ``decorator_from_middleware``, but returns a function

View File

@ -37,6 +37,17 @@ It also now includes trigram support, using the :lookup:`trigram_similar`
lookup, and the :class:`~django.contrib.postgres.search.TrigramSimilarity` and lookup, and the :class:`~django.contrib.postgres.search.TrigramSimilarity` and
:class:`~django.contrib.postgres.search.TrigramDistance` expressions. :class:`~django.contrib.postgres.search.TrigramDistance` expressions.
New-style middleware
--------------------
:doc:`A new style of middleware is introduced </topics/http/middleware>` to
solve the lack of strict request/response layering of the old-style of
middleware described in `DEP 0005
<https://github.com/django/deps/blob/master/final/0005-improved-middleware.rst>`_.
You'll need to :ref:`adapt old, custom middleware <upgrading-middleware>` and
switch from the ``MIDDLEWARE_CLASSES`` setting to the new :setting:`MIDDLEWARE`
setting to take advantage of the improvements.
Official support for Unicode usernames Official support for Unicode usernames
-------------------------------------- --------------------------------------

View File

@ -188,8 +188,7 @@ is an iterator.
Since :class:`~django.http.StreamingHttpResponse` does not have a ``content`` Since :class:`~django.http.StreamingHttpResponse` does not have a ``content``
attribute, middleware that needs access to the response content must test for attribute, middleware that needs access to the response content must test for
streaming responses and behave accordingly. See :ref:`response-middleware` for streaming responses and behave accordingly.
more information.
``{% verbatim %}`` template tag ``{% verbatim %}`` template tag
------------------------------- -------------------------------

View File

@ -838,7 +838,7 @@ Session invalidation on password change
``SessionAuthenticationMiddleware`` is enabled. In older ``SessionAuthenticationMiddleware`` is enabled. In older
versions, this protection only applies if versions, this protection only applies if
``django.contrib.auth.middleware.SessionAuthenticationMiddleware`` ``django.contrib.auth.middleware.SessionAuthenticationMiddleware``
is enabled in :setting:`MIDDLEWARE_CLASSES`. is enabled in :setting:`MIDDLEWARE`.
If your :setting:`AUTH_USER_MODEL` inherits from If your :setting:`AUTH_USER_MODEL` inherits from
:class:`~django.contrib.auth.models.AbstractBaseUser` or implements its own :class:`~django.contrib.auth.models.AbstractBaseUser` or implements its own

View File

@ -60,7 +60,7 @@ startproject <startproject>`, these consist of two items listed in your
</ref/contrib/contenttypes>`, which allows permissions to be associated with </ref/contrib/contenttypes>`, which allows permissions to be associated with
models you create. models you create.
and these items in your :setting:`MIDDLEWARE_CLASSES` setting: and these items in your :setting:`MIDDLEWARE` setting:
1. :class:`~django.contrib.sessions.middleware.SessionMiddleware` manages 1. :class:`~django.contrib.sessions.middleware.SessionMiddleware` manages
:doc:`sessions </topics/http/sessions>` across requests. :doc:`sessions </topics/http/sessions>` across requests.

View File

@ -447,9 +447,9 @@ Once the cache is set up, the simplest way to use caching is to cache your
entire site. You'll need to add entire site. You'll need to add
``'django.middleware.cache.UpdateCacheMiddleware'`` and ``'django.middleware.cache.UpdateCacheMiddleware'`` and
``'django.middleware.cache.FetchFromCacheMiddleware'`` to your ``'django.middleware.cache.FetchFromCacheMiddleware'`` to your
:setting:`MIDDLEWARE_CLASSES` setting, as in this example:: :setting:`MIDDLEWARE` setting, as in this example::
MIDDLEWARE_CLASSES = [ MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware',
@ -459,7 +459,7 @@ entire site. You'll need to add
No, that's not a typo: the "update" middleware must be first in the list, No, that's not a typo: the "update" middleware must be first in the list,
and the "fetch" middleware must be last. The details are a bit obscure, but and the "fetch" middleware must be last. The details are a bit obscure, but
see `Order of MIDDLEWARE_CLASSES`_ below if you'd like the full story. see `Order of MIDDLEWARE`_ below if you'd like the full story.
Then, add the following required settings to your Django settings file: Then, add the following required settings to your Django settings file:
@ -1217,11 +1217,11 @@ Example::
def myview(request): def myview(request):
... ...
Order of ``MIDDLEWARE_CLASSES`` Order of ``MIDDLEWARE``
=============================== =======================
If you use caching middleware, it's important to put each half in the right If you use caching middleware, it's important to put each half in the right
place within the :setting:`MIDDLEWARE_CLASSES` setting. That's because the cache place within the :setting:`MIDDLEWARE` setting. That's because the cache
middleware needs to know which headers by which to vary the cache storage. middleware needs to know which headers by which to vary the cache storage.
Middleware always adds something to the ``Vary`` response header when it can. Middleware always adds something to the ``Vary`` response header when it can.

View File

@ -1,957 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ActiveLayerIndex</key>
<integer>0</integer>
<key>ApplicationVersion</key>
<array>
<string>com.omnigroup.OmniGrafflePro</string>
<string>139.16.0.171715</string>
</array>
<key>AutoAdjust</key>
<true/>
<key>BackgroundGraphic</key>
<dict>
<key>Bounds</key>
<string>{{0, 0}, {559.28997802734375, 782.8900146484375}}</string>
<key>Class</key>
<string>SolidGraphic</string>
<key>ID</key>
<integer>2</integer>
<key>Style</key>
<dict>
<key>shadow</key>
<dict>
<key>Draws</key>
<string>NO</string>
</dict>
<key>stroke</key>
<dict>
<key>Draws</key>
<string>NO</string>
</dict>
</dict>
</dict>
<key>BaseZoom</key>
<integer>0</integer>
<key>CanvasOrigin</key>
<string>{0, 0}</string>
<key>ColumnAlign</key>
<integer>1</integer>
<key>ColumnSpacing</key>
<real>36</real>
<key>CreationDate</key>
<string>2012-12-09 18:55:12 +0000</string>
<key>Creator</key>
<string>Aymeric Augustin</string>
<key>DisplayScale</key>
<string>1.000 cm = 1.000 cm</string>
<key>GraphDocumentVersion</key>
<integer>8</integer>
<key>GraphicsList</key>
<array>
<dict>
<key>Bounds</key>
<string>{{144, 405}, {369, 27}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>33</integer>
<key>Shape</key>
<string>Bezier</string>
<key>ShapeData</key>
<dict>
<key>UnitPoints</key>
<array>
<string>{-0.5, -0.5}</string>
<string>{-0.5, -0.5}</string>
<string>{0.47959183673469341, -0.5}</string>
<string>{0.47959183673469408, -0.5}</string>
<string>{0.47959183673469341, -0.5}</string>
<string>{0.5, 0}</string>
<string>{0.5, 0}</string>
<string>{0.5, 0}</string>
<string>{0.47959183673469408, 0.5}</string>
<string>{0.47959183673469408, 0.5}</string>
<string>{0.47959183673469408, 0.5}</string>
<string>{-0.5, 0.5}</string>
<string>{-0.5, 0.5}</string>
<string>{-0.5, 0.5}</string>
<string>{-0.47560975609756084, 0}</string>
<string>{-0.47560975609756084, 0}</string>
<string>{-0.47560975609756084, 0}</string>
<string>{-0.5, -0.5}</string>
</array>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf0 view function}</string>
</dict>
</dict>
<dict>
<key>Bounds</key>
<string>{{229.5, 238.5}, {297, 36}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>31</integer>
<key>Rotation</key>
<real>270</real>
<key>Shape</key>
<string>AdjustableArrow</string>
<key>ShapeData</key>
<dict>
<key>width</key>
<real>27</real>
</dict>
<key>Style</key>
<dict>
<key>fill</key>
<dict>
<key>Color</key>
<dict>
<key>a</key>
<string>0.8</string>
<key>b</key>
<string>1</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>MiddleFraction</key>
<real>0.70634919404983521</real>
</dict>
<key>shadow</key>
<dict>
<key>Color</key>
<dict>
<key>a</key>
<string>0.4</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>0</string>
<key>r</key>
<string>0</string>
</dict>
<key>Draws</key>
<string>NO</string>
<key>Fuzziness</key>
<real>0.0</real>
<key>ShadowVector</key>
<string>{0, 2}</string>
</dict>
<key>stroke</key>
<dict>
<key>Color</key>
<dict>
<key>b</key>
<string>0</string>
<key>g</key>
<string>0</string>
<key>r</key>
<string>1</string>
</dict>
<key>Pattern</key>
<integer>1</integer>
</dict>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;\red255\green0\blue0;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf2 process_exception}</string>
</dict>
<key>TextRelativeArea</key>
<string>{{0.125, 0.25}, {0.75, 0.5}}</string>
<key>isConnectedShape</key>
<true/>
</dict>
<dict>
<key>Bounds</key>
<string>{{328.5, 229.5}, {315, 36}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>30</integer>
<key>Rotation</key>
<real>270</real>
<key>Shape</key>
<string>AdjustableArrow</string>
<key>ShapeData</key>
<dict>
<key>width</key>
<real>27</real>
</dict>
<key>Style</key>
<dict>
<key>fill</key>
<dict>
<key>Color</key>
<dict>
<key>a</key>
<string>0.8</string>
<key>b</key>
<string>1</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>MiddleFraction</key>
<real>0.70634919404983521</real>
</dict>
<key>shadow</key>
<dict>
<key>Color</key>
<dict>
<key>a</key>
<string>0.4</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>0</string>
<key>r</key>
<string>0</string>
</dict>
<key>Draws</key>
<string>NO</string>
<key>Fuzziness</key>
<real>0.0</real>
<key>ShadowVector</key>
<string>{0, 2}</string>
</dict>
<key>stroke</key>
<dict>
<key>Color</key>
<dict>
<key>b</key>
<string>0</string>
<key>g</key>
<string>0.501961</string>
<key>r</key>
<string>0</string>
</dict>
</dict>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;\red0\green128\blue0;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf2 process_response}</string>
</dict>
<key>TextRelativeArea</key>
<string>{{0.125, 0.25}, {0.75, 0.5}}</string>
<key>isConnectedShape</key>
<true/>
</dict>
<dict>
<key>Bounds</key>
<string>{{283.5, 238.5}, {297, 36}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>29</integer>
<key>Rotation</key>
<real>270</real>
<key>Shape</key>
<string>AdjustableArrow</string>
<key>ShapeData</key>
<dict>
<key>width</key>
<real>27</real>
</dict>
<key>Style</key>
<dict>
<key>fill</key>
<dict>
<key>Color</key>
<dict>
<key>a</key>
<string>0.8</string>
<key>b</key>
<string>1</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>MiddleFraction</key>
<real>0.70634919404983521</real>
</dict>
<key>shadow</key>
<dict>
<key>Color</key>
<dict>
<key>a</key>
<string>0.4</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>0</string>
<key>r</key>
<string>0</string>
</dict>
<key>Draws</key>
<string>NO</string>
<key>Fuzziness</key>
<real>0.0</real>
<key>ShadowVector</key>
<string>{0, 2}</string>
</dict>
<key>stroke</key>
<dict>
<key>Color</key>
<dict>
<key>b</key>
<string>0</string>
<key>g</key>
<string>0.501961</string>
<key>r</key>
<string>0</string>
</dict>
<key>Pattern</key>
<integer>1</integer>
</dict>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;\red0\green128\blue0;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf2 process_template_response}</string>
</dict>
<key>TextRelativeArea</key>
<string>{{0.125, 0.25}, {0.75, 0.5}}</string>
<key>isConnectedShape</key>
<true/>
</dict>
<dict>
<key>Bounds</key>
<string>{{27, 243}, {288, 36}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>28</integer>
<key>Rotation</key>
<real>90</real>
<key>Shape</key>
<string>AdjustableArrow</string>
<key>ShapeData</key>
<dict>
<key>width</key>
<real>27</real>
</dict>
<key>Style</key>
<dict>
<key>fill</key>
<dict>
<key>Color</key>
<dict>
<key>a</key>
<string>0.8</string>
<key>b</key>
<string>1</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>MiddleFraction</key>
<real>0.70634919404983521</real>
</dict>
<key>shadow</key>
<dict>
<key>Color</key>
<dict>
<key>a</key>
<string>0.4</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>0</string>
<key>r</key>
<string>0</string>
</dict>
<key>Draws</key>
<string>NO</string>
<key>Fuzziness</key>
<real>0.0</real>
<key>ShadowVector</key>
<string>{0, 2}</string>
</dict>
<key>stroke</key>
<dict>
<key>Color</key>
<dict>
<key>b</key>
<string>0</string>
<key>g</key>
<string>0.501961</string>
<key>r</key>
<string>0</string>
</dict>
</dict>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;\red0\green128\blue0;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf2 process_view}</string>
</dict>
<key>TextRelativeArea</key>
<string>{{0.125, 0.25}, {0.75, 0.5}}</string>
<key>isConnectedShape</key>
<true/>
</dict>
<dict>
<key>Bounds</key>
<string>{{-40.500000000767386, 220.49999999804004}, {297, 36}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>27</integer>
<key>Rotation</key>
<real>90</real>
<key>Shape</key>
<string>AdjustableArrow</string>
<key>ShapeData</key>
<dict>
<key>width</key>
<real>27</real>
</dict>
<key>Style</key>
<dict>
<key>fill</key>
<dict>
<key>Color</key>
<dict>
<key>a</key>
<string>0.8</string>
<key>b</key>
<string>1</string>
<key>g</key>
<string>1</string>
<key>r</key>
<string>1</string>
</dict>
<key>MiddleFraction</key>
<real>0.70634919404983521</real>
</dict>
<key>shadow</key>
<dict>
<key>Color</key>
<dict>
<key>a</key>
<string>0.4</string>
<key>b</key>
<string>0</string>
<key>g</key>
<string>0</string>
<key>r</key>
<string>0</string>
</dict>
<key>Draws</key>
<string>NO</string>
<key>Fuzziness</key>
<real>0.0</real>
<key>ShadowVector</key>
<string>{0, 2}</string>
</dict>
<key>stroke</key>
<dict>
<key>Color</key>
<dict>
<key>b</key>
<string>0</string>
<key>g</key>
<string>0.501961</string>
<key>r</key>
<string>0</string>
</dict>
</dict>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;\red0\green128\blue0;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf2 process_request}</string>
</dict>
<key>TextRelativeArea</key>
<string>{{0.125, 0.25}, {0.75, 0.5}}</string>
<key>isConnectedShape</key>
<true/>
</dict>
<dict>
<key>Bounds</key>
<string>{{360, 63}, {144, 27}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>12</integer>
<key>Magnets</key>
<array>
<string>{0, 1}</string>
<string>{0, -1}</string>
<string>{1, 0}</string>
<string>{-1, 0}</string>
</array>
<key>Shape</key>
<string>Rectangle</string>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf0 HttpResponse}</string>
</dict>
</dict>
<dict>
<key>Bounds</key>
<string>{{72, 63}, {144, 27}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>11</integer>
<key>Magnets</key>
<array>
<string>{0, 1}</string>
<string>{0, -1}</string>
<string>{1, 0}</string>
<string>{-1, 0}</string>
</array>
<key>Shape</key>
<string>Rectangle</string>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf0 HttpRequest}</string>
</dict>
</dict>
<dict>
<key>Bounds</key>
<string>{{72, 324}, {432, 27}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>10</integer>
<key>Magnets</key>
<array>
<string>{0, 1}</string>
<string>{0, -1}</string>
<string>{1, 0}</string>
<string>{-1, 0}</string>
</array>
<key>Shape</key>
<string>Rectangle</string>
<key>Style</key>
<dict>
<key>fill</key>
<dict>
<key>FillType</key>
<integer>2</integer>
<key>GradientAngle</key>
<real>90</real>
<key>GradientColor</key>
<dict>
<key>w</key>
<string>0.666667</string>
</dict>
</dict>
<key>stroke</key>
<dict>
<key>CornerRadius</key>
<real>5</real>
</dict>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf0 MessageMiddleware}</string>
</dict>
</dict>
<dict>
<key>Bounds</key>
<string>{{72, 279}, {432, 27}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>9</integer>
<key>Magnets</key>
<array>
<string>{0, 1}</string>
<string>{0, -1}</string>
<string>{1, 0}</string>
<string>{-1, 0}</string>
</array>
<key>Shape</key>
<string>Rectangle</string>
<key>Style</key>
<dict>
<key>fill</key>
<dict>
<key>FillType</key>
<integer>2</integer>
<key>GradientAngle</key>
<real>90</real>
<key>GradientColor</key>
<dict>
<key>w</key>
<string>0.666667</string>
</dict>
</dict>
<key>stroke</key>
<dict>
<key>CornerRadius</key>
<real>5</real>
</dict>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf0 AuthenticationMiddleware}</string>
</dict>
</dict>
<dict>
<key>Bounds</key>
<string>{{72, 234}, {432, 27}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>8</integer>
<key>Magnets</key>
<array>
<string>{0, 1}</string>
<string>{0, -1}</string>
<string>{1, 0}</string>
<string>{-1, 0}</string>
</array>
<key>Shape</key>
<string>Rectangle</string>
<key>Style</key>
<dict>
<key>fill</key>
<dict>
<key>FillType</key>
<integer>2</integer>
<key>GradientAngle</key>
<real>90</real>
<key>GradientColor</key>
<dict>
<key>w</key>
<string>0.666667</string>
</dict>
</dict>
<key>stroke</key>
<dict>
<key>CornerRadius</key>
<real>5</real>
</dict>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf0 CsrfViewMiddleware}</string>
</dict>
</dict>
<dict>
<key>Bounds</key>
<string>{{72, 189}, {432, 27}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>7</integer>
<key>Magnets</key>
<array>
<string>{0, 1}</string>
<string>{0, -1}</string>
<string>{1, 0}</string>
<string>{-1, 0}</string>
</array>
<key>Shape</key>
<string>Rectangle</string>
<key>Style</key>
<dict>
<key>fill</key>
<dict>
<key>FillType</key>
<integer>2</integer>
<key>GradientAngle</key>
<real>90</real>
<key>GradientColor</key>
<dict>
<key>w</key>
<string>0.666667</string>
</dict>
</dict>
<key>stroke</key>
<dict>
<key>CornerRadius</key>
<real>5</real>
</dict>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf0 SessionMiddleware}</string>
</dict>
</dict>
<dict>
<key>Bounds</key>
<string>{{72, 144}, {432, 27}}</string>
<key>Class</key>
<string>ShapedGraphic</string>
<key>ID</key>
<integer>6</integer>
<key>Magnets</key>
<array>
<string>{0, 1}</string>
<string>{0, -1}</string>
<string>{1, 0}</string>
<string>{-1, 0}</string>
</array>
<key>Shape</key>
<string>Rectangle</string>
<key>Style</key>
<dict>
<key>fill</key>
<dict>
<key>FillType</key>
<integer>2</integer>
<key>GradientAngle</key>
<real>90</real>
<key>GradientColor</key>
<dict>
<key>w</key>
<string>0.666667</string>
</dict>
</dict>
<key>stroke</key>
<dict>
<key>CornerRadius</key>
<real>5</real>
</dict>
</dict>
<key>Text</key>
<dict>
<key>Text</key>
<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
{\colortbl;\red255\green255\blue255;}
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
\f0\fs24 \cf0 CommonMiddleware}</string>
</dict>
</dict>
</array>
<key>GridInfo</key>
<dict>
<key>ShowsGrid</key>
<string>YES</string>
<key>SnapsToGrid</key>
<string>YES</string>
</dict>
<key>GuidesLocked</key>
<string>NO</string>
<key>GuidesVisible</key>
<string>YES</string>
<key>HPages</key>
<integer>1</integer>
<key>ImageCounter</key>
<integer>1</integer>
<key>KeepToScale</key>
<false/>
<key>Layers</key>
<array>
<dict>
<key>Lock</key>
<string>NO</string>
<key>Name</key>
<string>Calque 1</string>
<key>Print</key>
<string>YES</string>
<key>View</key>
<string>YES</string>
</dict>
</array>
<key>LayoutInfo</key>
<dict>
<key>Animate</key>
<string>NO</string>
<key>circoMinDist</key>
<real>18</real>
<key>circoSeparation</key>
<real>0.0</real>
<key>layoutEngine</key>
<string>dot</string>
<key>neatoSeparation</key>
<real>0.0</real>
<key>twopiSeparation</key>
<real>0.0</real>
</dict>
<key>LinksVisible</key>
<string>NO</string>
<key>MagnetsVisible</key>
<string>NO</string>
<key>MasterSheets</key>
<array/>
<key>ModificationDate</key>
<string>2012-12-09 19:48:54 +0000</string>
<key>Modifier</key>
<string>Aymeric Augustin</string>
<key>NotesVisible</key>
<string>NO</string>
<key>Orientation</key>
<integer>2</integer>
<key>OriginVisible</key>
<string>NO</string>
<key>PageBreaks</key>
<string>YES</string>
<key>PrintInfo</key>
<dict>
<key>NSBottomMargin</key>
<array>
<string>float</string>
<string>41</string>
</array>
<key>NSHorizonalPagination</key>
<array>
<string>coded</string>
<string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string>
</array>
<key>NSLeftMargin</key>
<array>
<string>float</string>
<string>18</string>
</array>
<key>NSPaperSize</key>
<array>
<string>size</string>
<string>{595.28997802734375, 841.8900146484375}</string>
</array>
<key>NSPrintReverseOrientation</key>
<array>
<string>int</string>
<string>0</string>
</array>
<key>NSRightMargin</key>
<array>
<string>float</string>
<string>18</string>
</array>
<key>NSTopMargin</key>
<array>
<string>float</string>
<string>18</string>
</array>
</dict>
<key>PrintOnePage</key>
<false/>
<key>ReadOnly</key>
<string>NO</string>
<key>RowAlign</key>
<integer>1</integer>
<key>RowSpacing</key>
<real>36</real>
<key>SheetTitle</key>
<string>Canevas 1</string>
<key>SmartAlignmentGuidesActive</key>
<string>YES</string>
<key>SmartDistanceGuidesActive</key>
<string>YES</string>
<key>UniqueID</key>
<integer>1</integer>
<key>UseEntirePage</key>
<false/>
<key>VPages</key>
<integer>1</integer>
<key>WindowInfo</key>
<dict>
<key>CurrentSheet</key>
<integer>0</integer>
<key>ExpandedCanvases</key>
<array/>
<key>Frame</key>
<string>{{248, 4}, {694, 874}}</string>
<key>ListView</key>
<true/>
<key>OutlineWidth</key>
<integer>142</integer>
<key>RightSidebar</key>
<false/>
<key>ShowRuler</key>
<true/>
<key>Sidebar</key>
<true/>
<key>SidebarWidth</key>
<integer>120</integer>
<key>VisibleRegion</key>
<string>{{0, 0}, {559, 735}}</string>
<key>Zoom</key>
<real>1</real>
<key>ZoomValues</key>
<array>
<array>
<string>Canevas 1</string>
<real>1</real>
<real>1</real>
</array>
</array>
</dict>
</dict>
</plist>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -16,18 +16,128 @@ how to write your own middleware. Django ships with some built-in middleware
you can use right out of the box. They're documented in the :doc:`built-in you can use right out of the box. They're documented in the :doc:`built-in
middleware reference </ref/middleware>`. middleware reference </ref/middleware>`.
.. versionchanged:: 1.10
A new style of middleware was introduced for use with the new
:setting:`MIDDLEWARE` setting. If you're using the old
:setting:`MIDDLEWARE_CLASSES` setting, you'll need to :ref:`adapt old,
custom middleware <upgrading-middleware>` before using the new setting.
This document describes new-style middleware. Refer to this page in older
versions of the documentation for a description of how old-style middleware
works.
Writing your own middleware
===========================
A middleware factory is a callable that takes a ``get_response`` callable and
returns a middleware. A middleware is a callable that takes a request and
returns a response, just like a view.
A middleware can be written as a function that looks like this::
def simple_middleware(get_response):
# One-time configuration and initialization.
def middleware(request):
# Code to be executed for each request before
# the view is called.
try:
response = get_response(request)
except Exception as e:
# Code to handle an exception that wasn't caught
# further up the chain, if desired.
...
# Code to be executed for each request/response after
# the view is called.
return response
return middleware
Or it can be written as a class with a ``__call__()`` method, like this::
class SimpleMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view is called.
try:
response = self.get_response(request)
except Exception as e:
# Code to handle an exception that wasn't caught
# further up the chain, if desired.
...
# Code to be executed for each request/response after
# the view is called.
return response
In both examples, the ``try``/``except`` isn't required if the middleware
doesn't need to handle any exceptions. If it is included, it should probably
catch something more specific than ``Exception``.
The ``get_response`` callable provided by Django might be the actual view (if
this is the last listed middleware) or it might be the next middleware in the
chain. The current middleware doesn't need to know or care what exactly it is,
just that it represents whatever comes next.
The above is a slight simplification -- the ``get_response`` callable for the
last middleware in the chain won't be the actual view but rather a wrapper
method from the handler which takes care of applying :ref:`view middleware
<view-middleware>`, calling the view with appropriate URL arguments, and
applying :ref:`template-response <template-response-middleware>` middleware.
Middleware can live anywhere on your Python path.
``__init__(get_response)``
--------------------------
Middleware classes must accept a ``get_response`` argument. You can also
initialize some global state for the middleware. Keep in mind a couple of
caveats:
* Django initializes your middleware with only the ``get_response`` argument,
so you can't define ``__init__()`` as requiring any other arguments.
* Unlike the ``__call__()`` method which get called once per request,
``__init__()`` is called only *once*, when the Web server starts.
.. versionchanged:: 1.10
In older versions, ``__init__`` was not called until the Web server
responded to its first request.
If you want to allow your middleware to be used in Django 1.9 and earlier,
make ``get_response`` an optional argument (``get_response=None``).
Marking middleware as unused
----------------------------
It's sometimes useful to determine at startup time whether a piece of
middleware should be used. In these cases, your middleware's ``__init__()``
method may raise :exc:`~django.core.exceptions.MiddlewareNotUsed`. Django will
then remove that middleware from the middleware process and log a debug message
to the :ref:`django-request-logger` logger when :setting:`DEBUG` is ``True``.
Activating middleware Activating middleware
===================== =====================
To activate a middleware component, add it to the To activate a middleware component, add it to the :setting:`MIDDLEWARE` list in
:setting:`MIDDLEWARE_CLASSES` list in your Django settings. your Django settings.
In :setting:`MIDDLEWARE_CLASSES`, each middleware component is represented by In :setting:`MIDDLEWARE`, each middleware component is represented by a string:
a string: the full Python path to the middleware's class name. For example, the full Python path to the middleware's class or function name. For example,
here's the default value created by :djadmin:`django-admin startproject here's the default value created by :djadmin:`django-admin startproject
<startproject>`:: <startproject>`::
MIDDLEWARE_CLASSES = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
@ -37,13 +147,12 @@ here's the default value created by :djadmin:`django-admin startproject
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
] ]
A Django installation doesn't require any middleware — A Django installation doesn't require any middleware — :setting:`MIDDLEWARE`
:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like — but it's strongly can be empty, if you'd like — but it's strongly suggested that you at least use
suggested that you at least use
:class:`~django.middleware.common.CommonMiddleware`. :class:`~django.middleware.common.CommonMiddleware`.
The order in :setting:`MIDDLEWARE_CLASSES` matters because a middleware can The order in :setting:`MIDDLEWARE` matters because a middleware can depend on
depend on other middleware. For instance, other middleware. For instance,
:class:`~django.contrib.auth.middleware.AuthenticationMiddleware` stores the :class:`~django.contrib.auth.middleware.AuthenticationMiddleware` stores the
authenticated user in the session; therefore, it must run after authenticated user in the session; therefore, it must run after
:class:`~django.contrib.sessions.middleware.SessionMiddleware`. See :class:`~django.contrib.sessions.middleware.SessionMiddleware`. See
@ -54,55 +163,21 @@ Hooks and application order
=========================== ===========================
During the request phase, before calling the view, Django applies middleware During the request phase, before calling the view, Django applies middleware
in the order it's defined in :setting:`MIDDLEWARE_CLASSES`, top-down. Two in the order it's defined in :setting:`MIDDLEWARE`, top-down. You can think of
hooks are available: it like an onion: each middleware class is a "layer" that wraps the view.
* :meth:`process_request` Middleware see only the changes made by middleware that run before it. A
* :meth:`process_view` middleware (and the view) is skipped entirely if a preceding middleware
short-circuits by returning a response without ever calling ``get_response``.
That response will only pass through the middleware that have already run.
During the response phase, after calling the view, middleware are applied in Similarly, a middleware that sees the request on the way in and doesn't return
reverse order, from the bottom up. Three hooks are available: a response is guaranteed that it will always see the response on the way back
out. If the middleware also wants to see any uncaught exception on the way out,
it can wrap its call to ``get_response()`` in a ``try``/``except``.
* :meth:`process_exception` (only if the view raised an exception) Besides the middleware pattern described earlier, you can add two other methods
* :meth:`process_template_response` (only for template responses) to class-based middleware:
* :meth:`process_response`
.. image:: _images/middleware.*
:alt: middleware application order
:width: 481
:height: 409
If you prefer, you can also think of it like an onion: each middleware class
is a "layer" that wraps the view.
The behavior of each hook is described below.
Writing your own middleware
===========================
Writing your own middleware is easy. Each middleware component is a single
Python class that defines one or more of the following methods:
.. _request-middleware:
``process_request()``
---------------------
.. method:: process_request(request)
``request`` is an :class:`~django.http.HttpRequest` object.
``process_request()`` is called on each request, before Django decides which
view to execute.
It should return either ``None`` or an :class:`~django.http.HttpResponse`
object. If it returns ``None``, Django will continue processing this request,
executing any other ``process_request()`` middleware, then, ``process_view()``
middleware, and finally, the appropriate view. If it returns an
:class:`~django.http.HttpResponse` object, Django won't bother calling any
other request, view or exception middleware, or the appropriate view; it'll
apply response middleware to that :class:`~django.http.HttpResponse`, and
return the result.
.. _view-middleware: .. _view-middleware:
@ -125,14 +200,13 @@ It should return either ``None`` or an :class:`~django.http.HttpResponse`
object. If it returns ``None``, Django will continue processing this request, object. If it returns ``None``, Django will continue processing this request,
executing any other ``process_view()`` middleware and, then, the appropriate executing any other ``process_view()`` middleware and, then, the appropriate
view. If it returns an :class:`~django.http.HttpResponse` object, Django won't view. If it returns an :class:`~django.http.HttpResponse` object, Django won't
bother calling any other view or exception middleware, or the appropriate bother calling the appropriate view; it'll apply response middleware to that
view; it'll apply response middleware to that :class:`~django.http.HttpResponse` and return the result.
:class:`~django.http.HttpResponse`, and return the result.
.. note:: .. note::
Accessing :attr:`request.POST <django.http.HttpRequest.POST>` inside Accessing :attr:`request.POST <django.http.HttpRequest.POST>` inside
middleware from ``process_request`` or ``process_view`` will prevent any middleware before the view runs or in ``process_view()`` will prevent any
view running after the middleware from being able to :ref:`modify the view running after the middleware from being able to :ref:`modify the
upload handlers for the request <modifying_upload_handlers_on_the_fly>`, upload handlers for the request <modifying_upload_handlers_on_the_fly>`,
and should normally be avoided. and should normally be avoided.
@ -170,41 +244,8 @@ called.
Middleware are run in reverse order during the response phase, which Middleware are run in reverse order during the response phase, which
includes ``process_template_response()``. includes ``process_template_response()``.
.. _response-middleware:
``process_response()``
----------------------
.. method:: process_response(request, response)
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is
the :class:`~django.http.HttpResponse` or
:class:`~django.http.StreamingHttpResponse` object returned by a Django view
or by a middleware.
``process_response()`` is called on all responses before they're returned to
the browser.
It must return an :class:`~django.http.HttpResponse` or
:class:`~django.http.StreamingHttpResponse` object. It could alter the given
``response``, or it could create and return a brand-new
:class:`~django.http.HttpResponse` or
:class:`~django.http.StreamingHttpResponse`.
Unlike the ``process_request()`` and ``process_view()`` methods, the
``process_response()`` method is always called, even if the
``process_request()`` and ``process_view()`` methods of the same middleware
class were skipped (because an earlier middleware method returned an
:class:`~django.http.HttpResponse`). In particular, this means that your
``process_response()`` method cannot rely on setup done in
``process_request()``.
Finally, remember that during the response phase, middleware are applied in
reverse order, from the bottom up. This means classes defined at the end of
:setting:`MIDDLEWARE_CLASSES` will be run first.
Dealing with streaming responses Dealing with streaming responses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ================================
Unlike :class:`~django.http.HttpResponse`, Unlike :class:`~django.http.HttpResponse`,
:class:`~django.http.StreamingHttpResponse` does not have a ``content`` :class:`~django.http.StreamingHttpResponse` does not have a ``content``
@ -229,66 +270,62 @@ must test for streaming responses and adjust their behavior accordingly::
.. _exception-middleware: .. _exception-middleware:
``process_exception()`` Exception middleware
----------------------- ====================
.. method:: process_exception(request, exception) A middleware that does some custom exception handling might looks like this::
``request`` is an :class:`~django.http.HttpRequest` object. ``exception`` is an class ExceptionMiddleware(object):
``Exception`` object raised by the view function. def __init__(self, get_response):
self.get_response = get_response
Django calls ``process_exception()`` when a view raises an exception. def __call__(self, request):
``process_exception()`` should return either ``None`` or an try:
:class:`~django.http.HttpResponse` object. If it returns an response = self.get_response(request)
:class:`~django.http.HttpResponse` object, the template response and response except Exception as e:
middleware will be applied, and the resulting response returned to the # Do something with the exception and possibly reraise it
browser. Otherwise, default exception handling kicks in. # unless you wish to silence it.
...
return response
Again, middleware are run in reverse order during the response phase, which Middleware that wants to do something for all exception responses, an HTTP 404
includes ``process_exception``. If an exception middleware returns a response, for example, need to both catch the appropriate exception (e.g. ``Http404``)
the middleware classes above that middleware will not be called at all. and look for regular responses with the status code of interest. You can
subclass :class:`~django.middleware.exception.ExceptionMiddleware` if you want
to transform exceptions into the appropriate response.
``__init__()`` .. _upgrading-middleware:
--------------
Most middleware classes won't need an initializer since middleware classes are Upgrading pre-Django 1.10-style middleware
essentially placeholders for the ``process_*`` methods. If you do need some ==========================================
global state you may use ``__init__`` to set up. However, keep in mind a couple
of caveats:
* Django initializes your middleware without any arguments, so you can't .. class:: django.utils.deprecation.MiddlewareMixin
define ``__init__`` as requiring any arguments. :module:
* Unlike the ``process_*`` methods which get called once per request, Django provides ``django.utils.deprecation.MiddlewareMixin`` to ease providing
``__init__`` gets called only *once*, when the Web server starts. the existing built-in middleware in both new-style and old-style forms and to
ease similar conversions of third-party middleware.
.. versionchanged:: 1.10 In most cases, this mixin will be sufficient to convert a middleware with
sufficient backwards-compatibility; the new short-circuiting semantics will be
harmless or even beneficial to the existing middleware.
In older versions, ``__init__`` was not called until the Web server In a few cases, a middleware class may need more invasive changes to adjust to
responded to its first request. the new semantics.
Marking middleware as unused For example, in the current request-handling logic, the handler transforms any
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ exception that passes through all ``process_exception`` middleware uncaught
into a response with appropriate status code (e.g. 404, 403, 400, or 500), and
then passes that response through the full chain of ``process_response``
middleware.
It's sometimes useful to determine at run-time whether a piece of middleware In new-style middleware, a given middleware only gets one shot at a given
should be used. In these cases, your middleware's ``__init__`` method may response or uncaught exception "on the way out," and will see either a returned
raise :exc:`django.core.exceptions.MiddlewareNotUsed`. Django will then remove response or an uncaught exception, but not both.
that piece of middleware from the middleware process and a debug message will
be logged to the ``django.request`` logger when :setting:`DEBUG` is set to
``True``.
Guidelines This means that certain middleware which want to do something with all 404
---------- responses (for example, the ``RedirectFallbackMiddleware`` and
``FlatpageFallbackMiddleware`` in ``django.contrib.redirects`` and
* Middleware classes don't have to subclass anything. ``django.contrib.flatpages``) now need to watch out for both a 404 response
and an uncaught ``Http404`` exception. They do this by subclassing
* The middleware class can live anywhere on your Python path. All Django :class:`~django.middleware.exception.ExceptionMiddleware`.
cares about is that the :setting:`MIDDLEWARE_CLASSES` setting includes
the path to it.
* Feel free to look at :doc:`Django's available middleware
</ref/middleware>` for examples.
* If you write a middleware component that you think would be useful to
other people, contribute to the community! :doc:`Let us know
</internals/contributing/index>`, and we'll consider adding it to Django.

View File

@ -18,13 +18,13 @@ Sessions are implemented via a piece of :doc:`middleware </ref/middleware>`.
To enable session functionality, do the following: To enable session functionality, do the following:
* Edit the :setting:`MIDDLEWARE_CLASSES` setting and make sure * Edit the :setting:`MIDDLEWARE` setting and make sure it contains
it contains ``'django.contrib.sessions.middleware.SessionMiddleware'``. ``'django.contrib.sessions.middleware.SessionMiddleware'``. The default
The default ``settings.py`` created by ``django-admin startproject`` ``settings.py`` created by ``django-admin startproject`` has
has ``SessionMiddleware`` activated. ``SessionMiddleware`` activated.
If you don't want to use sessions, you might as well remove the If you don't want to use sessions, you might as well remove the
``SessionMiddleware`` line from :setting:`MIDDLEWARE_CLASSES` and ``SessionMiddleware`` line from :setting:`MIDDLEWARE` and
``'django.contrib.sessions'`` from your :setting:`INSTALLED_APPS`. ``'django.contrib.sessions'`` from your :setting:`INSTALLED_APPS`.
It'll save you a small bit of overhead. It'll save you a small bit of overhead.

View File

@ -41,8 +41,8 @@ algorithm the system follows to determine which Python code to execute:
1. Django determines the root URLconf module to use. Ordinarily, 1. Django determines the root URLconf module to use. Ordinarily,
this is the value of the :setting:`ROOT_URLCONF` setting, but if the incoming this is the value of the :setting:`ROOT_URLCONF` setting, but if the incoming
``HttpRequest`` object has a :attr:`~django.http.HttpRequest.urlconf` ``HttpRequest`` object has a :attr:`~django.http.HttpRequest.urlconf`
attribute (set by middleware :ref:`request processing <request-middleware>`), attribute (set by middleware), its value will be used in place of the
its value will be used in place of the :setting:`ROOT_URLCONF` setting. :setting:`ROOT_URLCONF` setting.
2. Django loads that Python module and looks for the variable 2. Django loads that Python module and looks for the variable
``urlpatterns``. This should be a Python list of :func:`django.conf.urls.url` ``urlpatterns``. This should be a Python list of :func:`django.conf.urls.url`

View File

@ -175,13 +175,14 @@ the most likely choices.
Here's an example that stores the current timezone in the session. (It skips Here's an example that stores the current timezone in the session. (It skips
error handling entirely for the sake of simplicity.) error handling entirely for the sake of simplicity.)
Add the following middleware to :setting:`MIDDLEWARE_CLASSES`:: Add the following middleware to :setting:`MIDDLEWARE`::
import pytz import pytz
from django.utils import timezone from django.utils import timezone
from django.django.utils.deprecation import MiddlewareMixin
class TimezoneMiddleware(object): class TimezoneMiddleware(MiddlewareMixin):
def process_request(self, request): def process_request(self, request):
tzname = request.session.get('django_timezone') tzname = request.session.get('django_timezone')
if tzname: if tzname:

View File

@ -38,7 +38,7 @@ make some optimizations so as not to load the internationalization machinery.
.. note:: .. note::
Make sure you've activated translation for your project (the fastest way is Make sure you've activated translation for your project (the fastest way is
to check if :setting:`MIDDLEWARE_CLASSES` includes to check if :setting:`MIDDLEWARE` includes
:mod:`django.middleware.locale.LocaleMiddleware`). If you haven't yet, :mod:`django.middleware.locale.LocaleMiddleware`). If you haven't yet,
see :ref:`how-django-discovers-language-preference`. see :ref:`how-django-discovers-language-preference`.
@ -1422,7 +1422,7 @@ Django provides two mechanisms to internationalize URL patterns:
Using either one of these features requires that an active language be set Using either one of these features requires that an active language be set
for each request; in other words, you need to have for each request; in other words, you need to have
:class:`django.middleware.locale.LocaleMiddleware` in your :class:`django.middleware.locale.LocaleMiddleware` in your
:setting:`MIDDLEWARE_CLASSES` setting. :setting:`MIDDLEWARE` setting.
Language prefix in URL patterns Language prefix in URL patterns
------------------------------- -------------------------------
@ -2065,8 +2065,8 @@ prefer, then you also need to use the ``LocaleMiddleware``.
It customizes content for each user. It customizes content for each user.
To use ``LocaleMiddleware``, add ``'django.middleware.locale.LocaleMiddleware'`` To use ``LocaleMiddleware``, add ``'django.middleware.locale.LocaleMiddleware'``
to your :setting:`MIDDLEWARE_CLASSES` setting. Because middleware order to your :setting:`MIDDLEWARE` setting. Because middleware order matters, follow
matters, you should follow these guidelines: these guidelines:
* Make sure it's one of the first middlewares installed. * Make sure it's one of the first middlewares installed.
* It should come after ``SessionMiddleware``, because ``LocaleMiddleware`` * It should come after ``SessionMiddleware``, because ``LocaleMiddleware``
@ -2075,9 +2075,9 @@ matters, you should follow these guidelines:
to resolve the requested URL. to resolve the requested URL.
* If you use ``CacheMiddleware``, put ``LocaleMiddleware`` after it. * If you use ``CacheMiddleware``, put ``LocaleMiddleware`` after it.
For example, your :setting:`MIDDLEWARE_CLASSES` might look like this:: For example, your :setting:`MIDDLEWARE` might look like this::
MIDDLEWARE_CLASSES = [ MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',

View File

@ -1182,7 +1182,7 @@ easy::
class MiddlewareTestCase(TestCase): class MiddlewareTestCase(TestCase):
def test_cache_middleware(self): def test_cache_middleware(self):
with self.modify_settings(MIDDLEWARE_CLASSES={ with self.modify_settings(MIDDLEWARE={
'append': 'django.middleware.cache.FetchFromCacheMiddleware', 'append': 'django.middleware.cache.FetchFromCacheMiddleware',
'prepend': 'django.middleware.cache.UpdateCacheMiddleware', 'prepend': 'django.middleware.cache.UpdateCacheMiddleware',
'remove': [ 'remove': [
@ -1233,7 +1233,7 @@ decorator::
class MiddlewareTestCase(TestCase): class MiddlewareTestCase(TestCase):
@modify_settings(MIDDLEWARE_CLASSES={ @modify_settings(MIDDLEWARE={
'append': 'django.middleware.cache.FetchFromCacheMiddleware', 'append': 'django.middleware.cache.FetchFromCacheMiddleware',
'prepend': 'django.middleware.cache.UpdateCacheMiddleware', 'prepend': 'django.middleware.cache.UpdateCacheMiddleware',
}) })
@ -1245,7 +1245,7 @@ The decorator can also be applied to test case classes::
from django.test import TestCase, modify_settings from django.test import TestCase, modify_settings
@modify_settings(MIDDLEWARE_CLASSES={ @modify_settings(MIDDLEWARE={
'append': 'django.middleware.cache.FetchFromCacheMiddleware', 'append': 'django.middleware.cache.FetchFromCacheMiddleware',
'prepend': 'django.middleware.cache.UpdateCacheMiddleware', 'prepend': 'django.middleware.cache.UpdateCacheMiddleware',
}) })

View File

@ -2,7 +2,7 @@ import os
from django.utils._os import upath from django.utils._os import upath
AUTH_MIDDLEWARE_CLASSES = [ AUTH_MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
] ]

View File

@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType
from django.db.models import Q from django.db.models import Q
from django.test import SimpleTestCase, TestCase, override_settings from django.test import SimpleTestCase, TestCase, override_settings
from .settings import AUTH_MIDDLEWARE_CLASSES, AUTH_TEMPLATES from .settings import AUTH_MIDDLEWARE, AUTH_TEMPLATES
class MockUser(object): class MockUser(object):
@ -67,7 +67,7 @@ class AuthContextProcessorTests(TestCase):
def setUpTestData(cls): def setUpTestData(cls):
cls.superuser = User.objects.create_superuser(username='super', password='secret', email='super@example.com') cls.superuser = User.objects.create_superuser(username='super', password='secret', email='super@example.com')
@override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE_CLASSES) @override_settings(MIDDLEWARE=AUTH_MIDDLEWARE)
def test_session_not_accessed(self): def test_session_not_accessed(self):
""" """
Tests that the session is not accessed simply by including Tests that the session is not accessed simply by including
@ -76,7 +76,12 @@ class AuthContextProcessorTests(TestCase):
response = self.client.get('/auth_processor_no_attr_access/') response = self.client.get('/auth_processor_no_attr_access/')
self.assertContains(response, "Session not accessed") self.assertContains(response, "Session not accessed")
@override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE_CLASSES) @override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE, MIDDLEWARE=None)
def test_session_not_accessed_middleware_classes(self):
response = self.client.get('/auth_processor_no_attr_access/')
self.assertContains(response, "Session not accessed")
@override_settings(MIDDLEWARE=AUTH_MIDDLEWARE)
def test_session_is_accessed(self): def test_session_is_accessed(self):
""" """
Tests that the session is accessed if the auth context processor Tests that the session is accessed if the auth context processor
@ -85,6 +90,11 @@ class AuthContextProcessorTests(TestCase):
response = self.client.get('/auth_processor_attr_access/') response = self.client.get('/auth_processor_attr_access/')
self.assertContains(response, "Session accessed") self.assertContains(response, "Session accessed")
@override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE, MIDDLEWARE=None)
def test_session_is_accessed_middleware_classes(self):
response = self.client.get('/auth_processor_attr_access/')
self.assertContains(response, "Session accessed")
def test_perms_attrs(self): def test_perms_attrs(self):
u = User.objects.create_user(username='normal', password='secret') u = User.objects.create_user(username='normal', password='secret')
u.user_permissions.add( u.user_permissions.add(

View File

@ -23,7 +23,7 @@ class RemoteUserTest(TestCase):
def setUp(self): def setUp(self):
self.patched_settings = modify_settings( self.patched_settings = modify_settings(
AUTHENTICATION_BACKENDS={'append': self.backend}, AUTHENTICATION_BACKENDS={'append': self.backend},
MIDDLEWARE_CLASSES={'append': self.middleware}, MIDDLEWARE={'append': self.middleware},
) )
self.patched_settings.enable() self.patched_settings.enable()
@ -151,6 +151,21 @@ class RemoteUserTest(TestCase):
self.assertTrue(response.context['user'].is_anonymous) self.assertTrue(response.context['user'].is_anonymous)
@override_settings(MIDDLEWARE=None)
class RemoteUserTestMiddlewareClasses(RemoteUserTest):
def setUp(self):
self.patched_settings = modify_settings(
AUTHENTICATION_BACKENDS={'append': self.backend},
MIDDLEWARE_CLASSES={'append': [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
self.middleware,
]},
)
self.patched_settings.enable()
class RemoteUserNoCreateBackend(RemoteUserBackend): class RemoteUserNoCreateBackend(RemoteUserBackend):
"""Backend that doesn't create unknown users.""" """Backend that doesn't create unknown users."""
create_unknown_user = False create_unknown_user = False

View File

@ -1,5 +1,6 @@
from django.conf import settings from django.conf import settings
from django.core.checks.security import base, csrf, sessions from django.core.checks.security import base, csrf, sessions
from django.core.checks.utils import patch_middleware_message
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.test.utils import override_settings from django.test.utils import override_settings
@ -13,7 +14,7 @@ class CheckSessionCookieSecureTest(SimpleTestCase):
@override_settings( @override_settings(
SESSION_COOKIE_SECURE=False, SESSION_COOKIE_SECURE=False,
INSTALLED_APPS=["django.contrib.sessions"], INSTALLED_APPS=["django.contrib.sessions"],
MIDDLEWARE_CLASSES=[]) MIDDLEWARE=[])
def test_session_cookie_secure_with_installed_app(self): def test_session_cookie_secure_with_installed_app(self):
""" """
Warn if SESSION_COOKIE_SECURE is off and "django.contrib.sessions" is Warn if SESSION_COOKIE_SECURE is off and "django.contrib.sessions" is
@ -21,22 +22,38 @@ class CheckSessionCookieSecureTest(SimpleTestCase):
""" """
self.assertEqual(self.func(None), [sessions.W010]) self.assertEqual(self.func(None), [sessions.W010])
@override_settings(
SESSION_COOKIE_SECURE=False,
INSTALLED_APPS=["django.contrib.sessions"],
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=[])
def test_session_cookie_secure_with_installed_app_middleware_classes(self):
self.assertEqual(self.func(None), [sessions.W010])
@override_settings( @override_settings(
SESSION_COOKIE_SECURE=False, SESSION_COOKIE_SECURE=False,
INSTALLED_APPS=[], INSTALLED_APPS=[],
MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"]) MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_secure_with_middleware(self): def test_session_cookie_secure_with_middleware(self):
""" """
Warn if SESSION_COOKIE_SECURE is off and Warn if SESSION_COOKIE_SECURE is off and
"django.contrib.sessions.middleware.SessionMiddleware" is in "django.contrib.sessions.middleware.SessionMiddleware" is in
MIDDLEWARE_CLASSES. MIDDLEWARE.
""" """
self.assertEqual(self.func(None), [sessions.W011]) self.assertEqual(self.func(None), [sessions.W011])
@override_settings( @override_settings(
SESSION_COOKIE_SECURE=False, SESSION_COOKIE_SECURE=False,
INSTALLED_APPS=["django.contrib.sessions"], INSTALLED_APPS=[],
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"]) MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_secure_with_middleware_middleware_classes(self):
self.assertEqual(self.func(None), [patch_middleware_message(sessions.W011)])
@override_settings(
SESSION_COOKIE_SECURE=False,
INSTALLED_APPS=["django.contrib.sessions"],
MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_secure_both(self): def test_session_cookie_secure_both(self):
""" """
If SESSION_COOKIE_SECURE is off and we find both the session app and If SESSION_COOKIE_SECURE is off and we find both the session app and
@ -44,10 +61,18 @@ class CheckSessionCookieSecureTest(SimpleTestCase):
""" """
self.assertEqual(self.func(None), [sessions.W012]) self.assertEqual(self.func(None), [sessions.W012])
@override_settings(
SESSION_COOKIE_SECURE=False,
INSTALLED_APPS=["django.contrib.sessions"],
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_secure_both_middleware_classes(self):
self.assertEqual(self.func(None), [sessions.W012])
@override_settings( @override_settings(
SESSION_COOKIE_SECURE=True, SESSION_COOKIE_SECURE=True,
INSTALLED_APPS=["django.contrib.sessions"], INSTALLED_APPS=["django.contrib.sessions"],
MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"]) MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_secure_true(self): def test_session_cookie_secure_true(self):
""" """
If SESSION_COOKIE_SECURE is on, there's no warning about it. If SESSION_COOKIE_SECURE is on, there's no warning about it.
@ -64,7 +89,7 @@ class CheckSessionCookieHttpOnlyTest(SimpleTestCase):
@override_settings( @override_settings(
SESSION_COOKIE_HTTPONLY=False, SESSION_COOKIE_HTTPONLY=False,
INSTALLED_APPS=["django.contrib.sessions"], INSTALLED_APPS=["django.contrib.sessions"],
MIDDLEWARE_CLASSES=[]) MIDDLEWARE=[])
def test_session_cookie_httponly_with_installed_app(self): def test_session_cookie_httponly_with_installed_app(self):
""" """
Warn if SESSION_COOKIE_HTTPONLY is off and "django.contrib.sessions" Warn if SESSION_COOKIE_HTTPONLY is off and "django.contrib.sessions"
@ -75,19 +100,19 @@ class CheckSessionCookieHttpOnlyTest(SimpleTestCase):
@override_settings( @override_settings(
SESSION_COOKIE_HTTPONLY=False, SESSION_COOKIE_HTTPONLY=False,
INSTALLED_APPS=[], INSTALLED_APPS=[],
MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"]) MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_httponly_with_middleware(self): def test_session_cookie_httponly_with_middleware(self):
""" """
Warn if SESSION_COOKIE_HTTPONLY is off and Warn if SESSION_COOKIE_HTTPONLY is off and
"django.contrib.sessions.middleware.SessionMiddleware" is in "django.contrib.sessions.middleware.SessionMiddleware" is in
MIDDLEWARE_CLASSES. MIDDLEWARE.
""" """
self.assertEqual(self.func(None), [sessions.W014]) self.assertEqual(self.func(None), [sessions.W014])
@override_settings( @override_settings(
SESSION_COOKIE_HTTPONLY=False, SESSION_COOKIE_HTTPONLY=False,
INSTALLED_APPS=["django.contrib.sessions"], INSTALLED_APPS=["django.contrib.sessions"],
MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"]) MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_httponly_both(self): def test_session_cookie_httponly_both(self):
""" """
If SESSION_COOKIE_HTTPONLY is off and we find both the session app and If SESSION_COOKIE_HTTPONLY is off and we find both the session app and
@ -98,7 +123,7 @@ class CheckSessionCookieHttpOnlyTest(SimpleTestCase):
@override_settings( @override_settings(
SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_HTTPONLY=True,
INSTALLED_APPS=["django.contrib.sessions"], INSTALLED_APPS=["django.contrib.sessions"],
MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"]) MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_httponly_true(self): def test_session_cookie_httponly_true(self):
""" """
If SESSION_COOKIE_HTTPONLY is on, there's no warning about it. If SESSION_COOKIE_HTTPONLY is on, there's no warning about it.
@ -112,15 +137,15 @@ class CheckCSRFMiddlewareTest(SimpleTestCase):
from django.core.checks.security.csrf import check_csrf_middleware from django.core.checks.security.csrf import check_csrf_middleware
return check_csrf_middleware return check_csrf_middleware
@override_settings(MIDDLEWARE_CLASSES=[]) @override_settings(MIDDLEWARE=[], MIDDLEWARE_CLASSES=[])
def test_no_csrf_middleware(self): def test_no_csrf_middleware(self):
""" """
Warn if CsrfViewMiddleware isn't in MIDDLEWARE_CLASSES. Warn if CsrfViewMiddleware isn't in MIDDLEWARE.
""" """
self.assertEqual(self.func(None), [csrf.W003]) self.assertEqual(self.func(None), [csrf.W003])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"]) MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"])
def test_with_csrf_middleware(self): def test_with_csrf_middleware(self):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@ -132,25 +157,25 @@ class CheckCSRFCookieSecureTest(SimpleTestCase):
return check_csrf_cookie_secure return check_csrf_cookie_secure
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"], MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
CSRF_COOKIE_SECURE=False) CSRF_COOKIE_SECURE=False)
def test_with_csrf_cookie_secure_false(self): def test_with_csrf_cookie_secure_false(self):
""" """
Warn if CsrfViewMiddleware is in MIDDLEWARE_CLASSES but Warn if CsrfViewMiddleware is in MIDDLEWARE but
CSRF_COOKIE_SECURE isn't True. CSRF_COOKIE_SECURE isn't True.
""" """
self.assertEqual(self.func(None), [csrf.W016]) self.assertEqual(self.func(None), [csrf.W016])
@override_settings(MIDDLEWARE_CLASSES=[], CSRF_COOKIE_SECURE=False) @override_settings(MIDDLEWARE=[], MIDDLEWARE_CLASSES=[], CSRF_COOKIE_SECURE=False)
def test_with_csrf_cookie_secure_false_no_middleware(self): def test_with_csrf_cookie_secure_false_no_middleware(self):
""" """
No warning if CsrfViewMiddleware isn't in MIDDLEWARE_CLASSES, even if No warning if CsrfViewMiddleware isn't in MIDDLEWARE, even if
CSRF_COOKIE_SECURE is False. CSRF_COOKIE_SECURE is False.
""" """
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"], MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
CSRF_COOKIE_SECURE=True) CSRF_COOKIE_SECURE=True)
def test_with_csrf_cookie_secure_true(self): def test_with_csrf_cookie_secure_true(self):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@ -163,25 +188,25 @@ class CheckCSRFCookieHttpOnlyTest(SimpleTestCase):
return check_csrf_cookie_httponly return check_csrf_cookie_httponly
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"], MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
CSRF_COOKIE_HTTPONLY=False) CSRF_COOKIE_HTTPONLY=False)
def test_with_csrf_cookie_httponly_false(self): def test_with_csrf_cookie_httponly_false(self):
""" """
Warn if CsrfViewMiddleware is in MIDDLEWARE_CLASSES but Warn if CsrfViewMiddleware is in MIDDLEWARE but
CSRF_COOKIE_HTTPONLY isn't True. CSRF_COOKIE_HTTPONLY isn't True.
""" """
self.assertEqual(self.func(None), [csrf.W017]) self.assertEqual(self.func(None), [csrf.W017])
@override_settings(MIDDLEWARE_CLASSES=[], CSRF_COOKIE_HTTPONLY=False) @override_settings(MIDDLEWARE=[], MIDDLEWARE_CLASSES=[], CSRF_COOKIE_HTTPONLY=False)
def test_with_csrf_cookie_httponly_false_no_middleware(self): def test_with_csrf_cookie_httponly_false_no_middleware(self):
""" """
No warning if CsrfViewMiddleware isn't in MIDDLEWARE_CLASSES, even if No warning if CsrfViewMiddleware isn't in MIDDLEWARE, even if
CSRF_COOKIE_HTTPONLY is False. CSRF_COOKIE_HTTPONLY is False.
""" """
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"], MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
CSRF_COOKIE_HTTPONLY=True) CSRF_COOKIE_HTTPONLY=True)
def test_with_csrf_cookie_httponly_true(self): def test_with_csrf_cookie_httponly_true(self):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@ -193,15 +218,15 @@ class CheckSecurityMiddlewareTest(SimpleTestCase):
from django.core.checks.security.base import check_security_middleware from django.core.checks.security.base import check_security_middleware
return check_security_middleware return check_security_middleware
@override_settings(MIDDLEWARE_CLASSES=[]) @override_settings(MIDDLEWARE=[])
def test_no_security_middleware(self): def test_no_security_middleware(self):
""" """
Warn if SecurityMiddleware isn't in MIDDLEWARE_CLASSES. Warn if SecurityMiddleware isn't in MIDDLEWARE.
""" """
self.assertEqual(self.func(None), [base.W001]) self.assertEqual(self.func(None), [base.W001])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"]) MIDDLEWARE=["django.middleware.security.SecurityMiddleware"])
def test_with_security_middleware(self): def test_with_security_middleware(self):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@ -213,7 +238,7 @@ class CheckStrictTransportSecurityTest(SimpleTestCase):
return check_sts return check_sts
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_HSTS_SECONDS=0) SECURE_HSTS_SECONDS=0)
def test_no_sts(self): def test_no_sts(self):
""" """
@ -222,7 +247,7 @@ class CheckStrictTransportSecurityTest(SimpleTestCase):
self.assertEqual(self.func(None), [base.W004]) self.assertEqual(self.func(None), [base.W004])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[], MIDDLEWARE=[],
SECURE_HSTS_SECONDS=0) SECURE_HSTS_SECONDS=0)
def test_no_sts_no_middleware(self): def test_no_sts_no_middleware(self):
""" """
@ -232,7 +257,7 @@ class CheckStrictTransportSecurityTest(SimpleTestCase):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_HSTS_SECONDS=3600) SECURE_HSTS_SECONDS=3600)
def test_with_sts(self): def test_with_sts(self):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@ -245,7 +270,7 @@ class CheckStrictTransportSecuritySubdomainsTest(SimpleTestCase):
return check_sts_include_subdomains return check_sts_include_subdomains
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_HSTS_INCLUDE_SUBDOMAINS=False, SECURE_HSTS_INCLUDE_SUBDOMAINS=False,
SECURE_HSTS_SECONDS=3600) SECURE_HSTS_SECONDS=3600)
def test_no_sts_subdomains(self): def test_no_sts_subdomains(self):
@ -255,7 +280,7 @@ class CheckStrictTransportSecuritySubdomainsTest(SimpleTestCase):
self.assertEqual(self.func(None), [base.W005]) self.assertEqual(self.func(None), [base.W005])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[], MIDDLEWARE=[],
SECURE_HSTS_INCLUDE_SUBDOMAINS=False, SECURE_HSTS_INCLUDE_SUBDOMAINS=False,
SECURE_HSTS_SECONDS=3600) SECURE_HSTS_SECONDS=3600)
def test_no_sts_subdomains_no_middleware(self): def test_no_sts_subdomains_no_middleware(self):
@ -265,7 +290,7 @@ class CheckStrictTransportSecuritySubdomainsTest(SimpleTestCase):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_SSL_REDIRECT=False, SECURE_SSL_REDIRECT=False,
SECURE_HSTS_SECONDS=None) SECURE_HSTS_SECONDS=None)
def test_no_sts_subdomains_no_seconds(self): def test_no_sts_subdomains_no_seconds(self):
@ -275,7 +300,7 @@ class CheckStrictTransportSecuritySubdomainsTest(SimpleTestCase):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_HSTS_INCLUDE_SUBDOMAINS=True, SECURE_HSTS_INCLUDE_SUBDOMAINS=True,
SECURE_HSTS_SECONDS=3600) SECURE_HSTS_SECONDS=3600)
def test_with_sts_subdomains(self): def test_with_sts_subdomains(self):
@ -288,14 +313,14 @@ class CheckXFrameOptionsMiddlewareTest(SimpleTestCase):
from django.core.checks.security.base import check_xframe_options_middleware from django.core.checks.security.base import check_xframe_options_middleware
return check_xframe_options_middleware return check_xframe_options_middleware
@override_settings(MIDDLEWARE_CLASSES=[]) @override_settings(MIDDLEWARE=[])
def test_middleware_not_installed(self): def test_middleware_not_installed(self):
""" """
Warn if XFrameOptionsMiddleware isn't in MIDDLEWARE_CLASSES. Warn if XFrameOptionsMiddleware isn't in MIDDLEWARE.
""" """
self.assertEqual(self.func(None), [base.W002]) self.assertEqual(self.func(None), [base.W002])
@override_settings(MIDDLEWARE_CLASSES=["django.middleware.clickjacking.XFrameOptionsMiddleware"]) @override_settings(MIDDLEWARE=["django.middleware.clickjacking.XFrameOptionsMiddleware"])
def test_middleware_installed(self): def test_middleware_installed(self):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@ -307,26 +332,26 @@ class CheckXFrameOptionsDenyTest(SimpleTestCase):
return check_xframe_deny return check_xframe_deny
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.clickjacking.XFrameOptionsMiddleware"], MIDDLEWARE=["django.middleware.clickjacking.XFrameOptionsMiddleware"],
X_FRAME_OPTIONS='SAMEORIGIN', X_FRAME_OPTIONS='SAMEORIGIN',
) )
def test_x_frame_options_not_deny(self): def test_x_frame_options_not_deny(self):
""" """
Warn if XFrameOptionsMiddleware is in MIDDLEWARE_CLASSES but Warn if XFrameOptionsMiddleware is in MIDDLEWARE but
X_FRAME_OPTIONS isn't 'DENY'. X_FRAME_OPTIONS isn't 'DENY'.
""" """
self.assertEqual(self.func(None), [base.W019]) self.assertEqual(self.func(None), [base.W019])
@override_settings(MIDDLEWARE_CLASSES=[], X_FRAME_OPTIONS='SAMEORIGIN') @override_settings(MIDDLEWARE=[], X_FRAME_OPTIONS='SAMEORIGIN')
def test_middleware_not_installed(self): def test_middleware_not_installed(self):
""" """
No error if XFrameOptionsMiddleware isn't in MIDDLEWARE_CLASSES even if No error if XFrameOptionsMiddleware isn't in MIDDLEWARE even if
X_FRAME_OPTIONS isn't 'DENY'. X_FRAME_OPTIONS isn't 'DENY'.
""" """
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.clickjacking.XFrameOptionsMiddleware"], MIDDLEWARE=["django.middleware.clickjacking.XFrameOptionsMiddleware"],
X_FRAME_OPTIONS='DENY', X_FRAME_OPTIONS='DENY',
) )
def test_xframe_deny(self): def test_xframe_deny(self):
@ -340,7 +365,7 @@ class CheckContentTypeNosniffTest(SimpleTestCase):
return check_content_type_nosniff return check_content_type_nosniff
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_CONTENT_TYPE_NOSNIFF=False) SECURE_CONTENT_TYPE_NOSNIFF=False)
def test_no_content_type_nosniff(self): def test_no_content_type_nosniff(self):
""" """
@ -349,17 +374,17 @@ class CheckContentTypeNosniffTest(SimpleTestCase):
self.assertEqual(self.func(None), [base.W006]) self.assertEqual(self.func(None), [base.W006])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[], MIDDLEWARE=[],
SECURE_CONTENT_TYPE_NOSNIFF=False) SECURE_CONTENT_TYPE_NOSNIFF=False)
def test_no_content_type_nosniff_no_middleware(self): def test_no_content_type_nosniff_no_middleware(self):
""" """
Don't warn if SECURE_CONTENT_TYPE_NOSNIFF isn't True and Don't warn if SECURE_CONTENT_TYPE_NOSNIFF isn't True and
SecurityMiddleware isn't in MIDDLEWARE_CLASSES. SecurityMiddleware isn't in MIDDLEWARE.
""" """
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_CONTENT_TYPE_NOSNIFF=True) SECURE_CONTENT_TYPE_NOSNIFF=True)
def test_with_content_type_nosniff(self): def test_with_content_type_nosniff(self):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@ -372,7 +397,7 @@ class CheckXssFilterTest(SimpleTestCase):
return check_xss_filter return check_xss_filter
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_BROWSER_XSS_FILTER=False) SECURE_BROWSER_XSS_FILTER=False)
def test_no_xss_filter(self): def test_no_xss_filter(self):
""" """
@ -381,17 +406,17 @@ class CheckXssFilterTest(SimpleTestCase):
self.assertEqual(self.func(None), [base.W007]) self.assertEqual(self.func(None), [base.W007])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[], MIDDLEWARE=[],
SECURE_BROWSER_XSS_FILTER=False) SECURE_BROWSER_XSS_FILTER=False)
def test_no_xss_filter_no_middleware(self): def test_no_xss_filter_no_middleware(self):
""" """
Don't warn if SECURE_BROWSER_XSS_FILTER isn't True and Don't warn if SECURE_BROWSER_XSS_FILTER isn't True and
SecurityMiddleware isn't in MIDDLEWARE_CLASSES. SecurityMiddleware isn't in MIDDLEWARE.
""" """
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_BROWSER_XSS_FILTER=True) SECURE_BROWSER_XSS_FILTER=True)
def test_with_xss_filter(self): def test_with_xss_filter(self):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@ -404,7 +429,7 @@ class CheckSSLRedirectTest(SimpleTestCase):
return check_ssl_redirect return check_ssl_redirect
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_SSL_REDIRECT=False) SECURE_SSL_REDIRECT=False)
def test_no_ssl_redirect(self): def test_no_ssl_redirect(self):
""" """
@ -413,7 +438,7 @@ class CheckSSLRedirectTest(SimpleTestCase):
self.assertEqual(self.func(None), [base.W008]) self.assertEqual(self.func(None), [base.W008])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[], MIDDLEWARE=[],
SECURE_SSL_REDIRECT=False) SECURE_SSL_REDIRECT=False)
def test_no_ssl_redirect_no_middleware(self): def test_no_ssl_redirect_no_middleware(self):
""" """
@ -423,7 +448,7 @@ class CheckSSLRedirectTest(SimpleTestCase):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"], MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_SSL_REDIRECT=True) SECURE_SSL_REDIRECT=True)
def test_with_ssl_redirect(self): def test_with_ssl_redirect(self):
self.assertEqual(self.func(None), []) self.assertEqual(self.func(None), [])

View File

@ -27,7 +27,7 @@ MEDIA_ROOT = sys_tempfile.mkdtemp()
UPLOAD_TO = os.path.join(MEDIA_ROOT, 'test_upload') UPLOAD_TO = os.path.join(MEDIA_ROOT, 'test_upload')
@override_settings(MEDIA_ROOT=MEDIA_ROOT, ROOT_URLCONF='file_uploads.urls', MIDDLEWARE_CLASSES=[]) @override_settings(MEDIA_ROOT=MEDIA_ROOT, ROOT_URLCONF='file_uploads.urls', MIDDLEWARE=[])
class FileUploadTests(TestCase): class FileUploadTests(TestCase):
@classmethod @classmethod

View File

@ -9,7 +9,7 @@ from .settings import FLATPAGES_TEMPLATES
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'}) @modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'})
@override_settings( @override_settings(
LOGIN_URL='/accounts/login/', LOGIN_URL='/accounts/login/',
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
@ -97,3 +97,18 @@ class FlatpageCSRFTests(TestCase):
"POSTing to an unknown page isn't caught as a 403 CSRF error" "POSTing to an unknown page isn't caught as a 403 CSRF error"
response = self.client.post('/no_such_page/') response = self.client.post('/no_such_page/')
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
@override_settings(
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=[
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
],
)
class FlatpageCSRFMiddlewareClassesTests(FlatpageCSRFTests):
pass

View File

@ -47,18 +47,36 @@ class FlatpageAdminFormTests(TestCase):
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form.errors['url'], ["URL is missing a leading slash."]) self.assertEqual(form.errors['url'], ["URL is missing a leading slash."])
@override_settings(APPEND_SLASH=True, MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware']) @override_settings(APPEND_SLASH=True, MIDDLEWARE=['django.middleware.common.CommonMiddleware'])
def test_flatpage_requires_trailing_slash_with_append_slash(self): def test_flatpage_requires_trailing_slash_with_append_slash(self):
form = FlatpageForm(data=dict(url='/no_trailing_slash', **self.form_data)) form = FlatpageForm(data=dict(url='/no_trailing_slash', **self.form_data))
with translation.override('en'): with translation.override('en'):
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertEqual(form.errors['url'], ["URL is missing a trailing slash."]) self.assertEqual(form.errors['url'], ["URL is missing a trailing slash."])
@override_settings(APPEND_SLASH=False, MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware']) @override_settings(APPEND_SLASH=False, MIDDLEWARE=['django.middleware.common.CommonMiddleware'])
def test_flatpage_doesnt_requires_trailing_slash_without_append_slash(self): def test_flatpage_doesnt_requires_trailing_slash_without_append_slash(self):
form = FlatpageForm(data=dict(url='/no_trailing_slash', **self.form_data)) form = FlatpageForm(data=dict(url='/no_trailing_slash', **self.form_data))
self.assertTrue(form.is_valid()) self.assertTrue(form.is_valid())
@override_settings(
APPEND_SLASH=True, MIDDLEWARE=None,
MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'],
)
def test_flatpage_requires_trailing_slash_with_append_slash_middleware_classes(self):
form = FlatpageForm(data=dict(url='/no_trailing_slash', **self.form_data))
with translation.override('en'):
self.assertFalse(form.is_valid())
self.assertEqual(form.errors['url'], ["URL is missing a trailing slash."])
@override_settings(
APPEND_SLASH=False, MIDDLEWARE=None,
MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'],
)
def test_flatpage_doesnt_requires_trailing_slash_without_append_slash_middleware_classes(self):
form = FlatpageForm(data=dict(url='/no_trailing_slash', **self.form_data))
self.assertTrue(form.is_valid())
def test_flatpage_admin_form_url_uniqueness_validation(self): def test_flatpage_admin_form_url_uniqueness_validation(self):
"The flatpage admin form correctly enforces url uniqueness among flatpages of the same site" "The flatpage admin form correctly enforces url uniqueness among flatpages of the same site"
data = dict(url='/myflatpage1/', **self.form_data) data = dict(url='/myflatpage1/', **self.form_data)

View File

@ -40,7 +40,7 @@ class TestDataMixin(object):
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'}) @modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'})
@override_settings( @override_settings(
LOGIN_URL='/accounts/login/', LOGIN_URL='/accounts/login/',
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
@ -107,11 +107,26 @@ class FlatpageMiddlewareTests(TestDataMixin, TestCase):
self.assertContains(response, "<p>Isn't it special!</p>") self.assertContains(response, "<p>Isn't it special!</p>")
@override_settings(
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=[
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
],
)
class FlatpageMiddlewareClassesTests(FlatpageMiddlewareTests):
pass
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'}) @modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'})
@override_settings( @override_settings(
APPEND_SLASH=True, APPEND_SLASH=True,
LOGIN_URL='/accounts/login/', LOGIN_URL='/accounts/login/',
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
@ -172,3 +187,18 @@ class FlatpageMiddlewareAppendSlashTests(TestDataMixin, TestCase):
response = self.client.get('/') response = self.client.get('/')
self.assertContains(response, "<p>Root</p>") self.assertContains(response, "<p>Root</p>")
@override_settings(
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=[
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
],
)
class FlatpageAppendSlashMiddlewareClassesTests(FlatpageMiddlewareAppendSlashTests):
pass

View File

@ -2,25 +2,9 @@ from django.contrib.auth.models import AnonymousUser, User
from django.contrib.flatpages.models import FlatPage from django.contrib.flatpages.models import FlatPage
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.template import Context, Template, TemplateSyntaxError from django.template import Context, Template, TemplateSyntaxError
from django.test import TestCase, modify_settings, override_settings from django.test import TestCase
from .settings import FLATPAGES_TEMPLATES
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'})
@override_settings(
MIDDLEWARE_CLASSES=[
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
],
ROOT_URLCONF='flatpages_tests.urls',
TEMPLATES=FLATPAGES_TEMPLATES,
SITE_ID=1,
)
class FlatpageTemplateTagTests(TestCase): class FlatpageTemplateTagTests(TestCase):
@classmethod @classmethod

View File

@ -40,7 +40,7 @@ class TestDataMixin(object):
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'}) @modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'})
@override_settings( @override_settings(
LOGIN_URL='/accounts/login/', LOGIN_URL='/accounts/login/',
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
@ -102,7 +102,7 @@ class FlatpageViewTests(TestDataMixin, TestCase):
@override_settings( @override_settings(
APPEND_SLASH=True, APPEND_SLASH=True,
LOGIN_URL='/accounts/login/', LOGIN_URL='/accounts/login/',
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',

View File

@ -4,6 +4,7 @@ from __future__ import unicode_literals
import unittest import unittest
from django.core.exceptions import ImproperlyConfigured
from django.core.handlers.wsgi import WSGIHandler, WSGIRequest, get_script_name from django.core.handlers.wsgi import WSGIHandler, WSGIRequest, get_script_name
from django.core.signals import request_finished, request_started from django.core.signals import request_finished, request_started
from django.db import close_old_connections, connection from django.db import close_old_connections, connection
@ -166,6 +167,10 @@ class SignalsTests(SimpleTestCase):
self.assertEqual(self.signals, ['started', 'finished']) self.assertEqual(self.signals, ['started', 'finished'])
def empty_middleware(get_response):
pass
@override_settings(ROOT_URLCONF='handlers.urls') @override_settings(ROOT_URLCONF='handlers.urls')
class HandlerRequestTests(SimpleTestCase): class HandlerRequestTests(SimpleTestCase):
@ -199,6 +204,12 @@ class HandlerRequestTests(SimpleTestCase):
WSGIHandler()(environ, start_response) WSGIHandler()(environ, start_response)
self.assertEqual(start_response.status, '200 OK') self.assertEqual(start_response.status, '200 OK')
@override_settings(MIDDLEWARE=['handlers.tests.empty_middleware'])
def test_middleware_returns_none(self):
msg = 'Middleware factory handlers.tests.empty_middleware returned None.'
with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.client.get('/')
class ScriptNameTests(SimpleTestCase): class ScriptNameTests(SimpleTestCase):
def test_get_script_name(self): def test_get_script_name(self):

View File

@ -30,7 +30,7 @@ class PermanentRedirectLocaleMiddleWare(LocaleMiddleware):
('en', 'English'), ('en', 'English'),
('pt-br', 'Brazilian Portuguese'), ('pt-br', 'Brazilian Portuguese'),
], ],
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
], ],
@ -223,7 +223,7 @@ class URLRedirectTests(URLTestCaseBase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'i18n.patterns.tests.PermanentRedirectLocaleMiddleWare', 'i18n.patterns.tests.PermanentRedirectLocaleMiddleWare',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
], ],

View File

@ -1756,7 +1756,7 @@ class MultipleLocaleActivationTests(SimpleTestCase):
('en', 'English'), ('en', 'English'),
('fr', 'French'), ('fr', 'French'),
], ],
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
], ],
@ -1772,7 +1772,7 @@ class LocaleMiddlewareTests(TestCase):
self.assertContains(response, "Yes/No") self.assertContains(response, "Yes/No")
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
@ -1792,7 +1792,7 @@ class LocaleMiddlewareTests(TestCase):
('en', 'English'), ('en', 'English'),
('fr', 'French'), ('fr', 'French'),
], ],
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
], ],
@ -1828,7 +1828,7 @@ class UnprefixedDefaultLanguageTests(SimpleTestCase):
('en-us', 'English'), ('en-us', 'English'),
('pt-br', 'Portuguese (Brazil)'), ('pt-br', 'Portuguese (Brazil)'),
], ],
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
], ],

View File

@ -125,7 +125,7 @@ class HandlerLoggingTests(SetupDefaultLoggingMixin, LoggingCaptureMixin, SimpleT
DEBUG=True, DEBUG=True,
USE_I18N=True, USE_I18N=True,
LANGUAGES=[('en', 'English')], LANGUAGES=[('en', 'English')],
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
], ],

View File

@ -217,7 +217,7 @@ class BaseTests(object):
@modify_settings( @modify_settings(
INSTALLED_APPS={'remove': 'django.contrib.messages'}, INSTALLED_APPS={'remove': 'django.contrib.messages'},
MIDDLEWARE_CLASSES={'remove': 'django.contrib.messages.middleware.MessageMiddleware'}, MIDDLEWARE={'remove': 'django.contrib.messages.middleware.MessageMiddleware'},
) )
@override_settings( @override_settings(
MESSAGE_LEVEL=constants.DEBUG, MESSAGE_LEVEL=constants.DEBUG,
@ -243,7 +243,7 @@ class BaseTests(object):
@modify_settings( @modify_settings(
INSTALLED_APPS={'remove': 'django.contrib.messages'}, INSTALLED_APPS={'remove': 'django.contrib.messages'},
MIDDLEWARE_CLASSES={'remove': 'django.contrib.messages.middleware.MessageMiddleware'}, MIDDLEWARE={'remove': 'django.contrib.messages.middleware.MessageMiddleware'},
) )
@override_settings( @override_settings(
TEMPLATES=[{ TEMPLATES=[{

View File

@ -1,8 +1,10 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.http import HttpResponse from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class ProcessExceptionMiddleware(object): class ProcessExceptionMiddleware(MiddlewareMixin):
def process_exception(self, request, exception): def process_exception(self, request, exception):
return HttpResponse('Exception caught') return HttpResponse('Exception caught')

View File

@ -8,6 +8,7 @@ from django.template import engines
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.test import RequestFactory, SimpleTestCase, override_settings from django.test import RequestFactory, SimpleTestCase, override_settings
from django.test.utils import patch_logger from django.test.utils import patch_logger
from django.utils.deprecation import MiddlewareMixin
class TestException(Exception): class TestException(Exception):
@ -15,13 +16,14 @@ class TestException(Exception):
# A middleware base class that tracks which methods have been called # A middleware base class that tracks which methods have been called
class TestMiddleware(object): class TestMiddleware(MiddlewareMixin):
def __init__(self): def __init__(self, get_response=None):
self.process_request_called = False self.process_request_called = False
self.process_view_called = False self.process_view_called = False
self.process_response_called = False self.process_response_called = False
self.process_template_response_called = False self.process_template_response_called = False
self.process_exception_called = False self.process_exception_called = False
self.get_response = get_response
def process_request(self, request): def process_request(self, request):
self.process_request_called = True self.process_request_called = True
@ -115,7 +117,11 @@ class NoResponseMiddleware(TestMiddleware):
super(NoResponseMiddleware, self).process_response(request, response) super(NoResponseMiddleware, self).process_response(request, response)
@override_settings(ROOT_URLCONF='middleware_exceptions.urls') @override_settings(
ROOT_URLCONF='middleware_exceptions.urls',
MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'],
MIDDLEWARE=None,
)
class BaseMiddlewareExceptionTest(SimpleTestCase): class BaseMiddlewareExceptionTest(SimpleTestCase):
def setUp(self): def setUp(self):
@ -492,12 +498,10 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
# Check that the right middleware methods have been invoked # Check that the right middleware methods have been invoked
self.assert_middleware_usage(middleware, True, True, True, True, False) self.assert_middleware_usage(middleware, True, True, True, True, False)
@override_settings( @override_settings(MIDDLEWARE=['middleware_exceptions.middleware.ProcessExceptionMiddleware'])
MIDDLEWARE_CLASSES=['middleware_exceptions.middleware.ProcessExceptionMiddleware'],
)
def test_exception_in_render_passed_to_process_exception(self): def test_exception_in_render_passed_to_process_exception(self):
# Repopulate the list of middlewares since it's already been populated # Repopulate the list of middlewares since it's already been populated
# by setUp() before the MIDDLEWARE_CLASSES setting got overridden # by setUp() before the MIDDLEWARE setting got overridden.
self.client.handler.load_middleware() self.client.handler.load_middleware()
response = self.client.get('/middleware_exceptions/exception_in_render/') response = self.client.get('/middleware_exceptions/exception_in_render/')
self.assertEqual(response.content, b'Exception caught') self.assertEqual(response.content, b'Exception caught')
@ -868,7 +872,7 @@ class RootUrlconfTests(SimpleTestCase):
class MyMiddleware(object): class MyMiddleware(object):
def __init__(self): def __init__(self, get_response=None):
raise MiddlewareNotUsed raise MiddlewareNotUsed
def process_request(self, request): def process_request(self, request):
@ -877,7 +881,7 @@ class MyMiddleware(object):
class MyMiddlewareWithExceptionMessage(object): class MyMiddlewareWithExceptionMessage(object):
def __init__(self): def __init__(self, get_response=None):
raise MiddlewareNotUsed('spam eggs') raise MiddlewareNotUsed('spam eggs')
def process_request(self, request): def process_request(self, request):
@ -887,6 +891,7 @@ class MyMiddlewareWithExceptionMessage(object):
@override_settings( @override_settings(
DEBUG=True, DEBUG=True,
ROOT_URLCONF='middleware_exceptions.urls', ROOT_URLCONF='middleware_exceptions.urls',
MIDDLEWARE=['django.middleware.common.CommonMiddleware'],
) )
class MiddlewareNotUsedTests(SimpleTestCase): class MiddlewareNotUsedTests(SimpleTestCase):
@ -897,9 +902,7 @@ class MiddlewareNotUsedTests(SimpleTestCase):
with self.assertRaises(MiddlewareNotUsed): with self.assertRaises(MiddlewareNotUsed):
MyMiddleware().process_request(request) MyMiddleware().process_request(request)
@override_settings(MIDDLEWARE_CLASSES=[ @override_settings(MIDDLEWARE=['middleware_exceptions.tests.MyMiddleware'])
'middleware_exceptions.tests.MyMiddleware',
])
def test_log(self): def test_log(self):
with patch_logger('django.request', 'debug') as calls: with patch_logger('django.request', 'debug') as calls:
self.client.get('/middleware_exceptions/view/') self.client.get('/middleware_exceptions/view/')
@ -909,9 +912,7 @@ class MiddlewareNotUsedTests(SimpleTestCase):
"MiddlewareNotUsed: 'middleware_exceptions.tests.MyMiddleware'" "MiddlewareNotUsed: 'middleware_exceptions.tests.MyMiddleware'"
) )
@override_settings(MIDDLEWARE_CLASSES=[ @override_settings(MIDDLEWARE=['middleware_exceptions.tests.MyMiddlewareWithExceptionMessage'])
'middleware_exceptions.tests.MyMiddlewareWithExceptionMessage',
])
def test_log_custom_message(self): def test_log_custom_message(self):
with patch_logger('django.request', 'debug') as calls: with patch_logger('django.request', 'debug') as calls:
self.client.get('/middleware_exceptions/view/') self.client.get('/middleware_exceptions/view/')
@ -926,3 +927,11 @@ class MiddlewareNotUsedTests(SimpleTestCase):
with patch_logger('django.request', 'debug') as calls: with patch_logger('django.request', 'debug') as calls:
self.client.get('/middleware_exceptions/view/') self.client.get('/middleware_exceptions/view/')
self.assertEqual(len(calls), 0) self.assertEqual(len(calls), 0)
@override_settings(
MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'],
MIDDLEWARE=None,
)
class MiddlewareNotUsedMiddlewareClassesTests(MiddlewareNotUsedTests):
pass

View File

@ -26,16 +26,16 @@ class TestStartProjectSettings(TestCase):
shutil.copyfile(template_settings_py, test_settings_py) shutil.copyfile(template_settings_py, test_settings_py)
self.addCleanup(os.remove, test_settings_py) self.addCleanup(os.remove, test_settings_py)
def test_middleware_classes_headers(self): def test_middleware_headers(self):
""" """
Ensure headers sent by the default MIDDLEWARE_CLASSES do not Ensure headers sent by the default MIDDLEWARE don't inadvertently
inadvertently change. For example, we never want "Vary: Cookie" to change. For example, we never want "Vary: Cookie" to appear in the list
appear in the list since it prevents the caching of responses. since it prevents the caching of responses.
""" """
from django.conf.project_template.project_name.settings import MIDDLEWARE_CLASSES from django.conf.project_template.project_name.settings import MIDDLEWARE
with self.settings( with self.settings(
MIDDLEWARE_CLASSES=MIDDLEWARE_CLASSES, MIDDLEWARE=MIDDLEWARE,
ROOT_URLCONF='project_template.urls', ROOT_URLCONF='project_template.urls',
): ):
response = self.client.get('/empty/') response = self.client.get('/empty/')

View File

@ -8,7 +8,7 @@ from django.test import TestCase, modify_settings, override_settings
from django.utils import six from django.utils import six
@modify_settings(MIDDLEWARE_CLASSES={'append': 'django.contrib.redirects.middleware.RedirectFallbackMiddleware'}) @modify_settings(MIDDLEWARE={'append': 'django.contrib.redirects.middleware.RedirectFallbackMiddleware'})
@override_settings(APPEND_SLASH=False, SITE_ID=1) @override_settings(APPEND_SLASH=False, SITE_ID=1)
class RedirectTests(TestCase): class RedirectTests(TestCase):
@ -42,6 +42,18 @@ class RedirectTests(TestCase):
response = self.client.get('/initial') response = self.client.get('/initial')
self.assertEqual(response.status_code, 410) self.assertEqual(response.status_code, 410)
@override_settings(MIDDLEWARE=None)
@modify_settings(MIDDLEWARE_CLASSES={'append': 'django.contrib.redirects.middleware.RedirectFallbackMiddleware'})
def test_redirect_middleware_classes(self):
self.test_redirect()
@override_settings(MIDDLEWARE=None)
@modify_settings(MIDDLEWARE_CLASSES={'append': 'django.contrib.redirects.middleware.RedirectFallbackMiddleware'})
def test_more_redirects_middleware_classes(self):
self.test_redirect_with_append_slash()
self.test_redirect_with_append_slash_and_query_string()
self.test_response_gone()
@modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'}) @modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
def test_sites_not_installed(self): def test_sites_not_installed(self):
with self.assertRaises(ImproperlyConfigured): with self.assertRaises(ImproperlyConfigured):
@ -54,7 +66,7 @@ class OverriddenRedirectFallbackMiddleware(RedirectFallbackMiddleware):
response_redirect_class = http.HttpResponseRedirect response_redirect_class = http.HttpResponseRedirect
@modify_settings(MIDDLEWARE_CLASSES={'append': 'redirects_tests.tests.OverriddenRedirectFallbackMiddleware'}) @modify_settings(MIDDLEWARE={'append': 'redirects_tests.tests.OverriddenRedirectFallbackMiddleware'})
@override_settings(SITE_ID=1) @override_settings(SITE_ID=1)
class OverriddenRedirectMiddlewareTests(TestCase): class OverriddenRedirectMiddlewareTests(TestCase):

View File

@ -62,7 +62,7 @@ ALWAYS_INSTALLED_APPS = [
'django.contrib.staticfiles', 'django.contrib.staticfiles',
] ]
ALWAYS_MIDDLEWARE_CLASSES = [ ALWAYS_MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
@ -124,7 +124,7 @@ def setup(verbosity, test_labels, parallel):
'LANGUAGE_CODE': settings.LANGUAGE_CODE, 'LANGUAGE_CODE': settings.LANGUAGE_CODE,
'STATIC_URL': settings.STATIC_URL, 'STATIC_URL': settings.STATIC_URL,
'STATIC_ROOT': settings.STATIC_ROOT, 'STATIC_ROOT': settings.STATIC_ROOT,
'MIDDLEWARE_CLASSES': settings.MIDDLEWARE_CLASSES, 'MIDDLEWARE': settings.MIDDLEWARE,
} }
# Redirect some settings for the duration of these tests. # Redirect some settings for the duration of these tests.
@ -147,7 +147,7 @@ def setup(verbosity, test_labels, parallel):
}] }]
settings.LANGUAGE_CODE = 'en' settings.LANGUAGE_CODE = 'en'
settings.SITE_ID = 1 settings.SITE_ID = 1
settings.MIDDLEWARE_CLASSES = ALWAYS_MIDDLEWARE_CLASSES settings.MIDDLEWARE = ALWAYS_MIDDLEWARE
settings.MIGRATION_MODULES = { settings.MIGRATION_MODULES = {
# This lets us skip creating migrations for the test models as many of # This lets us skip creating migrations for the test models as many of
# them depend on one of the following contrib applications. # them depend on one of the following contrib applications.

View File

@ -4,13 +4,15 @@ import pickle
import time import time
from datetime import datetime from datetime import datetime
from django.conf import settings
from django.template import engines from django.template import engines
from django.template.response import ( from django.template.response import (
ContentNotRenderedError, SimpleTemplateResponse, TemplateResponse, ContentNotRenderedError, SimpleTemplateResponse, TemplateResponse,
) )
from django.test import RequestFactory, SimpleTestCase, override_settings from django.test import (
RequestFactory, SimpleTestCase, modify_settings, override_settings,
)
from django.test.utils import require_jinja2 from django.test.utils import require_jinja2
from django.utils.deprecation import MiddlewareMixin
from .utils import TEMPLATE_DIR from .utils import TEMPLATE_DIR
@ -21,7 +23,7 @@ test_processor_name = 'template_tests.test_response.test_processor'
# A test middleware that installs a temporary URLConf # A test middleware that installs a temporary URLConf
class CustomURLConfMiddleware(object): class CustomURLConfMiddleware(MiddlewareMixin):
def process_request(self, request): def process_request(self, request):
request.urlconf = 'template_tests.alternate_urls' request.urlconf = 'template_tests.alternate_urls'
@ -319,12 +321,8 @@ class TemplateResponseTest(SimpleTestCase):
pickle.dumps(unpickled_response) pickle.dumps(unpickled_response)
@override_settings( @modify_settings(MIDDLEWARE={'append': ['template_tests.test_response.CustomURLConfMiddleware']})
MIDDLEWARE_CLASSES=settings.MIDDLEWARE_CLASSES + [ @override_settings(ROOT_URLCONF='template_tests.urls')
'template_tests.test_response.CustomURLConfMiddleware'
],
ROOT_URLCONF='template_tests.urls',
)
class CustomURLConfTest(SimpleTestCase): class CustomURLConfTest(SimpleTestCase):
def test_custom_urlconf(self): def test_custom_urlconf(self):
@ -332,14 +330,15 @@ class CustomURLConfTest(SimpleTestCase):
self.assertContains(response, 'This is where you can find the snark: /snark/') self.assertContains(response, 'This is where you can find the snark: /snark/')
@override_settings( @modify_settings(
CACHE_MIDDLEWARE_SECONDS=2.0, MIDDLEWARE={
MIDDLEWARE_CLASSES=settings.MIDDLEWARE_CLASSES + [ 'append': [
'django.middleware.cache.FetchFromCacheMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware',
'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.cache.UpdateCacheMiddleware',
], ],
ROOT_URLCONF='template_tests.alternate_urls', },
) )
@override_settings(CACHE_MIDDLEWARE_SECONDS=2.0, ROOT_URLCONF='template_tests.alternate_urls')
class CacheMiddlewareTest(SimpleTestCase): class CacheMiddlewareTest(SimpleTestCase):
def test_middleware_caching(self): def test_middleware_caching(self):
@ -360,3 +359,33 @@ class CacheMiddlewareTest(SimpleTestCase):
self.assertEqual(response2.status_code, 200) self.assertEqual(response2.status_code, 200)
self.assertNotEqual(response.content, response2.content) self.assertNotEqual(response.content, response2.content)
@override_settings(
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=[
'django.middleware.cache.FetchFromCacheMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',
],
CACHE_MIDDLEWARE_SECONDS=2.0,
ROOT_URLCONF='template_tests.alternate_urls'
)
class CacheMiddlewareClassesTest(SimpleTestCase):
def test_middleware_caching(self):
response = self.client.get('/template_response_view/')
self.assertEqual(response.status_code, 200)
time.sleep(1.0)
response2 = self.client.get('/template_response_view/')
self.assertEqual(response2.status_code, 200)
self.assertEqual(response.content, response2.content)
time.sleep(2.0)
# Let the cache expire and test again
response2 = self.client.get('/template_response_view/')
self.assertEqual(response2.status_code, 200)
self.assertNotEqual(response.content, response2.content)

View File

@ -694,7 +694,7 @@ class ClientTest(TestCase):
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=['django.middleware.csrf.CsrfViewMiddleware'], MIDDLEWARE=['django.middleware.csrf.CsrfViewMiddleware'],
ROOT_URLCONF='test_client.urls', ROOT_URLCONF='test_client.urls',
) )
class CSRFEnabledClientTests(SimpleTestCase): class CSRFEnabledClientTests(SimpleTestCase):

View File

@ -1,37 +1,38 @@
from django.http import HttpResponse, StreamingHttpResponse from django.http import HttpResponse, StreamingHttpResponse
from django.urls import reverse from django.urls import reverse
from django.utils.deprecation import MiddlewareMixin
from . import urlconf_inner from . import urlconf_inner
class ChangeURLconfMiddleware(object): class ChangeURLconfMiddleware(MiddlewareMixin):
def process_request(self, request): def process_request(self, request):
request.urlconf = urlconf_inner.__name__ request.urlconf = urlconf_inner.__name__
class NullChangeURLconfMiddleware(object): class NullChangeURLconfMiddleware(MiddlewareMixin):
def process_request(self, request): def process_request(self, request):
request.urlconf = None request.urlconf = None
class ReverseInnerInResponseMiddleware(object): class ReverseInnerInResponseMiddleware(MiddlewareMixin):
def process_response(self, *args, **kwargs): def process_response(self, *args, **kwargs):
return HttpResponse(reverse('inner')) return HttpResponse(reverse('inner'))
class ReverseOuterInResponseMiddleware(object): class ReverseOuterInResponseMiddleware(MiddlewareMixin):
def process_response(self, *args, **kwargs): def process_response(self, *args, **kwargs):
return HttpResponse(reverse('outer')) return HttpResponse(reverse('outer'))
class ReverseInnerInStreaming(object): class ReverseInnerInStreaming(MiddlewareMixin):
def process_view(self, *args, **kwargs): def process_view(self, *args, **kwargs):
def stream(): def stream():
yield reverse('inner') yield reverse('inner')
return StreamingHttpResponse(stream()) return StreamingHttpResponse(stream())
class ReverseOuterInStreaming(object): class ReverseOuterInStreaming(MiddlewareMixin):
def process_view(self, *args, **kwargs): def process_view(self, *args, **kwargs):
def stream(): def stream():
yield reverse('outer') yield reverse('outer')

View File

@ -785,7 +785,7 @@ class RequestURLconfTests(SimpleTestCase):
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'%s.ChangeURLconfMiddleware' % middleware.__name__, '%s.ChangeURLconfMiddleware' % middleware.__name__,
] ]
) )
@ -799,7 +799,7 @@ class RequestURLconfTests(SimpleTestCase):
self.assertEqual(response.content, b'outer:,inner:/second_test/') self.assertEqual(response.content, b'outer:,inner:/second_test/')
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'%s.NullChangeURLconfMiddleware' % middleware.__name__, '%s.NullChangeURLconfMiddleware' % middleware.__name__,
] ]
) )
@ -817,7 +817,7 @@ class RequestURLconfTests(SimpleTestCase):
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'%s.ChangeURLconfMiddleware' % middleware.__name__, '%s.ChangeURLconfMiddleware' % middleware.__name__,
'%s.ReverseInnerInResponseMiddleware' % middleware.__name__, '%s.ReverseInnerInResponseMiddleware' % middleware.__name__,
] ]
@ -832,7 +832,7 @@ class RequestURLconfTests(SimpleTestCase):
self.assertEqual(response.content, b'/second_test/') self.assertEqual(response.content, b'/second_test/')
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'%s.ChangeURLconfMiddleware' % middleware.__name__, '%s.ChangeURLconfMiddleware' % middleware.__name__,
'%s.ReverseOuterInResponseMiddleware' % middleware.__name__, '%s.ReverseOuterInResponseMiddleware' % middleware.__name__,
] ]
@ -847,7 +847,7 @@ class RequestURLconfTests(SimpleTestCase):
self.client.get('/second_test/') self.client.get('/second_test/')
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'%s.ChangeURLconfMiddleware' % middleware.__name__, '%s.ChangeURLconfMiddleware' % middleware.__name__,
'%s.ReverseInnerInStreaming' % middleware.__name__, '%s.ReverseInnerInStreaming' % middleware.__name__,
] ]
@ -862,7 +862,7 @@ class RequestURLconfTests(SimpleTestCase):
self.assertEqual(b''.join(response), b'/second_test/') self.assertEqual(b''.join(response), b'/second_test/')
@override_settings( @override_settings(
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'%s.ChangeURLconfMiddleware' % middleware.__name__, '%s.ChangeURLconfMiddleware' % middleware.__name__,
'%s.ReverseOuterInStreaming' % middleware.__name__, '%s.ReverseOuterInStreaming' % middleware.__name__,
] ]

View File

@ -15,7 +15,7 @@ class CsrfViewTests(SimpleTestCase):
@override_settings( @override_settings(
USE_I18N=True, USE_I18N=True,
MIDDLEWARE_CLASSES=[ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
@ -38,6 +38,32 @@ class CsrfViewTests(SimpleTestCase):
"CSRF-verificatie mislukt. Verzoek afgebroken.", "CSRF-verificatie mislukt. Verzoek afgebroken.",
status_code=403) status_code=403)
@override_settings(
USE_I18N=True,
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=[
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
],
)
def test_translation_middleware_classes(self):
"""
Test that an invalid request is rejected with a localized error message.
"""
response = self.client.post('/')
self.assertContains(response, "Forbidden", status_code=403)
self.assertContains(response,
"CSRF verification failed. Request aborted.",
status_code=403)
with self.settings(LANGUAGE_CODE='nl'), override('en-us'):
response = self.client.post('/')
self.assertContains(response, "Verboden", status_code=403)
self.assertContains(response,
"CSRF-verificatie mislukt. Verzoek afgebroken.",
status_code=403)
@override_settings( @override_settings(
SECURE_PROXY_SSL_HEADER=('HTTP_X_FORWARDED_PROTO', 'https') SECURE_PROXY_SSL_HEADER=('HTTP_X_FORWARDED_PROTO', 'https')
) )

View File

@ -123,6 +123,26 @@ class I18NTests(TestCase):
# we force saving language to a cookie rather than a session # we force saving language to a cookie rather than a session
# by excluding session middleware and those which do require it # by excluding session middleware and those which do require it
test_settings = dict( test_settings = dict(
MIDDLEWARE=['django.middleware.common.CommonMiddleware'],
LANGUAGE_COOKIE_NAME='mylanguage',
LANGUAGE_COOKIE_AGE=3600 * 7 * 2,
LANGUAGE_COOKIE_DOMAIN='.example.com',
LANGUAGE_COOKIE_PATH='/test/',
)
with self.settings(**test_settings):
post_data = dict(language='pl', next='/views/')
response = self.client.post('/i18n/setlang/', data=post_data)
language_cookie = response.cookies.get('mylanguage')
self.assertEqual(language_cookie.value, 'pl')
self.assertEqual(language_cookie['domain'], '.example.com')
self.assertEqual(language_cookie['path'], '/test/')
self.assertEqual(language_cookie['max-age'], 3600 * 7 * 2)
def test_setlang_cookie_middleware_classes(self):
# we force saving language to a cookie rather than a session
# by excluding session middleware and those which do require it
test_settings = dict(
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'], MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'],
LANGUAGE_COOKIE_NAME='mylanguage', LANGUAGE_COOKIE_NAME='mylanguage',
LANGUAGE_COOKIE_AGE=3600 * 7 * 2, LANGUAGE_COOKIE_AGE=3600 * 7 * 2,
@ -150,7 +170,7 @@ class I18NTests(TestCase):
self.assertRedirects(response, encoded_url, fetch_redirect_response=False) self.assertRedirects(response, encoded_url, fetch_redirect_response=False)
self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], lang_code) self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], lang_code)
@modify_settings(MIDDLEWARE_CLASSES={ @modify_settings(MIDDLEWARE={
'append': 'django.middleware.locale.LocaleMiddleware', 'append': 'django.middleware.locale.LocaleMiddleware',
}) })
def test_lang_from_translated_i18n_pattern(self): def test_lang_from_translated_i18n_pattern(self):
@ -167,6 +187,27 @@ class I18NTests(TestCase):
) )
self.assertRedirects(response, '/en/translated/') self.assertRedirects(response, '/en/translated/')
@override_settings(
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=[
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
],
)
def test_lang_from_translated_i18n_pattern_middleware_classes(self):
response = self.client.post(
'/i18n/setlang/', data={'language': 'nl'},
follow=True, HTTP_REFERER='/en/translated/'
)
self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], 'nl')
self.assertRedirects(response, '/nl/vertaald/')
# And reverse
response = self.client.post(
'/i18n/setlang/', data={'language': 'en'},
follow=True, HTTP_REFERER='/nl/vertaald/'
)
self.assertRedirects(response, '/en/translated/')
@override_settings(ROOT_URLCONF='view_tests.urls') @override_settings(ROOT_URLCONF='view_tests.urls')
class JsI18NTests(SimpleTestCase): class JsI18NTests(SimpleTestCase):