diff options
Diffstat (limited to 'Emby.Dlna/Service/BaseControlHandler.cs')
| -rw-r--r-- | Emby.Dlna/Service/BaseControlHandler.cs | 196 |
1 files changed, 91 insertions, 105 deletions
diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs index 5f78674b8..581e4a286 100644 --- a/Emby.Dlna/Service/BaseControlHandler.cs +++ b/Emby.Dlna/Service/BaseControlHandler.cs @@ -1,81 +1,70 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; +using System.Threading.Tasks; using System.Xml; +using Diacritics.Extensions; using Emby.Dlna.Didl; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Extensions; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace Emby.Dlna.Service { public abstract class BaseControlHandler { - private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/"; - - protected readonly IServerConfigurationManager Config; - protected readonly ILogger _logger; - protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory; + private const string NsSoapEnv = "http://schemas.xmlsoap.org/soap/envelope/"; - protected BaseControlHandler(IServerConfigurationManager config, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + protected BaseControlHandler(IServerConfigurationManager config, ILogger logger) { Config = config; - _logger = logger; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; + Logger = logger; } - public ControlResponse ProcessControlRequest(ControlRequest request) + protected IServerConfigurationManager Config { get; } + + protected ILogger Logger { get; } + + public async Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request) { try { - var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLog; - - if (enableDebugLogging) - { - LogRequest(request); - } - - var response = ProcessControlRequestInternal(request); - - if (enableDebugLogging) - { - LogResponse(response); - } + LogRequest(request); + var response = await ProcessControlRequestInternalAsync(request).ConfigureAwait(false); + LogResponse(response); return response; } catch (Exception ex) { - _logger.LogError(ex, "Error processing control request"); + Logger.LogError(ex, "Error processing control request"); - return new ControlErrorHandler().GetResponse(ex); + return ControlErrorHandler.GetResponse(ex); } } - private ControlResponse ProcessControlRequestInternal(ControlRequest request) + private async Task<ControlResponse> ProcessControlRequestInternalAsync(ControlRequest request) { - ControlRequestInfo requestInfo = null; + ControlRequestInfo? requestInfo = null; - using (var streamReader = new StreamReader(request.InputXml)) + using (var streamReader = new StreamReader(request.InputXml, Encoding.UTF8)) { - var readerSettings = XmlReaderSettingsFactory.Create(false); - - readerSettings.CheckCharacters = false; - readerSettings.IgnoreProcessingInstructions = true; - readerSettings.IgnoreComments = true; - - using (var reader = XmlReader.Create(streamReader, readerSettings)) + var readerSettings = new XmlReaderSettings() { - requestInfo = ParseRequest(reader); - } + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true, + Async = true + }; + + using var reader = XmlReader.Create(streamReader, readerSettings); + requestInfo = await ParseRequestAsync(reader).ConfigureAwait(false); } - _logger.LogDebug("Received control request {0}", requestInfo.LocalName); - - var result = GetResult(requestInfo.LocalName, requestInfo.Headers); + Logger.LogDebug("Received control request {0}", requestInfo.LocalName); var settings = new XmlWriterSettings { @@ -89,17 +78,14 @@ namespace Emby.Dlna.Service { writer.WriteStartDocument(true); - writer.WriteStartElement("SOAP-ENV", "Envelope", NS_SOAPENV); - writer.WriteAttributeString(string.Empty, "encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/"); + writer.WriteStartElement("SOAP-ENV", "Envelope", NsSoapEnv); + writer.WriteAttributeString(string.Empty, "encodingStyle", NsSoapEnv, "http://schemas.xmlsoap.org/soap/encoding/"); - writer.WriteStartElement("SOAP-ENV", "Body", NS_SOAPENV); + writer.WriteStartElement("SOAP-ENV", "Body", NsSoapEnv); writer.WriteStartElement("u", requestInfo.LocalName + "Response", requestInfo.NamespaceURI); - foreach (var i in result) - { - writer.WriteStartElement(i.Key); - writer.WriteString(i.Value); - writer.WriteFullEndElement(); - } + + WriteResult(requestInfo.LocalName, requestInfo.Headers, writer); + writer.WriteFullEndElement(); writer.WriteFullEndElement(); @@ -107,25 +93,19 @@ namespace Emby.Dlna.Service writer.WriteEndDocument(); } - var xml = builder.ToString().Replace("xmlns:m=", "xmlns:u="); - - var controlResponse = new ControlResponse - { - Xml = xml, - IsSuccessful = true - }; + var xml = builder.ToString().Replace("xmlns:m=", "xmlns:u=", StringComparison.Ordinal); - //logger.LogDebug(xml); + var controlResponse = new ControlResponse(xml, true); controlResponse.Headers.Add("EXT", string.Empty); return controlResponse; } - private ControlRequestInfo ParseRequest(XmlReader reader) + private async Task<ControlRequestInfo> ParseRequestAsync(XmlReader reader) { - reader.MoveToContent(); - reader.Read(); + await reader.MoveToContentAsync().ConfigureAwait(false); + await reader.ReadAsync().ConfigureAwait(false); // Loop through each element while (!reader.EOF && reader.ReadState == ReadState.Interactive) @@ -138,74 +118,78 @@ namespace Emby.Dlna.Service { if (!reader.IsEmptyElement) { - using (var subReader = reader.ReadSubtree()) - { - return ParseBodyTag(subReader); - } + using var subReader = reader.ReadSubtree(); + return await ParseBodyTagAsync(subReader).ConfigureAwait(false); } else { - reader.Read(); + await reader.ReadAsync().ConfigureAwait(false); } + break; } + default: { - reader.Skip(); + await reader.SkipAsync().ConfigureAwait(false); break; } } } else { - reader.Read(); + await reader.ReadAsync().ConfigureAwait(false); } } - return new ControlRequestInfo(); + throw new EndOfStreamException("Stream ended but no body tag found."); } - private ControlRequestInfo ParseBodyTag(XmlReader reader) + private async Task<ControlRequestInfo> ParseBodyTagAsync(XmlReader reader) { - var result = new ControlRequestInfo(); + string? namespaceURI = null, localName = null; - reader.MoveToContent(); - reader.Read(); + await reader.MoveToContentAsync().ConfigureAwait(false); + await reader.ReadAsync().ConfigureAwait(false); // Loop through each element while (!reader.EOF && reader.ReadState == ReadState.Interactive) { if (reader.NodeType == XmlNodeType.Element) { - result.LocalName = reader.LocalName; - result.NamespaceURI = reader.NamespaceURI; + localName = reader.LocalName; + namespaceURI = reader.NamespaceURI; if (!reader.IsEmptyElement) { - using (var subReader = reader.ReadSubtree()) - { - ParseFirstBodyChild(subReader, result.Headers); - return result; - } + var result = new ControlRequestInfo(localName, namespaceURI); + using var subReader = reader.ReadSubtree(); + await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false); + return result; } else { - reader.Read(); + await reader.ReadAsync().ConfigureAwait(false); } } else { - reader.Read(); + await reader.ReadAsync().ConfigureAwait(false); } } - return result; + if (localName != null && namespaceURI != null) + { + return new ControlRequestInfo(localName, namespaceURI); + } + + throw new EndOfStreamException("Stream ended but no control found."); } - private void ParseFirstBodyChild(XmlReader reader, IDictionary<string, string> headers) + private async Task ParseFirstBodyChildAsync(XmlReader reader, IDictionary<string, string> headers) { - reader.MoveToContent(); - reader.Read(); + await reader.MoveToContentAsync().ConfigureAwait(false); + await reader.ReadAsync().ConfigureAwait(false); // Loop through each element while (!reader.EOF && reader.ReadState == ReadState.Interactive) @@ -213,23 +197,16 @@ namespace Emby.Dlna.Service if (reader.NodeType == XmlNodeType.Element) { // TODO: Should we be doing this here, or should it be handled earlier when decoding the request? - headers[reader.LocalName.RemoveDiacritics()] = reader.ReadElementContentAsString(); + headers[reader.LocalName.RemoveDiacritics()] = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); } else { - reader.Read(); + await reader.ReadAsync().ConfigureAwait(false); } } } - private class ControlRequestInfo - { - public string LocalName; - public string NamespaceURI; - public IDictionary<string, string> Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - } - - protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams); + protected abstract void WriteResult(string methodName, IReadOnlyDictionary<string, string> methodParams, XmlWriter xmlWriter); private void LogRequest(ControlRequest request) { @@ -238,10 +215,7 @@ namespace Emby.Dlna.Service return; } - var originalHeaders = request.Headers; - var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray()); - - _logger.LogDebug("Control request. Headers: {0}", headers); + Logger.LogDebug("Control request. Headers: {@Headers}", request.Headers); } private void LogResponse(ControlResponse response) @@ -251,11 +225,23 @@ namespace Emby.Dlna.Service return; } - var originalHeaders = response.Headers; - var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray()); - //builder.Append(response.Xml); + Logger.LogDebug("Control response. Headers: {@Headers}\n{Xml}", response.Headers, response.Xml); + } + + private class ControlRequestInfo + { + public ControlRequestInfo(string localName, string namespaceUri) + { + LocalName = localName; + NamespaceURI = namespaceUri; + Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); + } + + public string LocalName { get; set; } + + public string NamespaceURI { get; set; } - _logger.LogDebug("Control response. Headers: {0}", headers); + public Dictionary<string, string> Headers { get; } } } } |
