Merge pull request #2466 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2017-02-12 20:17:43 -05:00 committed by GitHub
commit 273aa822cf
25 changed files with 594 additions and 1105 deletions

View File

@ -215,6 +215,13 @@
<Compile Include="Security\RegRecord.cs" /> <Compile Include="Security\RegRecord.cs" />
<Compile Include="ServerManager\ServerManager.cs" /> <Compile Include="ServerManager\ServerManager.cs" />
<Compile Include="ServerManager\WebSocketConnection.cs" /> <Compile Include="ServerManager\WebSocketConnection.cs" />
<Compile Include="Services\ServiceMethod.cs" />
<Compile Include="Services\ResponseHelper.cs" />
<Compile Include="Services\HttpResult.cs" />
<Compile Include="Services\RequestHelper.cs" />
<Compile Include="Services\ServiceHandler.cs" />
<Compile Include="Services\ServiceController.cs" />
<Compile Include="Services\ServiceExec.cs" />
<Compile Include="Session\HttpSessionController.cs" /> <Compile Include="Session\HttpSessionController.cs" />
<Compile Include="Session\SessionManager.cs" /> <Compile Include="Session\SessionManager.cs" />
<Compile Include="Session\SessionWebSocketListener.cs" /> <Compile Include="Session\SessionWebSocketListener.cs" />

View File

@ -3,7 +3,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using ServiceStack; using ServiceStack;
using ServiceStack.Host;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -13,6 +12,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer; using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.SocketSharp; using Emby.Server.Implementations.HttpServer.SocketSharp;
using Emby.Server.Implementations.Services;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Common.Security; using MediaBrowser.Common.Security;
using MediaBrowser.Controller; using MediaBrowser.Controller;
@ -61,12 +61,15 @@ namespace Emby.Server.Implementations.HttpServer
private readonly Func<Type, Func<string, object>> _funcParseFn; private readonly Func<Type, Func<string, object>> _funcParseFn;
private readonly bool _enableDualModeSockets; private readonly bool _enableDualModeSockets;
public List<Action<IRequest, IResponse, object>> RequestFilters { get; set; }
private Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
public HttpListenerHost(IServerApplicationHost applicationHost, public HttpListenerHost(IServerApplicationHost applicationHost,
ILogger logger, ILogger logger,
IServerConfigurationManager config, IServerConfigurationManager config,
string serviceName, string serviceName,
string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, ICertificate certificate, IStreamFactory streamFactory, Func<Type, Func<string, object>> funcParseFn, bool enableDualModeSockets) string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, ICertificate certificate, IStreamFactory streamFactory, Func<Type, Func<string, object>> funcParseFn, bool enableDualModeSockets)
: base(serviceName) : base()
{ {
_appHost = applicationHost; _appHost = applicationHost;
DefaultRedirectPath = defaultRedirectPath; DefaultRedirectPath = defaultRedirectPath;
@ -85,6 +88,8 @@ namespace Emby.Server.Implementations.HttpServer
_config = config; _config = config;
_logger = logger; _logger = logger;
RequestFilters = new List<Action<IRequest, IResponse, object>>();
} }
public string GlobalResponse { get; set; } public string GlobalResponse { get; set; }
@ -99,18 +104,7 @@ namespace Emby.Server.Implementations.HttpServer
{typeof (ArgumentException), 400} {typeof (ArgumentException), 400}
}; };
public override void Configure() protected ILogger Logger
{
var requestFilters = _appHost.GetExports<IRequestFilter>().ToList();
foreach (var filter in requestFilters)
{
GlobalRequestFilters.Add(filter.Filter);
}
GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
}
protected override ILogger Logger
{ {
get get
{ {
@ -118,32 +112,73 @@ namespace Emby.Server.Implementations.HttpServer
} }
} }
public override T Resolve<T>()
{
return _appHost.Resolve<T>();
}
public override T TryResolve<T>()
{
return _appHost.TryResolve<T>();
}
public override object CreateInstance(Type type) public override object CreateInstance(Type type)
{ {
return _appHost.CreateInstance(type); return _appHost.CreateInstance(type);
} }
protected override ServiceController CreateServiceController() private ServiceController CreateServiceController()
{ {
var types = _restServices.Select(r => r.GetType()).ToArray(); var types = _restServices.Select(r => r.GetType()).ToArray();
return new ServiceController(() => types); return new ServiceController(() => types);
} }
public override ServiceStackHost Start(string listeningAtUrlBase) /// <summary>
/// Applies the request filters. Returns whether or not the request has been handled
/// and no more processing should be done.
/// </summary>
/// <returns></returns>
public void ApplyRequestFilters(IRequest req, IResponse res, object requestDto)
{ {
StartListener(); //Exec all RequestFilter attributes with Priority < 0
return this; var attributes = GetRequestFilterAttributes(requestDto.GetType());
var i = 0;
for (; i < attributes.Length && attributes[i].Priority < 0; i++)
{
var attribute = attributes[i];
attribute.RequestFilter(req, res, requestDto);
}
//Exec global filters
foreach (var requestFilter in RequestFilters)
{
requestFilter(req, res, requestDto);
}
//Exec remaining RequestFilter attributes with Priority >= 0
for (; i < attributes.Length && attributes[i].Priority >= 0; i++)
{
var attribute = attributes[i];
attribute.RequestFilter(req, res, requestDto);
}
}
public Type GetServiceTypeByRequest(Type requestType)
{
Type serviceType;
ServiceOperationsMap.TryGetValue(requestType, out serviceType);
return serviceType;
}
public void AddServiceInfo(Type serviceType, Type requestType, Type responseType)
{
ServiceOperationsMap[requestType] = serviceType;
}
private IHasRequestFilter[] GetRequestFilterAttributes(Type requestDtoType)
{
var attributes = requestDtoType.AllAttributes().OfType<IHasRequestFilter>().ToList();
var serviceType = GetServiceTypeByRequest(requestDtoType);
if (serviceType != null)
{
attributes.AddRange(serviceType.AllAttributes().OfType<IHasRequestFilter>());
}
attributes.Sort((x, y) => x.Priority - y.Priority);
return attributes.ToArray();
} }
/// <summary> /// <summary>
@ -531,11 +566,11 @@ namespace Emby.Server.Implementations.HttpServer
return; return;
} }
var handler = HttpHandlerFactory.GetHandler(httpReq, _logger); var handler = GetServiceHandler(httpReq);
if (handler != null) if (handler != null)
{ {
await handler.ProcessRequestAsync(httpReq, httpRes, operationName).ConfigureAwait(false); await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, operationName).ConfigureAwait(false);
} }
else else
{ {
@ -565,6 +600,35 @@ namespace Emby.Server.Implementations.HttpServer
} }
} }
// Entry point for HttpListener
public ServiceHandler GetServiceHandler(IHttpRequest httpReq)
{
var pathInfo = httpReq.PathInfo;
var pathParts = pathInfo.TrimStart('/').Split('/');
if (pathParts.Length == 0)
{
_logger.Error("Path parts empty for PathInfo: {0}, Url: {1}", pathInfo, httpReq.RawUrl);
return null;
}
string contentType;
var restPath = ServiceHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, _logger, out contentType);
if (restPath != null)
{
return new ServiceHandler
{
RestPath = restPath,
ResponseContentType = contentType
};
}
_logger.Error("Could not find handler for {0}", pathInfo);
return null;
}
private void Write(IResponse response, string text) private void Write(IResponse response, string text)
{ {
var bOutput = Encoding.UTF8.GetBytes(text); var bOutput = Encoding.UTF8.GetBytes(text);
@ -580,6 +644,7 @@ namespace Emby.Server.Implementations.HttpServer
httpRes.AddHeader("Location", url); httpRes.AddHeader("Location", url);
} }
public ServiceController ServiceController { get; private set; }
/// <summary> /// <summary>
/// Adds the rest handlers. /// Adds the rest handlers.
@ -593,12 +658,22 @@ namespace Emby.Server.Implementations.HttpServer
_logger.Info("Calling ServiceStack AppHost.Init"); _logger.Info("Calling ServiceStack AppHost.Init");
base.Init(); Instance = this;
ServiceController.Init(this);
var requestFilters = _appHost.GetExports<IRequestFilter>().ToList();
foreach (var filter in requestFilters)
{
RequestFilters.Add(filter.Filter);
}
GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
} }
public override RouteAttribute[] GetRouteAttributes(Type requestType) public override RouteAttribute[] GetRouteAttributes(Type requestType)
{ {
var routes = base.GetRouteAttributes(requestType).ToList(); var routes = requestType.AllAttributes<RouteAttribute>();
var clone = routes.ToList(); var clone = routes.ToList();
foreach (var route in clone) foreach (var route in clone)
@ -628,33 +703,6 @@ namespace Emby.Server.Implementations.HttpServer
return routes.ToArray(); return routes.ToArray();
} }
public override object GetTaskResult(Task task, string requestName)
{
try
{
var taskObject = task as Task<object>;
if (taskObject != null)
{
return taskObject.Result;
}
task.Wait();
var type = task.GetType().GetTypeInfo();
if (!type.IsGenericType)
{
return null;
}
Logger.Warn("Getting task result from " + requestName + " using reflection. For better performance have your api return Task<object>");
return type.GetDeclaredProperty("Result").GetValue(task);
}
catch (TypeAccessException)
{
return null; //return null for void Task's
}
}
public override Func<string, object> GetParseFn(Type propertyType) public override Func<string, object> GetParseFn(Type propertyType)
{ {
return _funcParseFn(propertyType); return _funcParseFn(propertyType);
@ -740,7 +788,7 @@ namespace Emby.Server.Implementations.HttpServer
public void StartServer(IEnumerable<string> urlPrefixes) public void StartServer(IEnumerable<string> urlPrefixes)
{ {
UrlPrefixes = urlPrefixes.ToList(); UrlPrefixes = urlPrefixes.ToList();
Start(UrlPrefixes.First()); StartListener();
} }
} }
} }

