# Buggy code
def index():
    """Render index page.

    Supported outputs: html, json, csv, rss.
    """

    # output_format
    output_format = request.form.get("format", "html")
    if output_format not in ["html", "csv", "json", "rss"]:
        output_format = "html"

    # check if there is query
    if request.form.get("q") is None:
        if output_format == "html":
            return render(
                "index.html",
            )
        else:
            return index_error(output_format, "No query"), 400

    # search
    search_query = None
    raw_text_query = None
    result_container = None
    try:
        search_query, raw_text_query = get_search_query_from_webapp(
            request.preferences, request.form
        )
        # search = Search(search_query) #  without plugins
        search = SearchWithPlugins(search_query, request.user_plugins, request)
        result_container = search.search()
    except Exception as e:
        # log exception
        logger.exception("search error")

        # is it an invalid input parameter or something else ?
        if issubclass(e.__class__, SearxParameterException):
            return index_error(output_format, e.message), 400
        else:
            return index_error(output_format, gettext("search error")), 500

    # results
    results = result_container.get_ordered_results()
    number_of_results = result_container.results_number()
    if number_of_results < result_container.results_length():
        number_of_results = 0

    # UI
    advanced_search = request.form.get("advanced_search", None)

    # Server-Timing header
    request.timings = result_container.get_timings()

    # output
    for result in results:
        if output_format == "html":
            if "content" in result and result["content"]:
                result["content"] = highlight_content(
                    escape(result["content"][:1024]), search_query.query
                )
            if "title" in result and result["title"]:
                result["title"] = highlight_content(
                    escape(result["title"] or ""), search_query.query
                )
        else:
            if result.get("content"):
                result["content"] = html_to_text(result["content"]).strip()
            # removing html content and whitespace duplications
            result["title"] = " ".join(html_to_text(result["title"]).strip().split())

        if "url" in result:
            result["pretty_url"] = prettify_url(result["url"])

        # TODO, check if timezone is calculated right
        if "publishedDate" in result:
            try:  # test if publishedDate >= 1900 (datetime module bug)
                result["pubdate"] = result["publishedDate"].strftime(
                    "%Y-%m-%d %H:%M:%S%z"
                )
            except ValueError:
                result["publishedDate"] = None
            else:
                if result["publishedDate"].replace(
                    tzinfo=None
                ) >= datetime.now() - timedelta(days=1):
                    timedifference = datetime.now() - result["publishedDate"].replace(
                        tzinfo=None
                    )
                    minutes = int((timedifference.seconds / 60) % 60)
                    hours = int(timedifference.seconds / 60 / 60)
                    if hours == 0:
                        result["publishedDate"] = gettext(
                            "{minutes} minute(s) ago"
                        ).format(minutes=minutes)
                    else:
                        result["publishedDate"] = gettext(
                            "{hours} hour(s), {minutes} minute(s) ago"
                        ).format(hours=hours, minutes=minutes)  # noqa
                else:
                    result["publishedDate"] = format_date(result["publishedDate"])

    if output_format == "json":
        return Response(
            json.dumps(
                {
                    "query": search_query.query.decode("utf-8"),
                    "number_of_results": number_of_results,
                    "results": results,
                    "answers": list(result_container.answers),
                    "corrections": list(result_container.corrections),
                    "infoboxes": result_container.infoboxes,
                    "suggestions": list(result_container.suggestions),
                    "unresponsive_engines": list(result_container.unresponsive_engines),
                },
                default=lambda item: list(item) if isinstance(item, set) else item,
            ),
            mimetype="application/json",
        )
    elif output_format == "csv":
        csv = UnicodeWriter(StringIO())
        keys = ("title", "url", "content", "host", "engine", "score", "type")
        csv.writerow(keys)
        for row in results:
            row["host"] = row["parsed_url"].netloc
            row["type"] = "result"
            csv.writerow([row.get(key, "") for key in keys])
        for a in result_container.answers:
            row = {"title": a, "type": "answer"}
            csv.writerow([row.get(key, "") for key in keys])
        for a in result_container.suggestions:
            row = {"title": a, "type": "suggestion"}
            csv.writerow([row.get(key, "") for key in keys])
        for a in result_container.corrections:
            row = {"title": a, "type": "correction"}
            csv.writerow([row.get(key, "") for key in keys])
        csv.stream.seek(0)
        response = Response(csv.stream.read(), mimetype="application/csv")
        cont_disp = "attachment;Filename=searx_-_{0}.csv".format(
            search_query.query.decode("utf-8")
        )
        response.headers.add("Content-Disposition", cont_disp)
        return response
    elif output_format == "rss":
        response_rss = render(
            "opensearch_response_rss.xml",
            results=results,
            answers=result_container.answers,
            corrections=result_container.corrections,
            suggestions=result_container.suggestions,
            q=request.form["q"],
            number_of_results=number_of_results,
            base_url=get_base_url(),
            override_theme="__common__",
        )
        return Response(response_rss, mimetype="text/xml")

    # HTML output format

    # suggestions: use RawTextQuery to get the suggestion URLs with the same bang
    suggestion_urls = list(
        map(
            lambda suggestion: {
                "url": raw_text_query.changeSearchQuery(suggestion).getFullQuery(),
                "title": suggestion,
            },
            result_container.suggestions,
        )
    )

    correction_urls = list(
        map(
            lambda correction: {
                "url": raw_text_query.changeSearchQuery(correction).getFullQuery(),
                "title": correction,
            },
            result_container.corrections,
        )
    )
    #
    return render(
        "results.html",
        results=results,
        q=request.form["q"],
        selected_categories=search_query.categories,
        pageno=search_query.pageno,
        time_range=search_query.time_range,
        number_of_results=format_decimal(number_of_results),
        advanced_search=advanced_search,
        suggestions=suggestion_urls,
        answers=result_container.answers,
        corrections=correction_urls,
        infoboxes=result_container.infoboxes,
        paging=result_container.paging,
        unresponsive_engines=result_container.unresponsive_engines,
        current_language=match_language(
            search_query.lang,
            LANGUAGE_CODES,
            fallback=request.preferences.get_value("language"),
        ),
        base_url=get_base_url(),
        theme=get_current_theme_name(),
        favicons=global_favicons[themes.index(get_current_theme_name())],
        timeout_limit=request.form.get("timeout_limit", None),
    )


