diff options
author | Markus Heiser <markus.heiser@darmarit.de> | 2021-04-03 13:56:47 +0200 |
---|---|---|
committer | Markus Heiser <markus@darmarit.de> | 2021-04-05 14:34:45 +0200 |
commit | 87e4c476216ab25206b4e583b4206e762c3b9fe0 (patch) | |
tree | ba0e363cd327fdd3122813dab313c597b5150266 /searx | |
parent | 9292571304376c2c463fb26ee0db89298bb00e6c (diff) | |
download | searxng-87e4c476216ab25206b4e583b4206e762c3b9fe0.tar.gz searxng-87e4c476216ab25206b4e583b4206e762c3b9fe0.zip |
[fix] url_for(..., _external=True) in templates
The `url_for` function in the template context is not the one from Flask, it is
the one from `webapp`. The `webapp.url_for_theme` is different from its
namesake of Flask and has it quirks, when called with argument `_external=True`.
The `webapp.url_for_theme` can't handle absolute URLs since it pokes a leading
'/', here is the snippet of the old code::
url = url_for(endpoint, **values)
if settings['server']['base_url']:
if url.startswith('/'):
url = url[1:]
url = urljoin(settings['server']['base_url'], url)
Next drawback of (Flask's) `_external=True` is, that it will not return the HTTP
scheme when searx (the Flask app) listens on http and is proxied by a https
server.
To get the right scheme `HTTP_X_SCHEME` is needed by Flask (werkzeug). Since
this is not provided in every environment (e.g. behind Apache mod_wsgi or the
HTTP header is not fully set for some other reasons) it is recommended to
get *script_name*, *server* and *scheme* from the configured `base_url`. If
`base_url` is specified, then these values from are given preference over any
Flask's generics.
BTW this patch normalize to use `url_for` in the `opensearch.xml` and drop the
need of `host` and `urljoin` in template's context.
Signed-off-by: Markus Heiser <markus@darmarit.de>
Diffstat (limited to 'searx')
-rw-r--r-- | searx/templates/__common__/opensearch.xml | 4 | ||||
-rwxr-xr-x | searx/webapp.py | 52 |
2 files changed, 32 insertions, 24 deletions
diff --git a/searx/templates/__common__/opensearch.xml b/searx/templates/__common__/opensearch.xml index 2476258c0..230f327a5 100644 --- a/searx/templates/__common__/opensearch.xml +++ b/searx/templates/__common__/opensearch.xml @@ -3,7 +3,7 @@ <ShortName>{{ instance_name }}</ShortName> <Description>a privacy-respecting, hackable metasearch engine</Description> <InputEncoding>UTF-8</InputEncoding> - <Image>{{ urljoin(host, url_for('static', filename='img/favicon.png')) }}</Image> + <Image>{{ url_for('static', filename='img/favicon.png', _external=True) }}</Image> <LongName>searx metasearch</LongName> {% if opensearch_method == 'get' %} <Url rel="results" type="text/html" method="get" template="{{ url_for('search', _external=True) }}?q={searchTerms}"/> @@ -13,7 +13,7 @@ </Url> {% endif %} {% if autocomplete %} - <Url rel="suggestions" type="application/x-suggestions+json" template="{{ host }}autocompleter?q={searchTerms}"/> + <Url rel="suggestions" type="application/x-suggestions+json" template="{{ url_for('autocompleter', _external=True) }}?q={searchTerms}"/> {% endif %} <Url type="application/opensearchdescription+xml" diff --git a/searx/webapp.py b/searx/webapp.py index ed1e9ce49..d6a5fb85f 100755 --- a/searx/webapp.py +++ b/searx/webapp.py @@ -40,7 +40,7 @@ from datetime import datetime, timedelta from time import time from html import escape from io import StringIO -from urllib.parse import urlencode, urljoin, urlparse +from urllib.parse import urlencode, urlparse from pygments import highlight from pygments.lexers import get_lexer_by_name @@ -269,14 +269,7 @@ def extract_domain(url): def get_base_url(): - if settings['server']['base_url']: - hostname = settings['server']['base_url'] - else: - scheme = 'http' - if request.is_secure: - scheme = 'https' - hostname = url_for('index', _external=True, _scheme=scheme) - return hostname + return url_for('index', _external=True) def get_current_theme_name(override=None): @@ -309,10 +302,6 @@ def url_for_theme(endpoint, override_theme=None, **values): if filename_with_theme in static_files: values['filename'] = filename_with_theme url = url_for(endpoint, **values) - if settings['server']['base_url']: - if url.startswith('/'): - url = url[1:] - url = urljoin(settings['server']['base_url'], url) return url @@ -812,7 +801,7 @@ def preferences(): # save preferences if request.method == 'POST': - resp = make_response(redirect(urljoin(settings['server']['base_url'], url_for('index')))) + resp = make_response(url_for('index', _external=True)) try: request.preferences.parse_form(request.form) except ValidationException: @@ -1002,11 +991,11 @@ def opensearch(): if request.headers.get('User-Agent', '').lower().find('webkit') >= 0: method = 'get' - ret = render('opensearch.xml', - opensearch_method=method, - host=get_base_url(), - urljoin=urljoin, - override_theme='__common__') + ret = render( + 'opensearch.xml', + opensearch_method=method, + override_theme='__common__' + ) resp = Response(response=ret, status=200, @@ -1027,7 +1016,7 @@ def favicon(): @app.route('/clear_cookies') def clear_cookies(): - resp = make_response(redirect(urljoin(settings['server']['base_url'], url_for('index')))) + resp = make_response(redirect(url_for('index', _external=True))) for cookie_name in request.cookies: resp.delete_cookie(cookie_name) return resp @@ -1128,19 +1117,38 @@ class ReverseProxyPathFix: ''' def __init__(self, app): + self.app = app + self.script_name = None + self.scheme = None + self.server = None + + if settings['server']['base_url']: + + # If base_url is specified, then these values from are given + # preference over any Flask's generics. + + base_url = urlparse(settings['server']['base_url']) + self.script_name = base_url.path + self.scheme = base_url.scheme + self.server = base_url.netloc def __call__(self, environ, start_response): - script_name = environ.get('HTTP_X_SCRIPT_NAME', '') + + script_name = self.script_name or environ.get('HTTP_X_SCRIPT_NAME', '') if script_name: environ['SCRIPT_NAME'] = script_name path_info = environ['PATH_INFO'] if path_info.startswith(script_name): environ['PATH_INFO'] = path_info[len(script_name):] - scheme = environ.get('HTTP_X_SCHEME', '') + scheme = self.scheme or environ.get('HTTP_X_SCHEME', '') if scheme: environ['wsgi.url_scheme'] = scheme + + server = self.server or environ.get('HTTP_X_FORWARDED_HOST', '') + if server: + environ['HTTP_HOST'] = server return self.app(environ, start_response) |