View File

@ -13,10 +13,10 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml; using System.Xml;
using Emby.Server.Implementations.HttpServer; using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.Services;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using ServiceStack; using ServiceStack;
using ServiceStack.Host;
using IRequest = MediaBrowser.Model.Services.IRequest; using IRequest = MediaBrowser.Model.Services.IRequest;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes; using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter; using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter;
@ -203,7 +203,11 @@ namespace Emby.Server.Implementations.HttpServer
// Do not use the memoryStreamFactory here, they don't place nice with compression // Do not use the memoryStreamFactory here, they don't place nice with compression
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
{ {
ContentTypes.Instance.SerializeToStream(request, dto, ms); var contentType = request.ResponseContentType;
var writerFn = RequestHelper.GetResponseWriter(contentType);
writerFn(dto, ms);
ms.Position = 0; ms.Position = 0;
var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

View File

@ -1,14 +1,12 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using ServiceStack.Host; using ServiceStack;
namespace ServiceStack namespace Emby.Server.Implementations.Services
{ {
public class HttpResult public class HttpResult
: IHttpResult, IAsyncStreamWriter : IHttpResult, IAsyncStreamWriter
@ -55,7 +53,7 @@ namespace ServiceStack
return; return;
} }
await HttpResponseExtensionsInternal.WriteObject(this.RequestContext, this.Response, response).ConfigureAwait(false); await ResponseHelper.WriteObject(this.RequestContext, this.Response, response).ConfigureAwait(false);
} }
} }
} }

View File

