mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-07-08 23:00:51 +02:00
Allow for dynamic cors response
This commit is contained in:
parent
0424d09b8d
commit
3c0484cc97
|
@ -135,13 +135,17 @@ namespace Jellyfin.Server.Extensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serviceCollection">The service collection.</param>
|
/// <param name="serviceCollection">The service collection.</param>
|
||||||
/// <param name="baseUrl">The base url for the API.</param>
|
/// <param name="baseUrl">The base url for the API.</param>
|
||||||
|
/// <param name="corsHosts">The configured cors hosts.</param>
|
||||||
/// <returns>The MVC builder.</returns>
|
/// <returns>The MVC builder.</returns>
|
||||||
public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, string baseUrl)
|
public static IMvcBuilder AddJellyfinApi(
|
||||||
|
this IServiceCollection serviceCollection,
|
||||||
|
string baseUrl,
|
||||||
|
string[] corsHosts)
|
||||||
{
|
{
|
||||||
return serviceCollection
|
return serviceCollection
|
||||||
.AddCors(options =>
|
.AddCors(options =>
|
||||||
{
|
{
|
||||||
options.AddPolicy(ServerCorsPolicy.DefaultPolicyName, ServerCorsPolicy.DefaultPolicy);
|
options.AddPolicy(ServerCorsPolicy.DefaultPolicyName, new ServerCorsPolicy(corsHosts).Policy);
|
||||||
})
|
})
|
||||||
.Configure<ForwardedHeadersOptions>(options =>
|
.Configure<ForwardedHeadersOptions>(options =>
|
||||||
{
|
{
|
||||||
|
|
68
Jellyfin.Server/Middleware/DynamicCorsMiddleware.cs
Normal file
68
Jellyfin.Server/Middleware/DynamicCorsMiddleware.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
namespace Jellyfin.Server.Middleware
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Dynamic cors middleware.
|
||||||
|
/// </summary>
|
||||||
|
public class DynamicCorsMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
private readonly ILogger<DynamicCorsMiddleware> _logger;
|
||||||
|
private readonly CorsMiddleware _corsMiddleware;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DynamicCorsMiddleware"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="next">Next request delegate.</param>
|
||||||
|
/// <param name="corsService">Instance of the <see cref="ICorsService"/> interface.</param>
|
||||||
|
/// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
|
||||||
|
/// <param name="policyName">The cors policy name.</param>
|
||||||
|
public DynamicCorsMiddleware(
|
||||||
|
RequestDelegate next,
|
||||||
|
ICorsService corsService,
|
||||||
|
ILoggerFactory loggerFactory,
|
||||||
|
string policyName)
|
||||||
|
{
|
||||||
|
_corsMiddleware = new CorsMiddleware(next, corsService, loggerFactory, policyName);
|
||||||
|
_next = next;
|
||||||
|
_logger = loggerFactory.CreateLogger<DynamicCorsMiddleware>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoke request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">Request context.</param>
|
||||||
|
/// <param name="corsPolicyProvider">Instance of the <see cref="ICorsPolicyProvider"/> interface.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
///
|
||||||
|
public async Task Invoke(HttpContext context, ICorsPolicyProvider corsPolicyProvider)
|
||||||
|
{
|
||||||
|
// Only execute if is preflight request.
|
||||||
|
if (string.Equals(context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
// Invoke original cors middleware.
|
||||||
|
await _corsMiddleware.Invoke(context, corsPolicyProvider).ConfigureAwait(false);
|
||||||
|
if (context.Response.Headers.TryGetValue(HeaderNames.AccessControlAllowOrigin, out var headerValue)
|
||||||
|
&& string.Equals(headerValue, "*", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
context.Response.Headers[HeaderNames.AccessControlAllowOrigin] = context.Request.Host.Value;
|
||||||
|
_logger.LogDebug("Overwriting CORS response header: {HeaderName}: {HeaderValue}", HeaderNames.AccessControlAllowOrigin, context.Request.Host.Value);
|
||||||
|
|
||||||
|
if (!context.Response.Headers.ContainsKey(HeaderNames.AccessControlAllowCredentials))
|
||||||
|
{
|
||||||
|
context.Response.Headers[HeaderNames.AccessControlAllowCredentials] = "true";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the next delegate/middleware in the pipeline
|
||||||
|
await this._next(context).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +1,47 @@
|
||||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||||
|
|
||||||
namespace Jellyfin.Server.Models
|
namespace Jellyfin.Server.Models
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Server Cors Policy.
|
/// Server Cors Policy.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ServerCorsPolicy
|
public class ServerCorsPolicy
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default policy name.
|
/// Default policy name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string DefaultPolicyName = "DefaultCorsPolicy";
|
public const string DefaultPolicyName = nameof(ServerCorsPolicy);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default Policy. Allow Everything.
|
/// Initializes a new instance of the <see cref="ServerCorsPolicy"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly CorsPolicy DefaultPolicy = new CorsPolicy
|
/// <param name="corsHosts">The configured cors hosts.</param>
|
||||||
|
public ServerCorsPolicy(string[] corsHosts)
|
||||||
{
|
{
|
||||||
// Allow any origin
|
var builder = new CorsPolicyBuilder()
|
||||||
Origins = { "*" },
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader();
|
||||||
|
|
||||||
// Allow any method
|
// No hosts configured or only default configured.
|
||||||
Methods = { "*" },
|
if (corsHosts.Length == 0
|
||||||
|
|| (corsHosts.Length == 1
|
||||||
|
&& string.Equals(corsHosts[0], "*", StringComparison.Ordinal)))
|
||||||
|
{
|
||||||
|
builder.AllowAnyOrigin();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.WithOrigins(corsHosts)
|
||||||
|
.AllowCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
// Allow any header
|
Policy = builder.Build();
|
||||||
Headers = { "*" }
|
}
|
||||||
};
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the cors policy.
|
||||||
|
/// </summary>
|
||||||
|
public CorsPolicy Policy { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,9 @@ namespace Jellyfin.Server
|
||||||
{
|
{
|
||||||
services.AddResponseCompression();
|
services.AddResponseCompression();
|
||||||
services.AddHttpContextAccessor();
|
services.AddHttpContextAccessor();
|
||||||
services.AddJellyfinApi(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/'));
|
services.AddJellyfinApi(
|
||||||
|
_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/'),
|
||||||
|
_serverConfigurationManager.Configuration.CorsHosts);
|
||||||
|
|
||||||
services.AddJellyfinApiSwagger();
|
services.AddJellyfinApiSwagger();
|
||||||
|
|
||||||
|
@ -78,11 +80,11 @@ namespace Jellyfin.Server
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseJellyfinApiSwagger(_serverConfigurationManager);
|
app.UseJellyfinApiSwagger(_serverConfigurationManager);
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
app.UseCors(ServerCorsPolicy.DefaultPolicyName);
|
app.UseMiddleware<DynamicCorsMiddleware>(ServerCorsPolicy.DefaultPolicyName);
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
if (_serverConfigurationManager.Configuration.EnableMetrics)
|
if (_serverConfigurationManager.Configuration.EnableMetrics)
|
||||||
{
|
{
|
||||||
// Must be registered after any middleware that could chagne HTTP response codes or the data will be bad
|
// Must be registered after any middleware that could change HTTP response codes or the data will be bad
|
||||||
app.UseHttpMetrics();
|
app.UseHttpMetrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -264,6 +264,11 @@ namespace MediaBrowser.Model.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public long SlowResponseThresholdMs { get; set; }
|
public long SlowResponseThresholdMs { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the cors hosts.
|
||||||
|
/// </summary>
|
||||||
|
public string[] CorsHosts { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
|
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -372,6 +377,7 @@ namespace MediaBrowser.Model.Configuration
|
||||||
|
|
||||||
EnableSlowResponseWarning = true;
|
EnableSlowResponseWarning = true;
|
||||||
SlowResponseThresholdMs = 500;
|
SlowResponseThresholdMs = 500;
|
||||||
|
CorsHosts = new[] { "*" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue