Add support for Cors (#714)

This commit is contained in:
Stef Heyenrath
2022-01-24 12:26:19 +01:00
committed by GitHub
parent d6c36bc23b
commit ccd433b202
15 changed files with 173 additions and 35 deletions

View File

@@ -6,8 +6,6 @@ using System.Threading;
using log4net; using log4net;
using log4net.Config; using log4net.Config;
using log4net.Repository; using log4net.Repository;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using WireMock.RequestBuilders; using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using WireMock.Server; using WireMock.Server;
@@ -35,33 +33,6 @@ namespace WireMock.Net.StandAlone.NETCoreApp
settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'"))); settings.Logger.Debug("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
/* https://stackoverflow.com/questions/31942037/how-to-enable-cors-in-asp-net-core */
/* Enable Cors */
var policyName = "MyPolicy";
settings.AdditionalServiceRegistration = services =>
{
services.AddCors(corsOptions =>
corsOptions.AddPolicy(policyName,
corsPolicyBuilder =>
{
corsPolicyBuilder
.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin();
}));
settings.Logger.Debug("Enable Cors");
};
/* Use Cors */
settings.PreWireMockMiddlewareInit = app =>
{
var appBuilder = (IApplicationBuilder)app;
appBuilder.UseCors(policyName);
settings.Logger.Debug("Use Cors");
};
_server = WireMockServer.Start(settings); _server = WireMockServer.Start(settings);
_server.Given(Request.Create().WithPath("/api/sap") _server.Given(Request.Create().WithPath("/api/sap")

View File

@@ -1,8 +1,8 @@
{ {
"profiles": { "profiles": {
"WireMock.Net.StandAlone.NETCoreApp": { "WireMock.Net.StandAlone.NETCoreApp": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "--Urls http://localhost:9091 --WireMockLogger WireMockConsoleLogger" "commandLineArgs": "--Urls http://localhost:9091 --CorsPolicyOptions AllowAll --WireMockLogger WireMockConsoleLogger"
} }
} }
} }

View File

@@ -1,5 +1,6 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using WireMock.Handlers; using WireMock.Handlers;
using WireMock.Types;
namespace WireMock.Admin.Settings namespace WireMock.Admin.Settings
{ {
@@ -53,5 +54,10 @@ namespace WireMock.Admin.Settings
/// Save unmatched requests to a file using the <see cref="IFileSystemHandler"/>. (default set to false). /// Save unmatched requests to a file using the <see cref="IFileSystemHandler"/>. (default set to false).
/// </summary> /// </summary>
public bool? SaveUnmatchedRequests { get; set; } public bool? SaveUnmatchedRequests { get; set; }
/// <summary>
/// Policies to use when using CORS. By default CORS is disabled. [Optional]
/// </summary>
public string CorsPolicyOptions { get; set; }
} }
} }

View File

@@ -0,0 +1,36 @@
using System;
namespace WireMock.Types
{
/// <summary>
/// Policies to use when using CORS.
/// </summary>
[Flags]
public enum CorsPolicyOptions
{
/// <summary>
/// Cors is disabled
/// </summary>
None = 0,
/// <summary>
/// Ensures that the policy allows any header.
/// </summary>
AllowAnyHeader = 0b00000001,
/// <summary>
/// Ensures that the policy allows any method.
/// </summary>
AllowAnyMethod = 0b00000010,
/// <summary>
/// Ensures that the policy allows any origin.
/// </summary>
AllowAnyOrigin = 0b00000100,
/// <summary>
/// Ensures that the policy allows any header, method and origin.
/// </summary>
AllowAll = AllowAnyHeader | AllowAnyMethod | AllowAnyOrigin
}
}

View File

@@ -0,0 +1,48 @@
#if NETCOREAPP3_1_OR_GREATER
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using WireMock.Types;
namespace WireMock.Owin
{
internal partial class AspNetCoreSelfHost
{
public void AddCors(IServiceCollection services)
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions > CorsPolicyOptions.None)
{
/* https://stackoverflow.com/questions/31942037/how-to-enable-cors-in-asp-net-core */
/* Enable Cors */
services.AddCors(corsOptions => corsOptions
.AddPolicy(CorsPolicyName,
corsPolicyBuilder =>
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyHeader))
{
corsPolicyBuilder.AllowAnyHeader();
}
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyMethod))
{
corsPolicyBuilder.AllowAnyMethod();
}
if (_wireMockMiddlewareOptions.CorsPolicyOptions.Value.HasFlag(CorsPolicyOptions.AllowAnyOrigin))
{
corsPolicyBuilder.AllowAnyOrigin();
}
}));
}
}
public void UseCors(IApplicationBuilder appBuilder)
{
if (_wireMockMiddlewareOptions.CorsPolicyOptions > CorsPolicyOptions.None)
{
/* Use Cors */
appBuilder.UseCors(CorsPolicyName);
}
}
}
}
#endif

View File

