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:
parent
05c888ffb8
commit
9baf692a58
|
@ -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 #
|
||||||
############
|
############
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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 = [
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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."),
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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():
|
||||||
|
|
|
@ -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
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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("/")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'``.
|
||||||
|
|
|
@ -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',
|
||||||
...
|
...
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
==============================
|
==============================
|
||||||
|
|
|
@ -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>`.
|
||||||
|
|
|
@ -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
|
||||||
===================================
|
===================================
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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 |
|
@ -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.
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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`
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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',
|
||||||
})
|
})
|
||||||
|
|
|
@ -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',
|
||||||
]
|
]
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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), [])
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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',
|
||||||
],
|
],
|
||||||
|
|
|
@ -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',
|
||||||
],
|
],
|
||||||
|
|
|
@ -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',
|
||||||
],
|
],
|
||||||
|
|
|
@ -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=[{
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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/')
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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__,
|
||||||
]
|
]
|
||||||
|
|
|
@ -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')
|
||||||
)
|
)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue