diff --git a/debian/debian_config_common.py b/debian/debian_config_common.py index 1c98a83..40bba1a 100644 --- a/debian/debian_config_common.py +++ b/debian/debian_config_common.py @@ -272,6 +272,14 @@ MIDDLEWARE = ( 'hobo.middleware.maintenance.MaintenanceMiddleware', ) + MIDDLEWARE +if 'django.middleware.common.CommonMiddleware' in MIDDLEWARE: + common_middleware_index = MIDDLEWARE.index('django.middleware.common.CommonMiddleware') + MIDDLEWARE = ( + MIDDLEWARE[:common_middleware_index] + + ('hobo.middleware.common.HoboCommonMiddleware',) + + MIDDLEWARE[common_middleware_index + 1 :] + ) + if PROJECT_NAME != 'wcs': MIDDLEWARE = ('hobo.middleware.RobotsTxtMiddleware',) + MIDDLEWARE diff --git a/hobo/middleware/common.py b/hobo/middleware/common.py new file mode 100644 index 0000000..5572d42 --- /dev/null +++ b/hobo/middleware/common.py @@ -0,0 +1,34 @@ +import django +from django.http import JsonResponse +from django.middleware.common import CommonMiddleware +from django.utils.translation import ugettext_lazy as _ + + +class HoboCommonMiddleware(CommonMiddleware): + def __call__(self, *args, **kwargs): + self.will_redirect_with_slash = False + return super().__call__(*args, **kwargs) + + def should_redirect_with_slash(self, request): + self.will_redirect_with_slash = super().should_redirect_with_slash(request) + return self.will_redirect_with_slash + + def forbid_redirect(self, request, response): + return bool( + self.will_redirect_with_slash + and isinstance(response, self.response_redirect_class) + and request.path_info.startswith('/api/') + and request.method in ("POST", "PUT", "PATCH") + ) + + def process_request(self, request): + response = super().process_request(request) + if self.forbid_redirect(request, response): + return JsonResponse({'err': 1, 'err_desc': _('URL must end with a slash.')}, status=404) + return response + + def process_response(self, request, response): + response = super().process_response(request, response) + if self.forbid_redirect(request, response): + return JsonResponse({'err': 1, 'err_desc': _('URL must end with a slash.')}, status=404) + return response diff --git a/tests/settings.py b/tests/settings.py index 52a9de8..9b10d98 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -17,6 +17,13 @@ MIDDLEWARE = MIDDLEWARE + ( 'hobo.middleware.maintenance.MaintenanceMiddleware', ) +common_middleware_index = MIDDLEWARE.index('django.middleware.common.CommonMiddleware') +MIDDLEWARE = ( + MIDDLEWARE[:common_middleware_index] + + ('hobo.middleware.common.HoboCommonMiddleware',) + + MIDDLEWARE[common_middleware_index + 1 :] +) + HOBO_MANAGER_HOMEPAGE_URL_VAR = 'portal_agent_url' DATABASES = { 'default': { diff --git a/tests/test_middlewares.py b/tests/test_middlewares.py new file mode 100644 index 0000000..a2dd751 --- /dev/null +++ b/tests/test_middlewares.py @@ -0,0 +1,15 @@ +def test_common_middleware(db, django_app_factory): + app = django_app_factory(csrf_checks=False) + + resp = app.get('/api/health/', status=200) + assert 'data' in resp.json + + resp = app.get('/api/health', status=301) + assert resp.location == '/api/health/' + + for method in (app.post, app.put, app.patch): + resp = method('/api/health/', status=200) + assert 'data' in resp.json + + resp = method('/api/health', status=404) + assert resp.json == {'err': 1, 'err_desc': 'URL must end with a slash.'} diff --git a/tests/test_version.py b/tests/test_version.py index 41f465c..fe3cb4d 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -12,6 +12,6 @@ def test_version_middleware(settings, client): # disable apt_cache to get stable test results hobo.scrutiny.wsgi.middleware.apt_cache = None - settings.MIDDLEWARE = ('hobo.middleware.version.VersionMiddleware',) + settings.MIDDLEWARE + settings.MIDDLEWARE = ('hobo.middleware.version.VersionMiddleware',) + tuple(settings.MIDDLEWARE) json_response = client.get('/__version__').json() assert set(json_response.keys()) == set(['pytest', 'pytest-django'])