middleware: subclass common middleware to avoid redirects in API (#69409)

This commit is contained in:
Valentin Deniaud 2022-09-26 14:01:30 +02:00
parent 22c8c2cb89
commit 5470d0083e
5 changed files with 65 additions and 1 deletions

View File

@ -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

34
hobo/middleware/common.py Normal file
View File

@ -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

View File

@ -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': {

15
tests/test_middlewares.py Normal file
View File

@ -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.'}

View File

@ -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'])