diff options
Diffstat (limited to 'searx/webapp.py')
| -rwxr-xr-x | searx/webapp.py | 130 |
1 files changed, 95 insertions, 35 deletions
diff --git a/searx/webapp.py b/searx/webapp.py index 23c5d70cc..4ecaab7d2 100755 --- a/searx/webapp.py +++ b/searx/webapp.py @@ -6,6 +6,7 @@ # pylint: disable=use-dict-literal from __future__ import annotations +import inspect import hashlib import hmac import json @@ -29,6 +30,8 @@ from pygments import highlight from pygments.lexers import get_lexer_by_name from pygments.formatters import HtmlFormatter # pylint: disable=no-name-in-module +from werkzeug.serving import is_running_from_reloader + import flask from flask import ( @@ -48,12 +51,12 @@ from flask_babel import ( format_decimal, ) +import searx from searx.extended_types import sxng_request from searx import ( logger, get_setting, settings, - searx_debug, ) from searx import infopage @@ -81,7 +84,6 @@ from searx.webutils import ( exception_classname_to_text, new_hmac, is_hmac_of, - is_flask_run_cmdline, group_engines_in_tab, ) from searx.webadapter import ( @@ -128,11 +130,6 @@ logger = logger.getChild('webapp') warnings.simplefilter("always") -# check secret_key -if not searx_debug and settings['server']['secret_key'] == 'ultrasecretkey': - logger.error('server.secret_key is not changed. Please use something else instead of ultrasecretkey.') - sys.exit(1) - # about static logger.debug('static directory is %s', settings['ui']['static_path']) static_files = get_static_files(settings['ui']['static_path']) @@ -1329,45 +1326,108 @@ def page_not_found(_e): return render('404.html'), 404 -# see https://flask.palletsprojects.com/en/1.1.x/cli/ -# True if "FLASK_APP=searx/webapp.py FLASK_ENV=development flask run" -flask_run_development = ( - os.environ.get("FLASK_APP") is not None and os.environ.get("FLASK_ENV") == 'development' and is_flask_run_cmdline() -) +def run(): + """Runs the application on a local development server. + + This run method is only called when SearXNG is started via ``__main__``:: + + python -m searx.webapp + + Do not use :ref:`run() <flask.Flask.run>` in a production setting. It is + not intended to meet security and performance requirements for a production + server. + + It is not recommended to use this function for development with automatic + reloading as this is badly supported. Instead you should be using the flask + command line script’s run support:: + + flask --app searx.webapp run --debug --reload --host 127.0.0.1 --port 8888 + + .. _Flask.run: https://flask.palletsprojects.com/en/stable/api/#flask.Flask.run + """ + + host: str = get_setting("server.bind_address") # type: ignore + port: int = get_setting("server.port") # type: ignore + + if searx.sxng_debug: + logger.debug("run local development server (DEBUG) on %s:%s", host, port) + app.run( + debug=True, + port=port, + host=host, + threaded=True, + extra_files=[DEFAULT_SETTINGS_FILE], + ) + else: + logger.debug("run local development server on %s:%s", host, port) + app.run(port=port, host=host, threaded=True) + + +def is_werkzeug_reload_active() -> bool: + """Returns ``True`` if server is is launched by :ref:`werkzeug.serving` and + the ``use_reload`` argument was set to ``True``. If this is the case, it + should be avoided that the server is initialized twice (:py:obj:`init`, + :py:obj:`run`). + + .. _werkzeug.serving: + https://werkzeug.palletsprojects.com/en/stable/serving/#werkzeug.serving.run_simple + """ + + # https://github.com/searxng/searxng/pull/1656#issuecomment-1214198941 + # https://github.com/searxng/searxng/pull/1616#issuecomment-1206137468 -# True if reload feature is activated of werkzeug, False otherwise (including uwsgi, etc..) -# __name__ != "__main__" if searx.webapp is imported (make test, make docs, uwsgi...) -# see run() at the end of this file : searx_debug activates the reload feature. -werkzeug_reloader = flask_run_development or (searx_debug and __name__ == "__main__") + frames = inspect.stack() + + if len(frames) > 1 and frames[-2].filename.endswith('flask/cli.py'): + # server was launched by "flask run", is argument "--reload" set? + if "--reload" in sys.argv or "--debug" in sys.argv: + return True + + elif frames[0].filename.endswith('searx/webapp.py'): + # server was launched by "python -m searx.webapp" / see run() + if searx.sxng_debug: + return True + + return False + + +def init(): + + if searx.sxng_debug or app.debug: + app.debug = True + searx.sxng_debug = True + + # check secret_key in production + + if not app.debug and get_setting("server.secret_key") == 'ultrasecretkey': + logger.error("server.secret_key is not changed. Please use something else instead of ultrasecretkey.") + sys.exit(1) + + # When automatic reloading is activated stop Flask from initialising twice. + # - https://github.com/pallets/flask/issues/5307#issuecomment-1774646119 + # - https://stackoverflow.com/a/25504196 + + reloader_active = is_werkzeug_reload_active() + werkzeug_run_main = is_running_from_reloader() + + if reloader_active and not werkzeug_run_main: + logger.info("in reloading mode and not in main loop, cancel the initialization") + return -# initialize the engines except on the first run of the werkzeug server. -if not werkzeug_reloader or (werkzeug_reloader and os.environ.get("WERKZEUG_RUN_MAIN") == "true"): locales_initialize() redis_initialize() searx.plugins.initialize(app) - searx.search.initialize( - enable_checker=True, - check_network=True, - enable_metrics=get_setting("general.enable_metrics"), - ) - limiter.initialize(app, settings) - favicons.init() + metrics: bool = get_setting("general.enable_metrics") # type: ignore + searx.search.initialize(enable_checker=True, check_network=True, enable_metrics=metrics) -def run(): - logger.debug('starting webserver on %s:%s', settings['server']['bind_address'], settings['server']['port']) - app.run( - debug=searx_debug, - use_debugger=searx_debug, - port=settings['server']['port'], - host=settings['server']['bind_address'], - threaded=True, - extra_files=[DEFAULT_SETTINGS_FILE], - ) + limiter.initialize(app, settings) + favicons.init() application = app patch_application(app) +init() if __name__ == "__main__": run() |