diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs
index bbbe5fb8d..5c64d731b 100644
--- a/Jellyfin.Api/Controllers/SystemController.cs
+++ b/Jellyfin.Api/Controllers/SystemController.cs
@@ -84,13 +84,19 @@ namespace Jellyfin.Api.Controllers
///
/// Pings the system.
///
+ /// Optional: Parameters to echo back in the response.
/// Information retrieved.
/// The server name.
[HttpGet("Ping", Name = "GetPingSystem")]
[HttpPost("Ping", Name = "PostPingSystem")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult PingSystem()
+ public ActionResult PingSystem([FromQuery]Dictionary? @params = null)
{
+ if (@params != null && @params.Count > 0)
+ {
+ Response.Headers.Add("querystring", string.Join("&", @params.Select(x => x.Key + "=" + x.Value)));
+ }
+
return _appHost.Name;
}
diff --git a/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs b/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs
index b18ba7051..44b30baac 100644
--- a/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs
+++ b/Jellyfin.Server/Middleware/UrlDecodeQueryFeature.cs
@@ -66,7 +66,14 @@ namespace Jellyfin.Server.Middleware
foreach (var pair in queryString)
{
var item = pair.Split('=', System.StringSplitOptions.RemoveEmptyEntries);
- pairs.Add(item[0], new StringValues(item.Length == 2 ? item[1] : string.Empty));
+ if (item.Length > 0)
+ {
+ pairs.Add(item[0], new StringValues(item.Length == 2 ? item[1] : string.Empty));
+ }
+ else
+ {
+ pairs.Add(pair, string.Empty);
+ }
}
_store = new QueryCollection(pairs);
diff --git a/tests/Jellyfin.Api.Tests/Controllers/EncodedQueryStringTest.cs b/tests/Jellyfin.Api.Tests/Controllers/EncodedQueryStringTest.cs
new file mode 100644
index 000000000..ce5ac11ea
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/Controllers/EncodedQueryStringTest.cs
@@ -0,0 +1,47 @@
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Jellyfin.Api.Tests.Controllers
+{
+ ///
+ /// Defines the test for encoded querystrings in the url.
+ ///
+ public class EncodedQueryStringTest : IClassFixture
+ {
+ private readonly JellyfinApplicationFactory _factory;
+
+ public EncodedQueryStringTest(JellyfinApplicationFactory factory)
+ {
+ _factory = factory;
+ }
+
+ [Fact]
+ public async Task Ensure_Ping_Working()
+ {
+ var client = _factory.CreateClient();
+
+ var response = await client.GetAsync("system/ping").ConfigureAwait(false);
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+
+ [Theory]
+ [InlineData("a=1&b=2&c=3", "a=1&b=2&c=3")] // won't be processed as there is more than 1.
+ [InlineData("a=1", "a=1")] // won't be processed as it has a value
+ [InlineData("%3D", "==")] // will decode with an empty string value '=' = ''.
+ [InlineData("a%3D1%26b%3D2%26c%3D3", "a=1&b=2&c=3")] // will be processed.
+
+ public async Task Ensure_Decoding_Of_Urls_Is_Working(string sourceUrl, string unencodedUrl)
+ {
+ var client = _factory.CreateClient();
+
+ var response = await client.GetAsync("system/ping?" + sourceUrl).ConfigureAwait(false);
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Equal(unencodedUrl, response.Headers.GetValues("querystring").First());
+ }
+ }
+}