Ticket #730: middleware_dict_single_instances_basic_sanity_checks-validation.diff

File middleware_dict_single_instances_basic_sanity_checks-validation.diff, 10.4 KB (added by mrts, 7 years ago)

Added validation as well. Consider this patch to be a draft of the general ideas, it's not even tested.

  • django/conf/project_template/settings.py

     
    5757#     'django.template.loaders.eggs.load_template_source',
    5858)
    5959
    60 MIDDLEWARE_CLASSES = (
    61     'django.middleware.common.CommonMiddleware',
    62     'django.contrib.sessions.middleware.SessionMiddleware',
    63     'django.contrib.auth.middleware.AuthenticationMiddleware',
    64     'django.middleware.doc.XViewMiddleware',
    65 )
     60MIDDLEWARE_CLASSES = {
     61    'request': (
     62        'django.middleware.common.CommonMiddleware',
     63        'django.contrib.sessions.middleware.SessionMiddleware',
     64        'django.contrib.auth.middleware.AuthenticationMiddleware',
     65    ),
     66    'response': (
     67        'django.contrib.sessions.middleware.SessionMiddleware',
     68#        'django.middleware.http.ConditionalGetMiddleware',
     69#        'django.middleware.gzip.GZipMiddleware',
     70        'django.middleware.common.CommonMiddleware',
     71    ),
     72    'view': (
     73        'django.middleware.doc.XViewMiddleware',
     74    ),
     75}
    6676
    6777ROOT_URLCONF = '{{ project_name }}.urls'
    6878
  • django/conf/global_settings.py

     
    291291# MIDDLEWARE #
    292292##############
    293293
    294 # List of middleware classes to use.  Order is important; in the request phase,
    295 # this middleware classes will be applied in the order given, and in the
    296 # response phase the middleware will be applied in reverse order.
    297 MIDDLEWARE_CLASSES = (
    298     'django.contrib.sessions.middleware.SessionMiddleware',
    299     'django.contrib.auth.middleware.AuthenticationMiddleware',
    300 #     'django.middleware.http.ConditionalGetMiddleware',
    301 #     'django.middleware.gzip.GZipMiddleware',
    302     'django.middleware.common.CommonMiddleware',
    303     'django.middleware.doc.XViewMiddleware',
    304 )
     294# List of middleware classes to use.  Order is important; all middleware types
     295# will be applied in the order given.
     296MIDDLEWARE_CLASSES = {
     297    'request': (
     298        'django.middleware.common.CommonMiddleware',
     299        'django.contrib.sessions.middleware.SessionMiddleware',
     300        'django.contrib.auth.middleware.AuthenticationMiddleware',
     301    ),
     302    'response': (
     303        'django.contrib.sessions.middleware.SessionMiddleware',
     304#        'django.middleware.http.ConditionalGetMiddleware',
     305#        'django.middleware.gzip.GZipMiddleware',
     306        'django.middleware.common.CommonMiddleware',
     307    ),
     308    'view': (
     309        'django.middleware.doc.XViewMiddleware',
     310    ),
     311}
    305312
    306313############
    307314# SESSIONS #
  • django/core/handlers/base.py

     
    11import sys
    22
    33from django import http
     4from django.core import exceptions
    45from django.core import signals
    56from django.utils.encoding import force_unicode
    67
     
    1617    def __init__(self):
    1718        self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None
    1819
    19     def load_middleware(self):
    20         """
    21         Populate middleware lists from settings.MIDDLEWARE_CLASSES.
    22 
    23         Must be called after the environment is fixed (see __call__).
    24         """
    25         from django.conf import settings
    26         from django.core import exceptions
     20    def _load_middleware_from_list(self, mw_paths):
    2721        self._request_middleware = []
    2822        self._view_middleware = []
    2923        self._response_middleware = []
    3024        self._exception_middleware = []
    31         for middleware_path in settings.MIDDLEWARE_CLASSES:
    32             try:
    33                 dot = middleware_path.rindex('.')
    34             except ValueError:
    35                 raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path
    36             mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
    37             try:
    38                 mod = __import__(mw_module, {}, {}, [''])
    39             except ImportError, e:
    40                 raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e)
    41             try:
    42                 mw_class = getattr(mod, mw_classname)
    43             except AttributeError:
    44                 raise exceptions.ImproperlyConfigured, 'Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname)
    45 
    46             try:
    47                 mw_instance = mw_class()
    48             except exceptions.MiddlewareNotUsed:
    49                 continue
    50 
     25        mw_instances = [ _middleware_instance_from_path(mw_path) for mw_path
     26                in mw_paths ]
     27        for mw_instance in mw_instances:
    5128            if hasattr(mw_instance, 'process_request'):
    5229                self._request_middleware.append(mw_instance.process_request)
    5330            if hasattr(mw_instance, 'process_view'):
     
    5734            if hasattr(mw_instance, 'process_exception'):
    5835                self._exception_middleware.insert(0, mw_instance.process_exception)
    5936
     37    def _load_middleware_from_dict(self, mw_dict):
     38        # fill the instances dict so that we have only one instance of each
     39        # middleware
     40        mw_instances = _middleware_instances_from_dict(mw_dict)
     41        # it would be easy to do validation here, but it would be expensive
     42        # for mw_path, mw_inst in mw_instances.items():
     43        #   for attr in ('request', 'view', 'response', 'exception'):
     44        #       if hasattr(mw_inst, attr) and mw_path not in mw_dict[attr]:
     45        #           raise ImproperlyConfigured("")
     46
     47        self._request_middleware = _particular_middleware_from_dicts('request',
     48                mw_instances, mw_dict)
     49        self._view_middleware = _particular_middleware_from_dicts('view',
     50                mw_instances, mw_dict)
     51        self._response_middleware = _particular_middleware_from_dicts('response',
     52                mw_instances, mw_dict)
     53        self._exception_middleware = _particular_middleware_from_dicts('exception',
     54                mw_instances, mw_dict)
     55
     56    def load_middleware(self):
     57        """
     58        Populate middleware lists from settings.MIDDLEWARE_CLASSES.
     59
     60        Must be called after the environment is fixed (see __call__).
     61        """
     62        from django.conf import settings
     63        if isinstance(settings.MIDDLEWARE_CLASSES, (tuple, list)):
     64            self._load_middleware_from_list(settings.MIDDLEWARE_CLASSES)
     65        elif isinstance(settings.MIDDLEWARE_CLASSES, (dict)):
     66            self._load_middleware_from_dict(settings.MIDDLEWARE_CLASSES)
     67        else:
     68            raise exceptions.ImproperlyConfigured("MIDDLEWARE_CLASSES setting "
     69                    "has to be either a tuple, list or a dict.")
     70
    6071    def get_response(self, request):
    6172        "Returns an HttpResponse object for the given HttpRequest"
    62         from django.core import exceptions, urlresolvers
     73        from django.core import urlresolvers
    6374        from django.conf import settings
    6475
    6576        # Apply request middleware
     
    171182            response = func(request, response)
    172183        return response
    173184
     185def validate_middleware(self):
     186    # A very rough attempt at validation, doesn't load the middleware.
     187    # Note that this assumes that if middleware has a process_foo method,
     188    # then it has to be registered in MIDDLEWARE_CLASSES['foo'].
     189    from django.conf import settings
     190    # if MIDDLEWARE_CLASSES is a list, no easy way to validate
     191    if isinstance(settings.MIDDLEWARE_CLASSES, (dict)):
     192        mw_dict = settings.MIDDLEWARE_CLASSES
     193        mw_instances = _middleware_instances_from_dict(mw_dict)
     194        for mw_path, mw_inst in mw_instances.items():
     195            for attr in ('request', 'view', 'response', 'exception'):
     196                if hasattr(mw_inst, attr) and mw_path not in mw_dict[attr]:
     197                    raise exceptions.ImproperlyConfigured("%s has to "
     198                            "be enabled for %s processing in "
     199                            "MIDDLEWARE_CLASSES setting." % (mw_path, attr))
     200
    174201def get_script_name(environ):
    175202    """
    176203    Returns the equivalent of the HTTP request's SCRIPT_NAME environment
     
    195222        return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))])
    196223    return force_unicode(environ.get('SCRIPT_NAME', u''))
    197224
     225def _middleware_instance_from_path(middleware_path):
     226    try:
     227        dot = middleware_path.rindex('.')
     228    except ValueError:
     229        raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path
     230    mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
     231    try:
     232        mod = __import__(mw_module, {}, {}, [''])
     233    except ImportError, e:
     234        raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e)
     235    try:
     236        mw_class = getattr(mod, mw_classname)
     237    except AttributeError:
     238        raise exceptions.ImproperlyConfigured, 'Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname)
     239    # I'm ignoring the MiddlewareNotUsed exception as it's not used in Django
     240    # according to grep, not documented and the only use case I can see is to
     241    # raise it in custom middleware __init__ to disable the middleware
     242    # temporarily. That can be better achieved with disabling it in settings
     243    # (where it is explicit and visible). If everybody is happy with that, the
     244    # exception should be removed from core.exceptions. See also #7820.
     245    return mw_class()
     246
     247def _particular_middleware_from_dicts(mw_type, mw_instance_dict, mw_dict):
     248    mw_instance_list = []
     249    for mw_path in mw_dict.get(mw_type, []):
     250        mw_instance = mw_instance_dict[mw_path]
     251        if not hasattr(mw_instance, 'process_' + mw_type):
     252            raise exceptions.ImproperlyConfigured("%s middleware needs "
     253                    "a 'process_%s' method, but it's missing from %s."
     254                    % (mw_type.title(), mw_type, mw_path))
     255        mw_instance_list.append(mw_instance)
     256    return mw_instance_list
     257
     258def _middleware_instances_from_dict(mw_dict):
     259    mw_instances = {}
     260    for mw_path_tuple in mw_dict.values():
     261        for mw_path in mw_path_tuple:
     262            if mw_path not in mw_instances:
     263                mw_instances[mw_path] = _middleware_instance_from_path(mw_path)
     264    return mw_instances
Back to Top