diff options
Diffstat (limited to 'addons/http_routing/models')
| -rw-r--r-- | addons/http_routing/models/ir_http.py | 77 |
1 files changed, 57 insertions, 20 deletions
diff --git a/addons/http_routing/models/ir_http.py b/addons/http_routing/models/ir_http.py index 78217881e65..71d62d054db 100644 --- a/addons/http_routing/models/ir_http.py +++ b/addons/http_routing/models/ir_http.py @@ -99,6 +99,7 @@ def slug(value): return str(identifier) return "%s-%d" % (slugname, identifier) + # NOTE: as the pattern is used as it for the ModelConverter (ir_http.py), do not use any flags _UNSLUG_RE = re.compile(r'(?:(\w{1,2}|\w[A-Za-z0-9-_]+?\w)-)?(-?\d+)(?=$|/)') @@ -128,7 +129,7 @@ def unslug_url(s): # Language tools # ------------------------------------------------------------ -def url_for(path_or_uri, lang_code=None): +def url_lang(path_or_uri, lang_code=None): ''' Given a relative URL, make it absolute and add the required lang or remove useless lang. Nothing will be done for absolute URL. @@ -164,10 +165,46 @@ def url_for(path_or_uri, lang_code=None): elif lang_url_code != default_lg.url_code or force_lang: ps.insert(1, lang_url_code) location = u'/'.join(ps) - return location +def url_for(url_from, lang_code=None, no_rewrite=False): + ''' Return the url with the rewriting applied. + Nothing will be done for absolute URL, or short URL from 1 char. + + :param url_from: The URL to convert. + :param lang_code: Must be the lang `code`. It could also be something + else, such as `'[lang]'` (used for url_return). + :param no_rewrite: don't try to match route with website.rewrite. + ''' + new_url = False + + # don't try to match route if we know that no rewrite has been loaded. + if not request.env['ir.http']._rewrite_len.get(request.website_routing): + no_rewrite = True + + # avoid useless check for 1 char URL '/', '#', ... and absolute URL + if not no_rewrite and url_from and (len(url_from) > 1 or not url_from.startswith('http')): + path, _, qs = url_from.partition('?') + req = request.httprequest + router = req.app.get_db_router(request.db).bind('') + try: + _ = router.match(path, method='POST') + except werkzeug.exceptions.MethodNotAllowed as e: + _ = router.match(path, method='GET') + except werkzeug.routing.RequestRedirect as e: + # remove query string from current env + new_url = e.new_url.split('?')[0] + # remove scheme and add query_string from url_from + new_url = new_url[7:] + (qs and '?%s' % qs or '') + except werkzeug.exceptions.NotFound as e: + new_url = url_from + except Exception as e: + raise e + + return url_lang(new_url or url_from, lang_code=lang_code) + + def is_multilang_url(local_url, lang_url_codes=None): ''' Check if the given URL content is supposed to be translated. To be considered as translatable, the URL should either: @@ -374,12 +411,15 @@ class IrHttp(models.AbstractModel): func = None routing_error = None + + # handle // in url + if request.httprequest.method == 'GET' and '//' in request.httprequest.path: + new_url = request.httprequest.path.replace('//', '/') + '?' + request.httprequest.query_string.decode('utf-8') + return werkzeug.utils.redirect(new_url, 301) + # locate the controller method try: - if request.httprequest.method == 'GET' and '//' in request.httprequest.path: - new_url = request.httprequest.path.replace('//', '/') + '?' + request.httprequest.query_string.decode('utf-8') - return werkzeug.utils.redirect(new_url, 301) - rule, arguments = cls._find_handler(return_rule=True) + rule, arguments = cls._match(request.httprequest.path) func = rule.endpoint request.is_frontend = func.routing.get('website', False) except werkzeug.exceptions.NotFound as e: @@ -388,13 +428,7 @@ class IrHttp(models.AbstractModel): request.is_frontend = True routing_error = e - request.is_frontend_multilang = ( - request.is_frontend and - (not func or (func and func.routing.get('multilang', func.routing['type'] == 'http'))) - ) - - cls._geoip_setup_resolver() - cls._geoip_resolve() + request.is_frontend_multilang = not func or (func and request.is_frontend and func.routing.get('multilang', func.routing['type'] == 'http')) # check authentication level try: @@ -405,6 +439,9 @@ class IrHttp(models.AbstractModel): except Exception as e: return cls._handle_exception(e) + cls._geoip_setup_resolver() + cls._geoip_resolve() + # For website routes (only), add website params on `request` if request.is_frontend: request.redirect = lambda url, code=302: werkzeug.utils.redirect(url_for(url), code) @@ -416,19 +453,19 @@ class IrHttp(models.AbstractModel): if request.routing_iteration == 1: is_a_bot = cls.is_a_bot() nearest_lang = not func and cls.get_nearest_lang(request.env['res.lang']._lang_get_code(path[1])) - url_lang = nearest_lang and path[1] + url_lg = nearest_lang and path[1] # The default lang should never be in the URL, and a wrong lang # should never be in the URL. - wrong_url_lang = url_lang and (url_lang != request.lang.url_code or url_lang == default_lg_id.url_code) + wrong_url_lg = url_lg and (url_lg != request.lang.url_code or url_lg == default_lg_id.url_code) # The lang is missing from the URL if multi lang is enabled for # the route and the current lang is not the default lang. # POST requests are excluded from this condition. - missing_url_lang = not url_lang and request.is_frontend_multilang and request.lang != default_lg_id and request.httprequest.method != 'POST' + missing_url_lg = not url_lg and request.is_frontend_multilang and request.lang != default_lg_id and request.httprequest.method != 'POST' # Bots should never be redirected when the lang is missing # because it is the only way for them to index the default lang. - if wrong_url_lang or (missing_url_lang and not is_a_bot): - if url_lang: + if wrong_url_lg or (missing_url_lg and not is_a_bot): + if url_lg: path.pop(1) if request.lang != default_lg_id: path.insert(1, request.lang.url_code) @@ -437,12 +474,12 @@ class IrHttp(models.AbstractModel): redirect = request.redirect(path + '?' + request.httprequest.query_string.decode('utf-8')) redirect.set_cookie('frontend_lang', request.lang.code) return redirect - elif url_lang: + elif url_lg: request.uid = None path.pop(1) routing_error = None return cls.reroute('/'.join(path) or '/') - elif missing_url_lang and is_a_bot: + elif missing_url_lg and is_a_bot: # Ensure that if the URL without lang is not redirected, the # current lang is indeed the default lang, because it is the # lang that bots should index in that case. |
