Ticket #5034: set_urlconf.diff

File set_urlconf.diff, 9.3 KB (added by SmileyChris, 7 years ago)
  • django/core/urlresolvers.py

     
    2828# be empty.
    2929_prefixes = {}
    3030
     31# Overridden URLconfs for each thread are stored here.
     32_urlconfs = {}
     33
    3134class Resolver404(Http404):
    3235    pass
    3336
     
    296299        return result + sub_match
    297300
    298301def resolve(path, urlconf=None):
     302    if urlconf is None:
     303        urlconf = get_urlconf()
    299304    return get_resolver(urlconf).resolve(path)
    300305
    301306def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None):
     307    if urlconf is None:
     308        urlconf = get_urlconf()
    302309    args = args or []
    303310    kwargs = kwargs or {}
    304311    if prefix is None:
     
    328335    """
    329336    return _prefixes.get(currentThread(), u'/')
    330337
     338def set_urlconf(urlconf_name):
     339    """
     340    Sets the URLconf for the current thread (overriding the default one in
     341    settings). Set to None to revert back to the default.
     342    """
     343    thread = currentThread()
     344    if urlconf_name:
     345        _urlconfs[thread] = urlconf_name
     346    else:
     347        # This is a lot faster than wrapping in a try/except.
     348        if thread in _urlconfs:
     349            del _urlconfs[thread]
     350
     351def get_urlconf(default=None):
     352    """
     353    Returns the root URLconf to use for the current thread if it has been
     354    changed from the default one.
     355    """
     356    thread = currentThread()
     357    # It's faster to check first than to do _urlconfs.get(thread)
     358    if thread in _urlconfs:
     359        return _urlconfs[thread]
     360    return default
  • django/core/handlers/base.py

     
    6363        from django.core import exceptions, urlresolvers
    6464        from django.conf import settings
    6565
     66        # Reset the urlconf for this thread.
     67        urlresolvers.set_urlconf(None)
     68
    6669        # Apply request middleware
    6770        for middleware_method in self._request_middleware:
    6871            response = middleware_method(request)
    6972            if response:
    7073                return response
    7174
    72         # Get urlconf from request object, if available.  Otherwise use default.
    73         urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF)
     75        # Get overridden urlconf for this thread, if available. Otherwise use
     76        # default.
     77        urlconf = urlresolvers.get_urlconf()
     78        if urlconf is None:
     79            # Get urlconf from request object, if available (deprecated).
     80            if hasattr(request, 'urlconf'):
     81                import warnings
     82                warnings.warn("The 'request.urlconf' attribute is deprecated. "
     83                              "Use the 'django.core.urlresolvers::set_urlconf'"
     84                              " method instead.", DeprecationWarning)
     85                urlconf = request.urlconf
     86                urlresolvers.set_urlconf(urlconf)
     87            else:
     88                urlconf = settings.ROOT_URLCONF
    7489
    7590        resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
    7691        try:
  • tests/regressiontests/urlpatterns_reverse/middleware.py

     
     1from django.core.urlresolvers import set_urlconf
     2
     3import urlconf_inner
     4
     5class ChangeUrlconfMiddleware:
     6    def process_request(self, request):
     7        set_urlconf(urlconf_inner.__name__)
  • tests/regressiontests/urlpatterns_reverse/tests.py

     
    11"Unit tests for reverse URL lookup"
    22
     3import re
     4import unittest
     5
    36from django.core.urlresolvers import reverse_helper, NoReverseMatch
    4 import re, unittest
     7from django.conf import settings
     8from django.test import TestCase
    59
     10import urlconf_outer
     11import urlconf_inner
     12import middleware
     13
    614test_data = (
    715    ('^places/(\d+)/$', 'places/3/', [3], {}),
    816    ('^places/(\d+)/$', 'places/3/', ['3'], {}),
     
    3644            else:
    3745                self.assertEquals(got, expected)
    3846
    39 if __name__ == "__main__":
    40     run_tests(1)
     47class SetUrlConf(TestCase):
     48    def setUp(self):
     49        self.root_urlconf = settings.ROOT_URLCONF
     50        self.middleware_classes = settings.MIDDLEWARE_CLASSES
     51        settings.ROOT_URLCONF = urlconf_outer.__name__
     52
     53    def tearDown(self):
     54        settings.ROOT_URLCONF = self.root_urlconf
     55        settings.MIDDLEWARE_CLASSES = self.middleware_classes
     56
     57    def test_handler(self):
     58        response = self.client.get('/test/me/')
     59        self.assertEqual(response.status_code, 200)
     60        self.assertEqual(response.content, 'outer:/test/me/,'
     61                                           'inner:/inner_urlconf/second_test/')
     62        response = self.client.get('/inner_urlconf/second_test/')
     63        self.assertEqual(response.status_code, 200)
     64        response = self.client.get('/second_test/')
     65        self.assertEqual(response.status_code, 404)
     66
     67    def test_handler_overridden(self):
     68        settings.MIDDLEWARE_CLASSES += (
     69            '%s.ChangeUrlconfMiddleware' % middleware.__name__,
     70        )
     71        response = self.client.get('/test/me/')
     72        self.assertEqual(response.status_code, 404)
     73        response = self.client.get('/inner_urlconf/second_test/')
     74        self.assertEqual(response.status_code, 404)
     75        response = self.client.get('/second_test/')
     76        self.assertEqual(response.status_code, 200)
     77        self.assertEqual(response.content, 'outer:,inner:/second_test/')
  • tests/regressiontests/urlpatterns_reverse/urlconf_inner.py

     
     1from django.conf.urls.defaults import *
     2from django.template import Template, Context
     3from django.http import HttpResponse
     4
     5def inner_view(request):
     6    content = Template('outer:{% url outer %},'
     7                       'inner:{% url inner %}').render(Context())
     8    return HttpResponse(content)
     9
     10urlpatterns = patterns('teacher_survey.views',
     11    url(r'^second_test/$', inner_view, name='inner'),
     12)
     13
  • tests/regressiontests/urlpatterns_reverse/urlconf_outer.py

     
     1from django.conf.urls.defaults import *
     2
     3import urlconf_inner
     4
     5urlpatterns = patterns('',
     6    url(r'^test/me/$', urlconf_inner.inner_view, name='outer'),
     7    url(r'^inner_urlconf/', include(urlconf_inner.__name__))
     8)
     9
  • docs/url_dispatch.txt

     
    3434
    3535    1. Django determines the root URLconf module to use. Ordinarily,
    3636       this is the value of the ``ROOT_URLCONF`` setting in your
    37        `settings file`_, but if the incoming ``HttpRequest`` object
    38        has an attribute called ``urlconf``, its value will be used in
    39        place of the ``ROOT_URLCONF`` setting.
     37       `settings file`_, but this can be overridden per request by calling the
     38       ``set_urlconf`` method found in ``django.core.urlresolvers`` (passing in
     39       the value to be used in place of the ``ROOT_URLCONF`` setting).
    4040    2. Django loads that Python module and looks for the variable
    4141       ``urlpatterns``. This should be a Python list, in the format returned by
    4242       the function ``django.conf.urls.defaults.patterns()``.
  • docs/settings.txt

     
    388388
    389389Still, note that there are always going to be sections of your debug output that
    390390are inappropriate for public consumption. File paths, configuration options, and
    391 the like all give attackers extra information about your server. 
     391the like all give attackers extra information about your server.
    392392
    393393It is also important to remember that when running with ``DEBUG`` turned on, Django
    394394will remember every SQL query it executes. This is useful when you are debugging,
     
    820820
    821821Default: Not defined
    822822
    823 A string representing the full Python import path to your root URLconf. For example:
    824 ``"mydjangoapps.urls"``. Can be overridden on a per-request basis by
    825 setting the attribute ``urlconf`` on the incoming ``HttpRequest``
    826 object. See `How Django processes a request`_ for details.
     823A string representing the full Python import path to your root URLconf. For
     824example: ``"mydjangoapps.urls"``. Can be overridden on a per-request basis by
     825using the ``set_urlconf`` method in ``django.core.urlresolvers``. See
     826`How Django processes a request`_ for details.
    827827
    828828.. _How Django processes a request: ../url_dispatch/#how-django-processes-a-request
    829829
Back to Top