From 5490fcc27f64b33879115c790c41b959fdd40d4c Mon Sep 17 00:00:00 2001 From: Jeremy Kersten Date: Tue, 13 Sep 2022 15:12:24 +0000 Subject: [PATCH] [FIX] http: convert DEFAULT_SESSION as a function get_default_session MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit avoid to have a dict by reference that will be global. Now get_default_session return a new dict each time for the context key. From this way the session.context['lang'] is not shared between several users on the same worker. To reproduce the bug, restart the server with 2 workers, make request in lang A on these 2 workers. DEFAULT_SESSION['context']['lang'] now is set to this lang A. Now, make request to an url without lang in path and without cookies and withtout session, you should be redirected to lang B (preferred lang from the request header) but you will be redirect to lang A due to the dict session.context that is shared for the worker... When we initialize the new Session, we get the wrong lang A as value for context.lang, so we don't recompute the expected lang for the end user. X-original-commit: 62179de74862210fe2a055d15b367b1850c24263 fwd-port of #100102 closes odoo/odoo#100910 X-original-commit: 42e46b2d89dde276f796b980f29e33cc216e7cb2 Signed-off-by: Jérémy Kersten --- addons/web/controllers/utils.py | 2 +- addons/web/tests/test_login.py | 2 +- addons/website/tools.py | 2 +- odoo/http.py | 35 ++++++++++++++++----------------- odoo/tests/common.py | 2 +- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/addons/web/controllers/utils.py b/addons/web/controllers/utils.py index cf625a623c9..18d6f5e0d90 100644 --- a/addons/web/controllers/utils.py +++ b/addons/web/controllers/utils.py @@ -101,7 +101,7 @@ def ensure_db(redirect='/web/database/selector'): # always switch the session to the computed db if db != request.session.db: request.session = http.root.session_store.new() - request.session.update(http.DEFAULT_SESSION, db=db) + request.session.update(http.get_default_session(), db=db) request.session.context['lang'] = request.default_lang() werkzeug.exceptions.abort(request.redirect(request.httprequest.url, 302)) diff --git a/addons/web/tests/test_login.py b/addons/web/tests/test_login.py index be6a863f4b0..e811c48d007 100644 --- a/addons/web/tests/test_login.py +++ b/addons/web/tests/test_login.py @@ -12,7 +12,7 @@ class TestWebLoginCommon(HttpCase): def login(self, username, password): """Log in with provided credentials and return response to POST request or raises for status.""" self.session = http.root.session_store.new() - self.session.update(http.DEFAULT_SESSION, db=get_db_name()) + self.session.update(http.get_default_session(), db=get_db_name()) self.opener = Opener(self.env.cr) self.opener.cookies.set('session_id', self.session.sid, domain=HOST, path='/') diff --git a/addons/website/tools.py b/addons/website/tools.py index 58109d9c24a..ac46d46a49a 100644 --- a/addons/website/tools.py +++ b/addons/website/tools.py @@ -46,7 +46,7 @@ def MockRequest( params={}, redirect=env['ir.http']._redirect, session=DotDict( - odoo.http.DEFAULT_SESSION, + odoo.http.get_default_session(), geoip={'country_code': country_code}, sale_order_id=sale_order_id, website_sale_current_pl=website_sale_current_pl, diff --git a/odoo/http.py b/odoo/http.py index e9cc901aaba..c40d69e9e6c 100644 --- a/odoo/http.py +++ b/odoo/http.py @@ -208,20 +208,19 @@ CSRF_TOKEN_SALT = 60 * 60 * 24 * 365 DEFAULT_LANG = 'en_US' # The dictionnary to initialise a new session with. -DEFAULT_SESSION = { - 'context': { - #'lang': request.default_lang() # must be set at runtime - }, - 'db': None, - 'debug': '', - 'login': None, - 'uid': None, - 'session_token': None, - # profiling - 'profile_session': None, - 'profile_collectors': None, - 'profile_params': None, -} +def get_default_session(): + return { + 'context': {}, # 'lang': request.default_lang() # must be set at runtime + 'db': None, + 'debug': '', + 'login': None, + 'uid': None, + 'session_token': None, + # profiling + 'profile_session': None, + 'profile_collectors': None, + 'profile_params': None, + } # The request mimetypes that transport JSON in their body. JSON_MIMETYPES = ('application/json', 'application/json-rpc') @@ -957,10 +956,10 @@ class Session(collections.abc.MutableMapping): }) def logout(self, keep_db=False): - db = self.db if keep_db else DEFAULT_SESSION['db'] # None + db = self.db if keep_db else get_default_session()['db'] # None debug = self.debug self.clear() - self.update(DEFAULT_SESSION, db=db, debug=debug) + self.update(get_default_session(), db=db, debug=debug) self.context['lang'] = request.default_lang() if request else DEFAULT_LANG self.should_rotate = True @@ -1115,7 +1114,7 @@ class Request: session.sid = sid # in case the session was not persisted session.is_explicit = is_explicit - for key, val in DEFAULT_SESSION.items(): + for key, val in get_default_session().items(): session.setdefault(key, val) if not session.context.get('lang'): session.context['lang'] = self.default_lang() @@ -1258,7 +1257,7 @@ class Request: return consteq(hm, hm_expected) def default_context(self): - return dict(DEFAULT_SESSION['context'], lang=self.default_lang()) + return dict(get_default_session()['context'], lang=self.default_lang()) def default_lang(self): """Returns default user language according to request specification diff --git a/odoo/tests/common.py b/odoo/tests/common.py index 5cf12570983..58ef4a315ea 100644 --- a/odoo/tests/common.py +++ b/odoo/tests/common.py @@ -1726,7 +1726,7 @@ class HttpCase(TransactionCase): odoo.http.root.session_store.delete(self.session) self.session = session = odoo.http.root.session_store.new() - session.update(odoo.http.DEFAULT_SESSION, db=get_db_name()) + session.update(odoo.http.get_default_session(), db=get_db_name()) session.context['lang'] = odoo.http.DEFAULT_LANG if user: # if authenticated