diff options
| author | Bond-009 <bond.009@outlook.com> | 2026-02-26 19:31:19 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-26 19:31:19 +0100 |
| commit | 25e8c6d5916682967c85175d11286b2d6b412d06 (patch) | |
| tree | 0abea6bd717a221cf9f74ebedecbfc6a43604218 | |
| parent | c11c33e1a8facc612d8d37b1e6d79e8f20edc238 (diff) | |
| parent | 37b50fe13c689e8fb89288da12f79bf7164e1194 (diff) | |
Merge pull request #16255 from cosu/fix/streaminfo-malformed-query-string
Fix malformed query string in StreamInfo.ToUrl() causing 500 error via proxies
| -rw-r--r-- | Jellyfin.Api/Helpers/StreamingHelpers.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/StreamInfo.cs | 12 | ||||
| -rw-r--r-- | tests/Jellyfin.Model.Tests/Dlna/StreamInfoTests.cs | 6 |
3 files changed, 12 insertions, 8 deletions
diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index 1e984542ec..c6823fa807 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -268,7 +268,7 @@ public static class StreamingHelpers Dictionary<string, string?> streamOptions = new Dictionary<string, string?>(); foreach (var param in queryString) { - if (char.IsLower(param.Key[0])) + if (param.Key.Length > 0 && char.IsLower(param.Key[0])) { // This was probably not parsed initially and should be a StreamOptions // or the generated URL should correctly serialize it diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 551bee89e3..7aad97ce01 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -895,7 +895,7 @@ public class StreamInfo if (SubProtocol == MediaStreamProtocol.hls) { - sb.Append("/master.m3u8?"); + sb.Append("/master.m3u8"); } else { @@ -906,10 +906,10 @@ public class StreamInfo sb.Append('.'); sb.Append(Container); } - - sb.Append('?'); } + var queryStart = sb.Length; + if (!string.IsNullOrEmpty(DeviceProfileId)) { sb.Append("&DeviceProfileId="); @@ -1133,6 +1133,12 @@ public class StreamInfo sb.Append(query); } + // Replace the first '&' with '?' to form a valid query string. + if (sb.Length > queryStart) + { + sb[queryStart] = '?'; + } + return sb.ToString(); } 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); } |
