aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/HttpServer
diff options
context:
space:
mode:
authorLuke <luke.pulverenti@gmail.com>2017-02-24 15:21:11 -0500
committerGitHub <noreply@github.com>2017-02-24 15:21:11 -0500
commitcd6b7f3bdc5bcbc6c68131cc40b71b68ac1b73a6 (patch)
tree48b8f6d94e3f762a486aa1c4fa6937cf23c18dee /Emby.Server.Implementations/HttpServer
parentc07e774ca9c0f234ec6899e17fc70301d1990290 (diff)
parent66a844e6399f1d79be8e10ea098ba6768e0d123b (diff)
Merge pull request #2489 from MediaBrowser/beta
Beta
Diffstat (limited to 'Emby.Server.Implementations/HttpServer')
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs187
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs9
2 files changed, 124 insertions, 72 deletions
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index 322cdf4f0..6fcdab874 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -2,8 +2,6 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
-using ServiceStack;
-using ServiceStack.Host;
using System;
using System.Collections.Generic;
using System.IO;
@@ -13,6 +11,7 @@ using System.Text;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.SocketSharp;
+using Emby.Server.Implementations.Services;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Security;
using MediaBrowser.Controller;
@@ -29,7 +28,7 @@ using SocketHttpListener.Primitives;
namespace Emby.Server.Implementations.HttpServer
{
- public class HttpListenerHost : ServiceStackHost, IHttpServer
+ public class HttpListenerHost : IHttpServer, IDisposable
{
private string DefaultRedirectPath { get; set; }
@@ -61,13 +60,21 @@ 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; }
+
+ private readonly Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
+ public static HttpListenerHost Instance { get; protected set; }
+
public HttpListenerHost(IServerApplicationHost applicationHost,
ILogger logger,
IServerConfigurationManager config,
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)
- : base(serviceName)
+ : base()
{
+ Instance = this;
+
_appHost = applicationHost;
DefaultRedirectPath = defaultRedirectPath;
_networkManager = networkManager;
@@ -85,6 +92,9 @@ namespace Emby.Server.Implementations.HttpServer
_config = config;
_logger = logger;
+
+ RequestFilters = new List<Action<IRequest, IResponse, object>>();
+ ResponseFilters = new List<Action<IRequest, IResponse, object>>();
}
public string GlobalResponse { get; set; }
@@ -99,18 +109,7 @@ namespace Emby.Server.Implementations.HttpServer
{typeof (ArgumentException), 400}
};
- public override void Configure()
- {
- 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
+ protected ILogger Logger
{
get
{
@@ -118,32 +117,73 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- public override T Resolve<T>()
+ public object CreateInstance(Type type)
{
- return _appHost.Resolve<T>();
+ return _appHost.CreateInstance(type);
}
- public override T TryResolve<T>()
+ private ServiceController CreateServiceController()
{
- return _appHost.TryResolve<T>();
+ var types = _restServices.Select(r => r.GetType()).ToArray();
+
+ return new ServiceController(() => types);
}
- public override object CreateInstance(Type type)
+ /// <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)
{
- return _appHost.CreateInstance(type);
+ //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 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);
+ }
}
- protected override ServiceController CreateServiceController()
+ public Type GetServiceTypeByRequest(Type requestType)
{
- var types = _restServices.Select(r => r.GetType()).ToArray();
+ Type serviceType;
+ ServiceOperationsMap.TryGetValue(requestType, out serviceType);
+ return serviceType;
+ }
- return new ServiceController(() => types);
+ public void AddServiceInfo(Type serviceType, Type requestType, Type responseType)
+ {
+ ServiceOperationsMap[requestType] = serviceType;
}
- public override ServiceStackHost Start(string listeningAtUrlBase)
+ private IHasRequestFilter[] GetRequestFilterAttributes(Type requestDtoType)
{
- StartListener();
- return this;
+ var attributes = requestDtoType.GetTypeInfo().GetCustomAttributes(true).OfType<IHasRequestFilter>().ToList();
+
+ var serviceType = GetServiceTypeByRequest(requestDtoType);
+ if (serviceType != null)
+ {
+ attributes.AddRange(serviceType.GetTypeInfo().GetCustomAttributes(true).OfType<IHasRequestFilter>());
+ }
+
+ attributes.Sort((x, y) => x.Priority - y.Priority);
+
+ return attributes.ToArray();
}
/// <summary>
@@ -531,11 +571,11 @@ namespace Emby.Server.Implementations.HttpServer
return;
}
- var handler = HttpHandlerFactory.GetHandler(httpReq, _logger);
+ var handler = GetServiceHandler(httpReq);
if (handler != null)
{
- await handler.ProcessRequestAsync(httpReq, httpRes, operationName).ConfigureAwait(false);
+ await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, operationName).ConfigureAwait(false);
}
else
{
@@ -565,6 +605,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)
{
var bOutput = Encoding.UTF8.GetBytes(text);
@@ -580,6 +649,7 @@ namespace Emby.Server.Implementations.HttpServer
httpRes.AddHeader("Location", url);
}
+ public ServiceController ServiceController { get; private set; }
/// <summary>
/// Adds the rest handlers.
@@ -593,12 +663,20 @@ namespace Emby.Server.Implementations.HttpServer
_logger.Info("Calling ServiceStack AppHost.Init");
- base.Init();
+ ServiceController.Init(this);
+
+ var requestFilters = _appHost.GetExports<IRequestFilter>().ToList();
+ foreach (var filter in requestFilters)
+ {
+ RequestFilters.Add(filter.Filter);
+ }
+
+ ResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
}
- public override RouteAttribute[] GetRouteAttributes(Type requestType)
+ public RouteAttribute[] GetRouteAttributes(Type requestType)
{
- var routes = base.GetRouteAttributes(requestType).ToList();
+ var routes = requestType.GetTypeInfo().GetCustomAttributes<RouteAttribute>(true).ToList();
var clone = routes.ToList();
foreach (var route in clone)
@@ -628,54 +706,27 @@ namespace Emby.Server.Implementations.HttpServer
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 Func<string, object> GetParseFn(Type propertyType)
{
return _funcParseFn(propertyType);
}
- public override void SerializeToJson(object o, Stream stream)
+ public void SerializeToJson(object o, Stream stream)
{
_jsonSerializer.SerializeToStream(o, stream);
}
- public override void SerializeToXml(object o, Stream stream)
+ public void SerializeToXml(object o, Stream stream)
{
_xmlSerializer.SerializeToStream(o, stream);
}
- public override object DeserializeXml(Type type, Stream stream)
+ public object DeserializeXml(Type type, Stream stream)
{
return _xmlSerializer.DeserializeFromStream(type, stream);
}
- public override object DeserializeJson(Type type, Stream stream)
+ public object DeserializeJson(Type type, Stream stream)
{
return _jsonSerializer.DeserializeFromStream(stream, type);
}
@@ -716,8 +767,6 @@ namespace Emby.Server.Implementations.HttpServer
{
if (_disposed) return;
- base.Dispose();
-
lock (_disposeLock)
{
if (_disposed) return;
@@ -731,7 +780,7 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- public override void Dispose()
+ public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
@@ -740,7 +789,7 @@ namespace Emby.Server.Implementations.HttpServer
public void StartServer(IEnumerable<string> urlPrefixes)
{
UrlPrefixes = urlPrefixes.ToList();
- Start(UrlPrefixes.First());
+ StartListener();
}
}
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index e78446bc8..6bfd83110 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -13,10 +13,9 @@ using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Emby.Server.Implementations.HttpServer;
+using Emby.Server.Implementations.Services;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
-using ServiceStack;
-using ServiceStack.Host;
using IRequest = MediaBrowser.Model.Services.IRequest;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter;
@@ -203,7 +202,11 @@ namespace Emby.Server.Implementations.HttpServer
// Do not use the memoryStreamFactory here, they don't place nice with compression
using (var ms = new MemoryStream())
{
- ContentTypes.Instance.SerializeToStream(request, dto, ms);
+ var contentType = request.ResponseContentType;
+ var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
+
+ writerFn(dto, ms);
+
ms.Position = 0;
var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);