From 2842b11e886d84f1f59bb267446f675df26922cc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 30 Jul 2025 17:14:55 +1000 Subject: [PATCH 1/5] Ensure invalid path extensions are skipped. Fix #233 --- .../ImageSharp.Web.Sample/Pages/Index.cshtml | 4 ++-- src/ImageSharp.Web/FormatUtilities.cs | 19 +++++++++++++------ .../Helpers/FormatUtilitiesTests.cs | 7 +++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/samples/ImageSharp.Web.Sample/Pages/Index.cshtml b/samples/ImageSharp.Web.Sample/Pages/Index.cshtml index c492abf4..73ad597b 100644 --- a/samples/ImageSharp.Web.Sample/Pages/Index.cshtml +++ b/samples/ImageSharp.Web.Sample/Pages/Index.cshtml @@ -52,10 +52,10 @@

- sixlabors.imagesharp.web.svg?width=300 + sixlabors.imagesharp.web.svg?width=300&format=jpg

- +

diff --git a/src/ImageSharp.Web/FormatUtilities.cs b/src/ImageSharp.Web/FormatUtilities.cs index 4e9cba52..395a38c8 100644 --- a/src/ImageSharp.Web/FormatUtilities.cs +++ b/src/ImageSharp.Web/FormatUtilities.cs @@ -53,12 +53,19 @@ public FormatUtilities(IOptions options) [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetExtensionFromUri(string uri, [NotNullWhen(true)] out string? extension) { + // Attempts to extract a valid image file extension from the URI. + // If the path contains a recognized extension, it is used. + // If the path lacks an extension and a query string is present, + // the method checks for a valid 'format' parameter as a fallback. + // Returns true if a supported extension is found in either location. extension = null; int query = uri.IndexOf('?'); ReadOnlySpan path; if (query > -1) { + path = uri.AsSpan(0, query); + if (uri.Contains(FormatWebProcessor.Format, StringComparison.OrdinalIgnoreCase) && QueryHelpers.ParseQuery(uri[query..]).TryGetValue(FormatWebProcessor.Format, out StringValues ext)) { @@ -68,15 +75,13 @@ public bool TryGetExtensionFromUri(string uri, [NotNullWhen(true)] out string? e { if (extSpan.Equals(e, StringComparison.OrdinalIgnoreCase)) { + // We've found a valid extension in the query. + // Now we need to check the path to see if there is a file extension and validate that. extension = e; - return true; + break; } } - - return false; } - - path = uri.AsSpan(0, query); } else { @@ -96,9 +101,11 @@ public bool TryGetExtensionFromUri(string uri, [NotNullWhen(true)] out string? e return true; } } + + return false; } - return false; + return extension != null; } /// diff --git a/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs b/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs index cbc150a8..727d4dfc 100644 --- a/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs +++ b/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs @@ -51,4 +51,11 @@ public void GetExtensionShouldRejectInvalidQueryStringFormatParameter() const string uri = "http://www.example.org/some/path/to/image.bmp?width=300&format=invalid"; Assert.False(FormatUtilities.TryGetExtensionFromUri(uri, out _)); } + + [Fact] + public void GetExtensionShouldRejectInvalidPathWithValidQueryStringFormatParameter() + { + const string uri = "http://www.example.org/some/path/to/image.svg?width=300&format=jpg"; + Assert.False(FormatUtilities.TryGetExtensionFromUri(uri, out _)); + } } From 5ed4b82e04fed233f2ef0c26b6c8e7a9513c60a4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 30 Jul 2025 17:25:37 +1000 Subject: [PATCH 2/5] Always use first extension --- src/ImageSharp.Web/FormatUtilities.cs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp.Web/FormatUtilities.cs b/src/ImageSharp.Web/FormatUtilities.cs index 395a38c8..31a6de80 100644 --- a/src/ImageSharp.Web/FormatUtilities.cs +++ b/src/ImageSharp.Web/FormatUtilities.cs @@ -88,21 +88,25 @@ public bool TryGetExtensionFromUri(string uri, [NotNullWhen(true)] out string? e path = uri; } - int extensionIndex; - if ((extensionIndex = path.LastIndexOf('.')) != -1) + // We don't need this if the query string has already provided a valid extension. + if (extension == null) { - ReadOnlySpan pathExtension = path[(extensionIndex + 1)..]; - - foreach (string e in this.extensions) + int extensionIndex; + if ((extensionIndex = path.LastIndexOf('.')) != -1) { - if (pathExtension.Equals(e, StringComparison.OrdinalIgnoreCase)) + ReadOnlySpan pathExtension = path[(extensionIndex + 1)..]; + + foreach (string e in this.extensions) { - extension = e; - return true; + if (pathExtension.Equals(e, StringComparison.OrdinalIgnoreCase)) + { + extension = e; + return true; + } } - } - return false; + return false; + } } return extension != null; From 229d9256274309011c8d67a37a14fa80b191396f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 30 Jul 2025 17:32:36 +1000 Subject: [PATCH 3/5] Fix test --- tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs b/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs index 727d4dfc..104336db 100644 --- a/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs +++ b/tests/ImageSharp.Web.Tests/Helpers/FormatUtilitiesTests.cs @@ -46,10 +46,10 @@ public void GetExtensionShouldAcknowledgeQueryStringFormatParameter() } [Fact] - public void GetExtensionShouldRejectInvalidQueryStringFormatParameter() + public void GetExtensionShouldAllowInvalidQueryStringFormatParameterWithValidExtension() { const string uri = "http://www.example.org/some/path/to/image.bmp?width=300&format=invalid"; - Assert.False(FormatUtilities.TryGetExtensionFromUri(uri, out _)); + Assert.True(FormatUtilities.TryGetExtensionFromUri(uri, out _)); } [Fact] From 628d341bd9f2a54e758e034398d0019db09b8ad6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 31 Jul 2025 11:20:16 +1000 Subject: [PATCH 4/5] Fix invalid condition --- src/ImageSharp.Web/FormatUtilities.cs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp.Web/FormatUtilities.cs b/src/ImageSharp.Web/FormatUtilities.cs index 31a6de80..928241bf 100644 --- a/src/ImageSharp.Web/FormatUtilities.cs +++ b/src/ImageSharp.Web/FormatUtilities.cs @@ -88,25 +88,23 @@ public bool TryGetExtensionFromUri(string uri, [NotNullWhen(true)] out string? e path = uri; } - // We don't need this if the query string has already provided a valid extension. - if (extension == null) + int extensionIndex; + if ((extensionIndex = path.LastIndexOf('.')) != -1) { - int extensionIndex; - if ((extensionIndex = path.LastIndexOf('.')) != -1) - { - ReadOnlySpan pathExtension = path[(extensionIndex + 1)..]; + ReadOnlySpan pathExtension = path[(extensionIndex + 1)..]; - foreach (string e in this.extensions) + foreach (string e in this.extensions) + { + if (pathExtension.Equals(e, StringComparison.OrdinalIgnoreCase)) { - if (pathExtension.Equals(e, StringComparison.OrdinalIgnoreCase)) - { - extension = e; - return true; - } + // We've found a valid extension in the path, however we do not + // want to overwrite an existing extension. + extension ??= e; + return true; } - - return false; } + + return false; } return extension != null; From 24a2782662447b4e367880bc9bb11e6cdfcac719 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 31 Jul 2025 11:23:13 +1000 Subject: [PATCH 5/5] Update ImageSharp reference. --- src/ImageSharp.Web/ImageSharp.Web.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp.Web/ImageSharp.Web.csproj b/src/ImageSharp.Web/ImageSharp.Web.csproj index aaf62cce..ccbd0346 100644 --- a/src/ImageSharp.Web/ImageSharp.Web.csproj +++ b/src/ImageSharp.Web/ImageSharp.Web.csproj @@ -46,7 +46,7 @@ - +