From dfe30bc4229a2553424840362db23399cf932db5 Mon Sep 17 00:00:00 2001 From: Iakov Lilo Date: Sat, 14 Jun 2025 12:02:24 +0600 Subject: [PATCH 1/2] Unescape relative path before accessing file provider The relative path was URL-encoded, which caused file lookups to fail for paths containing spaces or other special characters. Unescaping the path resolves the issue. --- src/Components/WebView/WebView/src/StaticContentProvider.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Components/WebView/WebView/src/StaticContentProvider.cs b/src/Components/WebView/WebView/src/StaticContentProvider.cs index 8fb7fd80cc8b..ece1d44fbc2f 100644 --- a/src/Components/WebView/WebView/src/StaticContentProvider.cs +++ b/src/Components/WebView/WebView/src/StaticContentProvider.cs @@ -27,6 +27,8 @@ public bool TryGetResponseContent(string requestUri, bool allowFallbackOnHostPag { var relativePath = _appBaseUri.MakeRelativeUri(fileUri).ToString(); + relativePath = Uri.UnescapeDataString(relativePath); + // Content in the file provider takes first priority // Next we may fall back on supplying the host page to support deep linking // If there's no match, fall back on serving embedded framework content From 0a06110dc796d71fcba36dee58d7af48f59ef297 Mon Sep 17 00:00:00 2001 From: Iakov Lilo Date: Mon, 16 Jun 2025 20:49:04 +0600 Subject: [PATCH 2/2] test: add test for serving files with whitespaces in their name This test verifies that TryGetResponseContent can handle file paths containing whitespaces and serves the expected content, ensuring the URL-encoding fix works as intended. --- .../test/StaticContentProviderTests.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Components/WebView/WebView/test/StaticContentProviderTests.cs b/src/Components/WebView/WebView/test/StaticContentProviderTests.cs index 24251eb0f77d..fcf7149a31ec 100644 --- a/src/Components/WebView/WebView/test/StaticContentProviderTests.cs +++ b/src/Components/WebView/WebView/test/StaticContentProviderTests.cs @@ -41,6 +41,38 @@ public void TryGetResponseContentReturnsCorrectContentTypeForNonPhysicalFile() Assert.Equal("text/css", contentTypeValue); } + [Fact] + public void TryGetResponseContentCanHandleWhitespaceInFileName() + { + // Arrange + const string cssFilePath = "file with whitespace.css"; + const string cssFileContent = "this is css"; + var inMemoryFileProvider = new InMemoryFileProvider( + new Dictionary + { + { cssFilePath, cssFileContent }, + }); + var appBase = "fake://0.0.0.0/"; + var scp = new StaticContentProvider(inMemoryFileProvider, new Uri(appBase), "fakehost.html"); + + // Act + Assert.True(scp.TryGetResponseContent( + requestUri: appBase + Uri.EscapeDataString(cssFilePath), + allowFallbackOnHostPage: false, + out var statusCode, + out var statusMessage, + out var content, + out var headers)); + + // Assert + var contentString = new StreamReader(content).ReadToEnd(); + Assert.Equal(200, statusCode); + Assert.Equal("OK", statusMessage); + Assert.Equal("this is css", contentString); + Assert.True(headers.TryGetValue("Content-Type", out var contentTypeValue)); + Assert.Equal("text/css", contentTypeValue); + } + private sealed class InMemoryFileProvider : IFileProvider { public InMemoryFileProvider(IDictionary filePathsAndContents)