From 75b8de7ce38c6c871ccd0af3c9c426c1237f99a7 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 13 Dec 2025 20:37:53 -0600 Subject: [PATCH] fix: workaround error when 'fanstatic.needed' missing from environ what i've seen in the wild seems to be caused by a crawler trying to fetch non-minified JS files, when the fanstatic resource library only includes minified JS files. still not sure why that would cause the specific error but oh well, this hopefully "solves" for now --- src/wuttaweb/handler.py | 10 +++++++++- tests/test_handler.py | 20 +++++++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/wuttaweb/handler.py b/src/wuttaweb/handler.py index 3b63022..615eae4 100644 --- a/src/wuttaweb/handler.py +++ b/src/wuttaweb/handler.py @@ -70,7 +70,15 @@ class WebHandler(GenericHandler): url = self.config.get("wuttaweb.favicon_url") if url: return url - return self.get_fanstatic_url(request, static.favicon) + + # nb. in rare circumstances i have received unhandled error email, + # which somehow was triggered by 'fanstatic.needed' being missing + # from the environ. not sure why that would happen, but it seems + # safe to ignore when it does - favicon is not *that* important. + if "fanstatic.needed" in request.environ: + return self.get_fanstatic_url(request, static.favicon) + + return "" def get_header_logo_url(self, request): """ diff --git a/tests/test_handler.py b/tests/test_handler.py index e7b0254..b038e47 100644 --- a/tests/test_handler.py +++ b/tests/test_handler.py @@ -34,9 +34,17 @@ class TestWebHandler(WebTestCase): self.assertEqual(url, "/fanstatic/wuttaweb_img/logo.png") # what about a subpath - self.request.script_name = "/testing" - url = handler.get_fanstatic_url(self.request, static.logo) - self.assertEqual(url, "/testing/fanstatic/wuttaweb_img/logo.png") + with patch.object(self.request, "script_name", new="/testing"): + url = handler.get_fanstatic_url(self.request, static.logo) + self.assertEqual(url, "/testing/fanstatic/wuttaweb_img/logo.png") + + # error if environ missing config/data + environ = dict(self.request.environ) + del environ["fanstatic.needed"] + with patch.object(self.request, "environ", new=environ): + self.assertRaises( + KeyError, handler.get_fanstatic_url, self.request, static.logo + ) def test_get_favicon_url(self): handler = self.make_handler() @@ -45,6 +53,12 @@ class TestWebHandler(WebTestCase): url = handler.get_favicon_url(self.request) self.assertEqual(url, "/fanstatic/wuttaweb_img/favicon.ico") + # returns empty if environ missing config/data + environ = dict(self.request.environ) + del environ["fanstatic.needed"] + with patch.object(self.request, "environ", new=environ): + self.assertEqual(handler.get_favicon_url(self.request), "") + # config override self.config.setdefault("wuttaweb.favicon_url", "/testing/other.ico") url = handler.get_favicon_url(self.request)