From 00ff6b4f583f629c71dd2dc05e4f2bd4b2f546b2 Mon Sep 17 00:00:00 2001 From: Jeff Dairiki Date: Thu, 21 Dec 2023 17:15:47 -0800 Subject: [PATCH] fix(_inject_tooldrawer): fix "bad escape \u" We were using re.sub() to inject the tooldrawer HTML. Re.sub treats backslashes in the replacement string specially. When the injected HTML includes a backslash (e.g. in JSON string data), this was resulting in a "bad escape \u" exception. --- lektor/admin/modules/serve.py | 5 ++++- tests/admin/test_serve.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lektor/admin/modules/serve.py b/lektor/admin/modules/serve.py index 4c8030cb4..26a9f99a4 100644 --- a/lektor/admin/modules/serve.py +++ b/lektor/admin/modules/serve.py @@ -80,7 +80,10 @@ def _inject_tooldrawer( tooldrawer_config=dataclasses.asdict(tooldrawer_config), tooldrawer_js=url_for("static", filename="tooldrawer.js"), ).encode("utf-8") - html = re.sub(rb"(?i)(?=|\Z)", tooldrawer_html, html, count=1) + match = re.search(rb"(?i)|\Z", html) + assert match is not None + head_end = match.start() + html = html[:head_end] + tooldrawer_html + html[head_end:] return html diff --git a/tests/admin/test_serve.py b/tests/admin/test_serve.py index 366487e6c..71dcaf4cb 100644 --- a/tests/admin/test_serve.py +++ b/tests/admin/test_serve.py @@ -75,6 +75,10 @@ def test_inject_tooldrawer(html_text, expect_at_tail): @pytest.mark.usefixtures("dummy_app_context") def test_inject_tooldrawer_adds_livereload(dummy_app, make_dummy_artifact): + # Exercises a bug: the injected HTML includes backslash escapes within JSON + # strings. re.sub(pat, repl, s) doesn't work in that case, as it treats backslashes + # in repl specially. This results in an exception: "re.error: bad escape \u at + # position [...]" dummy_app.register_blueprint(livereload.bp) artifact = make_dummy_artifact(artifact_name="ARTIFACT_NAME") config = make_tooldrawer_config("EDIT_URL", artifact) @@ -83,6 +87,12 @@ def test_inject_tooldrawer_adds_livereload(dummy_app, make_dummy_artifact): ) +@pytest.mark.usefixtures("dummy_app_context") +def test_inject_tooldrawer_unicode_escapes(): + config = make_tooldrawer_config("http://example.com/EDIT_URL?path=/foo&alt=de") + assert b"TOOLDRAWER_CONFIG" in serve._inject_tooldrawer(b"", config) + + @pytest.fixture def make_dummy_artifact(tmp_path): def make_dummy_artifact(