summaryrefslogtreecommitdiff
path: root/addons/http_routing/models
diff options
context:
space:
mode:
Diffstat (limited to 'addons/http_routing/models')
-rw-r--r--addons/http_routing/models/ir_http.py77
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.