Merge pull request #2855 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2017-08-30 14:53:37 -04:00 committed by GitHub
commit 00cb873164
18 changed files with 142 additions and 146 deletions

View File

@ -1614,7 +1614,7 @@ namespace Emby.Server.Implementations
{
try
{
ServerManager.Start(GetUrlPrefixes());
ServerManager.Start(GetUrlPrefixes().ToArray());
return;
}
catch (Exception ex)
@ -1631,7 +1631,7 @@ namespace Emby.Server.Implementations
try
{
ServerManager.Start(GetUrlPrefixes());
ServerManager.Start(GetUrlPrefixes().ToArray());
}
catch (Exception ex)
{

View File

@ -418,6 +418,8 @@ namespace Emby.Server.Implementations.Dto
{
dto.Type = "Recording";
dto.CanDownload = false;
dto.RunTimeTicks = null;
if (!string.IsNullOrWhiteSpace(dto.SeriesName))
{
dto.EpisodeTitle = dto.Name;

View File

@ -10,7 +10,6 @@ using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.SocketSharp;
using Emby.Server.Implementations.Services;
using MediaBrowser.Common.Net;
@ -34,7 +33,7 @@ namespace Emby.Server.Implementations.HttpServer
private string DefaultRedirectPath { get; set; }
private readonly ILogger _logger;
public IEnumerable<string> UrlPrefixes { get; private set; }
public string[] UrlPrefixes { get; private set; }
private readonly List<IService> _restServices = new List<IService>();
@ -62,8 +61,8 @@ namespace Emby.Server.Implementations.HttpServer
private readonly Func<Type, Func<string, object>> _funcParseFn;
private readonly bool _enableDualModeSockets;
public List<Action<IRequest, IResponse, object>> RequestFilters { get; set; }
public List<Action<IRequest, IResponse, object>> ResponseFilters { get; set; }
public Action<IRequest, IResponse, object>[] RequestFilters { get; set; }
public Action<IRequest, IResponse, object>[] ResponseFilters { get; set; }
private readonly Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
public static HttpListenerHost Instance { get; protected set; }
@ -95,8 +94,8 @@ namespace Emby.Server.Implementations.HttpServer
_logger = logger;
RequestFilters = new List<Action<IRequest, IResponse, object>>();
ResponseFilters = new List<Action<IRequest, IResponse, object>>();
RequestFilters = new Action<IRequest, IResponse, object>[] { };
ResponseFilters = new Action<IRequest, IResponse, object>[] { };
}
public string GlobalResponse { get; set; }
@ -135,7 +134,9 @@ namespace Emby.Server.Implementations.HttpServer
//Exec all RequestFilter attributes with Priority < 0
var attributes = GetRequestFilterAttributes(requestDto.GetType());
var i = 0;
for (; i < attributes.Length && attributes[i].Priority < 0; i++)
var count = attributes.Count;
for (; i < count && attributes[i].Priority < 0; i++)
{
var attribute = attributes[i];
attribute.RequestFilter(req, res, requestDto);
@ -148,7 +149,7 @@ namespace Emby.Server.Implementations.HttpServer
}
//Exec remaining RequestFilter attributes with Priority >= 0
for (; i < attributes.Length && attributes[i].Priority >= 0; i++)
for (; i < count && attributes[i].Priority >= 0; i++)
{
var attribute = attributes[i];
attribute.RequestFilter(req, res, requestDto);
@ -167,7 +168,7 @@ namespace Emby.Server.Implementations.HttpServer
ServiceOperationsMap[requestType] = serviceType;
}
private IHasRequestFilter[] GetRequestFilterAttributes(Type requestDtoType)
private List<IHasRequestFilter> GetRequestFilterAttributes(Type requestDtoType)
{
var attributes = requestDtoType.GetTypeInfo().GetCustomAttributes(true).OfType<IHasRequestFilter>().ToList();
@ -179,24 +180,7 @@ namespace Emby.Server.Implementations.HttpServer
attributes.Sort((x, y) => x.Priority - y.Priority);
return attributes.ToArray(attributes.Count);
}
/// <summary>
/// Starts the Web Service
/// </summary>
private void StartListener()
{
WebSocketSharpRequest.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes.First());
_listener = GetListener();
_listener.WebSocketConnected = OnWebSocketConnected;
_listener.WebSocketConnecting = OnWebSocketConnecting;
_listener.ErrorHandler = ErrorHandler;
_listener.RequestHandler = RequestHandler;
_listener.Start(UrlPrefixes);
return attributes;
}
public static string GetHandlerPathIfAny(string listenerUrl)
@ -698,13 +682,18 @@ namespace Emby.Server.Implementations.HttpServer
ServiceController.Init(this, types);
var requestFilters = _appHost.GetExports<IRequestFilter>().ToList();
foreach (var filter in requestFilters)
var list = new List<Action<IRequest, IResponse, object>>();
foreach (var filter in _appHost.GetExports<IRequestFilter>())
{
RequestFilters.Add(filter.Filter);
list.Add(filter.Filter);
}
ResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
RequestFilters = list.ToArray();
ResponseFilters = new Action<IRequest, IResponse, object>[]
{
new ResponseFilter(_logger).FilterResponse
};
}
public RouteAttribute[] GetRouteAttributes(Type requestType)
@ -819,10 +808,20 @@ namespace Emby.Server.Implementations.HttpServer
GC.SuppressFinalize(this);
}
public void StartServer(IEnumerable<string> urlPrefixes)
public void StartServer(string[] urlPrefixes)
{
UrlPrefixes = urlPrefixes.ToList();
StartListener();
UrlPrefixes = urlPrefixes;
WebSocketSharpRequest.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
_listener = GetListener();
_listener.WebSocketConnected = OnWebSocketConnected;
_listener.WebSocketConnecting = OnWebSocketConnecting;
_listener.ErrorHandler = ErrorHandler;
_listener.RequestHandler = RequestHandler;
_listener.Start(UrlPrefixes);
}
}
}