@ -1,43 +1,14 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using ServiceStack;
using MediaBrowser.Model.Services;
namespace ServiceStack.Host namespace Emby.Server.Implementations.Services
{ {
public class ContentTypes public class RequestHelper
{ {
public static ContentTypes Instance = new ContentTypes(); public static Func<Type, Stream, object> GetRequestReader(string contentType)
public void SerializeToStream(IRequest req, object response, Stream responseStream)
{ {
var contentType = req.ResponseContentType; switch (GetContentTypeWithoutEncoding(contentType))
var serializer = GetStreamSerializer(contentType);
serializer(response, responseStream);
}
public static Action<object, Stream> GetStreamSerializer(string contentType)
{
switch (GetRealContentType(contentType))
{
case "application/xml":
case "text/xml":
case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
return (o, s) => ServiceStackHost.Instance.SerializeToXml(o, s);
case "application/json":
case "text/json":
return (o, s) => ServiceStackHost.Instance.SerializeToJson(o, s);
}
return null;
}
public Func<Type, Stream, object> GetStreamDeserializer(string contentType)
{
switch (GetRealContentType(contentType))
{ {
case "application/xml": case "application/xml":
case "text/xml": case "text/xml":
@ -52,7 +23,24 @@ namespace ServiceStack.Host
return null; return null;
} }
private static string GetRealContentType(string contentType) public static Action<object, Stream> GetResponseWriter(string contentType)
{
switch (GetContentTypeWithoutEncoding(contentType))
{
case "application/xml":
case "text/xml":
case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
return (o, s) => ServiceStackHost.Instance.SerializeToXml(o, s);
case "application/json":
case "text/json":
return (o, s) => ServiceStackHost.Instance.SerializeToJson(o, s);
}
return null;
}
private static string GetContentTypeWithoutEncoding(string contentType)
{ {
return contentType == null return contentType == null
? null ? null

View File

@ -1,21 +1,17 @@
//Copyright (c) Service Stack LLC. All Rights Reserved.
//License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using ServiceStack.Host;
namespace ServiceStack namespace Emby.Server.Implementations.Services
{ {
public static class HttpResponseExtensionsInternal public static class ResponseHelper
{ {
public static async Task<bool> WriteToOutputStream(IResponse response, object result) private static async Task<bool> WriteToOutputStream(IResponse response, object result)
{ {
var asyncStreamWriter = result as IAsyncStreamWriter; var asyncStreamWriter = result as IAsyncStreamWriter;
if (asyncStreamWriter != null) if (asyncStreamWriter != null)
@ -54,24 +50,16 @@ namespace ServiceStack
return false; return false;
} }
/// <summary> public static Task WriteToResponse(IResponse httpRes, IRequest httpReq, object result)
/// End a ServiceStack Request with no content
/// </summary>
public static void EndRequestWithNoContent(this IResponse httpRes)
{
if (httpRes.StatusCode == (int)HttpStatusCode.OK)
{
httpRes.StatusCode = (int)HttpStatusCode.NoContent;
}
httpRes.SetContentLength(0);
}
public static Task WriteToResponse(this IResponse httpRes, IRequest httpReq, object result)
{ {
if (result == null) if (result == null)
{ {
httpRes.EndRequestWithNoContent(); if (httpRes.StatusCode == (int)HttpStatusCode.OK)
{
httpRes.StatusCode = (int)HttpStatusCode.NoContent;
}
httpRes.SetContentLength(0);
return Task.FromResult(true); return Task.FromResult(true);
} }
@ -80,10 +68,10 @@ namespace ServiceStack
{ {
httpResult.RequestContext = httpReq; httpResult.RequestContext = httpReq;
httpReq.ResponseContentType = httpResult.ContentType ?? httpReq.ResponseContentType; httpReq.ResponseContentType = httpResult.ContentType ?? httpReq.ResponseContentType;
return httpRes.WriteToResponseInternal(httpResult, httpReq); return WriteToResponseInternal(httpRes, httpResult, httpReq);
} }
return httpRes.WriteToResponseInternal(result, httpReq); return WriteToResponseInternal(httpRes, result, httpReq);
} }
/// <summary> /// <summary>
@ -94,7 +82,7 @@ namespace ServiceStack
/// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param> /// <param name="result">Whether or not it was implicity handled by ServiceStack's built-in handlers.</param>
/// <param name="request">The serialization context.</param> /// <param name="request">The serialization context.</param>
/// <returns></returns> /// <returns></returns>
private static async Task WriteToResponseInternal(this IResponse response, object result, IRequest request) private static async Task WriteToResponseInternal(IResponse response, object result, IRequest request)
{ {
var defaultContentType = request.ResponseContentType; var defaultContentType = request.ResponseContentType;
@ -173,7 +161,7 @@ namespace ServiceStack
public static async Task WriteObject(IRequest request, object result, IResponse response) public static async Task WriteObject(IRequest request, object result, IResponse response)
{ {
var contentType = request.ResponseContentType; var contentType = request.ResponseContentType;
var serializer = ContentTypes.GetStreamSerializer(contentType); var serializer = RequestHelper.GetResponseWriter(contentType);
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
{ {

View File

@ -1,13 +1,13 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using ServiceStack;
namespace ServiceStack.Host namespace Emby.Server.Implementations.Services
{ {
public delegate Task<object> InstanceExecFn(IRequest requestContext, object intance, object request); public delegate Task<object> InstanceExecFn(IRequest requestContext, object intance, object request);
public delegate object ActionInvokerFn(object intance, object request); public delegate object ActionInvokerFn(object intance, object request);
@ -15,21 +15,20 @@ namespace ServiceStack.Host
public class ServiceController public class ServiceController
{ {
public static ServiceController Instance;
private readonly Func<IEnumerable<Type>> _resolveServicesFn; private readonly Func<IEnumerable<Type>> _resolveServicesFn;
public ServiceController(Func<IEnumerable<Type>> resolveServicesFn) public ServiceController(Func<IEnumerable<Type>> resolveServicesFn)
{ {
Instance = this;
_resolveServicesFn = resolveServicesFn; _resolveServicesFn = resolveServicesFn;
this.RequestTypeFactoryMap = new Dictionary<Type, Func<IRequest, object>>();
} }
public Dictionary<Type, Func<IRequest, object>> RequestTypeFactoryMap { get; set; } public void Init(HttpListenerHost appHost)
public void Init()
{ {
foreach (var serviceType in _resolveServicesFn()) foreach (var serviceType in _resolveServicesFn())
{ {
RegisterService(serviceType); RegisterService(appHost, serviceType);
} }
} }
@ -40,15 +39,12 @@ namespace ServiceStack.Host
: type.GetTypeInfo().GenericTypeArguments; : type.GetTypeInfo().GenericTypeArguments;
} }
public void RegisterService(Type serviceType) public void RegisterService(HttpListenerHost appHost, Type serviceType)
{ {
var processedReqs = new HashSet<Type>(); var processedReqs = new HashSet<Type>();
var actions = ServiceExecGeneral.Reset(serviceType); var actions = ServiceExecGeneral.Reset(serviceType);
var requiresRequestStreamTypeInfo = typeof(IRequiresRequestStream).GetTypeInfo();
var appHost = ServiceStackHost.Instance;
foreach (var mi in serviceType.GetActions()) foreach (var mi in serviceType.GetActions())
{ {
var requestType = mi.GetParameters()[0].ParameterType; var requestType = mi.GetParameters()[0].ParameterType;
@ -66,20 +62,7 @@ namespace ServiceStack.Host
RegisterRestPaths(requestType); RegisterRestPaths(requestType);
appHost.Metadata.Add(serviceType, requestType, responseType); appHost.AddServiceInfo(serviceType, requestType, responseType);
if (requiresRequestStreamTypeInfo.IsAssignableFrom(requestType.GetTypeInfo()))
{
this.RequestTypeFactoryMap[requestType] = req =>
{
var restPath = req.GetRoute();
var request = RestHandler.CreateRequest(req, restPath, req.GetRequestParams(), ServiceStackHost.Instance.CreateInstance(requestType));
var rawReq = (IRequiresRequestStream)request;
rawReq.RequestStream = req.InputStream;
return rawReq;
};
}
} }
} }
@ -120,22 +103,7 @@ namespace ServiceStack.Host
pathsAtFirstMatch.Add(restPath); pathsAtFirstMatch.Add(restPath);
} }
public void AfterInit() public RestPath GetRestPathForRequest(string httpMethod, string pathInfo, ILogger logger)
{
var appHost = ServiceStackHost.Instance;
//Register any routes configured on Metadata.Routes
foreach (var restPath in appHost.RestPaths)
{
RegisterRestPath(restPath);
}
//Sync the RestPaths collections
appHost.RestPaths.Clear();
appHost.RestPaths.AddRange(RestPathMap.Values.SelectMany(x => x));
}
public RestPath GetRestPathForRequest(string httpMethod, string pathInfo)
{ {
var matchUsingPathParts = RestPath.GetPathPartsForMatching(pathInfo); var matchUsingPathParts = RestPath.GetPathPartsForMatching(pathInfo);
@ -144,19 +112,23 @@ namespace ServiceStack.Host
var yieldedHashMatches = RestPath.GetFirstMatchHashKeys(matchUsingPathParts); var yieldedHashMatches = RestPath.GetFirstMatchHashKeys(matchUsingPathParts);
foreach (var potentialHashMatch in yieldedHashMatches) foreach (var potentialHashMatch in yieldedHashMatches)
{ {
if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) continue; if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches))
{
continue;
}
var bestScore = -1; var bestScore = -1;
foreach (var restPath in firstMatches) foreach (var restPath in firstMatches)
{ {
var score = restPath.MatchScore(httpMethod, matchUsingPathParts); var score = restPath.MatchScore(httpMethod, matchUsingPathParts, logger);
if (score > bestScore) bestScore = score; if (score > bestScore) bestScore = score;
} }
if (bestScore > 0) if (bestScore > 0)
{ {
foreach (var restPath in firstMatches) foreach (var restPath in firstMatches)
{ {
if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts)) if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts, logger))
return restPath; return restPath;
} }
} }
@ -170,14 +142,14 @@ namespace ServiceStack.Host
var bestScore = -1; var bestScore = -1;
foreach (var restPath in firstMatches) foreach (var restPath in firstMatches)
{ {
var score = restPath.MatchScore(httpMethod, matchUsingPathParts); var score = restPath.MatchScore(httpMethod, matchUsingPathParts, logger);
if (score > bestScore) bestScore = score; if (score > bestScore) bestScore = score;
} }
if (bestScore > 0) if (bestScore > 0)
{ {
foreach (var restPath in firstMatches) foreach (var restPath in firstMatches)
{ {
if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts)) if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts, logger))
return restPath; return restPath;
} }
} }
@ -186,15 +158,15 @@ namespace ServiceStack.Host
return null; return null;
} }
public async Task<object> Execute(object requestDto, IRequest req) public async Task<object> Execute(HttpListenerHost appHost, object requestDto, IRequest req)
{ {
req.Dto = requestDto; req.Dto = requestDto;
var requestType = requestDto.GetType(); var requestType = requestDto.GetType();
req.OperationName = requestType.Name; req.OperationName = requestType.Name;
var serviceType = ServiceStackHost.Instance.Metadata.GetServiceTypeByRequest(requestType); var serviceType = appHost.GetServiceTypeByRequest(requestType);
var service = ServiceStackHost.Instance.CreateInstance(serviceType); var service = appHost.CreateInstance(serviceType);
//var service = typeFactory.CreateInstance(serviceType); //var service = typeFactory.CreateInstance(serviceType);

View File

@ -1,6 +1,3 @@
//Copyright (c) Service Stack LLC. All Rights Reserved.
//License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -8,11 +5,25 @@ using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using ServiceStack;
namespace ServiceStack.Host namespace Emby.Server.Implementations.Services
{ {
public static class ServiceExecExtensions public static class ServiceExecExtensions
{ {
public static HashSet<string> AllVerbs = new HashSet<string>(new[] {
"OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", // RFC 2616
"PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", // RFC 2518
"VERSION-CONTROL", "REPORT", "CHECKOUT", "CHECKIN", "UNCHECKOUT",
"MKWORKSPACE", "UPDATE", "LABEL", "MERGE", "BASELINE-CONTROL", "MKACTIVITY", // RFC 3253
"ORDERPATCH", // RFC 3648
"ACL", // RFC 3744
"PATCH", // https://datatracker.ietf.org/doc/draft-dusseault-http-patch/
"SEARCH", // https://datatracker.ietf.org/doc/draft-reschke-webdav-search/
"BCOPY", "BDELETE", "BMOVE", "BPROPFIND", "BPROPPATCH", "NOTIFY",
"POLL", "SUBSCRIBE", "UNSUBSCRIBE"
});
public static IEnumerable<MethodInfo> GetActions(this Type serviceType) public static IEnumerable<MethodInfo> GetActions(this Type serviceType)
{ {
foreach (var mi in serviceType.GetRuntimeMethods().Where(i => i.IsPublic && !i.IsStatic)) foreach (var mi in serviceType.GetRuntimeMethods().Where(i => i.IsPublic && !i.IsStatic))
@ -20,8 +31,8 @@ namespace ServiceStack.Host
if (mi.GetParameters().Length != 1) if (mi.GetParameters().Length != 1)
continue; continue;
var actionName = mi.Name.ToUpper(); var actionName = mi.Name;
if (!HttpMethods.AllVerbs.Contains(actionName) && actionName != ActionContext.AnyAction) if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase) && !string.Equals(actionName, ServiceMethod.AnyAction, StringComparison.OrdinalIgnoreCase))
continue; continue;
yield return mi; yield return mi;
@ -31,9 +42,9 @@ namespace ServiceStack.Host
internal static class ServiceExecGeneral internal static class ServiceExecGeneral
{ {
public static Dictionary<string, ActionContext> execMap = new Dictionary<string, ActionContext>(); public static Dictionary<string, ServiceMethod> execMap = new Dictionary<string, ServiceMethod>();
public static void CreateServiceRunnersFor(Type requestType, List<ActionContext> actions) public static void CreateServiceRunnersFor(Type requestType, List<ServiceMethod> actions)
{ {
foreach (var actionCtx in actions) foreach (var actionCtx in actions)
{ {
@ -45,12 +56,11 @@ namespace ServiceStack.Host
public static async Task<object> Execute(Type serviceType, IRequest request, object instance, object requestDto, string requestName) public static async Task<object> Execute(Type serviceType, IRequest request, object instance, object requestDto, string requestName)
{ {
var actionName = request.Verb var actionName = request.Verb ?? "POST";
?? HttpMethods.Post; //MQ Services
ActionContext actionContext; ServiceMethod actionContext;
if (ServiceExecGeneral.execMap.TryGetValue(ActionContext.Key(serviceType, actionName, requestName), out actionContext) if (ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.Key(serviceType, actionName, requestName), out actionContext)
|| ServiceExecGeneral.execMap.TryGetValue(ActionContext.AnyKey(serviceType, requestName), out actionContext)) || ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.AnyKey(serviceType, requestName), out actionContext))
{ {
if (actionContext.RequestFilters != null) if (actionContext.RequestFilters != null)
{ {
@ -67,7 +77,7 @@ namespace ServiceStack.Host
if (taskResponse != null) if (taskResponse != null)
{ {
await taskResponse.ConfigureAwait(false); await taskResponse.ConfigureAwait(false);
response = ServiceStackHost.Instance.GetTaskResult(taskResponse, requestName); response = ServiceHandler.GetTaskResult(taskResponse);
} }
return response; return response;
@ -77,19 +87,19 @@ namespace ServiceStack.Host
throw new NotImplementedException(string.Format("Could not find method named {1}({0}) or Any({0}) on Service {2}", requestDto.GetType().GetOperationName(), expectedMethodName, serviceType.GetOperationName())); throw new NotImplementedException(string.Format("Could not find method named {1}({0}) or Any({0}) on Service {2}", requestDto.GetType().GetOperationName(), expectedMethodName, serviceType.GetOperationName()));
} }
public static List<ActionContext> Reset(Type serviceType) public static List<ServiceMethod> Reset(Type serviceType)
{ {
var actions = new List<ActionContext>(); var actions = new List<ServiceMethod>();
foreach (var mi in serviceType.GetActions()) foreach (var mi in serviceType.GetActions())
{ {
var actionName = mi.Name.ToUpper(); var actionName = mi.Name;
var args = mi.GetParameters(); var args = mi.GetParameters();
var requestType = args[0].ParameterType; var requestType = args[0].ParameterType;
var actionCtx = new ActionContext var actionCtx = new ServiceMethod
{ {
Id = ActionContext.Key(serviceType, actionName, requestType.GetOperationName()) Id = ServiceMethod.Key(serviceType, actionName, requestType.GetOperationName())
}; };
try try

View File

@ -0,0 +1,297 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services;
using ServiceStack;
namespace Emby.Server.Implementations.Services
{
public class ServiceHandler
{
public async Task<object> HandleResponseAsync(object response)
{
var taskResponse = response as Task;
if (taskResponse == null)
{
return response;
}
await taskResponse.ConfigureAwait(false);
var taskResult = GetTaskResult(taskResponse);
var subTask = taskResult as Task;
if (subTask != null)
{
taskResult = GetTaskResult(subTask);
}
return taskResult;
}
internal static object GetTaskResult(Task task)
{
try
{
var taskObject = task as Task<object>;
if (taskObject != null)
{
return taskObject.Result;
}
task.Wait();
var type = task.GetType().GetTypeInfo();
if (!type.IsGenericType)
{
return null;
}
return type.GetDeclaredProperty("Result").GetValue(task);
}
catch (TypeAccessException)
{
return null; //return null for void Task's
}
}
protected static object CreateContentTypeRequest(IRequest httpReq, Type requestType, string contentType)
{
if (!string.IsNullOrEmpty(contentType) && httpReq.ContentLength > 0)
{
var deserializer = RequestHelper.GetRequestReader(contentType);
if (deserializer != null)
{
return deserializer(requestType, httpReq.InputStream);
}
}
return ServiceStackHost.Instance.CreateInstance(requestType); //Return an empty DTO, even for empty request bodies
}
public static RestPath FindMatchingRestPath(string httpMethod, string pathInfo, ILogger logger, out string contentType)
{
pathInfo = GetSanitizedPathInfo(pathInfo, out contentType);
return ServiceController.Instance.GetRestPathForRequest(httpMethod, pathInfo, logger);
}
public static string GetSanitizedPathInfo(string pathInfo, out string contentType)
{
contentType = null;
var pos = pathInfo.LastIndexOf('.');
if (pos >= 0)
{
var format = pathInfo.Substring(pos + 1);
contentType = GetFormatContentType(format);
if (contentType != null)
{
pathInfo = pathInfo.Substring(0, pos);
}
}
return pathInfo;
}
private static string GetFormatContentType(string format)
{
//built-in formats
if (format == "json")
return "application/json";
if (format == "xml")
return "application/xml";
return null;
}
public RestPath GetRestPath(string httpMethod, string pathInfo)
{
if (this.RestPath == null)
{
string contentType;
this.RestPath = FindMatchingRestPath(httpMethod, pathInfo, new NullLogger(), out contentType);
if (contentType != null)
ResponseContentType = contentType;
}
return this.RestPath;
}
public RestPath RestPath { get; set; }
// Set from SSHHF.GetHandlerForPathInfo()
public string ResponseContentType { get; set; }
public async Task ProcessRequestAsync(HttpListenerHost appHost, IRequest httpReq, IResponse httpRes, ILogger logger, string operationName)
{
var restPath = GetRestPath(httpReq.Verb, httpReq.PathInfo);
if (restPath == null)
{
throw new NotSupportedException("No RestPath found for: " + httpReq.Verb + " " + httpReq.PathInfo);
}
SetRoute(httpReq, restPath);
if (ResponseContentType != null)
httpReq.ResponseContentType = ResponseContentType;
var request = httpReq.Dto = CreateRequest(httpReq, restPath, logger);
appHost.ApplyRequestFilters(httpReq, httpRes, request);
var rawResponse = await appHost.ServiceController.Execute(appHost, request, httpReq).ConfigureAwait(false);
var response = await HandleResponseAsync(rawResponse).ConfigureAwait(false);
// Apply response filters
foreach (var responseFilter in appHost.GlobalResponseFilters)
{
responseFilter(httpReq, httpRes, response);
}
await ResponseHelper.WriteToResponse(httpRes, httpReq, response).ConfigureAwait(false);
}
public static object CreateRequest(IRequest httpReq, RestPath restPath, ILogger logger)
{
var requestType = restPath.RequestType;
if (RequireqRequestStream(requestType))
{
// Used by IRequiresRequestStream
return CreateRequiresRequestStreamRequest(httpReq, requestType);
}
var requestParams = GetFlattenedRequestParams(httpReq);
return CreateRequest(httpReq, restPath, requestParams);
}
private static bool RequireqRequestStream(Type requestType)
{
var requiresRequestStreamTypeInfo = typeof(IRequiresRequestStream).GetTypeInfo();
return requiresRequestStreamTypeInfo.IsAssignableFrom(requestType.GetTypeInfo());
}
private static IRequiresRequestStream CreateRequiresRequestStreamRequest(IRequest req, Type requestType)
{
var restPath = GetRoute(req);
var request = ServiceHandler.CreateRequest(req, restPath, GetRequestParams(req), ServiceStackHost.Instance.CreateInstance(requestType));
var rawReq = (IRequiresRequestStream)request;
rawReq.RequestStream = req.InputStream;
return rawReq;
}
public static object CreateRequest(IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams)
{
var requestDto = CreateContentTypeRequest(httpReq, restPath.RequestType, httpReq.ContentType);
return CreateRequest(httpReq, restPath, requestParams, requestDto);
}
public static object CreateRequest(IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams, object requestDto)
{
string contentType;
var pathInfo = !restPath.IsWildCardPath
? GetSanitizedPathInfo(httpReq.PathInfo, out contentType)
: httpReq.PathInfo;
return restPath.CreateRequest(pathInfo, requestParams, requestDto);
}
/// <summary>
/// Duplicate Params are given a unique key by appending a #1 suffix
/// </summary>
private static Dictionary<string, string> GetRequestParams(IRequest request)
{
var map = new Dictionary<string, string>();
foreach (var name in request.QueryString.Keys)
{
if (name == null) continue; //thank you ASP.NET
var values = request.QueryString.GetValues(name);
if (values.Length == 1)
{
map[name] = values[0];
}
else
{
for (var i = 0; i < values.Length; i++)
{
map[name + (i == 0 ? "" : "#" + i)] = values[i];
}
}
}
if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")) && request.FormData != null)
{
foreach (var name in request.FormData.Keys)
{
if (name == null) continue; //thank you ASP.NET
var values = request.FormData.GetValues(name);
if (values.Length == 1)
{
map[name] = values[0];
}
else
{
for (var i = 0; i < values.Length; i++)
{
map[name + (i == 0 ? "" : "#" + i)] = values[i];
}
}
}
}
return map;
}
private static bool IsMethod(string method, string expected)
{
return string.Equals(method, expected, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Duplicate params have their values joined together in a comma-delimited string
/// </summary>
private static Dictionary<string, string> GetFlattenedRequestParams(IRequest request)
{
var map = new Dictionary<string, string>();
foreach (var name in request.QueryString.Keys)
{
if (name == null) continue; //thank you ASP.NET
map[name] = request.QueryString[name];
}
if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")) && request.FormData != null)
{
foreach (var name in request.FormData.Keys)
{
if (name == null) continue; //thank you ASP.NET
map[name] = request.FormData[name];
}
}
return map;
}
private static void SetRoute(IRequest req, RestPath route)
{
req.Items["__route"] = route;
}
private static RestPath GetRoute(IRequest req)
{
object route;
req.Items.TryGetValue("__route", out route);
return route as RestPath;
}
}
}

View File

@ -1,11 +1,8 @@
using System; using System;
namespace ServiceStack.Host namespace Emby.Server.Implementations.Services
{ {
/// <summary> public class ServiceMethod
/// Context to capture IService action
/// </summary>
public class ActionContext
{ {
public const string AnyAction = "ANY"; public const string AnyAction = "ANY";

View File

@ -37,10 +37,6 @@
<Reference Include="Emby.Server.Core"> <Reference Include="Emby.Server.Core">
<HintPath>..\ThirdParty\emby\Emby.Server.Core.dll</HintPath> <HintPath>..\ThirdParty\emby\Emby.Server.Core.dll</HintPath>
</Reference> </Reference>
<Reference Include="INIFileParser, Version=2.3.0.0, Culture=neutral, PublicKeyToken=79af7b307b65cf3c, processorArchitecture=MSIL">
<HintPath>..\packages\ini-parser.2.3.0\lib\net20\INIFileParser.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.1\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath> <HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.1\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
<Private>True</Private> <Private>True</Private>
@ -79,28 +75,6 @@
<Compile Include="Cryptography\X520Attributes.cs" /> <Compile Include="Cryptography\X520Attributes.cs" />
<Compile Include="ImageEncoderHelper.cs" /> <Compile Include="ImageEncoderHelper.cs" />
<Compile Include="IO\MemoryStreamProvider.cs" /> <Compile Include="IO\MemoryStreamProvider.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\ChannelScan.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\ReportBlock.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpAppPacket.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpByePacket.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpListener.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpPacket.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpReceiverReportPacket.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpSenderReportPacket.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpSourceDescriptionPacket.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\SourceDescriptionBlock.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\SourceDescriptionItem.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtp\RtpListener.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtp\RtpPacket.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtsp\RtspMethod.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtsp\RtspRequest.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtsp\RtspResponse.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtsp\RtspSession.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Rtsp\RtspStatusCode.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\SatIpDiscovery.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\SatIpHost.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\TransmissionMode.cs" />
<Compile Include="LiveTv\TunerHosts\SatIp\Utils.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SystemEvents.cs" /> <Compile Include="SystemEvents.cs" />
</ItemGroup> </ItemGroup>
@ -136,175 +110,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0030.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0049.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0070.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0090.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0100.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0130.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0160.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0170.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0192.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0200.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0215.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0235.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0255.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0260.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0282.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0305.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0308.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0310.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0315.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0330.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0360.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0380.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0390.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0400.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0420.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0435.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0450.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0460.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0475.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0480.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0490.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0505.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0510.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0520.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0525.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0530.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0549.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0560.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0570.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0600.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0620.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0642.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0650.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0660.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0685.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0705.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0721.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0740.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0750.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0765.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0785.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0830.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0851.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0865.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0875.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0880.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0900.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0915.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0922.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0935.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0950.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\0965.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1005.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1030.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1055.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1082.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1100.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1105.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1130.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1155.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1160.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1180.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1195.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1222.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1240.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1250.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1280.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1320.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1340.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1380.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1400.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1440.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1500.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1520.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1540.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1560.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1590.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1600 OPTUS D1 FTA %28160.0E%29.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1600.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1620.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1640.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1660.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1690.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1720.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1800.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\1830.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2210.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2230.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2250.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2270.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2290.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2310.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2330.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2350.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2370.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2390.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2410.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2432.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2451.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2470.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2489.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2500.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2527.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2550.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2570.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2590.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2608.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2630.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2650.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2669.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2690.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2710.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2728.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2730.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2750.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2760.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2770.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2780.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2812.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2820.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2830.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2850.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2873.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2880.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2881.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2882.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2900.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2930.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2950.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2970.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2985.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\2990.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3020.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3045.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3070.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3100.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3125.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3150.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3169.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3195.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3225.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3255.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3285.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3300.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3325.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3355.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3380.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3400.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3420.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3450.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3460.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3475.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3490.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3520.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3527.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3550.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3560.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3592.ini" />
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3594.ini" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup />

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="ini-parser" version="2.3.0" targetFramework="net46" />
<package id="Microsoft.IO.RecyclableMemoryStream" version="1.2.1" targetFramework="net46" /> <package id="Microsoft.IO.RecyclableMemoryStream" version="1.2.1" targetFramework="net46" />
</packages> </packages>

View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using ServiceStack;
namespace ServiceStack.Support.WebHost
{
public static class FilterAttributeCache
{
public static MediaBrowser.Model.Services.IHasRequestFilter[] GetRequestFilterAttributes(Type requestDtoType)
{
var attributes = requestDtoType.AllAttributes().OfType<MediaBrowser.Model.Services.IHasRequestFilter>().ToList();
var serviceType = ServiceStackHost.Instance.Metadata.GetServiceTypeByRequest(requestDtoType);
if (serviceType != null)
{
attributes.AddRange(serviceType.AllAttributes().OfType<MediaBrowser.Model.Services.IHasRequestFilter>());
}
attributes.Sort((x,y) => x.Priority - y.Priority);
return attributes.ToArray();
}
}
}

View File

@ -1,176 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
namespace ServiceStack.Host
{
public class RestHandler
{
public string RequestName { get; set; }
public async Task<object> HandleResponseAsync(object response)
{
var taskResponse = response as Task;
if (taskResponse == null)
{
return response;
}
await taskResponse.ConfigureAwait(false);
var taskResult = ServiceStackHost.Instance.GetTaskResult(taskResponse, RequestName);
var subTask = taskResult as Task;
if (subTask != null)
{
taskResult = ServiceStackHost.Instance.GetTaskResult(subTask, RequestName);
}
return taskResult;
}
protected static object CreateContentTypeRequest(IRequest httpReq, Type requestType, string contentType)
{
if (!string.IsNullOrEmpty(contentType) && httpReq.ContentLength > 0)
{
var deserializer = ContentTypes.Instance.GetStreamDeserializer(contentType);
if (deserializer != null)
{
return deserializer(requestType, httpReq.InputStream);
}
}
return ServiceStackHost.Instance.CreateInstance(requestType); //Return an empty DTO, even for empty request bodies
}
protected static object GetCustomRequestFromBinder(IRequest httpReq, Type requestType)
{
Func<IRequest, object> requestFactoryFn;
ServiceStackHost.Instance.ServiceController.RequestTypeFactoryMap.TryGetValue(
requestType, out requestFactoryFn);
return requestFactoryFn != null ? requestFactoryFn(httpReq) : null;
}
public static RestPath FindMatchingRestPath(string httpMethod, string pathInfo, out string contentType)
{
pathInfo = GetSanitizedPathInfo(pathInfo, out contentType);
return ServiceStackHost.Instance.ServiceController.GetRestPathForRequest(httpMethod, pathInfo);
}
public static string GetSanitizedPathInfo(string pathInfo, out string contentType)
{
contentType = null;
var pos = pathInfo.LastIndexOf('.');
if (pos >= 0)
{
var format = pathInfo.Substring(pos + 1);
contentType = GetFormatContentType(format);
if (contentType != null)
{
pathInfo = pathInfo.Substring(0, pos);
}
}
return pathInfo;
}
private static string GetFormatContentType(string format)
{
//built-in formats
if (format == "json")
return "application/json";
if (format == "xml")
return "application/xml";
return null;
}
public RestPath GetRestPath(string httpMethod, string pathInfo)
{
if (this.RestPath == null)
{
string contentType;
this.RestPath = FindMatchingRestPath(httpMethod, pathInfo, out contentType);
if (contentType != null)
ResponseContentType = contentType;
}
return this.RestPath;
}
public RestPath RestPath { get; set; }
// Set from SSHHF.GetHandlerForPathInfo()
public string ResponseContentType { get; set; }
public async Task ProcessRequestAsync(IRequest httpReq, IResponse httpRes, string operationName)
{
var appHost = ServiceStackHost.Instance;
var restPath = GetRestPath(httpReq.Verb, httpReq.PathInfo);
if (restPath == null)
{
throw new NotSupportedException("No RestPath found for: " + httpReq.Verb + " " + httpReq.PathInfo);
}
httpReq.SetRoute(restPath);
if (ResponseContentType != null)
httpReq.ResponseContentType = ResponseContentType;
var request = httpReq.Dto = CreateRequest(httpReq, restPath);
appHost.ApplyRequestFilters(httpReq, httpRes, request);
var rawResponse = await ServiceStackHost.Instance.ServiceController.Execute(request, httpReq).ConfigureAwait(false);
var response = await HandleResponseAsync(rawResponse).ConfigureAwait(false);
appHost.ApplyResponseFilters(httpReq, httpRes, response);
await httpRes.WriteToResponse(httpReq, response).ConfigureAwait(false);
}
public static object CreateRequest(IRequest httpReq, RestPath restPath)
{
var dtoFromBinder = GetCustomRequestFromBinder(httpReq, restPath.RequestType);
if (dtoFromBinder != null)
return dtoFromBinder;
var requestParams = httpReq.GetFlattenedRequestParams();
return CreateRequest(httpReq, restPath, requestParams);
}
public static object CreateRequest(IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams)
{
var requestDto = CreateContentTypeRequest(httpReq, restPath.RequestType, httpReq.ContentType);
return CreateRequest(httpReq, restPath, requestParams, requestDto);
}
public static object CreateRequest(IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams, object requestDto)
{
string contentType;
var pathInfo = !restPath.IsWildCardPath
? GetSanitizedPathInfo(httpReq.PathInfo, out contentType)
: httpReq.PathInfo;
return restPath.CreateRequest(pathInfo, requestParams, requestDto);
}
/// <summary>
/// Used in Unit tests
/// </summary>
/// <returns></returns>
public object CreateRequest(IRequest httpReq, string operationName)
{
if (this.RestPath == null)
throw new ArgumentNullException("No RestPath found");
return CreateRequest(httpReq, this.RestPath);
}
}
}

View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
namespace ServiceStack.Host
{
public class ServiceMetadata
{
public ServiceMetadata()
{
this.OperationsMap = new Dictionary<Type, Type>();
}
public Dictionary<Type, Type> OperationsMap { get; protected set; }
public void Add(Type serviceType, Type requestType, Type responseType)
{
this.OperationsMap[requestType] = serviceType;
}
public Type GetServiceTypeByRequest(Type requestType)
{
Type serviceType;
OperationsMap.TryGetValue(requestType, out serviceType);
return serviceType;
}
}
}

View File

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

View File

@ -1,127 +0,0 @@
using System;
using System.Collections.Generic;
using MediaBrowser.Model.Services;
using ServiceStack.Host;
namespace ServiceStack
{
public static class HttpRequestExtensions
{
/**
*
Input: http://localhost:96/Cambia3/Temp/Test.aspx/path/info?q=item#fragment
Some HttpRequest path and URL properties:
Request.ApplicationPath: /Cambia3
Request.CurrentExecutionFilePath: /Cambia3/Temp/Test.aspx
Request.FilePath: /Cambia3/Temp/Test.aspx
Request.Path: /Cambia3/Temp/Test.aspx/path/info
Request.PathInfo: /path/info
Request.PhysicalApplicationPath: D:\Inetpub\wwwroot\CambiaWeb\Cambia3\
Request.QueryString: /Cambia3/Temp/Test.aspx/path/info?query=arg
Request.Url.AbsolutePath: /Cambia3/Temp/Test.aspx/path/info
Request.Url.AbsoluteUri: http://localhost:96/Cambia3/Temp/Test.aspx/path/info?query=arg
Request.Url.Fragment:
Request.Url.Host: localhost
Request.Url.LocalPath: /Cambia3/Temp/Test.aspx/path/info
Request.Url.PathAndQuery: /Cambia3/Temp/Test.aspx/path/info?query=arg
Request.Url.Port: 96
Request.Url.Query: ?query=arg
Request.Url.Scheme: http
Request.Url.Segments: /
Cambia3/
Temp/
Test.aspx/
path/
info
* */
/// <summary>
/// Duplicate Params are given a unique key by appending a #1 suffix
/// </summary>
public static Dictionary<string, string> GetRequestParams(this IRequest request)
{
var map = new Dictionary<string, string>();
foreach (var name in request.QueryString.Keys)
{
if (name == null) continue; //thank you ASP.NET
var values = request.QueryString.GetValues(name);
if (values.Length == 1)
{
map[name] = values[0];
}
else
{
for (var i = 0; i < values.Length; i++)
{
map[name + (i == 0 ? "" : "#" + i)] = values[i];
}
}
}
if ((request.Verb == HttpMethods.Post || request.Verb == HttpMethods.Put)
&& request.FormData != null)
{
foreach (var name in request.FormData.Keys)
{
if (name == null) continue; //thank you ASP.NET
var values = request.FormData.GetValues(name);
if (values.Length == 1)
{
map[name] = values[0];
}
else
{
for (var i = 0; i < values.Length; i++)
{
map[name + (i == 0 ? "" : "#" + i)] = values[i];
}
}
}
}
return map;
}
/// <summary>
/// Duplicate params have their values joined together in a comma-delimited string
/// </summary>
public static Dictionary<string, string> GetFlattenedRequestParams(this IRequest request)
{
var map = new Dictionary<string, string>();
foreach (var name in request.QueryString.Keys)
{
if (name == null) continue; //thank you ASP.NET
map[name] = request.QueryString[name];
}
if ((request.Verb == HttpMethods.Post || request.Verb == HttpMethods.Put)
&& request.FormData != null)
{
foreach (var name in request.FormData.Keys)
{
if (name == null) continue; //thank you ASP.NET
map[name] = request.FormData[name];
}
}
return map;
}
public static void SetRoute(this IRequest req, RestPath route)
{
req.Items["__route"] = route;
}
public static RestPath GetRoute(this IRequest req)
{
object route;
req.Items.TryGetValue("__route", out route);
return route as RestPath;
}
}
}

View File

@ -1,34 +0,0 @@
//Copyright (c) Service Stack LLC. All Rights Reserved.
//License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt
using System;
using System.Collections.Generic;
namespace ServiceStack
{
internal static class HttpMethods
{
static readonly string[] allVerbs = new[] {
"OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", // RFC 2616
"PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", // RFC 2518
"VERSION-CONTROL", "REPORT", "CHECKOUT", "CHECKIN", "UNCHECKOUT",
"MKWORKSPACE", "UPDATE", "LABEL", "MERGE", "BASELINE-CONTROL", "MKACTIVITY", // RFC 3253
"ORDERPATCH", // RFC 3648
"ACL", // RFC 3744
"PATCH", // https://datatracker.ietf.org/doc/draft-dusseault-http-patch/
"SEARCH", // https://datatracker.ietf.org/doc/draft-reschke-webdav-search/
"BCOPY", "BDELETE", "BMOVE", "BPROPFIND", "BPROPPATCH", "NOTIFY",
"POLL", "SUBSCRIBE", "UNSUBSCRIBE" //MS Exchange WebDav: http://msdn.microsoft.com/en-us/library/aa142917.aspx
};
public static HashSet<string> AllVerbs = new HashSet<string>(allVerbs);
public const string Get = "GET";
public const string Put = "PUT";
public const string Post = "POST";
public const string Delete = "DELETE";
public const string Options = "OPTIONS";
public const string Head = "HEAD";
public const string Patch = "PATCH";
}
}

View File

@ -3,26 +3,11 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace ServiceStack namespace ServiceStack
{ {
public static class ReflectionExtensions public static class ReflectionExtensions
{ {
public static bool IsInstanceOf(this Type type, Type thisOrBaseType)
{
while (type != null)
{
if (type == thisOrBaseType)
return true;
type = type.BaseType();
}
return false;
}
public static Type FirstGenericType(this Type type) public static Type FirstGenericType(this Type type)
{ {
while (type != null) while (type != null)
@ -54,44 +39,6 @@ namespace ServiceStack
return null; return null;
} }
public static PropertyInfo[] GetAllProperties(this Type type)
{
if (type.IsInterface())
{
var propertyInfos = new List<PropertyInfo>();
var considered = new List<Type>();
var queue = new Queue<Type>();
considered.Add(type);
queue.Enqueue(type);
while (queue.Count > 0)
{
var subType = queue.Dequeue();
foreach (var subInterface in subType.GetTypeInterfaces())
{
if (considered.Contains(subInterface)) continue;
considered.Add(subInterface);
queue.Enqueue(subInterface);
}
var typeProperties = subType.GetTypesProperties();
var newPropertyInfos = typeProperties
.Where(x => !propertyInfos.Contains(x));
propertyInfos.InsertRange(0, newPropertyInfos);
}
return propertyInfos.ToArray();
}
return type.GetTypesProperties()
.Where(t => t.GetIndexParameters().Length == 0) // ignore indexed properties
.ToArray();
}
public static PropertyInfo[] GetPublicProperties(this Type type) public static PropertyInfo[] GetPublicProperties(this Type type)
{ {
if (type.IsInterface()) if (type.IsInterface())
@ -139,9 +86,7 @@ namespace ServiceStack
public static PropertyInfo[] GetSerializableProperties(this Type type) public static PropertyInfo[] GetSerializableProperties(this Type type)
{ {
var properties = type.IsDto() var properties = type.GetPublicProperties();
? type.GetAllProperties()
: type.GetPublicProperties();
return properties.OnlySerializableProperties(type); return properties.OnlySerializableProperties(type);
} }
@ -150,14 +95,7 @@ namespace ServiceStack
public static PropertyInfo[] OnlySerializableProperties(this PropertyInfo[] properties, Type type = null) public static PropertyInfo[] OnlySerializableProperties(this PropertyInfo[] properties, Type type = null)
{ {
var isDto = type.IsDto(); var readableProperties = properties.Where(x => x.PropertyGetMethod(nonPublic: false) != null);
var readableProperties = properties.Where(x => x.PropertyGetMethod(nonPublic: isDto) != null);
if (isDto)
{
return readableProperties.Where(attr =>
attr.HasAttribute<DataMemberAttribute>()).ToArray();
}
// else return those properties that are not decorated with IgnoreDataMember // else return those properties that are not decorated with IgnoreDataMember
return readableProperties return readableProperties
@ -206,36 +144,6 @@ namespace ServiceStack
return pis.ToArray(); return pis.ToArray();
} }
internal static PropertyInfo[] GetTypesProperties(this Type subType)
{
var pis = new List<PropertyInfo>();
foreach (var pi in subType.GetRuntimeProperties())
{
var mi = pi.GetMethod ?? pi.SetMethod;
if (mi != null && mi.IsStatic) continue;
pis.Add(pi);
}
return pis.ToArray();
}
public static bool HasAttribute<T>(this Type type)
{
return type.AllAttributes().Any(x => x.GetType() == typeof(T));
}
public static bool HasAttribute<T>(this PropertyInfo pi)
{
return pi.AllAttributes().Any(x => x.GetType() == typeof(T));
}
public static bool IsDto(this Type type)
{
if (type == null)
return false;
return type.HasAttribute<DataContractAttribute>();
}
public static MethodInfo PropertyGetMethod(this PropertyInfo pi, bool nonPublic = false) public static MethodInfo PropertyGetMethod(this PropertyInfo pi, bool nonPublic = false)
{ {
return pi.GetMethod; return pi.GetMethod;
@ -246,25 +154,15 @@ namespace ServiceStack
return propertyInfo.GetCustomAttributes(true).ToArray(); return propertyInfo.GetCustomAttributes(true).ToArray();
} }
public static object[] AllAttributes(this PropertyInfo propertyInfo, Type attrType)
{
return propertyInfo.GetCustomAttributes(true).Where(x => attrType.IsInstanceOf(x.GetType())).ToArray();
}
public static object[] AllAttributes(this Type type) public static object[] AllAttributes(this Type type)
{ {
return type.GetTypeInfo().GetCustomAttributes(true).ToArray(); return type.GetTypeInfo().GetCustomAttributes(true).ToArray();
} }
public static TAttr[] AllAttributes<TAttr>(this PropertyInfo pi) public static List<TAttr> AllAttributes<TAttr>(this Type type)
{
return pi.AllAttributes(typeof(TAttr)).Cast<TAttr>().ToArray();
}
public static TAttr[] AllAttributes<TAttr>(this Type type)
where TAttr : Attribute where TAttr : Attribute
{ {
return type.GetTypeInfo().GetCustomAttributes<TAttr>(true).ToArray(); return type.GetTypeInfo().GetCustomAttributes<TAttr>(true).ToList();
} }
} }
} }

View File

@ -1,11 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Text; using System.Text;
using MediaBrowser.Model.Logging;
using ServiceStack.Serialization; using ServiceStack.Serialization;
namespace ServiceStack.Host namespace ServiceStack
{ {
public class RestPath public class RestPath
{ {
@ -46,11 +46,11 @@ namespace ServiceStack.Host
public string[] Verbs public string[] Verbs
{ {
get get
{ {
return allowsAllVerbs return allowsAllVerbs
? new[] { ActionContext.AnyAction } ? new[] { "ANY" }
: AllowedVerbs.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); : AllowedVerbs.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
} }
} }
@ -75,31 +75,36 @@ namespace ServiceStack.Host
return parts; return parts;
} }
public static IEnumerable<string> GetFirstMatchHashKeys(string[] pathPartsForMatching) public static List<string> GetFirstMatchHashKeys(string[] pathPartsForMatching)
{ {
var hashPrefix = pathPartsForMatching.Length + PathSeperator; var hashPrefix = pathPartsForMatching.Length + PathSeperator;
return GetPotentialMatchesWithPrefix(hashPrefix, pathPartsForMatching); return GetPotentialMatchesWithPrefix(hashPrefix, pathPartsForMatching);
} }
public static IEnumerable<string> GetFirstMatchWildCardHashKeys(string[] pathPartsForMatching) public static List<string> GetFirstMatchWildCardHashKeys(string[] pathPartsForMatching)
{ {
const string hashPrefix = WildCard + PathSeperator; const string hashPrefix = WildCard + PathSeperator;
return GetPotentialMatchesWithPrefix(hashPrefix, pathPartsForMatching); return GetPotentialMatchesWithPrefix(hashPrefix, pathPartsForMatching);
} }
private static IEnumerable<string> GetPotentialMatchesWithPrefix(string hashPrefix, string[] pathPartsForMatching) private static List<string> GetPotentialMatchesWithPrefix(string hashPrefix, string[] pathPartsForMatching)
{ {
var list = new List<string>();
foreach (var part in pathPartsForMatching) foreach (var part in pathPartsForMatching)
{ {
yield return hashPrefix + part; list.Add(hashPrefix + part);
var subParts = part.Split(ComponentSeperator); var subParts = part.Split(ComponentSeperator);
if (subParts.Length == 1) continue; if (subParts.Length == 1) continue;
foreach (var subPart in subParts) foreach (var subPart in subParts)
{ {
yield return hashPrefix + subPart; list.Add(hashPrefix + subPart);
} }
} }
return list;
} }
public RestPath(Type requestType, string path, string verbs, string summary = null, string notes = null) public RestPath(Type requestType, string path, string verbs, string summary = null, string notes = null)
@ -220,16 +225,14 @@ namespace ServiceStack.Host
private readonly Dictionary<string, string> propertyNamesMap = new Dictionary<string, string>(); private readonly Dictionary<string, string> propertyNamesMap = new Dictionary<string, string>();
public static Func<RestPath, string, string[], int> CalculateMatchScore { get; set; } public int MatchScore(string httpMethod, string[] withPathInfoParts, ILogger logger)
public int MatchScore(string httpMethod, string[] withPathInfoParts)
{ {
if (CalculateMatchScore != null)
return CalculateMatchScore(this, httpMethod, withPathInfoParts);
int wildcardMatchCount; int wildcardMatchCount;
var isMatch = IsMatch(httpMethod, withPathInfoParts, out wildcardMatchCount); var isMatch = IsMatch(httpMethod, withPathInfoParts, logger, out wildcardMatchCount);
if (!isMatch) return -1; if (!isMatch)
{
return -1;
}
var score = 0; var score = 0;
@ -255,19 +258,33 @@ namespace ServiceStack.Host
/// For performance withPathInfoParts should already be a lower case string /// For performance withPathInfoParts should already be a lower case string
/// to minimize redundant matching operations. /// to minimize redundant matching operations.
/// </summary> /// </summary>
/// <param name="httpMethod"></param> public bool IsMatch(string httpMethod, string[] withPathInfoParts, ILogger logger, out int wildcardMatchCount)
/// <param name="withPathInfoParts"></param>
/// <param name="wildcardMatchCount"></param>
/// <returns></returns>
public bool IsMatch(string httpMethod, string[] withPathInfoParts, out int wildcardMatchCount)
{ {
wildcardMatchCount = 0; wildcardMatchCount = 0;
if (withPathInfoParts.Length != this.PathComponentsCount && !this.IsWildCardPath) return false; if (withPathInfoParts.Length != this.PathComponentsCount && !this.IsWildCardPath)
if (!this.allowsAllVerbs && !StringContains(this.allowedVerbs, httpMethod)) return false; {
//logger.Info("withPathInfoParts mismatch for {0} for {1}", httpMethod, string.Join("/", withPathInfoParts));
return false;
}
if (!ExplodeComponents(ref withPathInfoParts)) return false; if (!this.allowsAllVerbs && !StringContains(this.allowedVerbs, httpMethod))
if (this.TotalComponentsCount != withPathInfoParts.Length && !this.IsWildCardPath) return false; {
//logger.Info("allowsAllVerbs mismatch for {0} for {1} allowedverbs {2}", httpMethod, string.Join("/", withPathInfoParts), this.allowedVerbs);
return false;
}
if (!ExplodeComponents(ref withPathInfoParts))
{
//logger.Info("ExplodeComponents mismatch for {0} for {1}", httpMethod, string.Join("/", withPathInfoParts));
return false;
}
if (this.TotalComponentsCount != withPathInfoParts.Length && !this.IsWildCardPath)
{
//logger.Info("TotalComponentsCount mismatch for {0} for {1}", httpMethod, string.Join("/", withPathInfoParts));
return false;
}
int pathIx = 0; int pathIx = 0;
for (var i = 0; i < this.TotalComponentsCount; i++) for (var i = 0; i < this.TotalComponentsCount; i++)
@ -277,7 +294,7 @@ namespace ServiceStack.Host
if (i < this.TotalComponentsCount - 1) if (i < this.TotalComponentsCount - 1)
{ {
// Continue to consume up until a match with the next literal // Continue to consume up until a match with the next literal
while (pathIx < withPathInfoParts.Length && withPathInfoParts[pathIx] != this.literalsToMatch[i + 1]) while (pathIx < withPathInfoParts.Length && !LiteralsEqual(withPathInfoParts[pathIx], this.literalsToMatch[i + 1]))
{ {
pathIx++; pathIx++;
wildcardMatchCount++; wildcardMatchCount++;
@ -286,6 +303,7 @@ namespace ServiceStack.Host
// Ensure there are still enough parts left to match the remainder // Ensure there are still enough parts left to match the remainder
if ((withPathInfoParts.Length - pathIx) < (this.TotalComponentsCount - i - 1)) if ((withPathInfoParts.Length - pathIx) < (this.TotalComponentsCount - i - 1))
{ {
//logger.Info("withPathInfoParts length mismatch for {0} for {1}", httpMethod, string.Join("/", withPathInfoParts));
return false; return false;
} }
} }
@ -306,7 +324,11 @@ namespace ServiceStack.Host
continue; continue;
} }
if (withPathInfoParts.Length <= pathIx || withPathInfoParts[pathIx] != literalToMatch) return false; if (withPathInfoParts.Length <= pathIx || !LiteralsEqual(withPathInfoParts[pathIx], literalToMatch))
{
//logger.Info("withPathInfoParts2 length mismatch for {0} for {1}. not equals: {2} != {3}.", httpMethod, string.Join("/", withPathInfoParts), withPathInfoParts[pathIx], literalToMatch);
return false;
}
pathIx++; pathIx++;
} }
} }
@ -314,6 +336,22 @@ namespace ServiceStack.Host
return pathIx == withPathInfoParts.Length; return pathIx == withPathInfoParts.Length;
} }
private bool LiteralsEqual(string str1, string str2)
{
// Most cases
if (string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase))
{
return true;
}
// Handle turkish i
str1 = str1.ToUpperInvariant();
str2 = str2.ToUpperInvariant();
// Invariant IgnoreCase would probably be better but it's not available in PCL
return string.Equals(str1, str2, StringComparison.CurrentCultureIgnoreCase);
}
private bool ExplodeComponents(ref string[] withPathInfoParts) private bool ExplodeComponents(ref string[] withPathInfoParts)
{ {
var totalComponents = new List<string>(); var totalComponents = new List<string>();
@ -374,9 +412,9 @@ namespace ServiceStack.Host
if (string.Equals("ignore", variableName, StringComparison.OrdinalIgnoreCase)) if (string.Equals("ignore", variableName, StringComparison.OrdinalIgnoreCase))
{ {
pathIx++; pathIx++;
continue; continue;
} }
throw new ArgumentException("Could not find property " throw new ArgumentException("Could not find property "
+ variableName + " on " + RequestType.GetOperationName()); + variableName + " on " + RequestType.GetOperationName());
} }

View File

@ -69,24 +69,11 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="HttpUtils.cs" />
<Compile Include="Host\ContentTypes.cs" />
<Compile Include="ReflectionExtensions.cs" /> <Compile Include="ReflectionExtensions.cs" />
<Compile Include="StringMapTypeDeserializer.cs" /> <Compile Include="StringMapTypeDeserializer.cs" />
<Compile Include="HttpResult.cs" />
<Compile Include="ServiceStackHost.cs" /> <Compile Include="ServiceStackHost.cs" />
<Compile Include="ServiceStackHost.Runtime.cs" />
<Compile Include="Host\ServiceExec.cs" />
<Compile Include="UrlExtensions.cs" /> <Compile Include="UrlExtensions.cs" />
<Compile Include="Host\ActionContext.cs" /> <Compile Include="RestPath.cs" />
<Compile Include="HttpRequestExtensions.cs" />
<Compile Include="Host\RestPath.cs" />
<Compile Include="Host\ServiceController.cs" />
<Compile Include="Host\ServiceMetadata.cs" />
<Compile Include="Host\RestHandler.cs" />
<Compile Include="HttpResponseExtensionsInternal.cs" />
<Compile Include="HttpHandlerFactory.cs" />
<Compile Include="FilterAttributeCache.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,57 +0,0 @@
// Copyright (c) Service Stack LLC. All Rights Reserved.
// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt
using MediaBrowser.Model.Services;
using ServiceStack.Support.WebHost;
namespace ServiceStack
{
public abstract partial class ServiceStackHost
{
/// <summary>
/// Applies the request filters. Returns whether or not the request has been handled
/// and no more processing should be done.
/// </summary>
/// <returns></returns>
public virtual void ApplyRequestFilters(IRequest req, IResponse res, object requestDto)
{
//Exec all RequestFilter attributes with Priority < 0
var attributes = FilterAttributeCache.GetRequestFilterAttributes(requestDto.GetType());
var i = 0;
for (; i < attributes.Length && attributes[i].Priority < 0; i++)
{
var attribute = attributes[i];
attribute.RequestFilter(req, res, requestDto);
}
//Exec global filters
foreach (var requestFilter in GlobalRequestFilters)
{
requestFilter(req, res, requestDto);
}
//Exec remaining RequestFilter attributes with Priority >= 0
for (; i < attributes.Length && attributes[i].Priority >= 0; i++)
{
var attribute = attributes[i];
attribute.RequestFilter(req, res, requestDto);
}
}
/// <summary>
/// Applies the response filters. Returns whether or not the request has been handled
/// and no more processing should be done.
/// </summary>
/// <returns></returns>
public virtual void ApplyResponseFilters(IRequest req, IResponse res, object response)
{
//Exec global filters
foreach (var responseFilter in GlobalResponseFilters)
{
responseFilter(req, res, response);
}
}
}
}

View File

@ -6,71 +6,24 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using ServiceStack.Host;
namespace ServiceStack namespace ServiceStack
{ {
public abstract partial class ServiceStackHost : IDisposable public abstract class ServiceStackHost : IDisposable
{ {
public static ServiceStackHost Instance { get; protected set; } public static ServiceStackHost Instance { get; protected set; }
protected ServiceStackHost(string serviceName) protected ServiceStackHost()
{ {
ServiceName = serviceName;
ServiceController = CreateServiceController();
RestPaths = new List<RestPath>();
Metadata = new ServiceMetadata();
GlobalRequestFilters = new List<Action<IRequest, IResponse, object>>();
GlobalResponseFilters = new List<Action<IRequest, IResponse, object>>(); GlobalResponseFilters = new List<Action<IRequest, IResponse, object>>();
} }
public abstract void Configure();
public abstract object CreateInstance(Type type); public abstract object CreateInstance(Type type);
protected abstract ServiceController CreateServiceController();
public virtual ServiceStackHost Init()
{
Instance = this;
ServiceController.Init();
Configure();
ServiceController.AfterInit();
return this;
}
public virtual ServiceStackHost Start(string urlBase)
{
throw new NotImplementedException("Start(listeningAtUrlBase) is not supported by this AppHost");
}
public string ServiceName { get; set; }
public ServiceMetadata Metadata { get; set; }
public ServiceController ServiceController { get; set; }
public List<RestPath> RestPaths = new List<RestPath>();
public List<Action<IRequest, IResponse, object>> GlobalRequestFilters { get; set; }
public List<Action<IRequest, IResponse, object>> GlobalResponseFilters { get; set; } public List<Action<IRequest, IResponse, object>> GlobalResponseFilters { get; set; }
public abstract T TryResolve<T>(); public abstract RouteAttribute[] GetRouteAttributes(Type requestType);
public abstract T Resolve<T>();
public virtual MediaBrowser.Model.Services.RouteAttribute[] GetRouteAttributes(Type requestType)
{
return requestType.AllAttributes<MediaBrowser.Model.Services.RouteAttribute>();
}
public abstract object GetTaskResult(Task task, string requestName);
public abstract Func<string, object> GetParseFn(Type propertyType); public abstract Func<string, object> GetParseFn(Type propertyType);
@ -85,20 +38,5 @@ namespace ServiceStack
Instance = null; Instance = null;
} }
protected abstract ILogger Logger
{
get;
}
public void OnLogError(Type type, string message)
{
Logger.Error(message);
}
public void OnLogError(Type type, string message, Exception ex)
{
Logger.ErrorException(message, ex);
}
} }
} }

View File

@ -48,11 +48,6 @@ namespace ServiceStack.Serialization
var propertyParseStringFn = GetParseFn(propertyType); var propertyParseStringFn = GetParseFn(propertyType);
var propertySerializer = new PropertySerializerEntry(propertySetFn, propertyParseStringFn) { PropertyType = propertyType }; var propertySerializer = new PropertySerializerEntry(propertySetFn, propertyParseStringFn) { PropertyType = propertyType };
var attr = propertyInfo.AllAttributes<DataMemberAttribute>().FirstOrDefault();
if (attr != null && attr.Name != null)
{
propertySetterMap[attr.Name] = propertySerializer;
}
propertySetterMap[propertyInfo.Name] = propertySerializer; propertySetterMap[propertyInfo.Name] = propertySerializer;
} }
} }

View File

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