Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Cors #714

Merged
merged 7 commits into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions examples/WireMock.Net.StandAlone.NETCoreApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
using log4net;
using log4net.Config;
using log4net.Repository;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
Expand Down Expand Up @@ -35,33 +33,6 @@ static void Main(string[] args)

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.Given(Request.Create().WithPath("/api/sap")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"profiles": {
"WireMock.Net.StandAlone.NETCoreApp": {
"commandName": "Project",
"commandLineArgs": "--Urls http://localhost:9091 --WireMockLogger WireMockConsoleLogger"
"commandName": "Project",
"commandLineArgs": "--Urls http://localhost:9091 --CorsPolicyOptions AllowAll --WireMockLogger WireMockConsoleLogger"
}
}
}
6 changes: 6 additions & 0 deletions src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text.RegularExpressions;
using WireMock.Handlers;
using WireMock.Types;

namespace WireMock.Admin.Settings
{
Expand Down Expand Up @@ -53,5 +54,10 @@ public class SettingsModel
/// Save unmatched requests to a file using the <see cref="IFileSystemHandler"/>. (default set to false).
/// </summary>
public bool? SaveUnmatchedRequests { get; set; }

/// <summary>
/// Policies to use when using CORS. By default CORS is disabled. [Optional]
/// </summary>
public string CorsPolicyOptions { get; set; }
}
}
36 changes: 36 additions & 0 deletions src/WireMock.Net.Abstractions/Types/CorsPolicyOptions.cs
Original file line number Diff line number Diff line change
@@ -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
}
}
48 changes: 48 additions & 0 deletions src/WireMock.Net/Owin/AspNetCoreSelfHost.NETCore.cs
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion src/WireMock.Net/Owin/AspNetCoreSelfHost.NETStandard.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#if USE_ASPNETCORE && !NETSTANDARD1_3
#if USE_ASPNETCORE && !NETSTANDARD1_3
using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WireMock.HttpsCertificate;
using WireMock.Types;

