jellyfin/Emby.Dlna/Service/BaseControlHandler.cs

262 lines
8.6 KiB
C#
Raw Normal View History

using System;
2016-10-29 22:22:20 +00:00
using System.Collections.Generic;
2016-11-04 08:31:05 +00:00
using System.IO;
2016-10-29 22:22:20 +00:00
using System.Linq;
using System.Text;
using System.Xml;
2016-11-04 08:31:05 +00:00
using Emby.Dlna.Didl;
2019-01-13 19:16:19 +00:00
using MediaBrowser.Controller.Configuration;
2016-12-04 21:30:38 +00:00
using MediaBrowser.Controller.Extensions;
2016-11-04 08:31:05 +00:00
using MediaBrowser.Model.Xml;
2019-01-13 19:16:19 +00:00
using Microsoft.Extensions.Logging;
2016-10-29 22:22:20 +00:00
2016-10-29 22:34:54 +00:00
namespace Emby.Dlna.Service
2016-10-29 22:22:20 +00:00
{
public abstract class BaseControlHandler
{
private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
2016-12-03 23:57:34 +00:00
2016-10-29 22:22:20 +00:00
protected readonly IServerConfigurationManager Config;
protected readonly ILogger _logger;
2016-11-04 08:31:05 +00:00
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
2016-10-29 22:22:20 +00:00
2016-11-04 08:31:05 +00:00
protected BaseControlHandler(IServerConfigurationManager config, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
2016-10-29 22:22:20 +00:00
{
Config = config;
_logger = logger;
2016-11-04 08:31:05 +00:00
XmlReaderSettingsFactory = xmlReaderSettingsFactory;
2016-10-29 22:22:20 +00:00
}
public ControlResponse ProcessControlRequest(ControlRequest request)
{
try
{
var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLog;
if (enableDebugLogging)
{
LogRequest(request);
}
var response = ProcessControlRequestInternal(request);
if (enableDebugLogging)
{
LogResponse(response);
}
return response;
}
catch (Exception ex)
{
2018-12-20 12:11:26 +00:00
_logger.LogError(ex, "Error processing control request");
2016-10-29 22:22:20 +00:00
return new ControlErrorHandler().GetResponse(ex);
}
}
private ControlResponse ProcessControlRequestInternal(ControlRequest request)
{
2016-11-04 08:31:05 +00:00
ControlRequestInfo requestInfo = null;
2016-10-29 22:22:20 +00:00
2016-11-04 08:31:05 +00:00
using (var streamReader = new StreamReader(request.InputXml))
2016-10-29 22:22:20 +00:00
{
2016-11-04 08:31:05 +00:00
var readerSettings = XmlReaderSettingsFactory.Create(false);
readerSettings.CheckCharacters = false;
readerSettings.IgnoreProcessingInstructions = true;
readerSettings.IgnoreComments = true;
using (var reader = XmlReader.Create(streamReader, readerSettings))
2016-10-29 22:22:20 +00:00
{
2016-11-04 08:31:05 +00:00
requestInfo = ParseRequest(reader);
2016-10-29 22:22:20 +00:00
}
}
_logger.LogDebug("Received control request {0}", requestInfo.LocalName);
2016-10-29 22:22:20 +00:00
2016-11-04 08:31:05 +00:00
var result = GetResult(requestInfo.LocalName, requestInfo.Headers);
2016-10-29 22:22:20 +00:00
2016-11-04 08:31:05 +00:00
var settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
CloseOutput = false
};
2016-10-29 22:22:20 +00:00
2016-11-04 08:31:05 +00:00
StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
2016-10-29 22:22:20 +00:00
2019-01-13 20:37:13 +00:00
using (var writer = XmlWriter.Create(builder, settings))
2016-10-29 22:22:20 +00:00
{
2016-11-04 08:31:05 +00:00
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", "Body", NS_SOAPENV);
writer.WriteStartElement("u", requestInfo.LocalName + "Response", requestInfo.NamespaceURI);
foreach (var i in result)
{
writer.WriteStartElement(i.Key);
writer.WriteString(i.Value);
2016-11-06 17:30:44 +00:00
writer.WriteFullEndElement();
2016-11-04 08:31:05 +00:00
}
2016-11-06 17:30:44 +00:00
writer.WriteFullEndElement();
writer.WriteFullEndElement();
2016-11-04 08:31:05 +00:00
2016-11-06 17:30:44 +00:00
writer.WriteFullEndElement();
2016-11-04 08:31:05 +00:00
writer.WriteEndDocument();
2016-10-29 22:22:20 +00:00
}
2016-11-04 08:31:05 +00:00
var xml = builder.ToString().Replace("xmlns:m=", "xmlns:u=");
2016-12-03 23:57:34 +00:00
2016-10-29 22:22:20 +00:00
var controlResponse = new ControlResponse
{
Xml = xml,
IsSuccessful = true
};
//logger.LogDebug(xml);
2016-10-29 22:22:20 +00:00
controlResponse.Headers.Add("EXT", string.Empty);
return controlResponse;
}
2016-11-04 08:31:05 +00:00
private ControlRequestInfo ParseRequest(XmlReader reader)
{
reader.MoveToContent();
reader.Read();
// Loop through each element
2016-12-03 21:46:06 +00:00
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
2016-11-04 08:31:05 +00:00
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.LocalName)
{
case "Body":
{
2016-12-03 23:57:34 +00:00
if (!reader.IsEmptyElement)
{
using (var subReader = reader.ReadSubtree())
{
return ParseBodyTag(subReader);
}
}
else
{
reader.Read();
}
break;
2016-11-04 08:31:05 +00:00
}
default:
{
reader.Skip();
break;
}
}
}
else
{
reader.Read();
}
}
return new ControlRequestInfo();
}
private ControlRequestInfo ParseBodyTag(XmlReader reader)
{
var result = new ControlRequestInfo();
reader.MoveToContent();
reader.Read();
// Loop through each element
2016-12-03 21:46:06 +00:00
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
2016-11-04 08:31:05 +00:00
{
if (reader.NodeType == XmlNodeType.Element)
{
result.LocalName = reader.LocalName;
result.NamespaceURI = reader.NamespaceURI;
2016-12-03 23:57:34 +00:00
if (!reader.IsEmptyElement)
2016-11-04 08:31:05 +00:00
{
2016-12-03 23:57:34 +00:00
using (var subReader = reader.ReadSubtree())
{
2016-12-04 21:30:38 +00:00
ParseFirstBodyChild(subReader, result.Headers);
2016-12-03 23:57:34 +00:00
return result;
}
}
else
{
reader.Read();
2016-11-04 08:31:05 +00:00
}
}
else
{
reader.Read();
}
}
return result;
}
2019-01-13 19:16:19 +00:00
private void ParseFirstBodyChild(XmlReader reader, IDictionary<string, string> headers)
2016-11-04 08:31:05 +00:00
{
reader.MoveToContent();
reader.Read();
// Loop through each element
2016-12-03 21:46:06 +00:00
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
2016-11-04 08:31:05 +00:00
{
if (reader.NodeType == XmlNodeType.Element)
{
2016-12-04 21:30:38 +00:00
// TODO: Should we be doing this here, or should it be handled earlier when decoding the request?
headers[reader.LocalName.RemoveDiacritics()] = reader.ReadElementContentAsString();
2016-11-04 08:31:05 +00:00
}
else
{
reader.Read();
}
}
}
private class ControlRequestInfo
{
public string LocalName;
public string NamespaceURI;
2019-01-13 19:16:19 +00:00
public IDictionary<string, string> Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
2016-11-04 08:31:05 +00:00
}
2016-12-04 21:30:38 +00:00
protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams);
2016-10-29 22:22:20 +00:00
private void LogRequest(ControlRequest request)
{
if (!Config.GetDlnaConfiguration().EnableDebugLog)
{
return;
}
2016-10-29 22:22:20 +00:00
var originalHeaders = request.Headers;
2018-12-28 15:48:26 +00:00
var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
2016-10-29 22:22:20 +00:00
_logger.LogDebug("Control request. Headers: {0}", headers);
2016-10-29 22:22:20 +00:00
}
private void LogResponse(ControlResponse response)
{
if (!Config.GetDlnaConfiguration().EnableDebugLog)
{
return;
}
2016-10-29 22:22:20 +00:00
var originalHeaders = response.Headers;
2018-09-12 17:26:21 +00:00
var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
//builder.Append(response.Xml);
2016-10-29 22:22:20 +00:00
_logger.LogDebug("Control response. Headers: {0}", headers);
2016-10-29 22:22:20 +00:00
}
}
}