aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Services
diff options
context:
space:
mode:
authorLogicalPhallacy <44458166+LogicalPhallacy@users.noreply.github.com>2019-08-06 00:26:19 -0700
committerGitHub <noreply@github.com>2019-08-06 00:26:19 -0700
commit984e415c66cbd995d12ea95a3a9d3e2561ce4869 (patch)
tree1799942f3836641786c0e29249801bdb46aac0f4 /Emby.Server.Implementations/Services
parentc2667f99f4d50f4f7d9bbeec50e8491e52468962 (diff)
parent89f592687ee7ae7f0e0fffd884dbf2890476410a (diff)
Merge pull request #5 from jellyfin/master
Merge up to latest master
Diffstat (limited to 'Emby.Server.Implementations/Services')
-rw-r--r--Emby.Server.Implementations/Services/HttpResult.cs5
-rw-r--r--Emby.Server.Implementations/Services/ResponseHelper.cs81
-rw-r--r--Emby.Server.Implementations/Services/ServiceController.cs54
-rw-r--r--Emby.Server.Implementations/Services/ServiceHandler.cs106
-rw-r--r--Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs8
-rw-r--r--Emby.Server.Implementations/Services/SwaggerService.cs20
6 files changed, 122 insertions, 152 deletions
diff --git a/Emby.Server.Implementations/Services/HttpResult.cs b/Emby.Server.Implementations/Services/HttpResult.cs
index b6758486c..2b5963a77 100644
--- a/Emby.Server.Implementations/Services/HttpResult.cs
+++ b/Emby.Server.Implementations/Services/HttpResult.cs
@@ -43,6 +43,11 @@ namespace Emby.Server.Implementations.Services
{
var contentLength = bytesResponse.Length;
+ if (response != null)
+ {
+ response.OriginalResponse.ContentLength = contentLength;
+ }
+
if (contentLength > 0)
{
await responseStream.WriteAsync(bytesResponse, 0, contentLength, cancellationToken).ConfigureAwait(false);
diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs
index 0301ff335..251ba3529 100644
--- a/Emby.Server.Implementations/Services/ResponseHelper.cs
+++ b/Emby.Server.Implementations/Services/ResponseHelper.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Net;
using System.Text;
@@ -20,6 +21,8 @@ namespace Emby.Server.Implementations.Services
{
response.StatusCode = (int)HttpStatusCode.NoContent;
}
+
+ response.OriginalResponse.ContentLength = 0;
return Task.CompletedTask;
}
@@ -39,11 +42,6 @@ namespace Emby.Server.Implementations.Services
response.StatusCode = httpResult.Status;
response.StatusDescription = httpResult.StatusCode.ToString();
- //if (string.IsNullOrEmpty(httpResult.ContentType))
- //{
- // httpResult.ContentType = defaultContentType;
- //}
- //response.ContentType = httpResult.ContentType;
}
var responseOptions = result as IHasHeaders;
@@ -53,6 +51,7 @@ namespace Emby.Server.Implementations.Services
{
if (string.Equals(responseHeaders.Key, "Content-Length", StringComparison.OrdinalIgnoreCase))
{
+ response.OriginalResponse.ContentLength = long.Parse(responseHeaders.Value, CultureInfo.InvariantCulture);
continue;
}
@@ -72,52 +71,37 @@ namespace Emby.Server.Implementations.Services
response.ContentType += "; charset=utf-8";
}
- var asyncStreamWriter = result as IAsyncStreamWriter;
- if (asyncStreamWriter != null)
- {
- return asyncStreamWriter.WriteToAsync(response.OutputStream, cancellationToken);
- }
-
- var streamWriter = result as IStreamWriter;
- if (streamWriter != null)
+ switch (result)
{
- streamWriter.WriteTo(response.OutputStream);
- return Task.CompletedTask;
- }
-
- var fileWriter = result as FileWriter;
- if (fileWriter != null)
- {
- return fileWriter.WriteToAsync(response, cancellationToken);
- }
-
- var stream = result as Stream;
- if (stream != null)
- {
- return CopyStream(stream, response.OutputStream);
- }
+ case IAsyncStreamWriter asyncStreamWriter:
+ return asyncStreamWriter.WriteToAsync(response.OutputStream, cancellationToken);
+ case IStreamWriter streamWriter:
+ streamWriter.WriteTo(response.OutputStream);
+ return Task.CompletedTask;
+ case FileWriter fileWriter:
+ return fileWriter.WriteToAsync(response, cancellationToken);
+ case Stream stream:
+ return CopyStream(stream, response.OutputStream);
+ case byte[] bytes:
+ response.ContentType = "application/octet-stream";
+ response.OriginalResponse.ContentLength = bytes.Length;
+
+ if (bytes.Length > 0)
+ {
+ return response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
+ }
- var bytes = result as byte[];
- if (bytes != null)
- {
- response.ContentType = "application/octet-stream";
+ return Task.CompletedTask;
+ case string responseText:
+ var responseTextAsBytes = Encoding.UTF8.GetBytes(responseText);
+ response.OriginalResponse.ContentLength = responseTextAsBytes.Length;
- if (bytes.Length > 0)
- {
- return response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
- }
- return Task.CompletedTask;
- }
+ if (responseTextAsBytes.Length > 0)
+ {
+ return response.OutputStream.WriteAsync(responseTextAsBytes, 0, responseTextAsBytes.Length, cancellationToken);
+ }
- var responseText = result as string;
- if (responseText != null)
- {
- bytes = Encoding.UTF8.GetBytes(responseText);
- if (bytes.Length > 0)
- {
- return response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
- }
- return Task.CompletedTask;
+ return Task.CompletedTask;
}
return WriteObject(request, result, response);
@@ -143,14 +127,13 @@ namespace Emby.Server.Implementations.Services
ms.Position = 0;
var contentLength = ms.Length;
+ response.OriginalResponse.ContentLength = contentLength;
if (contentLength > 0)
{
await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false);
}
}
-
- //serializer(result, outputStream);
}
}
}
diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs
index 5796956d8..5e3d529c6 100644
--- a/Emby.Server.Implementations/Services/ServiceController.cs
+++ b/Emby.Server.Implementations/Services/ServiceController.cs
@@ -1,26 +1,17 @@
using System;
using System.Collections.Generic;
-using System.Reflection;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using MediaBrowser.Model.Services;
namespace Emby.Server.Implementations.Services
{
- public delegate Task<object> InstanceExecFn(IRequest requestContext, object intance, object request);
public delegate object ActionInvokerFn(object intance, object request);
public delegate void VoidActionInvokerFn(object intance, object request);
public class ServiceController
{
- public static ServiceController Instance;
-
- public ServiceController()
- {
- Instance = this;
- }
-
- public void Init(HttpListenerHost appHost, Type[] serviceTypes)
+ public void Init(HttpListenerHost appHost, IEnumerable<Type> serviceTypes)
{
foreach (var serviceType in serviceTypes)
{
@@ -37,7 +28,11 @@ namespace Emby.Server.Implementations.Services
foreach (var mi in serviceType.GetActions())
{
var requestType = mi.GetParameters()[0].ParameterType;
- if (processedReqs.Contains(requestType)) continue;
+ if (processedReqs.Contains(requestType))
+ {
+ continue;
+ }
+
processedReqs.Add(requestType);
ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions);
@@ -55,18 +50,6 @@ namespace Emby.Server.Implementations.Services
}
}
- public static Type FirstGenericType(Type type)
- {
- while (type != null)
- {
- if (type.GetTypeInfo().IsGenericType)
- return type;
-
- type = type.GetTypeInfo().BaseType;
- }
- return null;
- }
-
public readonly RestPath.RestPathMap RestPathMap = new RestPath.RestPathMap();
public void RegisterRestPaths(HttpListenerHost appHost, Type requestType, Type serviceType)
@@ -84,17 +67,24 @@ namespace Emby.Server.Implementations.Services
public void RegisterRestPath(RestPath restPath)
{
- if (!restPath.Path.StartsWith("/"))
+ if (restPath.Path[0] != '/')
+ {
throw new ArgumentException(string.Format("Route '{0}' on '{1}' must start with a '/'", restPath.Path, restPath.RequestType.GetMethodName()));
+ }
+
if (restPath.Path.IndexOfAny(InvalidRouteChars) != -1)
+ {
throw new ArgumentException(string.Format("Route '{0}' on '{1}' contains invalid chars. ", restPath.Path, restPath.RequestType.GetMethodName()));
+ }
- if (!RestPathMap.TryGetValue(restPath.FirstMatchHashKey, out List<RestPath> pathsAtFirstMatch))
+ if (RestPathMap.TryGetValue(restPath.FirstMatchHashKey, out List<RestPath> pathsAtFirstMatch))
{
- pathsAtFirstMatch = new List<RestPath>();
- RestPathMap[restPath.FirstMatchHashKey] = pathsAtFirstMatch;
+ pathsAtFirstMatch.Add(restPath);
+ }
+ else
+ {
+ RestPathMap[restPath.FirstMatchHashKey] = new List<RestPath>() { restPath };
}
- pathsAtFirstMatch.Add(restPath);
}
public RestPath GetRestPathForRequest(string httpMethod, string pathInfo)
@@ -155,17 +145,15 @@ namespace Emby.Server.Implementations.Services
return null;
}
- public Task<object> Execute(HttpListenerHost appHost, object requestDto, IRequest req)
+ public Task<object> Execute(HttpListenerHost httpHost, object requestDto, IRequest req)
{
req.Dto = requestDto;
var requestType = requestDto.GetType();
req.OperationName = requestType.Name;
- var serviceType = appHost.GetServiceTypeByRequest(requestType);
-
- var service = appHost.CreateInstance(serviceType);
+ var serviceType = httpHost.GetServiceTypeByRequest(requestType);
- //var service = typeFactory.CreateInstance(serviceType);
+ var service = httpHost.CreateInstance(serviceType);
var serviceRequiresContext = service as IRequiresRequest;
if (serviceRequiresContext != null)
diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs
index 3c8adfc98..d32fce1c7 100644
--- a/Emby.Server.Implementations/Services/ServiceHandler.cs
+++ b/Emby.Server.Implementations/Services/ServiceHandler.cs
@@ -11,6 +11,16 @@ namespace Emby.Server.Implementations.Services
{
public class ServiceHandler
{
+ public RestPath RestPath { get; }
+
+ public string ResponseContentType { get; }
+
+ internal ServiceHandler(RestPath restPath, string responseContentType)
+ {
+ RestPath = restPath;
+ ResponseContentType = responseContentType;
+ }
+
protected static Task<object> CreateContentTypeRequest(HttpListenerHost host, IRequest httpReq, Type requestType, string contentType)
{
if (!string.IsNullOrEmpty(contentType) && httpReq.ContentLength > 0)
@@ -18,24 +28,18 @@ namespace Emby.Server.Implementations.Services
var deserializer = RequestHelper.GetRequestReader(host, contentType);
if (deserializer != null)
{
- return deserializer(requestType, httpReq.InputStream);
+ return deserializer.Invoke(requestType, httpReq.InputStream);
}
}
- return Task.FromResult(host.CreateInstance(requestType));
- }
-
- public static RestPath FindMatchingRestPath(string httpMethod, string pathInfo, out string contentType)
- {
- pathInfo = GetSanitizedPathInfo(pathInfo, out contentType);
- return ServiceController.Instance.GetRestPathForRequest(httpMethod, pathInfo);
+ return Task.FromResult(host.CreateInstance(requestType));
}
public static string GetSanitizedPathInfo(string pathInfo, out string contentType)
{
contentType = null;
var pos = pathInfo.LastIndexOf('.');
- if (pos >= 0)
+ if (pos != -1)
{
var format = pathInfo.Substring(pos + 1);
contentType = GetFormatContentType(format);
@@ -44,58 +48,38 @@ namespace Emby.Server.Implementations.Services
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)
+ switch (format)
{
- this.RestPath = FindMatchingRestPath(httpMethod, pathInfo, out string contentType);
-
- if (contentType != null)
- ResponseContentType = contentType;
+ case "json": return "application/json";
+ case "xml": return "application/xml";
+ default: return null;
}
- 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, CancellationToken cancellationToken)
+ public async Task ProcessRequestAsync(HttpListenerHost httpHost, IRequest httpReq, IResponse httpRes, ILogger logger, CancellationToken cancellationToken)
{
- var restPath = GetRestPath(httpReq.Verb, httpReq.PathInfo);
- if (restPath == null)
- {
- throw new NotSupportedException("No RestPath found for: " + httpReq.Verb + " " + httpReq.PathInfo);
- }
-
- SetRoute(httpReq, restPath);
+ httpReq.Items["__route"] = RestPath;
if (ResponseContentType != null)
+ {
httpReq.ResponseContentType = ResponseContentType;
+ }
- var request = httpReq.Dto = await CreateRequest(appHost, httpReq, restPath, logger).ConfigureAwait(false);
+ var request = httpReq.Dto = await CreateRequest(httpHost, httpReq, RestPath, logger).ConfigureAwait(false);
- appHost.ApplyRequestFilters(httpReq, httpRes, request);
+ httpHost.ApplyRequestFilters(httpReq, httpRes, request);
- var response = await appHost.ServiceController.Execute(appHost, request, httpReq).ConfigureAwait(false);
+ var response = await httpHost.ServiceController.Execute(httpHost, request, httpReq).ConfigureAwait(false);
// Apply response filters
- foreach (var responseFilter in appHost.ResponseFilters)
+ foreach (var responseFilter in httpHost.ResponseFilters)
{
responseFilter(httpReq, httpRes, response);
}
@@ -152,7 +136,11 @@ namespace Emby.Server.Implementations.Services
foreach (var name in request.QueryString.Keys)
{
- if (name == null) continue; //thank you ASP.NET
+ if (name == null)
+ {
+ // thank you ASP.NET
+ continue;
+ }
var values = request.QueryString[name];
if (values.Count == 1)
@@ -175,7 +163,11 @@ namespace Emby.Server.Implementations.Services
{
foreach (var name in formData.Keys)
{
- if (name == null) continue; //thank you ASP.NET
+ if (name == null)
+ {
+ // thank you ASP.NET
+ continue;
+ }
var values = formData.GetValues(name);
if (values.Count == 1)
@@ -210,7 +202,12 @@ namespace Emby.Server.Implementations.Services
foreach (var name in request.QueryString.Keys)
{
- if (name == null) continue; //thank you ASP.NET
+ if (name == null)
+ {
+ // thank you ASP.NET
+ continue;
+ }
+
map[name] = request.QueryString[name];
}
@@ -221,7 +218,12 @@ namespace Emby.Server.Implementations.Services
{
foreach (var name in formData.Keys)
{
- if (name == null) continue; //thank you ASP.NET
+ if (name == null)
+ {
+ // thank you ASP.NET
+ continue;
+ }
+
map[name] = formData[name];
}
}
@@ -229,17 +231,5 @@ namespace Emby.Server.Implementations.Services
return map;
}
-
- private static void SetRoute(IRequest req, RestPath route)
- {
- req.Items["__route"] = route;
- }
-
- private static RestPath GetRoute(IRequest req)
- {
- req.Items.TryGetValue("__route", out var route);
- return route as RestPath;
- }
}
-
}
diff --git a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs
index f835aa1b5..c27eb7686 100644
--- a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs
+++ b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs
@@ -48,7 +48,7 @@ namespace Emby.Server.Implementations.Services
foreach (var propertyInfo in RestPath.GetSerializableProperties(type))
{
- var propertySetFn = TypeAccessor.GetSetPropertyMethod(type, propertyInfo);
+ var propertySetFn = TypeAccessor.GetSetPropertyMethod(propertyInfo);
var propertyType = propertyInfo.PropertyType;
var propertyParseStringFn = GetParseFn(propertyType);
var propertySerializer = new PropertySerializerEntry(propertySetFn, propertyParseStringFn, propertyType);
@@ -71,7 +71,7 @@ namespace Emby.Server.Implementations.Services
string propertyName = pair.Key;
string propertyTextValue = pair.Value;
- if (string.IsNullOrEmpty(propertyTextValue)
+ if (propertyTextValue == null
|| !propertySetterMap.TryGetValue(propertyName, out propertySerializerEntry)
|| propertySerializerEntry.PropertySetFn == null)
{
@@ -110,9 +110,9 @@ namespace Emby.Server.Implementations.Services
}
}
- internal class TypeAccessor
+ internal static class TypeAccessor
{
- public static Action<object, object> GetSetPropertyMethod(Type type, PropertyInfo propertyInfo)
+ public static Action<object, object> GetSetPropertyMethod(PropertyInfo propertyInfo)
{
if (!propertyInfo.CanWrite || propertyInfo.GetIndexParameters().Length > 0)
{
diff --git a/Emby.Server.Implementations/Services/SwaggerService.cs b/Emby.Server.Implementations/Services/SwaggerService.cs
index 3e6970eef..d22386436 100644
--- a/Emby.Server.Implementations/Services/SwaggerService.cs
+++ b/Emby.Server.Implementations/Services/SwaggerService.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Services;
+using Emby.Server.Implementations.HttpServer;
namespace Emby.Server.Implementations.Services
{
@@ -109,10 +109,16 @@ namespace Emby.Server.Implementations.Services
public class SwaggerService : IService, IRequiresRequest
{
+ private readonly IHttpServer _httpServer;
private SwaggerSpec _spec;
public IRequest Request { get; set; }
+ public SwaggerService(IHttpServer httpServer)
+ {
+ _httpServer = httpServer;
+ }
+
public object Get(GetSwaggerSpec request)
{
return _spec ?? (_spec = GetSpec());
@@ -181,7 +187,8 @@ namespace Emby.Server.Implementations.Services
{
var paths = new SortedDictionary<string, Dictionary<string, SwaggerMethod>>();
- var all = ServiceController.Instance.RestPathMap.OrderBy(i => i.Key, StringComparer.OrdinalIgnoreCase).ToList();
+ // REVIEW: this can be done better
+ var all = ((HttpListenerHost)_httpServer).ServiceController.RestPathMap.OrderBy(i => i.Key, StringComparer.OrdinalIgnoreCase).ToList();
foreach (var current in all)
{
@@ -192,11 +199,8 @@ namespace Emby.Server.Implementations.Services
continue;
}
- if (info.Path.StartsWith("/mediabrowser", StringComparison.OrdinalIgnoreCase))
- {
- continue;
- }
- if (info.Path.StartsWith("/jellyfin", StringComparison.OrdinalIgnoreCase))
+ if (info.Path.StartsWith("/mediabrowser", StringComparison.OrdinalIgnoreCase)
+ || info.Path.StartsWith("/jellyfin", StringComparison.OrdinalIgnoreCase))
{
continue;
}