add request logging

This commit is contained in:
Luke Pulverenti 2016-12-04 16:30:38 -05:00
parent 7ed6c67db0
commit 401a6b8f4a
12 changed files with 96 additions and 237 deletions

View file

@ -4,6 +4,7 @@ using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading.Tasks; using System.Threading.Tasks;
using Emby.Common.Implementations.Networking;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
@ -18,11 +19,6 @@ namespace Emby.Common.Implementations.Net
// but that wasn't really the point so kept to YAGNI principal for now, even if the // but that wasn't really the point so kept to YAGNI principal for now, even if the
// interfaces are a bit ugly, specific and make assumptions. // interfaces are a bit ugly, specific and make assumptions.
/// <summary>
/// Used by RSSDP components to create implementations of the <see cref="IUdpSocket"/> interface, to perform platform agnostic socket communications.
/// </summary>
private IPAddress _LocalIP;
private readonly ILogger _logger; private readonly ILogger _logger;
public SocketFactory(ILogger logger) public SocketFactory(ILogger logger)
@ -33,7 +29,6 @@ namespace Emby.Common.Implementations.Net
} }
_logger = logger; _logger = logger;
_LocalIP = IPAddress.Any;
} }
public ISocket CreateSocket(IpAddressFamily family, MediaBrowser.Model.Net.SocketType socketType, MediaBrowser.Model.Net.ProtocolType protocolType, bool dualMode) public ISocket CreateSocket(IpAddressFamily family, MediaBrowser.Model.Net.SocketType socketType, MediaBrowser.Model.Net.ProtocolType protocolType, bool dualMode)
@ -66,7 +61,7 @@ namespace Emby.Common.Implementations.Net
try try
{ {
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
return new UdpSocket(retVal, localPort, _LocalIP); return new UdpSocket(retVal, localPort, IPAddress.Any);
} }
catch catch
{ {
@ -80,9 +75,8 @@ namespace Emby.Common.Implementations.Net
/// <summary> /// <summary>
/// Creates a new UDP socket that is a member of the SSDP multicast local admin group and binds it to the specified local port. /// Creates a new UDP socket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
/// </summary> /// </summary>
/// <param name="localPort">An integer specifying the local port to bind the socket to.</param>
/// <returns>An implementation of the <see cref="IUdpSocket"/> interface used by RSSDP components to perform socket operations.</returns> /// <returns>An implementation of the <see cref="IUdpSocket"/> interface used by RSSDP components to perform socket operations.</returns>
public IUdpSocket CreateSsdpUdpSocket(int localPort) public IUdpSocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort)
{ {
if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort"); if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
@ -91,8 +85,11 @@ namespace Emby.Common.Implementations.Net
{ {
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4); retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.255.255.250"), _LocalIP));
return new UdpSocket(retVal, localPort, _LocalIP); var localIp = NetworkManager.ToIPAddress(localIpAddress);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.255.255.250"), localIp));
return new UdpSocket(retVal, localPort, localIp);
} }
catch catch
{ {
@ -134,10 +131,13 @@ namespace Emby.Common.Implementations.Net
//retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); //retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive); retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse(ipAddress), _LocalIP));
var localIp = IPAddress.Any;
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse(ipAddress), localIp));
retVal.MulticastLoopback = true; retVal.MulticastLoopback = true;
return new UdpSocket(retVal, localPort, _LocalIP); return new UdpSocket(retVal, localPort, localIp);
} }
catch catch
{ {

View file

@ -20,7 +20,6 @@ namespace Emby.Common.Implementations.Net
private Socket _Socket; private Socket _Socket;
private int _LocalPort; private int _LocalPort;
#endregion #endregion
#region Constructors #region Constructors
@ -31,12 +30,19 @@ namespace Emby.Common.Implementations.Net
_Socket = socket; _Socket = socket;
_LocalPort = localPort; _LocalPort = localPort;
LocalIPAddress = NetworkManager.ToIpAddressInfo(ip);
_Socket.Bind(new IPEndPoint(ip, _LocalPort)); _Socket.Bind(new IPEndPoint(ip, _LocalPort));
} }
#endregion #endregion
public IpAddressInfo LocalIPAddress
{
get;
private set;
}
#region IUdpSocket Members #region IUdpSocket Members
public Task<SocketReceiveResult> ReceiveAsync() public Task<SocketReceiveResult> ReceiveAsync()
@ -50,18 +56,18 @@ namespace Emby.Common.Implementations.Net
state.TaskCompletionSource = tcs; state.TaskCompletionSource = tcs;
#if NETSTANDARD1_6 #if NETSTANDARD1_6
_Socket.ReceiveFromAsync(new ArraySegment<Byte>(state.Buffer),SocketFlags.None, state.EndPoint) _Socket.ReceiveFromAsync(new ArraySegment<Byte>(state.Buffer),SocketFlags.None, state.RemoteEndPoint)
.ContinueWith((task, asyncState) => .ContinueWith((task, asyncState) =>
{ {
if (task.Status != TaskStatus.Faulted) if (task.Status != TaskStatus.Faulted)
{ {
var receiveState = asyncState as AsyncReceiveState; var receiveState = asyncState as AsyncReceiveState;
receiveState.EndPoint = task.Result.RemoteEndPoint; receiveState.RemoteEndPoint = task.Result.RemoteEndPoint;
ProcessResponse(receiveState, () => task.Result.ReceivedBytes); ProcessResponse(receiveState, () => task.Result.ReceivedBytes, LocalIPAddress);
} }
}, state); }, state);
#else #else
_Socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.EndPoint, ProcessResponse, state); _Socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.RemoteEndPoint, ProcessResponse, state);
#endif #endif
return tcs.Task; return tcs.Task;
@ -74,6 +80,8 @@ namespace Emby.Common.Implementations.Net
if (buffer == null) throw new ArgumentNullException("messageData"); if (buffer == null) throw new ArgumentNullException("messageData");
if (endPoint == null) throw new ArgumentNullException("endPoint"); if (endPoint == null) throw new ArgumentNullException("endPoint");
var ipEndPoint = NetworkManager.ToIPEndPoint(endPoint);
#if NETSTANDARD1_6 #if NETSTANDARD1_6
if (size != buffer.Length) if (size != buffer.Length)
@ -83,14 +91,14 @@ namespace Emby.Common.Implementations.Net
buffer = copy; buffer = copy;
} }
_Socket.SendTo(buffer, new IPEndPoint(IPAddress.Parse(endPoint.IpAddress.ToString()), endPoint.Port)); _Socket.SendTo(buffer, ipEndPoint);
return Task.FromResult(true); return Task.FromResult(true);
#else #else
var taskSource = new TaskCompletionSource<bool>(); var taskSource = new TaskCompletionSource<bool>();
try try
{ {
_Socket.BeginSendTo(buffer, 0, size, SocketFlags.None, new System.Net.IPEndPoint(IPAddress.Parse(endPoint.IpAddress.ToString()), endPoint.Port), result => _Socket.BeginSendTo(buffer, 0, size, SocketFlags.None, ipEndPoint, result =>
{ {
try try
{ {
@ -109,7 +117,7 @@ namespace Emby.Common.Implementations.Net
taskSource.TrySetException(ex); taskSource.TrySetException(ex);
} }
//_Socket.SendTo(messageData, new System.Net.IPEndPoint(IPAddress.Parse(endPoint.IPAddress), endPoint.Port)); //_Socket.SendTo(messageData, new System.Net.IPEndPoint(IPAddress.Parse(RemoteEndPoint.IPAddress), RemoteEndPoint.Port));
return taskSource.Task; return taskSource.Task;
#endif #endif
@ -133,19 +141,20 @@ namespace Emby.Common.Implementations.Net
#region Private Methods #region Private Methods
private static void ProcessResponse(AsyncReceiveState state, Func<int> receiveData) private static void ProcessResponse(AsyncReceiveState state, Func<int> receiveData, IpAddressInfo localIpAddress)
{ {
try try
{ {
var bytesRead = receiveData(); var bytesRead = receiveData();
var ipEndPoint = state.EndPoint as IPEndPoint; var ipEndPoint = state.RemoteEndPoint as IPEndPoint;
state.TaskCompletionSource.SetResult( state.TaskCompletionSource.SetResult(
new SocketReceiveResult() new SocketReceiveResult
{ {
Buffer = state.Buffer, Buffer = state.Buffer,
ReceivedBytes = bytesRead, ReceivedBytes = bytesRead,
RemoteEndPoint = ToIpEndPointInfo(ipEndPoint) RemoteEndPoint = ToIpEndPointInfo(ipEndPoint),
LocalIPAddress = localIpAddress
} }
); );
} }
@ -182,15 +191,16 @@ namespace Emby.Common.Implementations.Net
var state = asyncResult.AsyncState as AsyncReceiveState; var state = asyncResult.AsyncState as AsyncReceiveState;
try try
{ {
var bytesRead = state.Socket.EndReceiveFrom(asyncResult, ref state.EndPoint); var bytesRead = state.Socket.EndReceiveFrom(asyncResult, ref state.RemoteEndPoint);
var ipEndPoint = state.EndPoint as IPEndPoint; var ipEndPoint = state.RemoteEndPoint as IPEndPoint;
state.TaskCompletionSource.SetResult( state.TaskCompletionSource.SetResult(
new SocketReceiveResult new SocketReceiveResult
{ {
Buffer = state.Buffer, Buffer = state.Buffer,
ReceivedBytes = bytesRead, ReceivedBytes = bytesRead,
RemoteEndPoint = ToIpEndPointInfo(ipEndPoint) RemoteEndPoint = ToIpEndPointInfo(ipEndPoint),
LocalIPAddress = LocalIPAddress
} }
); );
} }
@ -211,13 +221,13 @@ namespace Emby.Common.Implementations.Net
private class AsyncReceiveState private class AsyncReceiveState
{ {
public AsyncReceiveState(Socket socket, EndPoint endPoint) public AsyncReceiveState(Socket socket, EndPoint remoteEndPoint)
{ {
this.Socket = socket; this.Socket = socket;
this.EndPoint = endPoint; this.RemoteEndPoint = remoteEndPoint;
} }
public EndPoint EndPoint; public EndPoint RemoteEndPoint;
public byte[] Buffer = new byte[8192]; public byte[] Buffer = new byte[8192];
public Socket Socket { get; private set; } public Socket Socket { get; private set; }

View file

@ -27,7 +27,7 @@ namespace Emby.Common.Implementations.Networking
private List<IpAddressInfo> _localIpAddresses; private List<IpAddressInfo> _localIpAddresses;
private readonly object _localIpAddressSyncLock = new object(); private readonly object _localIpAddressSyncLock = new object();
public IEnumerable<IpAddressInfo> GetLocalIpAddresses() public List<IpAddressInfo> GetLocalIpAddresses()
{ {
const int cacheMinutes = 5; const int cacheMinutes = 5;

View file

@ -14,7 +14,7 @@ namespace Emby.Dlna.ConnectionManager
{ {
private readonly DeviceProfile _profile; private readonly DeviceProfile _profile;
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams) protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
{ {
if (string.Equals(methodName, "GetProtocolInfo", StringComparison.OrdinalIgnoreCase)) if (string.Equals(methodName, "GetProtocolInfo", StringComparison.OrdinalIgnoreCase))
{ {
@ -26,7 +26,7 @@ namespace Emby.Dlna.ConnectionManager
private IEnumerable<KeyValuePair<string, string>> HandleGetProtocolInfo() private IEnumerable<KeyValuePair<string, string>> HandleGetProtocolInfo()
{ {
return new Headers(true) return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{ {
{ "Source", _profile.ProtocolInfo }, { "Source", _profile.ProtocolInfo },
{ "Sink", "" } { "Sink", "" }

View file

@ -65,7 +65,7 @@ namespace Emby.Dlna.ContentDirectory
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager, mediaEncoder); _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager, mediaEncoder);
} }
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams) protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
{ {
var deviceId = "test"; var deviceId = "test";
@ -118,17 +118,20 @@ namespace Emby.Dlna.ContentDirectory
_userDataManager.SaveUserData(user.Id, item, userdata, UserDataSaveReason.TogglePlayed, _userDataManager.SaveUserData(user.Id, item, userdata, UserDataSaveReason.TogglePlayed,
CancellationToken.None); CancellationToken.None);
return new Headers(); return new Dictionary<string,string>(StringComparer.OrdinalIgnoreCase);
} }
private IEnumerable<KeyValuePair<string, string>> HandleGetSearchCapabilities() private IEnumerable<KeyValuePair<string, string>> HandleGetSearchCapabilities()
{ {
return new Headers(true) { { "SearchCaps", "res@resolution,res@size,res@duration,dc:title,dc:creator,upnp:actor,upnp:artist,upnp:genre,upnp:album,dc:date,upnp:class,@id,@refID,@protocolInfo,upnp:author,dc:description,pv:avKeywords" } }; return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "SearchCaps", "res@resolution,res@size,res@duration,dc:title,dc:creator,upnp:actor,upnp:artist,upnp:genre,upnp:album,dc:date,upnp:class,@id,@refID,@protocolInfo,upnp:author,dc:description,pv:avKeywords" }
};
} }
private IEnumerable<KeyValuePair<string, string>> HandleGetSortCapabilities() private IEnumerable<KeyValuePair<string, string>> HandleGetSortCapabilities()
{ {
return new Headers(true) return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{ {
{ "SortCaps", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating" } { "SortCaps", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating" }
}; };
@ -136,7 +139,7 @@ namespace Emby.Dlna.ContentDirectory
private IEnumerable<KeyValuePair<string, string>> HandleGetSortExtensionCapabilities() private IEnumerable<KeyValuePair<string, string>> HandleGetSortExtensionCapabilities()
{ {
return new Headers(true) return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{ {
{ "SortExtensionCaps", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating" } { "SortExtensionCaps", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating" }
}; };
@ -144,14 +147,14 @@ namespace Emby.Dlna.ContentDirectory
private IEnumerable<KeyValuePair<string, string>> HandleGetSystemUpdateID() private IEnumerable<KeyValuePair<string, string>> HandleGetSystemUpdateID()
{ {
var headers = new Headers(true); var headers = new Dictionary<string,string>(StringComparer.OrdinalIgnoreCase);
headers.Add("Id", _systemUpdateId.ToString(_usCulture)); headers.Add("Id", _systemUpdateId.ToString(_usCulture));
return headers; return headers;
} }
private IEnumerable<KeyValuePair<string, string>> HandleGetFeatureList() private IEnumerable<KeyValuePair<string, string>> HandleGetFeatureList()
{ {
return new Headers(true) return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{ {
{ "FeatureList", GetFeatureListXml() } { "FeatureList", GetFeatureListXml() }
}; };
@ -159,7 +162,7 @@ namespace Emby.Dlna.ContentDirectory
private IEnumerable<KeyValuePair<string, string>> HandleXGetFeatureList() private IEnumerable<KeyValuePair<string, string>> HandleXGetFeatureList()
{ {
return new Headers(true) return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{ {
{ "FeatureList", GetFeatureListXml() } { "FeatureList", GetFeatureListXml() }
}; };
@ -183,12 +186,24 @@ namespace Emby.Dlna.ContentDirectory
return builder.ToString(); return builder.ToString();
} }
private async Task<IEnumerable<KeyValuePair<string, string>>> HandleBrowse(Headers sparams, User user, string deviceId) public string GetValueOrDefault(IDictionary<string, string> sparams, string key, string defaultValue)
{
string val;
if (sparams.TryGetValue(key, out val))
{
return val;
}
return defaultValue;
}
private async Task<IEnumerable<KeyValuePair<string, string>>> HandleBrowse(IDictionary<string, string> sparams, User user, string deviceId)
{ {
var id = sparams["ObjectID"]; var id = sparams["ObjectID"];
var flag = sparams["BrowseFlag"]; var flag = sparams["BrowseFlag"];
var filter = new Filter(sparams.GetValueOrDefault("Filter", "*")); var filter = new Filter(GetValueOrDefault(sparams, "Filter", "*"));
var sortCriteria = new SortCriteria(sparams.GetValueOrDefault("SortCriteria", "")); var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", ""));
var provided = 0; var provided = 0;
@ -294,11 +309,11 @@ namespace Emby.Dlna.ContentDirectory
}; };
} }
private async Task<IEnumerable<KeyValuePair<string, string>>> HandleSearch(Headers sparams, User user, string deviceId) private async Task<IEnumerable<KeyValuePair<string, string>>> HandleSearch(IDictionary<string, string> sparams, User user, string deviceId)
{ {
var searchCriteria = new SearchCriteria(sparams.GetValueOrDefault("SearchCriteria", "")); var searchCriteria = new SearchCriteria(GetValueOrDefault(sparams, "SearchCriteria", ""));
var sortCriteria = new SortCriteria(sparams.GetValueOrDefault("SortCriteria", "")); var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", ""));
var filter = new Filter(sparams.GetValueOrDefault("Filter", "*")); var filter = new Filter(GetValueOrDefault(sparams, "Filter", "*"));
// sort example: dc:title, dc:date // sort example: dc:title, dc:date

View file

@ -152,7 +152,6 @@
<Compile Include="Profiles\XboxOneProfile.cs" /> <Compile Include="Profiles\XboxOneProfile.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Server\DescriptionXmlBuilder.cs" /> <Compile Include="Server\DescriptionXmlBuilder.cs" />
<Compile Include="Server\Headers.cs" />
<Compile Include="Server\UpnpDevice.cs" /> <Compile Include="Server\UpnpDevice.cs" />
<Compile Include="Service\BaseControlHandler.cs" /> <Compile Include="Service\BaseControlHandler.cs" />
<Compile Include="Service\BaseService.cs" /> <Compile Include="Service\BaseService.cs" />

View file

@ -54,6 +54,7 @@ namespace Emby.Dlna.Main
private readonly ITimerFactory _timerFactory; private readonly ITimerFactory _timerFactory;
private readonly ISocketFactory _socketFactory; private readonly ISocketFactory _socketFactory;
private readonly IEnvironmentInfo _environmentInfo; private readonly IEnvironmentInfo _environmentInfo;
private readonly INetworkManager _networkManager;
private ISsdpCommunicationsServer _communicationsServer; private ISsdpCommunicationsServer _communicationsServer;
@ -69,7 +70,7 @@ namespace Emby.Dlna.Main
IUserDataManager userDataManager, IUserDataManager userDataManager,
ILocalizationManager localization, ILocalizationManager localization,
IMediaSourceManager mediaSourceManager, IMediaSourceManager mediaSourceManager,
IDeviceDiscovery deviceDiscovery, IMediaEncoder mediaEncoder, ISocketFactory socketFactory, ITimerFactory timerFactory, IEnvironmentInfo environmentInfo) IDeviceDiscovery deviceDiscovery, IMediaEncoder mediaEncoder, ISocketFactory socketFactory, ITimerFactory timerFactory, IEnvironmentInfo environmentInfo, INetworkManager networkManager)
{ {
_config = config; _config = config;
_appHost = appHost; _appHost = appHost;
@ -87,6 +88,7 @@ namespace Emby.Dlna.Main
_socketFactory = socketFactory; _socketFactory = socketFactory;
_timerFactory = timerFactory; _timerFactory = timerFactory;
_environmentInfo = environmentInfo; _environmentInfo = environmentInfo;
_networkManager = networkManager;
_logger = logManager.GetLogger("Dlna"); _logger = logManager.GetLogger("Dlna");
} }
@ -156,7 +158,7 @@ namespace Emby.Dlna.Main
{ {
if (_communicationsServer == null) if (_communicationsServer == null)
{ {
_communicationsServer = new SsdpCommunicationsServer(_socketFactory) _communicationsServer = new SsdpCommunicationsServer(_socketFactory, _networkManager, _logger)
{ {
IsShared = true IsShared = true
}; };

View file

@ -11,7 +11,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
{ {
public class ControlHandler : BaseControlHandler public class ControlHandler : BaseControlHandler
{ {
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams) protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
{ {
if (string.Equals(methodName, "IsAuthorized", StringComparison.OrdinalIgnoreCase)) if (string.Equals(methodName, "IsAuthorized", StringComparison.OrdinalIgnoreCase))
return HandleIsAuthorized(); return HandleIsAuthorized();
@ -23,7 +23,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
private IEnumerable<KeyValuePair<string, string>> HandleIsAuthorized() private IEnumerable<KeyValuePair<string, string>> HandleIsAuthorized()
{ {
return new Headers(true) return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{ {
{ "Result", "1" } { "Result", "1" }
}; };
@ -31,7 +31,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
private IEnumerable<KeyValuePair<string, string>> HandleIsValidated() private IEnumerable<KeyValuePair<string, string>> HandleIsValidated()
{ {
return new Headers(true) return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{ {
{ "Result", "1" } { "Result", "1" }
}; };

View file

@ -1,169 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Emby.Dlna.Server
{
public class Headers : IDictionary<string, string>
{
private readonly bool _asIs = false;
private readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
private readonly static Regex Validator = new Regex(@"^[a-z\d][a-z\d_.-]+$", RegexOptions.IgnoreCase);
public Headers(bool asIs)
{
_asIs = asIs;
}
public Headers()
: this(asIs: false)
{
}
public int Count
{
get
{
return _dict.Count;
}
}
public string HeaderBlock
{
get
{
var hb = new StringBuilder();
foreach (var h in this)
{
hb.AppendFormat("{0}: {1}\r\n", h.Key, h.Value);
}
return hb.ToString();
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public ICollection<string> Keys
{
get
{
return _dict.Keys;
}
}
public ICollection<string> Values
{
get
{
return _dict.Values;
}
}
public string this[string key]
{
get
{
return _dict[Normalize(key)];
}
set
{
_dict[Normalize(key)] = value;
}
}
private string Normalize(string header)
{
if (!_asIs)
{
header = header.ToLower();
}
header = header.Trim();
if (!Validator.IsMatch(header))
{
throw new ArgumentException("Invalid header: " + header);
}
return header;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _dict.GetEnumerator();
}
public void Add(KeyValuePair<string, string> item)
{
Add(item.Key, item.Value);
}
public void Add(string key, string value)
{
_dict.Add(Normalize(key), value);
}
public void Clear()
{
_dict.Clear();
}
public bool Contains(KeyValuePair<string, string> item)
{
var p = new KeyValuePair<string, string>(Normalize(item.Key), item.Value);
return _dict.Contains(p);
}
public bool ContainsKey(string key)
{
return _dict.ContainsKey(Normalize(key));
}
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return _dict.GetEnumerator();
}
public bool Remove(string key)
{
return _dict.Remove(Normalize(key));
}
public bool Remove(KeyValuePair<string, string> item)
{
return Remove(item.Key);
}
public override string ToString()
{
return string.Format("({0})", string.Join(", ", (from x in _dict
select string.Format("{0}={1}", x.Key, x.Value))));
}
public bool TryGetValue(string key, out string value)
{
return _dict.TryGetValue(Normalize(key), out value);
}
public string GetValueOrDefault(string key, string defaultValue)
{
string val;
if (TryGetValue(key, out val))
{
return val;
}
return defaultValue;
}
}
}

View file

@ -9,6 +9,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Xml; using System.Xml;
using Emby.Dlna.Didl; using Emby.Dlna.Didl;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Xml; using MediaBrowser.Model.Xml;
namespace Emby.Dlna.Service namespace Emby.Dlna.Service
@ -185,8 +186,7 @@ namespace Emby.Dlna.Service
{ {
using (var subReader = reader.ReadSubtree()) using (var subReader = reader.ReadSubtree())
{ {
result.Headers = ParseFirstBodyChild(subReader); ParseFirstBodyChild(subReader, result.Headers);
return result; return result;
} }
} }
@ -204,10 +204,8 @@ namespace Emby.Dlna.Service
return result; return result;
} }
private Headers ParseFirstBodyChild(XmlReader reader) private void ParseFirstBodyChild(XmlReader reader, IDictionary<string,string> headers)
{ {
var result = new Headers();
reader.MoveToContent(); reader.MoveToContent();
reader.Read(); reader.Read();
@ -216,25 +214,24 @@ namespace Emby.Dlna.Service
{ {
if (reader.NodeType == XmlNodeType.Element) if (reader.NodeType == XmlNodeType.Element)
{ {
result.Add(reader.LocalName, reader.ReadElementContentAsString()); // TODO: Should we be doing this here, or should it be handled earlier when decoding the request?
headers[reader.LocalName.RemoveDiacritics()] = reader.ReadElementContentAsString();
} }
else else
{ {
reader.Read(); reader.Read();
} }
} }
return result;
} }
private class ControlRequestInfo private class ControlRequestInfo
{ {
public string LocalName; public string LocalName;
public string NamespaceURI; public string NamespaceURI;
public Headers Headers = new Headers(); public IDictionary<string, string> Headers = new Dictionary<string,string>(StringComparer.OrdinalIgnoreCase);
} }
protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams); protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams);
private void LogRequest(ControlRequest request) private void LogRequest(ControlRequest request)
{ {

View file

@ -518,7 +518,7 @@ namespace Emby.Server.Implementations.HttpServer
return; return;
} }
var handler = HttpHandlerFactory.GetHandler(httpReq); var handler = HttpHandlerFactory.GetHandler(httpReq, _logger);
if (handler != null) if (handler != null)
{ {

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using ServiceStack.Host; using ServiceStack.Host;
@ -9,12 +10,16 @@ namespace ServiceStack
public class HttpHandlerFactory public class HttpHandlerFactory
{ {
// Entry point for HttpListener // Entry point for HttpListener
public static RestHandler GetHandler(IHttpRequest httpReq) public static RestHandler GetHandler(IHttpRequest httpReq, ILogger logger)
{ {
var pathInfo = httpReq.PathInfo; var pathInfo = httpReq.PathInfo;
var pathParts = pathInfo.TrimStart('/').Split('/'); var pathParts = pathInfo.TrimStart('/').Split('/');
if (pathParts.Length == 0) return null; if (pathParts.Length == 0)
{
logger.Error("Path parts empty for PathInfo: {0}, Url: {1}", pathInfo, httpReq.RawUrl);
return null;
}
string contentType; string contentType;
var restPath = RestHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, out contentType); var restPath = RestHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, out contentType);