namespace WireMock.Owin
{
Expand Down
8 changes: 8 additions & 0 deletions src/WireMock.Net/Owin/AspNetCoreSelfHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace WireMock.Owin
{
internal partial class AspNetCoreSelfHost : IOwinSelfHost
{
private const string CorsPolicyName = "WireMock.Net - Policy";

private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly IWireMockMiddlewareOptions _wireMockMiddlewareOptions;
private readonly IWireMockLogger _logger;
Expand Down Expand Up @@ -68,12 +70,18 @@ public Task StartAsync()
services.AddSingleton<IOwinRequestMapper, OwinRequestMapper>();
services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>();

#if NETCOREAPP3_1_OR_GREATER
AddCors(services);
#endif
_wireMockMiddlewareOptions.AdditionalServiceRegistration?.Invoke(services);
})
.Configure(appBuilder =>
{
appBuilder.UseMiddleware<GlobalExceptionMiddleware>();

#if NETCOREAPP3_1_OR_GREATER
UseCors(appBuilder);
#endif
_wireMockMiddlewareOptions.PreWireMockMiddlewareInit?.Invoke(appBuilder);

appBuilder.UseMiddleware<WireMockMiddleware>();
Expand Down
4 changes: 4 additions & 0 deletions src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Util;
using JetBrains.Annotations;
using WireMock.Types;
#if !USE_ASPNETCORE
using Owin;
#else
Expand Down Expand Up @@ -39,6 +41,8 @@ internal interface IWireMockMiddlewareOptions

#if USE_ASPNETCORE
Action<IServiceCollection> AdditionalServiceRegistration { get; set; }

CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif

IFileSystemHandler FileSystemHandler { get; set; }
Expand Down
3 changes: 3 additions & 0 deletions src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Types;
using WireMock.Util;
#if !USE_ASPNETCORE
using Owin;
Expand Down Expand Up @@ -39,6 +40,8 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions

#if USE_ASPNETCORE
public Action<IServiceCollection> AdditionalServiceRegistration { get; set; }

public CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif

/// <inheritdoc cref="IWireMockMiddlewareOptions.FileSystemHandler"/>
Expand Down
13 changes: 12 additions & 1 deletion src/WireMock.Net/Server/WireMockServer.Admin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,11 @@ private ResponseMessage SettingsGet(RequestMessage requestMessage)
HandleRequestsSynchronously = _settings.HandleRequestsSynchronously,
ThrowExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails,
UseRegexExtended = _settings.UseRegexExtended,
SaveUnmatchedRequests = _settings.SaveUnmatchedRequests
SaveUnmatchedRequests = _settings.SaveUnmatchedRequests,

#if USE_ASPNETCORE
CorsPolicyOptions = _settings.CorsPolicyOptions?.ToString()
#endif
};

return ToJson(model);
Expand All @@ -315,6 +319,13 @@ private ResponseMessage SettingsUpdate(RequestMessage requestMessage)
_settings.UseRegexExtended = settings.UseRegexExtended;
_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");
}
#endregion Settings
Expand Down
2 changes: 2 additions & 0 deletions src/WireMock.Net/Server/WireMockServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ protected WireMockServer(IWireMockServerSettings settings)

#if USE_ASPNETCORE
_options.AdditionalServiceRegistration = _settings.AdditionalServiceRegistration;
_options.CorsPolicyOptions = _settings.CorsPolicyOptions;

_httpServer = new AspNetCoreSelfHost(_options, urlOptions);
#else
_httpServer = new OwinSelfHost(_options, urlOptions);
Expand Down
7 changes: 7 additions & 0 deletions src/WireMock.Net/Settings/IWireMockServerSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using WireMock.RegularExpressions;
#if USE_ASPNETCORE
using Microsoft.Extensions.DependencyInjection;
using WireMock.Types;
#endif

namespace WireMock.Settings
Expand Down Expand Up @@ -135,6 +136,12 @@ public interface IWireMockServerSettings
/// </summary>
[PublicAPI]
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

/// <summary>
Expand Down
5 changes: 5 additions & 0 deletions src/WireMock.Net/Settings/WireMockServerSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Types;
#if USE_ASPNETCORE
using Microsoft.Extensions.DependencyInjection;
#endif
Expand Down Expand Up @@ -97,6 +98,10 @@ public class WireMockServerSettings : IWireMockServerSettings
[PublicAPI]
[JsonIgnore]
public Action<IServiceCollection> AdditionalServiceRegistration { get; set; }

/// <inheritdoc cref="IWireMockServerSettings.CorsPolicyOptions"/>
[PublicAPI]
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
#endif

/// <inheritdoc cref="IWireMockServerSettings.Logger"/>
Expand Down
16 changes: 14 additions & 2 deletions src/WireMock.Net/Settings/WireMockServerSettingsParser.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System;
using System.Linq;
using JetBrains.Annotations;
using WireMock.Logging;
using Stef.Validation;
using WireMock.Logging;
using WireMock.Types;

namespace WireMock.Settings
{
Expand Down Expand Up @@ -50,9 +53,18 @@ public static bool TryParseArguments([NotNull] string[] args, out IWireMockServe
HandleRequestsSynchronously = parser.GetBoolValue("HandleRequestsSynchronously"),
ThrowExceptionWhenMatcherFails = parser.GetBoolValue("ThrowExceptionWhenMatcherFails"),
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)
{
settings.Logger = logger;
Expand Down
24 changes: 24 additions & 0 deletions test/WireMock.Net.Tests/WireMockServerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;
using WireMock.Types;
using WireMock.Util;
using Xunit;

Expand Down Expand Up @@ -97,6 +98,29 @@ public async Task WireMockServer_Should_respond_a_redirect_without_body()
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]
public async Task WireMockServer_Should_delay_responses_for_a_given_route()
{
Expand Down