Ticket #7930: handle-force-script-name.diff

File handle-force-script-name.diff, 10.8 KB (added by nkryptic, 2 years ago)
  • django/contrib/staticfiles/handlers.py

    diff --git a/django/contrib/staticfiles/handlers.py b/django/contrib/staticfiles/handlers.py
    index 5174586..f041f74 100644
    a b except ImportError: # Python 2 
    77
    88from django.conf import settings
    99from django.core.handlers.base import get_path_info
    10 from django.core.handlers.wsgi import WSGIHandler
     10from django.core.handlers.wsgi import WSGIHandler, UrlPrefixAwareMixin
    1111
    1212from django.contrib.staticfiles import utils
    1313from django.contrib.staticfiles.views import serve
    1414
    15 class StaticFilesHandler(WSGIHandler):
     15class StaticFilesHandler(UrlPrefixAwareMixin, WSGIHandler):
    1616    """
    1717    WSGI middleware that intercepts calls to the static files directory, as
    1818    defined by the STATIC_URL setting, and serves those files.
    class StaticFilesHandler(WSGIHandler): 
    3131
    3232    def get_base_url(self):
    3333        utils.check_settings()
    34         return settings.STATIC_URL
     34        return self.fix_path(settings.STATIC_URL)
    3535
    3636    def _should_handle(self, path):
    3737        """
    class StaticFilesHandler(WSGIHandler): 
    5353        """
    5454        Actually serves the request path.
    5555        """
    56         return serve(request, self.file_path(request.path), insecure=True)
     56        path = self.fix_path(request.path)
     57        return serve(request, self.file_path(path), insecure=True)
    5758
    5859    def get_response(self, request):
    5960        from django.http import Http404
    6061
    61         if self._should_handle(request.path):
     62        if self._should_handle(self.fix_path(request.path)):
    6263            try:
    6364                return self.serve(request)
    6465            except Http404 as e:
  • django/core/handlers/wsgi.py

    diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py
    index a9fa094..c25249c 100644
    a b class WSGIHandler(base.BaseHandler): 
    266266            response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
    267267        start_response(force_str(status), response_headers)
    268268        return response
     269
     270
     271class UrlPrefixAwareMixin(object):
     272    _url_prefix = None
     273    _url_prefix_fetched = False
     274   
     275    @property
     276    def url_prefix(self):
     277        """
     278        Get the FORCE_SCRIPT_NAME from settings or None
     279        """
     280        if not self._url_prefix_fetched:
     281            from django.conf import settings
     282            self._url_prefix = getattr(settings, 'FORCE_SCRIPT_NAME', None)
     283            self._url_prefix_fetched = True
     284        return self._url_prefix
     285
     286    def fix_path(self, path):
     287        """
     288        Strips FORCE_SCRIPT_NAME from the front of the url
     289        """
     290        if self.url_prefix and path.startswith(self.url_prefix):
     291            path = path[len(self.url_prefix):]
     292        return path
     293   
     294    def is_prefixed(self, path):
     295        return not(self.url_prefix) or path.startswith(self.url_prefix)
     296
     297
     298class UrlPrefixAwareHandler(UrlPrefixAwareMixin, WSGIHandler):
     299    """
     300    WSGI middleware that does nothing if FORCE_SCRIPT_NAME is not defined.
     301   
     302    When FORCE_SCRIPT_NAME is defined:
     303      * this middleware will strip it from PATH_INFO in the environ before
     304        passing environ to the next handler
     305      * requests that do not begin with FORCE_SCRIPT_NAME will receive a
     306        400 Bad Request response
     307    """
     308    def __init__(self, application):
     309        self.application = application
     310        super(UrlPrefixAwareHandler, self).__init__()
     311
     312    def get_response(self, request):
     313        logger.warning('Bad Request (Prefixed url required when using FORCE_SCRIPT_NAME)',
     314            extra={
     315                'status_code': 400,
     316            }
     317        )
     318        return http.HttpResponseBadRequest()
     319
     320    def __call__(self, environ, start_response):
     321        if self.url_prefix:
     322            path_info = base.get_path_info(environ)
     323            if not self.is_prefixed(path_info):
     324                return super(UrlPrefixAwareHandler, self).__call__(environ, start_response)
     325            environ['PATH_INFO'] = self.fix_path(path_info)
     326        return self.application(environ, start_response)
  • django/core/management/commands/runserver.py

    diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
    index 391e0b4..a4f71be 100644
    a b import socket 
    77
    88from django.core.management.base import BaseCommand, CommandError
    99from django.core.servers.basehttp import run, WSGIServerException, get_internal_wsgi_application
     10from django.core.handlers.wsgi import UrlPrefixAwareHandler
    1011from django.utils import autoreload
    1112
    1213naiveip_re = re.compile(r"""^(?:
    class Command(BaseCommand): 
    110111
    111112        try:
    112113            handler = self.get_handler(*args, **options)
     114            handler = UrlPrefixAwareHandler(handler)
    113115            run(self.addr, int(self.port), handler,
    114116                ipv6=self.use_ipv6, threading=threading)
    115117        except WSGIServerException as e:
  • django/test/signals.py

    diff --git a/django/test/signals.py b/django/test/signals.py
    index a96bdff..3e8caf2 100644
    a b def file_storage_changed(**kwargs): 
    7979    if kwargs['setting'] in ('MEDIA_ROOT', 'DEFAULT_FILE_STORAGE'):
    8080        from django.core.files.storage import default_storage
    8181        default_storage._wrapped = empty
     82
     83@receiver(setting_changed)
     84def fix_script_prefix(**kwargs):
     85    if kwargs['setting'] == 'FORCE_SCRIPT_NAME':
     86        from django.core.urlresolvers import set_script_prefix
     87        set_script_prefix('/')
     88 No newline at end of file
  • django/test/testcases.py

    diff --git a/django/test/testcases.py b/django/test/testcases.py
    index c311540..12b2151 100644
    a b import threading 
    1717import errno
    1818
    1919from django.conf import settings
     20from django.core.handlers.wsgi import UrlPrefixAwareHandler
    2021from django.contrib.staticfiles.handlers import StaticFilesHandler
    2122from django.core import mail
    2223from django.core.exceptions import ValidationError, ImproperlyConfigured
    class _MediaFilesHandler(StaticFilesHandler): 
    10141015        return settings.MEDIA_ROOT
    10151016
    10161017    def get_base_url(self):
    1017         return settings.MEDIA_URL
     1018        return self.fix_path(settings.MEDIA_URL)
    10181019
    10191020    def serve(self, request):
    1020         relative_url = request.path[len(self.base_url[2]):]
     1021        path = self.fix_path(request.path)
     1022        relative_url = path[len(self.base_url[2]):]
    10211023        return serve(request, relative_url, document_root=self.get_base_dir())
    10221024
    10231025
    class LiveServerThread(threading.Thread): 
    10491051        try:
    10501052            # Create the handler for serving static and media files
    10511053            handler = StaticFilesHandler(_MediaFilesHandler(WSGIHandler()))
     1054            handler = UrlPrefixAwareHandler(handler)
    10521055
    10531056            # Go through the list of possible ports, hoping that we can find
    10541057            # one that is free to use for the WSGI server.
  • tests/regressiontests/handlers/tests.py

    diff --git a/tests/regressiontests/handlers/tests.py b/tests/regressiontests/handlers/tests.py
    index 3557a63..5e92062 100644
    a b  
    1 from django.core.handlers.wsgi import WSGIHandler
     1from django.core.handlers.wsgi import WSGIHandler, UrlPrefixAwareHandler
    22from django.core import signals
    33from django.test import RequestFactory, TestCase
    44from django.test.utils import override_settings
    class SignalsTests(TestCase): 
    5858        self.assertEqual(self.signals, ['started'])
    5959        self.assertEqual(b''.join(response.streaming_content), b"streaming content")
    6060        self.assertEqual(self.signals, ['started', 'finished'])
     61
     62
     63@override_settings(FORCE_SCRIPT_NAME='/prefixed-example')
     64class PrefixedHandlerTests(TestCase):
     65    urls = 'regressiontests.handlers.urls'
     66
     67    def test_unprefixed_path(self):
     68        environ = RequestFactory().get('/regular/').environ
     69        handler = UrlPrefixAwareHandler(WSGIHandler())
     70        response = handler(environ, lambda *a, **k: None)
     71        self.assertEqual(response.status_code, 400)
     72
     73    def test_prefix_path(self):
     74        environ = RequestFactory().get('/prefixed-example/regular/').environ
     75        handler = UrlPrefixAwareHandler(WSGIHandler())
     76        response = handler(environ, lambda *a, **k: None)
     77        self.assertEqual(response.content, b"regular content")
  • tests/regressiontests/servers/tests.py

    diff --git a/tests/regressiontests/servers/tests.py b/tests/regressiontests/servers/tests.py
    index 1a7552e..084fd78 100644
    a b class LiveServerViews(LiveServerBase): 
    144144        self.assertIn(b"QUERY_STRING: 'q=%D1%82%D0%B5%D1%81%D1%82'", f.read())
    145145
    146146
     147class LiveServerUrlPrefixedViews(LiveServerBase):
     148   
     149    @classmethod
     150    def setUpClass(cls):
     151        # Override settings
     152        newsettings = {}
     153        newsettings.update(TEST_SETTINGS)
     154        newsettings.update({
     155            'FORCE_SCRIPT_NAME': '/live-example',
     156            'MEDIA_URL': '/live-example/media/',
     157            'STATIC_URL': '/live-example/static/',
     158        })
     159        cls.settings_override = override_settings(**newsettings)
     160        cls.settings_override.enable()
     161        super(LiveServerBase, cls).setUpClass()
     162
     163    def test_bad_request(self):
     164        """
     165        Ensure that the LiveServerTestCase serves 400s.
     166        """
     167        try:
     168            self.urlopen('/')
     169        except HTTPError as err:
     170            self.assertEqual(err.code, 400, 'Expected 400 response')
     171        else:
     172            self.fail('Expected 400 response')
     173   
     174    def test_404(self):
     175        """
     176        Ensure that the LiveServerTestCase serves 404s.
     177        Refs #2879.
     178        """
     179        try:
     180            self.urlopen('/live-example/')
     181        except HTTPError as err:
     182            self.assertEqual(err.code, 404, 'Expected 404 response')
     183        else:
     184            self.fail('Expected 404 response')
     185
     186    def test_view(self):
     187        """
     188        Ensure that the LiveServerTestCase serves views.
     189        Refs #2879.
     190        """
     191        f = self.urlopen('/live-example/example_view/')
     192        self.assertEqual(f.read(), b'example view')
     193
     194    def test_static_files(self):
     195        """
     196        Ensure that the LiveServerTestCase serves static files.
     197        Refs #2879.
     198        """
     199        f = self.urlopen('/live-example/static/example_static_file.txt')
     200        self.assertEqual(f.read().rstrip(b'\r\n'), b'example static file')
     201
     202    def test_media_files(self):
     203        """
     204        Ensure that the LiveServerTestCase serves media files.
     205        Refs #2879.
     206        """
     207        f = self.urlopen('/live-example/media/example_media_file.txt')
     208        self.assertEqual(f.read().rstrip(b'\r\n'), b'example media file')
     209
     210
    147211class LiveServerDatabase(LiveServerBase):
    148212
    149213    def test_fixtures_loaded(self):
Back to Top