# Traceback (urllib3.exceptions.ReadTimeoutError)
Exception in thread aeb1ee8b-0fe7-4e90-8f29-0c487673c1eb:
Traceback (most recent call last):
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 421, in _make_request
six.raise_from(e, None)
File "<string>", line 3, in raise_from
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 416, in _make_request
httplib_response = conn.getresponse()
File "/home/n/.pyenv/versions/3.6.3/lib/python3.6/http/client.py", line 1331, in getresponse
response.begin()
File "/home/n/.pyenv/versions/3.6.3/lib/python3.6/http/client.py", line 297, in begin
version, status, reason = self._read_status()
File "/home/n/.pyenv/versions/3.6.3/lib/python3.6/http/client.py", line 258, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "/home/n/.pyenv/versions/3.6.3/lib/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/urllib3/contrib/pyopenssl.py", line 326, in recv_into
raise timeout("The read operation timed out")
socket.timeout: The read operation timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/requests/adapters.py", line 449, in send
timeout=timeout
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 720, in urlopen
method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/urllib3/util/retry.py", line 400, in increment
raise six.reraise(type(error), error, _stacktrace)
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/urllib3/packages/six.py", line 735, in reraise
raise value
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 672, in urlopen
chunked=chunked,
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 423, in _make_request
self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/urllib3/connectionpool.py", line 331, in _raise_timeout
self, url, "Read timed out. (read timeout=%s)" % timeout_value
urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='gitlab.com', port=443): Read timed out. (read timeout=1.0)

During handling of the above exception, another exception occurred:


