201 lines
7.0 KiB
C#
201 lines
7.0 KiB
C#
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 taskResults = taskResult as Task[];
|
|
|
|
if (taskResults == null)
|
|
{
|
|
var subTask = taskResult as Task;
|
|
if (subTask != null)
|
|
taskResult = ServiceStackHost.Instance.GetTaskResult(subTask, RequestName);
|
|
|
|
return taskResult;
|
|
}
|
|
|
|
if (taskResults.Length == 0)
|
|
{
|
|
return new object[] { };
|
|
}
|
|
|
|
var firstResponse = ServiceStackHost.Instance.GetTaskResult(taskResults[0], RequestName);
|
|
var batchedResponses = firstResponse != null
|
|
? (object[])Array.CreateInstance(firstResponse.GetType(), taskResults.Length)
|
|
: new object[taskResults.Length];
|
|
batchedResponses[0] = firstResponse;
|
|
for (var i = 1; i < taskResults.Length; i++)
|
|
{
|
|
batchedResponses[i] = ServiceStackHost.Instance.GetTaskResult(taskResults[i], RequestName);
|
|
}
|
|
return batchedResponses;
|
|
}
|
|
|
|
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);
|
|
|
|
if (appHost.ApplyRequestFilters(httpReq, httpRes, request))
|
|
return;
|
|
|
|
var rawResponse = await ServiceStackHost.Instance.ServiceController.Execute(request, httpReq).ConfigureAwait(false);
|
|
|
|
if (httpRes.IsClosed)
|
|
return;
|
|
|
|
var response = await HandleResponseAsync(rawResponse).ConfigureAwait(false);
|
|
|
|
if (appHost.ApplyResponseFilters(httpReq, httpRes, response))
|
|
return;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|