Remove duplicate CommonMiddleware from MIDDLEWARE#2436
Open
pyxelr wants to merge 1 commit into
Open
Conversation
django.middleware.common.CommonMiddleware was listed twice in the MIDDLEWARE tuple.
Symptoms when the chain runs twice:
* For users whose django_session.session_data row cannot be verified by
signing.loads (e.g. after a SECRET_KEY rotation), the second pass of
CommonMiddleware.process_response runs against responses for which the
session/messages state ends up half-initialised, surfacing as a generic
500 page with no traceback on every 404 path, every APPEND_SLASH 301,
and assets like /favicon.ico. With-slash URLs that match a real view
return 200 because the corruption is silently swallowed (decode -> {}).
* Content-Length is computed twice on every response.
Removing the duplicate restores the standard middleware behaviour: a
corrupted session decodes to {} once, the user is treated as anonymous,
and 404/redirect responses are returned normally.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
django.middleware.common.CommonMiddlewareis listed twice in theMIDDLEWAREtuple insrc/settings/base.py. This PR removes the second occurrence.Why
Per Django's middleware onion model, each entry in
MIDDLEWAREis an independent layer whoseprocess_responseruns on every request. DuplicatingCommonMiddlewaretherefore runs itsprocess_requestonce but itsprocess_responsetwice per request, which has two effects:Content-Lengthis computed twice on every response (harmless but wasteful).Real symptom that brought this to our attention — for users whose
django_session.session_datarow cannot be verified bysigning.loads()(e.g. after aSECRET_KEYrotation), the secondprocess_responsepass raises an exception that Django converts to a generic500page. No traceback is preserved in logs (Django wraps the exception before logging), only the one-linedjango.utils.log:log_response - Internal Server Error: <path>is emitted — logged twice, which is itself a side effect of the duplicate. We did not isolate the exact line that raises; likely candidates are the second-passshould_redirect_with_slashcheck or downstream middleware reading from the half-initialised session (e.g.MessageMiddleware'sFallbackStorage), but this is inferred from behaviour, not from a captured stack trace.The 500 is observed on every non-200 path for affected users:
APPEND_SLASHredirect (e.g./competitions/8→/competitions/8/)/competitions/<missing_id>/,/forums/null/,/favicon.ico, …)200correctly, because the session-decode failure is silently swallowed (decode returns{}and the user is treated as anonymous).Removing the duplicate restores the standard Django middleware behaviour. A corrupted session decodes to
{}exactly once viaSessionMiddleware, the user falls back toAnonymousUser, and 404/redirect responses are returned normally.Reproduction (Django 5.2,
SESSION_ENGINE='django.contrib.sessions.backends.db')/competitions/8/(exists)/competitions/8(no slash)/competitions/<missing>//favicon.icoSteps to reproduce:
django_sessionwhosesession_datawas signed with a differentSECRET_KEY(or simply replace any existing row'ssession_datawith arbitrarysigning.dumps(...)output produced under a different key).sessionidcookie to any non-200 path on the running site.500 Server Error.After removing the duplicate, the same request returns the expected
301/404.Diff
@@ MIDDLEWARE = ( 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', # 'corsheaders.middleware.CorsMiddleware', # BB - 'django.middleware.common.CommonMiddleware', 'middleware.BlockBannedUsersMiddleware' )Risk
Minimal — restores the documented Django middleware ordering pattern (a single
CommonMiddlewarebetweenSessionMiddlewareandCsrfViewMiddleware). No other settings file overrides this tuple in a way that depends on the duplicate. Patch has been running on a live deployment for ~24h with no regressions observed.