113 """REST API of SearXNG's favicon proxy service
117 /favicon_proxy?authority=<...>&h=<...>
120 Domain name :rfc:`3986` / see :py:obj:`favicon_url`
123 HMAC :rfc:`2104`, build up from the :ref:`server.secret_key <settings
127 authority = sxng_request.args.get(
'authority')
130 if not authority
or "/" in authority:
137 sxng_request.args.get(
'h',
''),
141 resolver = sxng_request.preferences.get_value(
'favicon_resolver')
143 if not resolver
or resolver
not in CFG.resolver_map.keys():
148 if data
is not None and mime
is not None:
149 resp = flask.Response(data, mimetype=mime)
150 resp.headers[
'Cache-Control'] = f
"max-age={CFG.max_age}"
154 theme = sxng_request.preferences.get_value(
"theme")
155 fav, mimetype = CFG.favicon(theme=theme)
156 return flask.send_from_directory(fav.parent, fav.name, mimetype=mimetype)
159def search_favicon(resolver: str, authority: str) -> tuple[
None | bytes,
None | str]:
160 """Sends the request to the favicon resolver and returns a tuple for the
161 favicon. The tuple consists of ``(data, mime)``, if the resolver has not
162 determined a favicon, both values are ``None``.
165 Binary data of the favicon.
168 Mime type of the favicon.
172 data, mime = (
None,
None)
174 func = CFG.get_resolver(resolver)
179 data_mime = cache.CACHE(resolver, authority)
180 if data_mime
is not None:
184 data, mime = func(authority, timeout=CFG.resolver_timeout)
185 if data
is None or mime
is None:
186 data, mime = (
None,
None)
188 except (HTTPError, SearxEngineResponseException):
191 cache.CACHE.set(resolver, authority, mime, data)
196 """Function to generate the image URL used for favicons in SearXNG's result
197 lists. The ``authority`` argument (aka netloc / :rfc:`3986`) is usually a
198 (sub-) domain name. This function is used in the HTML (jinja) templates.
202 <div class="favicon">
203 <img src="{{ favicon_url(result.parsed_url.netloc) }}">
206 The returned URL is a route to :py:obj:`favicon_proxy` REST API.
208 If the favicon is already in the cache, the returned URL is a `data URL`_
209 (something like ``data:image/png;base64,...``). By generating a data url from
210 the :py:obj:`.cache.FaviconCache`, additional HTTP roundtripps via the
211 :py:obj:`favicon_proxy` are saved. However, it must also be borne in mind
212 that data urls are not cached in the client (web browser).
214 .. _data URL: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
218 resolver = sxng_request.preferences.get_value(
'favicon_resolver')
220 if not resolver
or resolver
not in CFG.resolver_map.keys():
223 data_mime = cache.CACHE(resolver, authority)
225 if data_mime == (
None,
None):
227 theme = sxng_request.preferences.get_value(
"theme")
228 return CFG.favicon_data_url(theme=theme)
230 if data_mime
is not None:
231 data, mime = data_mime
232 return f
"data:{mime};base64,{str(base64.b64encode(data), 'utf-8')}"
234 h = new_hmac(CFG.secret_key, authority.encode())
235 proxy_url = flask.url_for(
'favicon_proxy')
236 query = urllib.parse.urlencode({
"authority": authority,
"h": h})
237 return f
"{proxy_url}?{query}"