View File

@ -487,69 +487,8 @@ namespace Emby.Server.Implementations.HttpServer
return result;
}
var compress = ShouldCompressResponse(requestContext, contentType);
var hasHeaders = await GetStaticResult(requestContext, options, compress).ConfigureAwait(false);
AddResponseHeaders(hasHeaders, options.ResponseHeaders);
return hasHeaders;
}
/// <summary>
/// Shoulds the compress response.
/// </summary>
/// <param name="requestContext">The request context.</param>
/// <param name="contentType">Type of the content.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
private bool ShouldCompressResponse(IRequest requestContext, string contentType)
{
// It will take some work to support compression with byte range requests
if (!string.IsNullOrWhiteSpace(requestContext.Headers.Get("Range")))
{
return false;
}
// Don't compress media
if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
{
return false;
}
// Don't compress images
if (contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (contentType.StartsWith("font/", StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (contentType.StartsWith("application/", StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(contentType, "application/x-javascript", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (string.Equals(contentType, "application/xml", StringComparison.OrdinalIgnoreCase))
{
return true;
}
return false;
}
return true;
}
/// <summary>
/// The us culture
/// </summary>
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
private async Task<IHasHeaders> GetStaticResult(IRequest requestContext, StaticResultOptions options, bool compress)
{
var isHeadRequest = options.IsHeadRequest;
var factoryFn = options.ContentFactory;
var contentType = options.ContentType;
var responseHeaders = options.ResponseHeaders;
//var requestedCompressionType = GetCompressionType(requestContext);
@ -558,22 +497,28 @@ namespace Emby.Server.Implementations.HttpServer
if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
{
return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
var hasHeaders = new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
{
OnComplete = options.OnComplete,
OnError = options.OnError,
FileShare = options.FileShare
};
AddResponseHeaders(hasHeaders, options.ResponseHeaders);
return hasHeaders;
}
if (!string.IsNullOrWhiteSpace(rangeHeader))
{
var stream = await factoryFn().ConfigureAwait(false);
return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
var hasHeaders = new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
{
OnComplete = options.OnComplete
};
AddResponseHeaders(hasHeaders, options.ResponseHeaders);
return hasHeaders;
}
else
{
@ -588,14 +533,22 @@ namespace Emby.Server.Implementations.HttpServer
return GetHttpResult(new byte[] { }, contentType, true);
}
return new StreamWriter(stream, contentType, _logger)
var hasHeaders = new StreamWriter(stream, contentType, _logger)
{
OnComplete = options.OnComplete,
OnError = options.OnError
};
AddResponseHeaders(hasHeaders, options.ResponseHeaders);
return hasHeaders;
}
}
/// <summary>
/// The us culture
/// </summary>
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary>
/// Adds the caching responseHeaders.
/// </summary>

View File

@ -1,10 +1,8 @@
using MediaBrowser.Model.Logging;
using System;
using System.Globalization;
using System.Linq;
using MediaBrowser.Model.Services;
using SocketHttpListener.Net;
using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.HttpServer
{
@ -30,7 +28,20 @@ namespace Emby.Server.Implementations.HttpServer
}
else
{
var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray(headers.Count));
var headerText = string.Empty;
var index = 0;
foreach (var i in headers)
{
if (index > 0)
{
headerText += ", ";
}
headerText += i.Name + "=" + i.Value;
index++;
}
logger.Info("HTTP {0} {1}. {2}", method, url, headerText);
}
@ -49,7 +60,8 @@ namespace Emby.Server.Implementations.HttpServer
var durationMs = duration.TotalMilliseconds;
var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray());
//var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray());
var headerText = string.Empty;
logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4} {5}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url, headerText);
}
}

