[FIX] core: check browser lang is installed
A visitor could visit a web page having a lang in its context that is not installed in the databased he is connected to. The problem is that visitors are not logged-in thus it is not possible to determine their lang via their `res.users` preferences. The lang used instead is the lang set in the `Accept-Language` header of the incoming request, that header is set by various browsers in accordance to the user system preferences or browser settings. The browser lang (`Request.best`) is only parsed according to the `babel` database, it is a lang syntactically speaking but not necessary a lang that is installed in the database. At the moment the browser lang is set in the context (inside of `Request._get_dbname_and_session`), it is not possible to verify it is installed in the database as no connection to any database as been established yet. Instead the lang is validated inside of `ir.http._pre_dispatch` which is the method responsible to prepare/fix various stuff on the request/session/context. In regard to93b684d3c7, we prefer to fallback on English, hence the modification in `get_lang`. closes odoo/odoo#116683 Reference-to:93b684d3c7([FIX] base: lang should fallback on english instead of arab) X-original-commit: 743e97667e44cdaab6db334d807cf3d409cea621 Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
This commit is contained in:
@@ -29,7 +29,7 @@ from odoo.exceptions import AccessDenied, AccessError, MissingError
|
||||
from odoo.http import request, Response, ROUTING_KEYS, Stream
|
||||
from odoo.modules.registry import Registry
|
||||
from odoo.service import security
|
||||
from odoo.tools import consteq, submap
|
||||
from odoo.tools import get_lang, submap
|
||||
from odoo.tools.translate import code_translations
|
||||
from odoo.modules.module import get_resource_path, get_module_path
|
||||
|
||||
@@ -144,6 +144,11 @@ class IrHttp(models.AbstractModel):
|
||||
if isinstance(val, models.BaseModel) and isinstance(val._uid, RequestUID):
|
||||
args[key] = val.with_user(request.env.uid)
|
||||
|
||||
# verify the default language set in the context is valid,
|
||||
# otherwise fallback on the company lang, english or the first
|
||||
# lang installed
|
||||
request.update_context(lang=get_lang(request.env)._get_cached('code'))
|
||||
|
||||
@classmethod
|
||||
def _dispatch(cls, endpoint):
|
||||
result = endpoint(**request.params)
|
||||
|
||||
@@ -67,6 +67,10 @@ class TestHttp(http.Controller):
|
||||
def echo_http_csrf(self, **kwargs):
|
||||
return str(kwargs)
|
||||
|
||||
@http.route('/test_http/echo-http-context-lang', type='http', auth='public', methods=['GET'], csrf=False)
|
||||
def echo_http_context_lang(self, **kwargs):
|
||||
return request.env.context.get('lang', '')
|
||||
|
||||
@http.route('/test_http/echo-json', type='json', auth='none', methods=['POST'], csrf=False)
|
||||
def echo_json(self, **kwargs):
|
||||
return kwargs
|
||||
|
||||
@@ -88,3 +88,46 @@ class TestHttpSession(TestHttpBase):
|
||||
res = self.multidb_url_open('/test_http/greeting-user')
|
||||
res.raise_for_status()
|
||||
self.assertEqual(res.status_code, 200, "Should not be redirected to /web/login")
|
||||
|
||||
def test_session5_default_lang(self):
|
||||
self.env['res.lang']._activate_lang('en_US') # default lang
|
||||
lang_fr = self.env['res.lang']._activate_lang('fr_FR')
|
||||
|
||||
with self.subTest(case='no preferred lang'):
|
||||
res = self.url_open('/test_http/echo-http-context-lang')
|
||||
self.assertEqual(res.text, 'en_US')
|
||||
|
||||
with self.subTest(case='fr preferred and fr_FR enabled'):
|
||||
res = self.url_open('/test_http/echo-http-context-lang', headers={
|
||||
'Accept-Language': 'fr',
|
||||
})
|
||||
self.assertEqual(res.text, 'fr_FR')
|
||||
|
||||
with self.subTest(case='fr preferred but fr_FR disabled'):
|
||||
lang_fr.active = False
|
||||
res = self.url_open('/test_http/echo-http-context-lang', headers={
|
||||
'Accept-Language': 'fr',
|
||||
})
|
||||
self.assertEqual(res.text, 'en_US')
|
||||
|
||||
def test_session6_saved_lang(self):
|
||||
session = self.authenticate('demo', 'demo')
|
||||
self.env['res.lang']._activate_lang('en_US') # default lang
|
||||
lang_fr = self.env['res.lang']._activate_lang('fr_FR')
|
||||
|
||||
with self.subTest(case='no saved lang'):
|
||||
res = self.url_open('/test_http/echo-http-context-lang')
|
||||
self.assertEqual(res.text, 'en_US')
|
||||
|
||||
with self.subTest(case='fr saved and fr_FR enabled'):
|
||||
session.context['lang'] = 'fr_FR'
|
||||
odoo.http.root.session_store.save(session)
|
||||
res = self.url_open('/test_http/echo-http-context-lang')
|
||||
self.assertEqual(res.text, 'fr_FR')
|
||||
|
||||
with self.subTest(case='fr saved but fr_FR disabled'):
|
||||
session['lang'] = 'fr_FR'
|
||||
odoo.http.root.session_store.save(session)
|
||||
lang_fr.active = False
|
||||
res = self.url_open('/test_http/echo-http-context-lang')
|
||||
self.assertEqual(res.text, 'en_US')
|
||||
|
||||
+2
-2
@@ -1312,14 +1312,14 @@ def get_lang(env, lang_code=False):
|
||||
"""
|
||||
Retrieve the first lang object installed, by checking the parameter lang_code,
|
||||
the context and then the company. If no lang is installed from those variables,
|
||||
fallback on the first lang installed in the system.
|
||||
fallback on english or on the first lang installed in the system.
|
||||
|
||||
:param env:
|
||||
:param str lang_code: the locale (i.e. en_US)
|
||||
:return res.lang: the first lang found that is installed on the system.
|
||||
"""
|
||||
langs = [code for code, _ in env['res.lang'].get_installed()]
|
||||
lang = langs[0]
|
||||
lang = 'en_US' if 'en_US' in langs else langs[0]
|
||||
if lang_code and lang_code in langs:
|
||||
lang = lang_code
|
||||
elif env.context.get('lang') in langs:
|
||||
|
||||
Reference in New Issue
Block a user