From 37b50fe13c689e8fb89288da12f79bf7164e1194 Mon Sep 17 00:00:00 2001 From: Cosmin Dumitru Date: Wed, 18 Feb 2026 21:08:35 +0100 Subject: Fix malformed query string in StreamInfo.ToUrl() causing 500 error via proxies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit StreamInfo.ToUrl() generated URLs like `/master.m3u8?&DeviceId=...` (note `?&`) because `?` was appended to the path and all parameters started with `&`. When the first optional parameter (DeviceProfileId) was null, the result was a malformed query string. This is harmless when clients hit Jellyfin directly (ASP.NET Core tolerates `?&`), but when accessed through a reverse proxy that parses and re-serializes the URL (e.g. Home Assistant ingress via aiohttp/yarl), `?&` becomes `?=&` — introducing an empty-key query parameter. ParseStreamOptions then crashes on `param.Key[0]` with IndexOutOfRangeException. Changes: - StreamInfo.ToUrl(): Track query start position and replace the first `&` with `?` after all parameters are appended, producing valid query strings - ParseStreamOptions: Guard against empty query parameter keys - Tests: Remove .Replace("?&", "?") workaround that masked the bug Co-Authored-By: Claude Opus 4.6 --- tests/Jellyfin.Model.Tests/Dlna/StreamInfoTests.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/Jellyfin.Model.Tests/Dlna/StreamInfoTests.cs b/tests/Jellyfin.Model.Tests/Dlna/StreamInfoTests.cs index 8dea468064..4b3126fe11 100644 --- a/tests/Jellyfin.Model.Tests/Dlna/StreamInfoTests.cs +++ b/tests/Jellyfin.Model.Tests/Dlna/StreamInfoTests.cs @@ -216,8 +216,7 @@ public class StreamInfoTests string legacyUrl = streamInfo.ToUrl_Original(BaseUrl, "123"); - // New version will return and & after the ? due to optional parameters. - string newUrl = streamInfo.ToUrl(BaseUrl, "123", null).Replace("?&", "?", StringComparison.OrdinalIgnoreCase); + string newUrl = streamInfo.ToUrl(BaseUrl, "123", null); Assert.Equal(legacyUrl, newUrl, ignoreCase: true); } @@ -234,8 +233,7 @@ public class StreamInfoTests FillAllProperties(streamInfo); string legacyUrl = streamInfo.ToUrl_Original(BaseUrl, "123"); - // New version will return and & after the ? due to optional parameters. - string newUrl = streamInfo.ToUrl(BaseUrl, "123", null).Replace("?&", "?", StringComparison.OrdinalIgnoreCase); + string newUrl = streamInfo.ToUrl(BaseUrl, "123", null); Assert.Equal(legacyUrl, newUrl, ignoreCase: true); } -- cgit v1.2.3