mirror of https://github.com/Squidex/squidex.git
75 changed files with 287 additions and 1182 deletions
@ -1,20 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Microsoft.Extensions.Configuration |
|||
{ |
|||
public sealed class Alternatives : Dictionary<string, Action> |
|||
{ |
|||
public Alternatives() |
|||
: base(StringComparer.OrdinalIgnoreCase) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,70 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Globalization; |
|||
using System.Linq; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Text; |
|||
|
|||
namespace Microsoft.Extensions.Configuration |
|||
{ |
|||
public static class ConfigurationExtensions |
|||
{ |
|||
public static T GetOptionalValue<T>(this IConfiguration config, string path, T defaultValue = default) |
|||
{ |
|||
var value = config.GetValue(path, defaultValue!); |
|||
|
|||
return value; |
|||
} |
|||
|
|||
public static int GetOptionalValue(this IConfiguration config, string path, int defaultValue) |
|||
{ |
|||
var value = config.GetValue<string>(path); |
|||
|
|||
if (string.IsNullOrWhiteSpace(value) || !int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) |
|||
{ |
|||
result = defaultValue; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
public static string GetRequiredValue(this IConfiguration config, string path) |
|||
{ |
|||
var value = config.GetValue<string>(path); |
|||
|
|||
if (string.IsNullOrWhiteSpace(value)) |
|||
{ |
|||
var name = string.Join(" ", path.Split(':').Select(x => x.ToPascalCase())); |
|||
|
|||
throw new ConfigurationException($"Configure the {name} with '{path}'."); |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
|
|||
public static string ConfigureByOption(this IConfiguration config, string path, Alternatives options) |
|||
{ |
|||
var value = config.GetRequiredValue(path); |
|||
|
|||
if (options.TryGetValue(value, out var action)) |
|||
{ |
|||
action(); |
|||
} |
|||
else if (options.TryGetValue("default", out action)) |
|||
{ |
|||
action(); |
|||
} |
|||
else |
|||
{ |
|||
throw new ConfigurationException($"Unsupported value '{value}' for '{path}', supported: {string.Join(" ", options.Keys)}."); |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
} |
|||
} |
|||
@ -1,26 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Runtime.Serialization; |
|||
|
|||
namespace Squidex.Infrastructure |
|||
{ |
|||
[Serializable] |
|||
public class ConfigurationException : Exception |
|||
{ |
|||
public ConfigurationException(string message, Exception? inner = null) |
|||
: base(message, inner) |
|||
{ |
|||
} |
|||
|
|||
protected ConfigurationException(SerializationInfo info, StreamingContext context) |
|||
: base(info, context) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,38 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Squidex.Infrastructure |
|||
{ |
|||
public sealed class DelegateInitializer : IInitializable |
|||
{ |
|||
private readonly string name; |
|||
private readonly Func<CancellationToken, Task> action; |
|||
|
|||
public DelegateInitializer(string name, Func<CancellationToken, Task> action) |
|||
{ |
|||
Guard.NotNull(action, nameof(action)); |
|||
|
|||
this.name = name; |
|||
|
|||
this.action = action; |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return name; |
|||
} |
|||
|
|||
public Task InitializeAsync(CancellationToken ct = default) |
|||
{ |
|||
return action(ct); |
|||
} |
|||
} |
|||
} |
|||
@ -1,110 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Linq; |
|||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Microsoft.Extensions.DependencyInjection |
|||
{ |
|||
public static class DependencyInjectionExtensions |
|||
{ |
|||
public delegate void Registrator(Type serviceType, Func<IServiceProvider, object> implementationFactory); |
|||
|
|||
public sealed class InterfaceRegistrator<T> where T : notnull |
|||
{ |
|||
private readonly Registrator register; |
|||
private readonly Registrator registerOptional; |
|||
|
|||
public InterfaceRegistrator(Registrator register, Registrator registerOptional) |
|||
{ |
|||
this.register = register; |
|||
this.registerOptional = registerOptional; |
|||
|
|||
var interfaces = typeof(T).GetInterfaces(); |
|||
|
|||
if (interfaces.Contains(typeof(IInitializable))) |
|||
{ |
|||
register(typeof(IInitializable), c => c.GetRequiredService<T>()); |
|||
} |
|||
|
|||
if (interfaces.Contains(typeof(IBackgroundProcess))) |
|||
{ |
|||
register(typeof(IBackgroundProcess), c => c.GetRequiredService<T>()); |
|||
} |
|||
} |
|||
|
|||
public InterfaceRegistrator<T> AsSelf() |
|||
{ |
|||
return this; |
|||
} |
|||
|
|||
public InterfaceRegistrator<T> AsOptional<TInterface>() |
|||
{ |
|||
if (typeof(TInterface) != typeof(T)) |
|||
{ |
|||
registerOptional(typeof(TInterface), c => c.GetRequiredService<T>()); |
|||
} |
|||
|
|||
return this; |
|||
} |
|||
|
|||
public InterfaceRegistrator<T> As<TInterface>() |
|||
{ |
|||
if (typeof(TInterface) != typeof(T)) |
|||
{ |
|||
register(typeof(TInterface), c => c.GetRequiredService<T>()); |
|||
} |
|||
|
|||
return this; |
|||
} |
|||
} |
|||
|
|||
public static InterfaceRegistrator<T> AddTransientAs<T>(this IServiceCollection services, Func<IServiceProvider, T> factory) where T : class |
|||
{ |
|||
services.AddTransient(typeof(T), factory); |
|||
|
|||
return new InterfaceRegistrator<T>((t, f) => services.AddTransient(t, f), services.TryAddTransient); |
|||
} |
|||
|
|||
public static InterfaceRegistrator<T> AddTransientAs<T>(this IServiceCollection services) where T : class |
|||
{ |
|||
services.AddTransient<T, T>(); |
|||
|
|||
return new InterfaceRegistrator<T>((t, f) => services.AddTransient(t, f), services.TryAddTransient); |
|||
} |
|||
|
|||
public static InterfaceRegistrator<T> AddSingletonAs<T>(this IServiceCollection services, Func<IServiceProvider, T> factory) where T : class |
|||
{ |
|||
services.AddSingleton(typeof(T), factory); |
|||
|
|||
return new InterfaceRegistrator<T>((t, f) => services.AddSingleton(t, f), services.TryAddSingleton); |
|||
} |
|||
|
|||
public static InterfaceRegistrator<T> AddSingletonAs<T>(this IServiceCollection services) where T : class |
|||
{ |
|||
services.AddSingleton<T, T>(); |
|||
|
|||
return new InterfaceRegistrator<T>((t, f) => services.AddSingleton(t, f), services.TryAddSingleton); |
|||
} |
|||
|
|||
public static InterfaceRegistrator<T> AddScopedAs<T>(this IServiceCollection services, Func<IServiceProvider, T> factory) where T : class |
|||
{ |
|||
services.AddScoped(typeof(T), factory); |
|||
|
|||
return new InterfaceRegistrator<T>((t, f) => services.AddScoped(t, f), services.TryAddScoped); |
|||
} |
|||
|
|||
public static InterfaceRegistrator<T> AddScopedAs<T>(this IServiceCollection services) where T : class |
|||
{ |
|||
services.AddScoped<T, T>(); |
|||
|
|||
return new InterfaceRegistrator<T>((t, f) => services.AddScoped(t, f), services.TryAddScoped); |
|||
} |
|||
} |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Squidex.Infrastructure |
|||
{ |
|||
public interface IBackgroundProcess |
|||
{ |
|||
Task StartAsync(CancellationToken ct); |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Squidex.Infrastructure |
|||
{ |
|||
public interface IInitializable |
|||
{ |
|||
int Order => 0; |
|||
|
|||
Task InitializeAsync(CancellationToken ct = default); |
|||
} |
|||
} |
|||
@ -1,44 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Http; |
|||
|
|||
namespace Squidex.Web.Pipeline |
|||
{ |
|||
public class CleanupHostMiddleware |
|||
{ |
|||
private readonly RequestDelegate next; |
|||
|
|||
public CleanupHostMiddleware(RequestDelegate next) |
|||
{ |
|||
this.next = next; |
|||
} |
|||
|
|||
public Task InvokeAsync(HttpContext context) |
|||
{ |
|||
var request = context.Request; |
|||
|
|||
if (request.Host.HasValue && (HasHttpsPort(request) || HasHttpPort(request))) |
|||
{ |
|||
request.Host = new HostString(request.Host.Host); |
|||
} |
|||
|
|||
return next(context); |
|||
} |
|||
|
|||
private static bool HasHttpPort(HttpRequest request) |
|||
{ |
|||
return request.Scheme == "http" && request.Host.Port == 80; |
|||
} |
|||
|
|||
private static bool HasHttpsPort(HttpRequest request) |
|||
{ |
|||
return request.Scheme == "https" && request.Host.Port == 443; |
|||
} |
|||
} |
|||
} |
|||
@ -1,159 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Web |
|||
{ |
|||
public sealed class UrlsOptions |
|||
{ |
|||
private readonly HashSet<HostString> allTrustedHosts = new HashSet<HostString>(); |
|||
private string baseUrl; |
|||
private string[]? trustedHosts; |
|||
|
|||
public string[]? KnownProxies { get; set; } |
|||
|
|||
public bool EnableForwardHeaders { get; set; } = true; |
|||
|
|||
public bool EnforceHTTPS { get; set; } = false; |
|||
|
|||
public bool EnforceHost { get; set; } = false; |
|||
|
|||
public int? HttpsPort { get; set; } = 443; |
|||
|
|||
public string BaseUrl |
|||
{ |
|||
get |
|||
{ |
|||
return baseUrl; |
|||
} |
|||
set |
|||
{ |
|||
if (TryBuildHost(value, out var host)) |
|||
{ |
|||
allTrustedHosts.Add(host); |
|||
} |
|||
|
|||
baseUrl = value; |
|||
} |
|||
} |
|||
|
|||
public string[]? TrustedHosts |
|||
{ |
|||
get |
|||
{ |
|||
return trustedHosts; |
|||
} |
|||
set |
|||
{ |
|||
if (trustedHosts != null) |
|||
{ |
|||
foreach (var canidate in trustedHosts) |
|||
{ |
|||
if (TryBuildHost(canidate, out var host)) |
|||
{ |
|||
allTrustedHosts.Add(host); |
|||
} |
|||
} |
|||
} |
|||
|
|||
trustedHosts = value; |
|||
} |
|||
} |
|||
|
|||
public bool IsAllowedHost(string? url) |
|||
{ |
|||
if (!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out var uri)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return IsAllowedHost(uri); |
|||
} |
|||
|
|||
public bool IsAllowedHost(Uri uri) |
|||
{ |
|||
if (!uri.IsAbsoluteUri) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
return allTrustedHosts.Contains(BuildHost(uri)); |
|||
} |
|||
|
|||
public string BuildUrl(string path, bool trailingSlash = true) |
|||
{ |
|||
if (string.IsNullOrWhiteSpace(BaseUrl)) |
|||
{ |
|||
throw new ConfigurationException("Configure BaseUrl with 'urls:baseUrl'."); |
|||
} |
|||
|
|||
return BaseUrl.BuildFullUrl(path, trailingSlash); |
|||
} |
|||
|
|||
public HostString BuildHost() |
|||
{ |
|||
if (string.IsNullOrWhiteSpace(BaseUrl)) |
|||
{ |
|||
throw new ConfigurationException("Configure BaseUrl with 'urls:baseUrl'."); |
|||
} |
|||
|
|||
if (!TryBuildHost(BaseUrl, out var host)) |
|||
{ |
|||
throw new ConfigurationException("Configure BaseUrl with 'urls:baseUrl' host name."); |
|||
} |
|||
|
|||
return host; |
|||
} |
|||
|
|||
private static bool TryBuildHost(string urlOrHost, out HostString host) |
|||
{ |
|||
host = default; |
|||
|
|||
if (string.IsNullOrWhiteSpace(urlOrHost)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (Uri.TryCreate(urlOrHost, UriKind.Absolute, out var uri1)) |
|||
{ |
|||
host = BuildHost(uri1); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
if (Uri.TryCreate($"http://{urlOrHost}", UriKind.Absolute, out var uri2)) |
|||
{ |
|||
host = BuildHost(uri2); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private static HostString BuildHost(Uri uri) |
|||
{ |
|||
return BuildHost(uri.Host, uri.Port); |
|||
} |
|||
|
|||
private static HostString BuildHost(string host, int port) |
|||
{ |
|||
if (port == 443 || port == 80) |
|||
{ |
|||
return new HostString(host.ToLowerInvariant()); |
|||
} |
|||
else |
|||
{ |
|||
return new HostString(host.ToLowerInvariant(), port); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,38 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Log; |
|||
|
|||
namespace Squidex.Config.Startup |
|||
{ |
|||
public sealed class BackgroundHost : SafeHostedService |
|||
{ |
|||
private readonly IEnumerable<IBackgroundProcess> targets; |
|||
|
|||
public BackgroundHost(IEnumerable<IBackgroundProcess> targets, ISemanticLog log) |
|||
: base(log) |
|||
{ |
|||
this.targets = targets; |
|||
} |
|||
|
|||
protected override async Task StartAsync(ISemanticLog log, CancellationToken ct) |
|||
{ |
|||
foreach (var target in targets.Distinct()) |
|||
{ |
|||
await target.StartAsync(ct); |
|||
|
|||
log.LogInformation(w => w.WriteProperty("backgroundSystem", target.ToString())); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Log; |
|||
|
|||
namespace Squidex.Config.Startup |
|||
{ |
|||
public sealed class InitializerHost : SafeHostedService |
|||
{ |
|||
private readonly IEnumerable<IInitializable> targets; |
|||
|
|||
public InitializerHost(IEnumerable<IInitializable> targets, ISemanticLog log) |
|||
: base(log) |
|||
{ |
|||
this.targets = targets; |
|||
} |
|||
|
|||
protected override async Task StartAsync(ISemanticLog log, CancellationToken ct) |
|||
{ |
|||
foreach (var target in targets.Distinct().OrderBy(x => x.Order)) |
|||
{ |
|||
await target.InitializeAsync(ct); |
|||
|
|||
log.LogInformation(w => w.WriteProperty("initializedSystem", target.ToString())); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,47 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Squidex.Log; |
|||
|
|||
namespace Squidex.Config.Startup |
|||
{ |
|||
public abstract class SafeHostedService : IHostedService |
|||
{ |
|||
private readonly ISemanticLog log; |
|||
private bool isStarted; |
|||
|
|||
protected SafeHostedService(ISemanticLog log) |
|||
{ |
|||
this.log = log; |
|||
} |
|||
|
|||
public async Task StartAsync(CancellationToken cancellationToken) |
|||
{ |
|||
await StartAsync(log, cancellationToken); |
|||
|
|||
isStarted = true; |
|||
} |
|||
|
|||
public async Task StopAsync(CancellationToken cancellationToken) |
|||
{ |
|||
if (isStarted) |
|||
{ |
|||
await StopAsync(log, cancellationToken); |
|||
} |
|||
} |
|||
|
|||
protected abstract Task StartAsync(ISemanticLog log, CancellationToken ct); |
|||
|
|||
protected virtual Task StopAsync(ISemanticLog log, CancellationToken ct) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -1,75 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Xunit; |
|||
|
|||
#pragma warning disable RECS0092 // Convert field to readonly
|
|||
|
|||
namespace Squidex.Web.Pipeline |
|||
{ |
|||
public class CleanupHostMiddlewareTests |
|||
{ |
|||
private readonly CleanupHostMiddleware sut; |
|||
private bool isNextCalled; |
|||
|
|||
public CleanupHostMiddlewareTests() |
|||
{ |
|||
Task Next(HttpContext context) |
|||
{ |
|||
isNextCalled = true; |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
sut = new CleanupHostMiddleware(Next); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_cleanup_host_if_https_schema_contains_default_port() |
|||
{ |
|||
var httpContext = new DefaultHttpContext(); |
|||
|
|||
httpContext.Request.Scheme = "https"; |
|||
httpContext.Request.Host = new HostString("host", 443); |
|||
|
|||
await sut.InvokeAsync(httpContext); |
|||
|
|||
Assert.Null(httpContext.Request.Host.Port); |
|||
Assert.True(isNextCalled); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_cleanup_host_if_http_schema_contains_default_port() |
|||
{ |
|||
var httpContext = new DefaultHttpContext(); |
|||
|
|||
httpContext.Request.Scheme = "http"; |
|||
httpContext.Request.Host = new HostString("host", 80); |
|||
|
|||
await sut.InvokeAsync(httpContext); |
|||
|
|||
Assert.Null(httpContext.Request.Host.Port); |
|||
Assert.True(isNextCalled); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_not_cleanup_host_if_http_schema_contains_other_port() |
|||
{ |
|||
var httpContext = new DefaultHttpContext(); |
|||
|
|||
httpContext.Request.Scheme = "http"; |
|||
httpContext.Request.Host = new HostString("host", 8080); |
|||
|
|||
await sut.InvokeAsync(httpContext); |
|||
|
|||
Assert.Equal(8080, httpContext.Request.Host.Port); |
|||
Assert.True(isNextCalled); |
|||
} |
|||
} |
|||
} |
|||
@ -1,65 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Xunit; |
|||
|
|||
namespace Squidex.Web |
|||
{ |
|||
public sealed class UrlsOptionsTests |
|||
{ |
|||
private readonly UrlsOptions sut = new UrlsOptions |
|||
{ |
|||
BaseUrl = "http://localhost" |
|||
}; |
|||
|
|||
[Theory] |
|||
[InlineData("/url")] |
|||
[InlineData("/url/")] |
|||
[InlineData("url")] |
|||
public void Should_build_url_with_leading_slash(string path) |
|||
{ |
|||
var url = sut.BuildUrl(path); |
|||
|
|||
Assert.Equal("http://localhost/url/", url); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData("/url")] |
|||
[InlineData("/url/")] |
|||
[InlineData("url")] |
|||
public void Should_build_url_without_leading_slash(string path) |
|||
{ |
|||
var url = sut.BuildUrl(path, false); |
|||
|
|||
Assert.Equal("http://localhost/url", url); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_allow_same_host() |
|||
{ |
|||
Assert.True(sut.IsAllowedHost("http://localhost")); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_allow_https_port() |
|||
{ |
|||
Assert.True(sut.IsAllowedHost("https://localhost")); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_allow_other_host() |
|||
{ |
|||
Assert.False(sut.IsAllowedHost("https://other:5000")); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_not_allow_same_host_with_other_port() |
|||
{ |
|||
Assert.False(sut.IsAllowedHost("https://localhost:3000")); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue