[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>
			
			
This commit is contained in:
		
							parent
							
								
									9292571304
								
							
						
					
					
						commit
						87e4c47621
					
				@ -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"
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user