From bb13ea82bb6310d998b5eec75031a4e70b7df0f2 Mon Sep 17 00:00:00 2001 From: Laurianti Date: Thu, 1 Oct 2026 13:04:33 +0200 Subject: [PATCH] .Net: Percent-decode non-base64 data URIs in BinaryContent --- .../Contents/BinaryContent.cs | 7 +++++-- .../Contents/BinaryContentTests.cs | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/dotnet/src/SemanticKernel.Abstractions/Contents/BinaryContent.cs b/dotnet/src/SemanticKernel.Abstractions/Contents/BinaryContent.cs index c215a4eec93f..05e7c3577e5d 100644 --- a/dotnet/src/SemanticKernel.Abstractions/Contents/BinaryContent.cs +++ b/dotnet/src/SemanticKernel.Abstractions/Contents/BinaryContent.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Net; using System.Text; using System.Text.Json.Serialization; using Microsoft.SemanticKernel.Text; @@ -306,8 +307,10 @@ private void SetData(ReadOnlyMemory? data) } else { - // Defaults to UTF8 encoding if format is not provided. - this._data = Encoding.UTF8.GetBytes(parsedDataUri.Data!); + // Defaults to UTF8 encoding if format is not provided. Per RFC 2397, each %xx escape is the octet it names, + // and '+' is a literal plus, not a space as in form encoding. + byte[] bytes = Encoding.UTF8.GetBytes(parsedDataUri.Data!.Replace("+", "%2B")); + this._data = WebUtility.UrlDecodeToBytes(bytes, 0, bytes.Length); } } diff --git a/dotnet/src/SemanticKernel.UnitTests/Contents/BinaryContentTests.cs b/dotnet/src/SemanticKernel.UnitTests/Contents/BinaryContentTests.cs index 9ce8e356f2c4..9bc722d3438d 100644 --- a/dotnet/src/SemanticKernel.UnitTests/Contents/BinaryContentTests.cs +++ b/dotnet/src/SemanticKernel.UnitTests/Contents/BinaryContentTests.cs @@ -311,4 +311,18 @@ public void ReturnUTF8EncodedWhenDataIsNotBase64(string path) // Act & Assert Assert.Equal("01-02-03-04", Encoding.UTF8.GetString(content.Data!.Value.ToArray())); } + + [Theory] + [InlineData("data:,A%20brief%20note", new byte[] { 0x41, 0x20, 0x62, 0x72, 0x69, 0x65, 0x66, 0x20, 0x6E, 0x6F, 0x74, 0x65 })] + [InlineData("data:application/octet-stream,%FF%00%80", new byte[] { 0xFF, 0x00, 0x80 })] + [InlineData("data:text/plain;charset=iso-8859-1,caf%E9", new byte[] { 0x63, 0x61, 0x66, 0xE9 })] + [InlineData("data:text/plain,1+1=2", new byte[] { 0x31, 0x2B, 0x31, 0x3D, 0x32 })] + public void ReturnPercentDecodedOctetsWhenDataIsNotBase64(string path, byte[] expectedData) + { + // Arrange + var content = new BinaryContent(path); + + // Act & Assert + Assert.Equal(expectedData, content.Data!.Value.ToArray()); + } }