View File

@ -7,7 +7,6 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Emby.Server.Implementations.HttpServer.Security
@ -78,7 +77,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
if (!IsExemptFromRoles(auth, authAttribtues, info))
{
var roles = authAttribtues.GetRoles().ToList();
var roles = authAttribtues.GetRoles();
ValidateRoles(roles, user);
}
@ -162,7 +161,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
return false;
}
private void ValidateRoles(List<string> roles, User user)
private void ValidateRoles(string[] roles, User user)
{
if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase))
{

View File

@ -3,8 +3,8 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Services;
using System.Linq;
namespace Emby.Server.Implementations.HttpServer.Security
{
@ -90,7 +90,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
AccessToken = token
});
var tokenInfo = result.Items.FirstOrDefault();
var tokenInfo = result.Items.Length > 0 ? result.Items[0] : null;
if (tokenInfo != null)
{

View File

@ -112,7 +112,7 @@ namespace Emby.Server.Implementations.ServerManager
/// <summary>
/// Starts this instance.
/// </summary>
public void Start(IEnumerable<string> urlPrefixes)
public void Start(string[] urlPrefixes)
{
ReloadHttpServer(urlPrefixes);
}
@ -120,7 +120,7 @@ namespace Emby.Server.Implementations.ServerManager
/// <summary>
/// Restarts the Http Server, or starts it if not currently running
/// </summary>
private void ReloadHttpServer(IEnumerable<string> urlPrefixes)
private void ReloadHttpServer(string[] urlPrefixes)
{
_logger.Info("Loading Http Server");

View File

@ -24,19 +24,33 @@ namespace Emby.Server.Implementations.Services
"POLL", "SUBSCRIBE", "UNSUBSCRIBE"
});
public static IEnumerable<MethodInfo> GetActions(this Type serviceType)
public static List<MethodInfo> GetActions(this Type serviceType)
{
foreach (var mi in serviceType.GetRuntimeMethods().Where(i => i.IsPublic && !i.IsStatic))
var list = new List<MethodInfo>();
foreach (var mi in serviceType.GetRuntimeMethods())
{
if (!mi.IsPublic)
{
continue;
}
if (mi.IsStatic)
{
continue;
}
if (mi.GetParameters().Length != 1)
continue;
var actionName = mi.Name;
if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase) && !string.Equals(actionName, ServiceMethod.AnyAction, StringComparison.OrdinalIgnoreCase))
if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase))
continue;
yield return mi;
list.Add(mi);
}
return list;
}
}
@ -59,8 +73,7 @@ namespace Emby.Server.Implementations.Services
var actionName = request.Verb ?? "POST";
ServiceMethod actionContext;
if (ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.Key(serviceType, actionName, requestName), out actionContext)
|| ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.AnyKey(serviceType, requestName), out actionContext))
if (ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.Key(serviceType, actionName, requestName), out actionContext))
{
if (actionContext.RequestFilters != null)
{

View File

@ -4,8 +4,6 @@ namespace Emby.Server.Implementations.Services
{
public class ServiceMethod
{
public const string AnyAction = "ANY";
public string Id { get; set; }
public ActionInvokerFn ServiceAction { get; set; }
@ -15,10 +13,5 @@ namespace Emby.Server.Implementations.Services
{
return serviceType.FullName + " " + method.ToUpper() + " " + requestDtoName;
}
public static string AnyKey(Type serviceType, string requestDtoName)
{
return Key(serviceType, AnyAction, requestDtoName);
}
}
}

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Emby.Server.Implementations.Services
@ -64,11 +63,16 @@ namespace Emby.Server.Implementations.Services
if (instance == null)
instance = _CreateInstanceFn(type);
foreach (var pair in keyValuePairs.Where(x => !string.IsNullOrEmpty(x.Value)))
foreach (var pair in keyValuePairs)
{
propertyName = pair.Key;
propertyTextValue = pair.Value;
if (string.IsNullOrEmpty(propertyTextValue))
{
continue;
}
if (!propertySetterMap.TryGetValue(propertyName, out propertySerializerEntry))
{
if (propertyName == "v")
@ -115,7 +119,7 @@ namespace Emby.Server.Implementations.Services
{
public static Action<object, object> GetSetPropertyMethod(Type type, PropertyInfo propertyInfo)
{
if (!propertyInfo.CanWrite || propertyInfo.GetIndexParameters().Any()) return null;
if (!propertyInfo.CanWrite || propertyInfo.GetIndexParameters().Length > 0) return null;
var setMethodInfo = propertyInfo.SetMethod;
return (instance, value) => setMethodInfo.Invoke(instance, new[] { value });

View File

@ -70,24 +70,27 @@ namespace MediaBrowser.Api.Dlna
public Stream RequestStream { get; set; }
}
[Route("/Dlna/{UuId}/mediareceiverregistrar/events", Summary = "Processes an event subscription request")]
[Route("/Dlna/{UuId}/mediareceiverregistrar/events", "SUBSCRIBE", Summary = "Processes an event subscription request")]
[Route("/Dlna/{UuId}/mediareceiverregistrar/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")]
public class ProcessMediaReceiverRegistrarEventRequest
{
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")]
public string UuId { get; set; }
}
[Route("/Dlna/{UuId}/contentdirectory/events", Summary = "Processes an event subscription request")]
[Route("/Dlna/{UuId}/contentdirectory/events", "SUBSCRIBE", Summary = "Processes an event subscription request")]
[Route("/Dlna/{UuId}/contentdirectory/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")]
public class ProcessContentDirectoryEventRequest
{
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")]
public string UuId { get; set; }
}
[Route("/Dlna/{UuId}/connectionmanager/events", Summary = "Processes an event subscription request")]
[Route("/Dlna/{UuId}/connectionmanager/events", "SUBSCRIBE", Summary = "Processes an event subscription request")]
[Route("/Dlna/{UuId}/connectionmanager/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")]
public class ProcessConnectionManagerEventRequest
{
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")]
public string UuId { get; set; }
}
@ -200,17 +203,32 @@ namespace MediaBrowser.Api.Dlna
}
}
public object Any(ProcessContentDirectoryEventRequest request)
public object Subscribe(ProcessContentDirectoryEventRequest request)
{
return ProcessEventRequest(_contentDirectory);
}
public object Any(ProcessConnectionManagerEventRequest request)
public object Subscribe(ProcessConnectionManagerEventRequest request)
{
return ProcessEventRequest(_connectionManager);
}
public object Any(ProcessMediaReceiverRegistrarEventRequest request)
public object Subscribe(ProcessMediaReceiverRegistrarEventRequest request)
{
return ProcessEventRequest(_mediaReceiverRegistrar);
}
public object Unsubscribe(ProcessContentDirectoryEventRequest request)
{
return ProcessEventRequest(_contentDirectory);
}
public object Unsubscribe(ProcessConnectionManagerEventRequest request)
{
return ProcessEventRequest(_connectionManager);
}
public object Unsubscribe(ProcessMediaReceiverRegistrarEventRequest request)
{
return ProcessEventRequest(_mediaReceiverRegistrar);
}

View File

@ -298,7 +298,7 @@ namespace MediaBrowser.Api
/// <returns>IEnumerable{FileSystemEntryInfo}.</returns>
private IEnumerable<FileSystemEntryInfo> GetFileSystemEntries(GetDirectoryContents request)
{
var entries = _fileSystem.GetFileSystemEntries(request.Path).Where(i =>
var entries = _fileSystem.GetFileSystemEntries(request.Path).OrderBy(i => i.FullName).Where(i =>
{
if (!request.IncludeHidden && i.IsHidden)
{

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Controller.Net
@ -50,7 +49,7 @@ namespace MediaBrowser.Controller.Net
get { return 0; }
}
public IEnumerable<string> GetRoles()
public string[] GetRoles()
{
return (Roles ?? string.Empty).Split(new []{ ',' }, StringSplitOptions.RemoveEmptyEntries);
}
@ -61,6 +60,6 @@ namespace MediaBrowser.Controller.Net
bool EscapeParentalControl { get; }
bool AllowBeforeStartupWizard { get; }
IEnumerable<string> GetRoles();
string[] GetRoles();
}
}

View File

@ -13,13 +13,13 @@ namespace MediaBrowser.Controller.Net
/// Gets the URL prefix.
/// </summary>
/// <value>The URL prefix.</value>
IEnumerable<string> UrlPrefixes { get; }
string[] UrlPrefixes { get; }
/// <summary>
/// Starts the specified server name.
/// </summary>
/// <param name="urlPrefixes">The URL prefixes.</param>
void StartServer(IEnumerable<string> urlPrefixes);
void StartServer(string[] urlPrefixes);
/// <summary>
/// Stops this instance.

View File

@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Net
/// Starts this instance.
/// </summary>
/// <param name="urlPrefixes">The URL prefixes.</param>
void Start(IEnumerable<string> urlPrefixes);
void Start(string[] urlPrefixes);
/// <summary>
/// Sends a message to all clients currently connected via a web socket

View File

@ -58,12 +58,16 @@ namespace MediaBrowser.Model.Dlna
private static ResolutionConfiguration GetResolutionConfiguration(int outputBitrate)
{
ResolutionConfiguration previousOption = null;
foreach (var config in Configurations)
{
if (outputBitrate <= config.MaxBitrate)
{
return config;
return previousOption ?? config;
}
previousOption = config;
}
return null;

View File

@ -1,3 +1,3 @@
using System.Reflection;
[assembly: AssemblyVersion("3.2.30.2")]
[assembly: AssemblyVersion("3.2.30.3")]