Skip to content

fix: decode percent-encoded filenames before asset URL rewrite - #38962

Open
Waleed-Mujahid wants to merge 1 commit into
openedx:masterfrom
edly-io:fix/static-replace-unicode-double-encoding-upstream
Open

fix: decode percent-encoded filenames before asset URL rewrite#38962
Waleed-Mujahid wants to merge 1 commit into
openedx:masterfrom
edly-io:fix/static-replace-unicode-double-encoding-upstream

Conversation

@Waleed-Mujahid

@Waleed-Mujahid Waleed-Mujahid commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Description

When an HTML component contains an asset URL with a percent-encoded unicode filename — e.g. an image named Se_protéger.png which TinyMCE encodes as /static/Se_prot%C3%A9ger.png — the replace_static_urls pipeline double-encodes it into a broken URL.

Root cause: replace_static_url passes the raw rest capture group (already percent-encoded by the browser/editor) directly into StaticContent.get_canonicalized_asset_path(), which internally calls quote_plus. That re-encodes the literal % character, turning %C3%A9%25C3%25A9. The resulting asset URL does not match the stored asset key and returns a 404.

Fix: Call urllib.parse.unquote(rest) before building the asset key, so the filename is decoded once to its raw unicode form (é) and then re-encoded cleanly once by get_canonicalized_asset_path.

unquote (not unquote_plus) is intentional — + must remain a literal + in asset paths, not be decoded to a space.

The fix is scoped to the Mongo-backed asset branch of replace_static_url and does not affect the staticfiles lookup path.

Supporting information

  • Confirmed broken in courses with non-ASCII (French, Arabic, etc.) filenames saved via TinyMCE or the Files & Uploads MFE.
  • Tested on a live Sumac stage instance with French course content — asset URLs with accented filenames resolve correctly after the fix.
  • No behavior change for ASCII-only filenames (unquote is a no-op on input that contains no percent-encoded sequences).

Testing

Unit test added: test_replace_static_url_with_percent_encoded_unicode

  • Input: <img src="/static/Se_prot%C3%A9ger.png" />
  • Asserts %25C3%25A9 is absent from the output (no double-encoding)
  • Asserts get_canonicalized_asset_path is called with the decoded filename Se_protéger.png
pytest common/djangoapps/static_replace/test/test_static_replace.py -v -k test_replace_static_url_with_percent_encoded_unicode

@Waleed-Mujahid
Waleed-Mujahid force-pushed the fix/static-replace-unicode-double-encoding-upstream branch from ea2ab71 to 3ebc438 Compare August 7, 2026 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant