|
|
|
@ -2,6 +2,7 @@
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using Nancy;
|
|
|
|
|
using Nancy.Bootstrapper;
|
|
|
|
|
using NzbDrone.Common.Extensions;
|
|
|
|
|
|
|
|
|
|
namespace NzbDrone.Api.Extensions.Pipelines
|
|
|
|
|
{
|
|
|
|
@ -11,10 +12,25 @@ namespace NzbDrone.Api.Extensions.Pipelines
|
|
|
|
|
|
|
|
|
|
public void Register(IPipelines pipelines)
|
|
|
|
|
{
|
|
|
|
|
pipelines.AfterRequest.AddItemToEndOfPipeline((Action<NancyContext>) Handle);
|
|
|
|
|
pipelines.BeforeRequest.AddItemToEndOfPipeline(HandleRequest);
|
|
|
|
|
pipelines.AfterRequest.AddItemToEndOfPipeline(HandleResponse);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Handle(NancyContext context)
|
|
|
|
|
private Response HandleRequest(NancyContext context)
|
|
|
|
|
{
|
|
|
|
|
if (context == null || context.Request.Method != "OPTIONS")
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var response = new Response()
|
|
|
|
|
.WithStatusCode(HttpStatusCode.OK)
|
|
|
|
|
.WithContentType("");
|
|
|
|
|
ApplyResponseHeaders(response, context.Request);
|
|
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleResponse(NancyContext context)
|
|
|
|
|
{
|
|
|
|
|
if (context == null || context.Response.Headers.ContainsKey(AccessControlHeaders.AllowOrigin))
|
|
|
|
|
{
|
|
|
|
@ -26,21 +42,39 @@ namespace NzbDrone.Api.Extensions.Pipelines
|
|
|
|
|
|
|
|
|
|
private static void ApplyResponseHeaders(Response response, Request request)
|
|
|
|
|
{
|
|
|
|
|
var allowedMethods = "GET, OPTIONS, PATCH, POST, PUT, DELETE";
|
|
|
|
|
|
|
|
|
|
if (response.Headers.ContainsKey("Allow"))
|
|
|
|
|
if (request.IsApiRequest())
|
|
|
|
|
{
|
|
|
|
|
allowedMethods = response.Headers["Allow"];
|
|
|
|
|
// Allow Cross-Origin access to the API since it's protected with the apikey, and nothing else.
|
|
|
|
|
ApplyCorsResponseHeaders(response, request, "*", "GET, OPTIONS, PATCH, POST, PUT, DELETE");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var requestedHeaders = string.Join(", ", request.Headers[AccessControlHeaders.RequestHeaders]);
|
|
|
|
|
else if (request.IsSharedContentRequest())
|
|
|
|
|
{
|
|
|
|
|
// Allow Cross-Origin access to specific shared content such as mediacovers and images.
|
|
|
|
|
ApplyCorsResponseHeaders(response, request, "*", "GET, OPTIONS");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Disallow Cross-Origin access for any other route.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response.Headers.Add(AccessControlHeaders.AllowOrigin, "*");
|
|
|
|
|
response.Headers.Add(AccessControlHeaders.AllowMethods, allowedMethods);
|
|
|
|
|
private static void ApplyCorsResponseHeaders(Response response, Request request, string allowOrigin, string allowedMethods)
|
|
|
|
|
{
|
|
|
|
|
response.Headers.Add(AccessControlHeaders.AllowOrigin, allowOrigin);
|
|
|
|
|
|
|
|
|
|
if (request.Headers[AccessControlHeaders.RequestHeaders].Any())
|
|
|
|
|
if (request.Method == "OPTIONS")
|
|
|
|
|
{
|
|
|
|
|
response.Headers.Add(AccessControlHeaders.AllowHeaders, requestedHeaders);
|
|
|
|
|
if (response.Headers.ContainsKey("Allow"))
|
|
|
|
|
{
|
|
|
|
|
allowedMethods = response.Headers["Allow"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response.Headers.Add(AccessControlHeaders.AllowMethods, allowedMethods);
|
|
|
|
|
|
|
|
|
|
if (request.Headers[AccessControlHeaders.RequestHeaders].Any())
|
|
|
|
|
{
|
|
|
|
|
var requestedHeaders = string.Join(", ", request.Headers[AccessControlHeaders.RequestHeaders]);
|
|
|
|
|
|
|
|
|
|
response.Headers.Add(AccessControlHeaders.AllowHeaders, requestedHeaders);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|