@@ -1,10 +1,11 @@
#if USE_ASPNETCORE && !NETSTANDARD1_3 #if USE_ASPNETCORE && !NETSTANDARD1_3
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using WireMock.HttpsCertificate; using WireMock.HttpsCertificate;
using WireMock.Types;
namespace WireMock.Owin namespace WireMock.Owin
{ {

View File

@@ -18,6 +18,8 @@ namespace WireMock.Owin
{ {
internal partial class AspNetCoreSelfHost : IOwinSelfHost internal partial class AspNetCoreSelfHost : IOwinSelfHost
{ {
private const string CorsPolicyName = "WireMock.Net - Policy";
private readonly CancellationTokenSource _cts = new CancellationTokenSource(); private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly IWireMockMiddlewareOptions _wireMockMiddlewareOptions; private readonly IWireMockMiddlewareOptions _wireMockMiddlewareOptions;
private readonly IWireMockLogger _logger; private readonly IWireMockLogger _logger;
@@ -68,12 +70,18 @@ namespace WireMock.Owin
services.AddSingleton<IOwinRequestMapper, OwinRequestMapper>(); services.AddSingleton<IOwinRequestMapper, OwinRequestMapper>();
services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>(); services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>();
#if NETCOREAPP3_1_OR_GREATER
AddCors(services);
#endif
_wireMockMiddlewareOptions.AdditionalServiceRegistration?.Invoke(services); _wireMockMiddlewareOptions.AdditionalServiceRegistration?.Invoke(services);
}) })
.Configure(appBuilder => .Configure(appBuilder =>
{ {
appBuilder.UseMiddleware<GlobalExceptionMiddleware>(); appBuilder.UseMiddleware<GlobalExceptionMiddleware>();
#if NETCOREAPP3_1_OR_GREATER
UseCors(appBuilder);
#endif
_wireMockMiddlewareOptions.PreWireMockMiddlewareInit?.Invoke(appBuilder); _wireMockMiddlewareOptions.PreWireMockMiddlewareInit?.Invoke(appBuilder);
appBuilder.UseMiddleware<WireMockMiddleware>(); appBuilder.UseMiddleware<WireMockMiddleware>();

View File

@@ -4,6 +4,8 @@ using WireMock.Handlers;
using WireMock.Logging; using WireMock.Logging;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Util; using WireMock.Util;
using JetBrains.Annotations;
using WireMock.Types;
#if !USE_ASPNETCORE #if !USE_ASPNETCORE
using Owin; using Owin;
#else #else
@@ -39,6 +41,8 @@ namespace WireMock.Owin
#if USE_ASPNETCORE #if USE_ASPNETCORE
Action<IServiceCollection> AdditionalServiceRegistration { get; set; } Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif #endif
IFileSystemHandler FileSystemHandler { get; set; } IFileSystemHandler FileSystemHandler { get; set; }

View File

@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using WireMock.Handlers; using WireMock.Handlers;
using WireMock.Logging; using WireMock.Logging;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Types;
using WireMock.Util; using WireMock.Util;
#if !USE_ASPNETCORE #if !USE_ASPNETCORE
using Owin; using Owin;
@@ -39,6 +40,8 @@ namespace WireMock.Owin
#if USE_ASPNETCORE #if USE_ASPNETCORE
public Action<IServiceCollection> AdditionalServiceRegistration { get; set; } public Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif #endif
/// <inheritdoc cref="IWireMockMiddlewareOptions.FileSystemHandler"/> /// <inheritdoc cref="IWireMockMiddlewareOptions.FileSystemHandler"/>

View File

@@ -293,7 +293,11 @@ namespace WireMock.Server
HandleRequestsSynchronously = _settings.HandleRequestsSynchronously, HandleRequestsSynchronously = _settings.HandleRequestsSynchronously,
ThrowExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails, ThrowExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails,
UseRegexExtended = _settings.UseRegexExtended, UseRegexExtended = _settings.UseRegexExtended,
SaveUnmatchedRequests = _settings.SaveUnmatchedRequests SaveUnmatchedRequests = _settings.SaveUnmatchedRequests,
#if USE_ASPNETCORE
CorsPolicyOptions = _settings.CorsPolicyOptions?.ToString()
#endif
}; };
return ToJson(model); return ToJson(model);
@@ -315,6 +319,13 @@ namespace WireMock.Server
_settings.UseRegexExtended = settings.UseRegexExtended; _settings.UseRegexExtended = settings.UseRegexExtended;
_settings.SaveUnmatchedRequests = settings.SaveUnmatchedRequests; _settings.SaveUnmatchedRequests = settings.SaveUnmatchedRequests;
#if USE_ASPNETCORE
if (Enum.TryParse<CorsPolicyOptions>(settings.CorsPolicyOptions, true, out var corsPolicyOptions))
{
_settings.CorsPolicyOptions = corsPolicyOptions;
}
#endif
return ResponseMessageBuilder.Create("Settings updated"); return ResponseMessageBuilder.Create("Settings updated");
} }
#endregion Settings #endregion Settings

View File

@@ -243,6 +243,8 @@ namespace WireMock.Server
#if USE_ASPNETCORE #if USE_ASPNETCORE
_options.AdditionalServiceRegistration = _settings.AdditionalServiceRegistration; _options.AdditionalServiceRegistration = _settings.AdditionalServiceRegistration;
_options.CorsPolicyOptions = _settings.CorsPolicyOptions;
_httpServer = new AspNetCoreSelfHost(_options, urlOptions); _httpServer = new AspNetCoreSelfHost(_options, urlOptions);
#else #else
_httpServer = new OwinSelfHost(_options, urlOptions); _httpServer = new OwinSelfHost(_options, urlOptions);

View File

@@ -11,6 +11,7 @@ using WireMock.Matchers;
using WireMock.RegularExpressions; using WireMock.RegularExpressions;
#if USE_ASPNETCORE #if USE_ASPNETCORE
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using WireMock.Types;
#endif #endif
namespace WireMock.Settings namespace WireMock.Settings
@@ -135,6 +136,12 @@ namespace WireMock.Settings
/// </summary> /// </summary>
[PublicAPI] [PublicAPI]
Action<IServiceCollection> AdditionalServiceRegistration { get; set; } Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
/// <summary>
/// Policies to use when using CORS. By default CORS is disabled. [Optional]
/// </summary>
[PublicAPI]
CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif #endif
/// <summary> /// <summary>

View File

@@ -7,6 +7,7 @@ using WireMock.Admin.Mappings;
using WireMock.Handlers; using WireMock.Handlers;
using WireMock.Logging; using WireMock.Logging;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Types;
#if USE_ASPNETCORE #if USE_ASPNETCORE
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
#endif #endif
@@ -97,6 +98,10 @@ namespace WireMock.Settings
[PublicAPI] [PublicAPI]
[JsonIgnore] [JsonIgnore]
public Action<IServiceCollection> AdditionalServiceRegistration { get; set; } public Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
/// <inheritdoc cref="IWireMockServerSettings.CorsPolicyOptions"/>
[PublicAPI]
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif #endif
/// <inheritdoc cref="IWireMockServerSettings.Logger"/> /// <inheritdoc cref="IWireMockServerSettings.Logger"/>

View File

@@ -1,6 +1,9 @@
using System;
using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Logging;
using Stef.Validation; using Stef.Validation;
using WireMock.Logging;
using WireMock.Types;
namespace WireMock.Settings namespace WireMock.Settings
{ {
@@ -50,9 +53,18 @@ namespace WireMock.Settings
HandleRequestsSynchronously = parser.GetBoolValue("HandleRequestsSynchronously"), HandleRequestsSynchronously = parser.GetBoolValue("HandleRequestsSynchronously"),
ThrowExceptionWhenMatcherFails = parser.GetBoolValue("ThrowExceptionWhenMatcherFails"), ThrowExceptionWhenMatcherFails = parser.GetBoolValue("ThrowExceptionWhenMatcherFails"),
UseRegexExtended = parser.GetBoolValue(nameof(IWireMockServerSettings.UseRegexExtended), true), UseRegexExtended = parser.GetBoolValue(nameof(IWireMockServerSettings.UseRegexExtended), true),
SaveUnmatchedRequests = parser.GetBoolValue(nameof(IWireMockServerSettings.SaveUnmatchedRequests)) SaveUnmatchedRequests = parser.GetBoolValue(nameof(IWireMockServerSettings.SaveUnmatchedRequests)),
}; };
#if USE_ASPNETCORE
settings.CorsPolicyOptions = parser.GetValue(
nameof(IWireMockServerSettings.CorsPolicyOptions), values =>
{
var value = string.Join(string.Empty, values);
return Enum.TryParse<CorsPolicyOptions>(value, true, out var corsPolicyOptions) ? corsPolicyOptions : CorsPolicyOptions.None;
});
#endif
if (logger != null) if (logger != null)
{ {
settings.Logger = logger; settings.Logger = logger;

View File

@@ -17,6 +17,7 @@ using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using WireMock.Server; using WireMock.Server;
using WireMock.Settings; using WireMock.Settings;
using WireMock.Types;
using WireMock.Util; using WireMock.Util;
using Xunit; using Xunit;
@@ -97,6 +98,29 @@ namespace WireMock.Net.Tests
server.Stop(); server.Stop();
} }
#if NETCOREAPP3_1_OR_GREATER
[Fact]
public async Task WireMockServer_WithCorsPolicyOptions_Should_Work_Correct()
{
// Arrange
var settings = new WireMockServerSettings
{
CorsPolicyOptions = CorsPolicyOptions.AllowAll
};
var server = WireMockServer.Start(settings);
server.Given(Request.Create().WithPath("/*")).RespondWith(Response.Create().WithBody("x"));
// Act
var response = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + "/foo").ConfigureAwait(false);
// Asser.
response.Should().Be("x");
server.Stop();
}
#endif
[Fact] [Fact]
public async Task WireMockServer_Should_delay_responses_for_a_given_route() public async Task WireMockServer_Should_delay_responses_for_a_given_route()
{ {