Traceback (most recent call last):
File "/home/n/p/searx/searx/search.py", line 160, in search_one_http_request_safe
search_results = search_one_http_request(engine, query, request_params)
File "/home/n/p/searx/searx/search.py", line 93, in search_one_http_request
response = send_http_request(engine, request_params)
File "/home/n/p/searx/searx/search.py", line 77, in send_http_request
return req(request_params['url'], **request_args)
File "/home/n/p/searx/searx/poolrequests.py", line 133, in get
return request('get', url, **kwargs)
File "/home/n/p/searx/searx/poolrequests.py", line 109, in request
response = session.request(method=method, url=url, **kwargs)
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/requests/sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/requests/sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/requests/adapters.py", line 529, in send
raise ReadTimeout(e, request=request)
requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='gitlab.com', port=443): Read timed out. (read timeout=1.0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/n/.pyenv/versions/3.6.3/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/home/n/.pyenv/versions/3.6.3/lib/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "/home/n/p/searx/searx/search.py", line 107, in search_one_request_safe
return search_one_http_request_safe(engine_name, query, request_params, result_container, start_time, timeout_limit)
File "/home/n/p/searx/searx/search.py", line 189, in search_one_http_request_safe
result_container.add_unresponsive_engine((engine_name, gettext('timeout')))
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/flask_babel/__init__.py", line 548, in gettext
t = get_translations()
File "searx/webapp.py", line 168, in _get_translations
translation_locale = request.form.get('use-translation')
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/werkzeug/local.py", line 347, in __getattr__
return getattr(self._get_current_object(), name)
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/werkzeug/local.py", line 306, in _get_current_object
return self.__local()
File "/home/n/p/searx/venv3.6/lib/python3.6/site-packages/flask/globals.py", line 37, in _lookup_req_object
raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.

This typically means that you attempted to use functionality that needed
an active HTTP request.  Consult the documentation on testing for
information about how to avoid this problem.

# Fixed code
def index():
    """Render index page.

    Supported outputs: html, json, csv, rss.
    """

    # output_format
    output_format = request.form.get("format", "html")
    if output_format not in ["html", "csv", "json", "rss"]:
        output_format = "html"

    # check if there is query
    if request.form.get("q") is None:
        if output_format == "html":
            return render(
                "index.html",
            )
        else:
            return index_error(output_format, "No query"), 400

    # search
    search_query = None
    raw_text_query = None
    result_container = None
    try:
        search_query, raw_text_query = get_search_query_from_webapp(
            request.preferences, request.form
        )
        # search = Search(search_query) #  without plugins
        search = SearchWithPlugins(search_query, request.user_plugins, request)
        result_container = search.search()
    except Exception as e:
        # log exception
        logger.exception("search error")

        # is it an invalid input parameter or something else ?
        if issubclass(e.__class__, SearxParameterException):
            return index_error(output_format, e.message), 400
        else:
            return index_error(output_format, gettext("search error")), 500

    # results
    results = result_container.get_ordered_results()
    number_of_results = result_container.results_number()
    if number_of_results < result_container.results_length():
        number_of_results = 0

    # UI
    advanced_search = request.form.get("advanced_search", None)

    # Server-Timing header
    request.timings = result_container.get_timings()

    # output
    for result in results:
        if output_format == "html":
            if "content" in result and result["content"]:
                result["content"] = highlight_content(
                    escape(result["content"][:1024]), search_query.query
                )
            if "title" in result and result["title"]:
                result["title"] = highlight_content(
                    escape(result["title"] or ""), search_query.query
                )
        else:
            if result.get("content"):
                result["content"] = html_to_text(result["content"]).strip()
            # removing html content and whitespace duplications
            result["title"] = " ".join(html_to_text(result["title"]).strip().split())

        if "url" in result:
            result["pretty_url"] = prettify_url(result["url"])

        # TODO, check if timezone is calculated right
        if "publishedDate" in result:
            try:  # test if publishedDate >= 1900 (datetime module bug)
                result["pubdate"] = result["publishedDate"].strftime(
                    "%Y-%m-%d %H:%M:%S%z"
                )
            except ValueError:
                result["publishedDate"] = None
            else:
                if result["publishedDate"].replace(
                    tzinfo=None
                ) >= datetime.now() - timedelta(days=1):
                    timedifference = datetime.now() - result["publishedDate"].replace(
                        tzinfo=None
                    )
                    minutes = int((timedifference.seconds / 60) % 60)
                    hours = int(timedifference.seconds / 60 / 60)
                    if hours == 0:
                        result["publishedDate"] = gettext(
                            "{minutes} minute(s) ago"
                        ).format(minutes=minutes)
                    else:
                        result["publishedDate"] = gettext(
                            "{hours} hour(s), {minutes} minute(s) ago"
                        ).format(hours=hours, minutes=minutes)  # noqa
                else:
                    result["publishedDate"] = format_date(result["publishedDate"])

    if output_format == "json":
        return Response(
            json.dumps(
                {
                    "query": search_query.query.decode("utf-8"),
                    "number_of_results": number_of_results,
                    "results": results,
                    "answers": list(result_container.answers),
                    "corrections": list(result_container.corrections),
                    "infoboxes": result_container.infoboxes,
                    "suggestions": list(result_container.suggestions),
                    "unresponsive_engines": __get_translated_errors(
                        result_container.unresponsive_engines
                    ),
                },  # noqa
                default=lambda item: list(item) if isinstance(item, set) else item,
            ),
            mimetype="application/json",
        )
    elif output_format == "csv":
        csv = UnicodeWriter(StringIO())
        keys = ("title", "url", "content", "host", "engine", "score", "type")
        csv.writerow(keys)
        for row in results:
            row["host"] = row["parsed_url"].netloc
            row["type"] = "result"
            csv.writerow([row.get(key, "") for key in keys])
        for a in result_container.answers:
            row = {"title": a, "type": "answer"}
            csv.writerow([row.get(key, "") for key in keys])
        for a in result_container.suggestions:
            row = {"title": a, "type": "suggestion"}
            csv.writerow([row.get(key, "") for key in keys])
        for a in result_container.corrections:
            row = {"title": a, "type": "correction"}
            csv.writerow([row.get(key, "") for key in keys])
        csv.stream.seek(0)
        response = Response(csv.stream.read(), mimetype="application/csv")
        cont_disp = "attachment;Filename=searx_-_{0}.csv".format(
            search_query.query.decode("utf-8")
        )
        response.headers.add("Content-Disposition", cont_disp)
        return response
    elif output_format == "rss":
        response_rss = render(
            "opensearch_response_rss.xml",
            results=results,
            answers=result_container.answers,
            corrections=result_container.corrections,
            suggestions=result_container.suggestions,
            q=request.form["q"],
            number_of_results=number_of_results,
            base_url=get_base_url(),
            override_theme="__common__",
        )
        return Response(response_rss, mimetype="text/xml")

    # HTML output format

    # suggestions: use RawTextQuery to get the suggestion URLs with the same bang
    suggestion_urls = list(
        map(
            lambda suggestion: {
                "url": raw_text_query.changeSearchQuery(suggestion).getFullQuery(),
                "title": suggestion,
            },
            result_container.suggestions,
        )
    )

    correction_urls = list(
        map(
            lambda correction: {
                "url": raw_text_query.changeSearchQuery(correction).getFullQuery(),
                "title": correction,
            },
            result_container.corrections,
        )
    )
    #
    return render(
        "results.html",
        results=results,
        q=request.form["q"],
        selected_categories=search_query.categories,
        pageno=search_query.pageno,
        time_range=search_query.time_range,
        number_of_results=format_decimal(number_of_results),
        advanced_search=advanced_search,
        suggestions=suggestion_urls,
        answers=result_container.answers,
        corrections=correction_urls,
        infoboxes=result_container.infoboxes,
        paging=result_container.paging,
        unresponsive_engines=__get_translated_errors(
            result_container.unresponsive_engines
        ),
        current_language=match_language(
            search_query.lang,
            LANGUAGE_CODES,
            fallback=request.preferences.get_value("language"),
        ),
        base_url=get_base_url(),
        theme=get_current_theme_name(),
        favicons=global_favicons[themes.index(get_current_theme_name())],
        timeout_limit=request.form.get("timeout_limit", None),
    )