|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Xml;
|
|
|
|
|
using Emby.Dlna.Didl;
|
|
|
|
|
using MediaBrowser.Controller.Configuration;
|
|
|
|
@ -15,44 +16,34 @@ namespace Emby.Dlna.Service
|
|
|
|
|
{
|
|
|
|
|
private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
|
|
|
|
|
|
|
|
|
|
protected readonly IServerConfigurationManager Config;
|
|
|
|
|
protected readonly ILogger _logger;
|
|
|
|
|
protected IServerConfigurationManager Config { get; }
|
|
|
|
|
protected ILogger Logger { get; }
|
|
|
|
|
|
|
|
|
|
protected BaseControlHandler(IServerConfigurationManager config, ILogger logger)
|
|
|
|
|
{
|
|
|
|
|
Config = config;
|
|
|
|
|
_logger = logger;
|
|
|
|
|
Logger = logger;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ControlResponse ProcessControlRequest(ControlRequest request)
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
@ -69,19 +60,18 @@ namespace Emby.Dlna.Service
|
|
|
|
|
|
|
|
|
|
using (var reader = XmlReader.Create(streamReader, readerSettings))
|
|
|
|
|
{
|
|
|
|
|
requestInfo = ParseRequest(reader);
|
|
|
|
|
requestInfo = await ParseRequestAsync(reader).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_logger.LogDebug("Received control request {0}", requestInfo.LocalName);
|
|
|
|
|
Logger.LogDebug("Received control request {0}", requestInfo.LocalName);
|
|
|
|
|
|
|
|
|
|
var result = GetResult(requestInfo.LocalName, requestInfo.Headers);
|
|
|
|
|
|
|
|
|
|
var settings = new XmlWriterSettings
|
|
|
|
|
{
|
|
|
|
|
Encoding = Encoding.UTF8,
|
|
|
|
|
CloseOutput = false,
|
|
|
|
|
Async = true
|
|
|
|
|
CloseOutput = false
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
|
|
|
|
@ -116,17 +106,15 @@ namespace Emby.Dlna.Service
|
|
|
|
|
IsSuccessful = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//logger.LogDebug(xml);
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
@ -141,37 +129,38 @@ namespace Emby.Dlna.Service
|
|
|
|
|
{
|
|
|
|
|
using (var subReader = reader.ReadSubtree())
|
|
|
|
|
{
|
|
|
|
|
return ParseBodyTag(subReader);
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ControlRequestInfo ParseBodyTag(XmlReader reader)
|
|
|
|
|
private async Task<ControlRequestInfo> ParseBodyTagAsync(XmlReader reader)
|
|
|
|
|
{
|
|
|
|
|
var result = new ControlRequestInfo();
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
@ -185,28 +174,28 @@ namespace Emby.Dlna.Service
|
|
|
|
|
{
|
|
|
|
|
using (var subReader = reader.ReadSubtree())
|
|
|
|
|
{
|
|
|
|
|
ParseFirstBodyChild(subReader, result.Headers);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
@ -214,20 +203,20 @@ 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);
|
|
|
|
|
public string LocalName { get; set; }
|
|
|
|
|
public string NamespaceURI { get; set; }
|
|
|
|
|
public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams);
|
|
|
|
@ -239,10 +228,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: {@Header}", request.Headers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LogResponse(ControlResponse response)
|
|
|
|
@ -252,11 +238,7 @@ 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: {0}", headers);
|
|
|
|
|
Logger.LogDebug("Control response. Headers: {@Headers}\n{Xml}", response.Headers, response.Xml);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|