fix(content): URL-decode content-collection file path before lookup (spaces/umlauts) (#326)#336
Merged
Merged
Conversation
…326) The /static/{**path} file-serving endpoint looked up the collection with the raw catch-all route value. ASP.NET Core leaves catch-all parameters percent-encoded (so the multi-segment path's '/' separators survive), so a file under a folder with a space or umlaut arrived as 'Reports/Data%20Extraction/%C3%9Cbersicht%202025.pdf' and missed the stored 'Reports/Data Extraction/Übersicht 2025.pdf' — every file under such a folder appeared to have vanished from the portal, while a kernel read with the decoded path succeeded. RenderPdf builds the URL with Uri.EscapeDataString per segment; the serving side never applied the inverse. Add DecodeContentPath (per-segment Uri.UnescapeDataString — handles %20 AND UTF-8 %C3%9C, without turning an escaped slash into a false separator) and apply it where the file path is built in both endpoint patterns. A plain ASCII path carries no escapes, so decoding is a no-op — never a double-decode. Test: real file-system content collection with a space+umlaut path; the encoded path misses, the decoded path resolves the file with bytes intact, plus a theory pinning decode-exactly-once. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Test Results (shard 5)774 tests +154 592 ✅ +154 3m 6s ⏱️ + 1m 21s Results for commit 7c8a260. ± Comparison against base commit 339c21f. This pull request removes 15 and adds 169 tests. Note that renamed tests count towards both. |
Test Results 56 files ± 0 56 suites ±0 22m 3s ⏱️ +34s Results for commit 7c8a260. ± Comparison against base commit 339c21f. This pull request removes 15 and adds 169 tests. Note that renamed tests count towards both. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #326
Problem
Content-collection files whose path contains a space (or a non-ASCII umlaut) 404 from a deployed portal. The
/static/{**path}file-serving endpoint looked up the collection with the raw catch-all route value, which ASP.NET Core leaves percent-encoded (catch-all parameters keep their encoding so the multi-segment path's/separators survive). So a file stored atreached the collection lookup as
Every file under such a folder appeared to have vanished from the portal UI, while a kernel read with the decoded path (
IContentService/ContentCollection.GetContentAsync) succeeded — bytes intact. ASCII/space-free paths were unaffected.Root cause
ContentLayoutArea.RenderPdfbuilds the/static/...URL withUri.EscapeDataStringon each path segment, butResolveStaticinBlazorHostingExtensionsnever applied the inverse before handing the path to the collection lookup — so%20/%C3%9CreachedGetContentAsyncverbatim and missed the real stored path.Fix
Add
DecodeContentPath— per-segmentUri.UnescapeDataString(restores%20and UTF-8 escapes like%C3%9C→Ü, without turning an escaped slash into a false separator) — and apply it where the file path is built in both endpoint patterns (/static/{collection}/{filePath}and/static/{address}/{collection}/{filePath}). Applied only to the file-path portion (not the already-handled collection segment), at the boundary where the still-encoded catch-all value is consumed, so it decodes exactly once — a plain ASCII path carries no escapes and is a no-op.Test
ContentPathDecodingTest(MeshWeaver.Hosting.Blazor.Test,HubTestBase, no mocking):Reports/Data Extraction/Übersicht 2025.pdf; the raw encoded path misses (reproduces the bug), the decoded path resolves the file with bytes intact.%20-in-name case that would break under a double-decode (decode-exactly-once).Release
-warnaserror -p:CIRun=truebuild of the touched project + test project is clean; all 6 tests pass locally.🤖 Generated with Claude Code