From 9352a243744d5d6805f80dc57792919f15ca5b90 Mon Sep 17 00:00:00 2001 From: SeaEagle1 Date: Fri, 12 May 2023 17:53:27 +0200 Subject: [PATCH 1/2] Rescue PlayTo function in case of malformed Xml response (port from 10.8 fix) --- Emby.Dlna/PlayTo/DlnaHttpClient.cs | 31 +++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/Emby.Dlna/PlayTo/DlnaHttpClient.cs b/Emby.Dlna/PlayTo/DlnaHttpClient.cs index 75ff542dd8..9930f0ede1 100644 --- a/Emby.Dlna/PlayTo/DlnaHttpClient.cs +++ b/Emby.Dlna/PlayTo/DlnaHttpClient.cs @@ -2,9 +2,11 @@ using System; using System.Globalization; +using System.IO; using System.Net.Http; using System.Net.Mime; using System.Text; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml; @@ -54,15 +56,34 @@ namespace Emby.Dlna.PlayTo LoadOptions.None, cancellationToken).ConfigureAwait(false); } - catch (XmlException ex) + catch (XmlException) { - _logger.LogError(ex, "Failed to parse response"); - if (_logger.IsEnabled(LogLevel.Debug)) + // try correcting the Xml response with common errors + var xmlString = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); + + // find and replace unescaped ampersands (&) + Regex regex = new Regex(@"(&(?![a-z]*;))"); + xmlString = regex.Replace(xmlString, @"&"); + + try { - _logger.LogDebug("Malformed response: {Content}\n", await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false)); + // retry reading Xml + var xmlReader = new StringReader(xmlString); + return await XDocument.LoadAsync( + xmlReader, + LoadOptions.None, + cancellationToken).ConfigureAwait(false); } + catch (XmlException ex) + { + _logger.LogError(ex, "Failed to parse response"); + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Malformed response: {Content}\n", xmlString); + } - return null; + return null; + } } } From 126047bfd6fbb3156c07905b8cf58506cde2c664 Mon Sep 17 00:00:00 2001 From: SeaEagle1 Date: Sat, 13 May 2023 00:07:20 +0200 Subject: [PATCH 2/2] Use compile-time generated regex and remove loglevel check --- Emby.Dlna/PlayTo/DlnaHttpClient.cs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Emby.Dlna/PlayTo/DlnaHttpClient.cs b/Emby.Dlna/PlayTo/DlnaHttpClient.cs index 9930f0ede1..4e9903f26a 100644 --- a/Emby.Dlna/PlayTo/DlnaHttpClient.cs +++ b/Emby.Dlna/PlayTo/DlnaHttpClient.cs @@ -17,7 +17,10 @@ using Microsoft.Extensions.Logging; namespace Emby.Dlna.PlayTo { - public class DlnaHttpClient + /// + /// Http client for Dlna PlayTo function. + /// + public partial class DlnaHttpClient { private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; @@ -62,8 +65,7 @@ namespace Emby.Dlna.PlayTo var xmlString = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); // find and replace unescaped ampersands (&) - Regex regex = new Regex(@"(&(?![a-z]*;))"); - xmlString = regex.Replace(xmlString, @"&"); + xmlString = EscapeAmpersandRegex().Replace(xmlString, "&"); try { @@ -77,10 +79,7 @@ namespace Emby.Dlna.PlayTo catch (XmlException ex) { _logger.LogError(ex, "Failed to parse response"); - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug("Malformed response: {Content}\n", xmlString); - } + _logger.LogDebug("Malformed response: {Content}\n", xmlString); return null; } @@ -125,5 +124,12 @@ namespace Emby.Dlna.PlayTo // Have to await here instead of returning the Task directly, otherwise request would be disposed too soon return await SendRequestAsync(request, cancellationToken).ConfigureAwait(false); } + + /// + /// Compile-time generated regular expression for escaping ampersands. + /// + /// Compiled regular expression. + [GeneratedRegex("(&(?![a-z]*;))")] + private static partial Regex EscapeAmpersandRegex(); } }