diff --git a/examples/WireMock.Net.Console.Record.NETCoreApp/Program.cs b/examples/WireMock.Net.Console.Record.NETCoreApp/Program.cs
index 547266bc..604b6615 100644
--- a/examples/WireMock.Net.Console.Record.NETCoreApp/Program.cs
+++ b/examples/WireMock.Net.Console.Record.NETCoreApp/Program.cs
@@ -1,4 +1,6 @@
using Newtonsoft.Json;
+using WireMock.RequestBuilders;
+using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;
@@ -13,16 +15,26 @@ namespace WireMock.Net.Console.Proxy.NETCoreApp
Urls = new[] { "http://localhost:9091/", "https://localhost:9443/" },
StartAdminInterface = true,
ReadStaticMappings = false,
- ProxyAndRecordSettings = new ProxyAndRecordSettings
- {
- Url = "https://www.google.com",
- //ClientX509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)",
- SaveMapping = true,
- SaveMappingToFile = false,
- ExcludedHeaders = new [] { "dnt", "Content-Length" }
- }
+ //ProxyAndRecordSettings = new ProxyAndRecordSettings
+ //{
+ // Url = "https://www.google.com",
+ // //ClientX509Certificate2ThumbprintOrSubjectName = "www.yourclientcertname.com OR yourcertificatethumbprint (only if the service you're proxying to requires it)",
+ // SaveMapping = true,
+ // SaveMappingToFile = false,
+ // ExcludedHeaders = new [] { "dnt", "Content-Length" }
+ //}
});
+ server
+ .Given(Request.Create().UsingGet())
+ .RespondWith(Response.Create()
+ .WithProxy(new ProxyAndRecordSettings
+ {
+ Url = "http://postman-echo.com/post",
+ SaveMapping = true,
+ SaveMappingToFile = true
+ }));
+
System.Console.WriteLine("Press any key to stop the server");
System.Console.ReadKey();
server.Stop();
diff --git a/examples/WireMock.Net.Console.Record.NETCoreApp/WireMock.Net.Console.Proxy.NETCoreApp.csproj b/examples/WireMock.Net.Console.Record.NETCoreApp/WireMock.Net.Console.Proxy.NETCoreApp.csproj
index c0c3c194..1526ba1f 100644
--- a/examples/WireMock.Net.Console.Record.NETCoreApp/WireMock.Net.Console.Proxy.NETCoreApp.csproj
+++ b/examples/WireMock.Net.Console.Record.NETCoreApp/WireMock.Net.Console.Proxy.NETCoreApp.csproj
@@ -2,7 +2,7 @@
Exe
- netcoreapp1.1
+ net5.0
../../WireMock.Net-Logo.ico
diff --git a/src/WireMock.Net/Http/HttpClientHelper.cs b/src/WireMock.Net/Http/HttpClientBuilder.cs
similarity index 69%
rename from src/WireMock.Net/Http/HttpClientHelper.cs
rename to src/WireMock.Net/Http/HttpClientBuilder.cs
index 76247d61..00b2dea2 100644
--- a/src/WireMock.Net/Http/HttpClientHelper.cs
+++ b/src/WireMock.Net/Http/HttpClientBuilder.cs
@@ -1,17 +1,13 @@
-using JetBrains.Annotations;
-using System;
-using System.Net;
+using System.Net;
using System.Net.Http;
-using System.Threading.Tasks;
using WireMock.HttpsCertificate;
using WireMock.Settings;
-using WireMock.Validation;
namespace WireMock.Http
{
- internal static class HttpClientHelper
+ internal static class HttpClientBuilder
{
- public static HttpClient CreateHttpClient(IProxyAndRecordSettings settings)
+ public static HttpClient Build(IProxyAndRecordSettings settings)
{
#if NETSTANDARD || NETCOREAPP3_1 || NET5_0
var handler = new HttpClientHandler
@@ -57,32 +53,14 @@ namespace WireMock.Http
{
handler.Proxy.Credentials = new NetworkCredential(settings.WebProxySettings.UserName, settings.WebProxySettings.Password);
}
- }
-
+ }
+
#if !NETSTANDARD1_3
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) => true;
#endif
-
+
return new HttpClient(handler);
}
-
- public static async Task SendAsync([NotNull] HttpClient client, [NotNull] RequestMessage requestMessage, string url, bool deserializeJson, bool decompressGzipAndDeflate)
- {
- Check.NotNull(client, nameof(client));
- Check.NotNull(requestMessage, nameof(requestMessage));
-
- var originalUri = new Uri(requestMessage.Url);
- var requiredUri = new Uri(url);
-
- // Create HttpRequestMessage
- var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, url);
-
- // Call the URL
- var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);
-
- // Create ResponseMessage
- return await HttpResponseMessageHelper.CreateAsync(httpResponseMessage, requiredUri, originalUri, deserializeJson, decompressGzipAndDeflate);
- }
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/IMapping.cs b/src/WireMock.Net/IMapping.cs
index a28bd526..6cdcf0e2 100644
--- a/src/WireMock.Net/IMapping.cs
+++ b/src/WireMock.Net/IMapping.cs
@@ -71,7 +71,7 @@ namespace WireMock
/// The WireMockServerSettings.
///
IWireMockServerSettings Settings { get; }
-
+
///
/// Is State started ?
///
diff --git a/src/WireMock.Net/Mapping.cs b/src/WireMock.Net/Mapping.cs
index 6c215be0..9952f4ef 100644
--- a/src/WireMock.Net/Mapping.cs
+++ b/src/WireMock.Net/Mapping.cs
@@ -68,9 +68,18 @@ namespace WireMock
/// State in which the current mapping can occur. [Optional]
/// The next state which will occur after the current mapping execution. [Optional]
/// Only when the current state is executed this number, the next state which will occur. [Optional]
- public Mapping(Guid guid, [CanBeNull] string title, [CanBeNull] string path,
- [NotNull] IWireMockServerSettings settings, [NotNull] IRequestMatcher requestMatcher, [NotNull] IResponseProvider provider,
- int priority, [CanBeNull] string scenario, [CanBeNull] string executionConditionState, [CanBeNull] string nextState, [CanBeNull] int? stateTimes)
+ public Mapping(
+ Guid guid,
+ [CanBeNull] string title,
+ [CanBeNull] string path,
+ [NotNull] IWireMockServerSettings settings,
+ [NotNull] IRequestMatcher requestMatcher,
+ [NotNull] IResponseProvider provider,
+ int priority,
+ [CanBeNull] string scenario,
+ [CanBeNull] string executionConditionState,
+ [CanBeNull] string nextState,
+ [CanBeNull] int? stateTimes)
{
Guid = guid;
Title = title;
@@ -82,7 +91,7 @@ namespace WireMock
Scenario = scenario;
ExecutionConditionState = executionConditionState;
NextState = nextState;
- StateTimes = stateTimes;
+ StateTimes = stateTimes;
}
///
diff --git a/src/WireMock.Net/Owin/WireMockMiddleware.cs b/src/WireMock.Net/Owin/WireMockMiddleware.cs
index 5047306c..e6f9cac1 100644
--- a/src/WireMock.Net/Owin/WireMockMiddleware.cs
+++ b/src/WireMock.Net/Owin/WireMockMiddleware.cs
@@ -8,6 +8,7 @@ using WireMock.Owin.Mappers;
using WireMock.Serialization;
using WireMock.Types;
using WireMock.Validation;
+using WireMock.ResponseBuilders;
#if !USE_ASPNETCORE
using Microsoft.Owin;
using IContext = Microsoft.Owin.IOwinContext;
@@ -129,6 +130,22 @@ namespace WireMock.Owin
response = await targetMapping.ProvideResponseAsync(request);
+ var responseBuilder = targetMapping.Provider as Response;
+
+ if (responseBuilder?.ProxyAndRecordSettings?.SaveMapping == true || targetMapping?.Settings?.ProxyAndRecordSettings?.SaveMapping == true)
+ {
+ _options.Mappings.TryAdd(targetMapping.Guid, targetMapping);
+ }
+
+ if (responseBuilder?.ProxyAndRecordSettings?.SaveMappingToFile == true || targetMapping?.Settings?.ProxyAndRecordSettings?.SaveMappingToFile == true)
+ {
+ var matcherMapper = new MatcherMapper(targetMapping.Settings);
+ var mappingConverter = new MappingConverter(matcherMapper);
+ var mappingToFileSaver = new MappingToFileSaver(targetMapping.Settings, mappingConverter);
+
+ mappingToFileSaver.SaveMappingToFile(targetMapping);
+ }
+
if (targetMapping.Scenario != null)
{
UpdateScenarioState(targetMapping);
diff --git a/src/WireMock.Net/Proxy/ProxyHelper.cs b/src/WireMock.Net/Proxy/ProxyHelper.cs
new file mode 100644
index 00000000..d4410f21
--- /dev/null
+++ b/src/WireMock.Net/Proxy/ProxyHelper.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Threading.Tasks;
+using HandlebarsDotNet.Helpers.Validation;
+using JetBrains.Annotations;
+using WireMock.Http;
+using WireMock.Matchers;
+using WireMock.RequestBuilders;
+using WireMock.ResponseBuilders;
+using WireMock.Settings;
+using WireMock.Types;
+using WireMock.Util;
+
+namespace WireMock.Proxy
+{
+ internal class ProxyHelper
+ {
+ private readonly IWireMockServerSettings _settings;
+
+ public ProxyHelper([NotNull] IWireMockServerSettings settings)
+ {
+ Guard.NotNull(settings, nameof(settings));
+ _settings = settings;
+ }
+
+ public async Task<(ResponseMessage ResponseMessage, IMapping Mapping)> SendAsync(
+ [NotNull] IProxyAndRecordSettings proxyAndRecordSettings,
+ [NotNull] HttpClient client,
+ [NotNull] RequestMessage requestMessage,
+ [NotNull] string url)
+ {
+ Guard.NotNull(client, nameof(client));
+ Guard.NotNull(requestMessage, nameof(requestMessage));
+ Guard.NotNull(url, nameof(url));
+
+ var originalUri = new Uri(requestMessage.Url);
+ var requiredUri = new Uri(url);
+
+ // Create HttpRequestMessage
+ var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, url);
+
+ // Call the URL
+ var httpResponseMessage = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead);
+
+ // Create ResponseMessage
+ bool deserializeJson = !_settings.DisableJsonBodyParsing.GetValueOrDefault(false);
+ bool decompressGzipAndDeflate = !_settings.DisableRequestBodyDecompressing.GetValueOrDefault(false);
+
+ var responseMessage = await HttpResponseMessageHelper.CreateAsync(httpResponseMessage, requiredUri, originalUri, deserializeJson, decompressGzipAndDeflate);
+
+ IMapping mapping = null;
+ if (HttpStatusRangeParser.IsMatch(proxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
+ (proxyAndRecordSettings.SaveMapping || proxyAndRecordSettings.SaveMappingToFile))
+ {
+ mapping = ToMapping(proxyAndRecordSettings, requestMessage, responseMessage);
+ }
+
+ return (responseMessage, mapping);
+ }
+
+ private IMapping ToMapping(IProxyAndRecordSettings proxyAndRecordSettings, RequestMessage requestMessage, ResponseMessage responseMessage)
+ {
+ string[] excludedHeaders = proxyAndRecordSettings.ExcludedHeaders ?? new string[] { };
+ string[] excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? new string[] { };
+
+ var request = Request.Create();
+ request.WithPath(requestMessage.Path);
+ request.UsingMethod(requestMessage.Method);
+
+ requestMessage.Query.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
+ requestMessage.Cookies.Loop((key, value) =>
+ {
+ if (!excludedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
+ {
+ request.WithCookie(key, value);
+ }
+ });
+
+ var allExcludedHeaders = new List(excludedHeaders) { "Cookie" };
+ requestMessage.Headers.Loop((key, value) =>
+ {
+ if (!allExcludedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
+ {
+ request.WithHeader(key, value.ToArray());
+ }
+ });
+
+ bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
+ switch (requestMessage.BodyData?.DetectedBodyType)
+ {
+ case BodyType.Json:
+ request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson, true, throwExceptionWhenMatcherFails));
+ break;
+
+ case BodyType.String:
+ request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, throwExceptionWhenMatcherFails, requestMessage.BodyData.BodyAsString));
+ break;
+
+ case BodyType.Bytes:
+ request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
+ break;
+ }
+
+ var response = Response.Create(responseMessage);
+
+ return new Mapping(Guid.NewGuid(), string.Empty, null, _settings, request, response, 0, null, null, null, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/ResponseBuilders/Response.WithProxy.cs b/src/WireMock.Net/ResponseBuilders/Response.WithProxy.cs
index b43880cb..526364e0 100644
--- a/src/WireMock.Net/ResponseBuilders/Response.WithProxy.cs
+++ b/src/WireMock.Net/ResponseBuilders/Response.WithProxy.cs
@@ -9,15 +9,10 @@ namespace WireMock.ResponseBuilders
{
private HttpClient _httpClientForProxy;
- ///
- /// The Proxy URL to use.
- ///
- public string ProxyUrl { get; private set; }
-
///
/// The WebProxy settings.
///
- public IWebProxySettings WebProxySettings { get; private set; }
+ public IProxyAndRecordSettings ProxyAndRecordSettings { get; private set; }
///
public IResponseBuilder WithProxy(string proxyUrl, string clientX509Certificate2ThumbprintOrSubjectName = null)
@@ -38,10 +33,9 @@ namespace WireMock.ResponseBuilders
{
Check.NotNull(settings, nameof(settings));
- ProxyUrl = settings.Url;
- WebProxySettings = settings.WebProxySettings;
+ ProxyAndRecordSettings = settings;
- _httpClientForProxy = HttpClientHelper.CreateHttpClient(settings);
+ _httpClientForProxy = HttpClientBuilder.Build(settings);
return this;
}
}
diff --git a/src/WireMock.Net/ResponseBuilders/Response.cs b/src/WireMock.Net/ResponseBuilders/Response.cs
index 061552b8..b999bd55 100644
--- a/src/WireMock.Net/ResponseBuilders/Response.cs
+++ b/src/WireMock.Net/ResponseBuilders/Response.cs
@@ -7,7 +7,7 @@ using System.Net;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
-using WireMock.Http;
+using WireMock.Proxy;
using WireMock.ResponseProviders;
using WireMock.Settings;
using WireMock.Transformers;
@@ -312,7 +312,7 @@ namespace WireMock.ResponseBuilders
await Task.Delay(Delay.Value);
}
- if (ProxyUrl != null && _httpClientForProxy != null)
+ if (ProxyAndRecordSettings != null && _httpClientForProxy != null)
{
string RemoveFirstOccurrence(string source, string find)
{
@@ -323,16 +323,19 @@ namespace WireMock.ResponseBuilders
var requestUri = new Uri(requestMessage.Url);
// Build the proxy url and skip duplicates
- string extra = RemoveFirstOccurrence(requestUri.LocalPath.TrimEnd('/'), new Uri(ProxyUrl).LocalPath.TrimEnd('/'));
- requestMessage.ProxyUrl = ProxyUrl + extra + requestUri.Query;
+ string extra = RemoveFirstOccurrence(requestUri.LocalPath.TrimEnd('/'), new Uri(ProxyAndRecordSettings.Url).LocalPath.TrimEnd('/'));
+ requestMessage.ProxyUrl = ProxyAndRecordSettings.Url + extra + requestUri.Query;
- return await HttpClientHelper.SendAsync(
+ var proxyHelper = new ProxyHelper(settings);
+
+ var (proxyResponseMessage, mapping) = await proxyHelper.SendAsync(
+ ProxyAndRecordSettings,
_httpClientForProxy,
requestMessage,
- requestMessage.ProxyUrl,
- !settings.DisableJsonBodyParsing.GetValueOrDefault(false),
- !settings.DisableRequestBodyDecompressing.GetValueOrDefault(false)
+ requestMessage.ProxyUrl
);
+
+ return proxyResponseMessage;
}
ResponseMessage responseMessage;
diff --git a/src/WireMock.Net/ResponseProviders/IResponseProvider.cs b/src/WireMock.Net/ResponseProviders/IResponseProvider.cs
index a3813b4c..6d33443b 100644
--- a/src/WireMock.Net/ResponseProviders/IResponseProvider.cs
+++ b/src/WireMock.Net/ResponseProviders/IResponseProvider.cs
@@ -1,7 +1,7 @@
// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License.
// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
-using JetBrains.Annotations;
using System.Threading.Tasks;
+using JetBrains.Annotations;
using WireMock.Settings;
namespace WireMock.ResponseProviders
diff --git a/src/WireMock.Net/Serialization/JsonSerializationConstants.cs b/src/WireMock.Net/Serialization/JsonSerializationConstants.cs
new file mode 100644
index 00000000..b251a340
--- /dev/null
+++ b/src/WireMock.Net/Serialization/JsonSerializationConstants.cs
@@ -0,0 +1,19 @@
+using Newtonsoft.Json;
+
+namespace WireMock.Serialization
+{
+ internal static class JsonSerializationConstants
+ {
+ public static readonly JsonSerializerSettings JsonSerializerSettingsDefault = new JsonSerializerSettings
+ {
+ Formatting = Formatting.Indented,
+ NullValueHandling = NullValueHandling.Ignore
+ };
+
+ public static readonly JsonSerializerSettings JsonSerializerSettingsIncludeNullValues = new JsonSerializerSettings
+ {
+ Formatting = Formatting.Indented,
+ NullValueHandling = NullValueHandling.Include
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs
index 90cbf966..6e4167f9 100644
--- a/src/WireMock.Net/Serialization/MappingConverter.cs
+++ b/src/WireMock.Net/Serialization/MappingConverter.cs
@@ -101,7 +101,7 @@ namespace WireMock.Serialization
}
}
- if (!string.IsNullOrEmpty(response.ProxyUrl))
+ if (response.ProxyAndRecordSettings != null)
{
mappingModel.Response.StatusCode = null;
mappingModel.Response.Headers = null;
@@ -115,9 +115,9 @@ namespace WireMock.Serialization
mappingModel.Response.UseTransformer = null;
mappingModel.Response.UseTransformerForBodyAsFile = null;
mappingModel.Response.BodyEncoding = null;
- mappingModel.Response.ProxyUrl = response.ProxyUrl;
+ mappingModel.Response.ProxyUrl = response.ProxyAndRecordSettings.Url;
mappingModel.Response.Fault = null;
- mappingModel.Response.WebProxy = MapWebProxy(response.WebProxySettings);
+ mappingModel.Response.WebProxy = MapWebProxy(response.ProxyAndRecordSettings.WebProxySettings);
}
else
{
diff --git a/src/WireMock.Net/Serialization/MappingToFileSaver.cs b/src/WireMock.Net/Serialization/MappingToFileSaver.cs
new file mode 100644
index 00000000..6b6581fc
--- /dev/null
+++ b/src/WireMock.Net/Serialization/MappingToFileSaver.cs
@@ -0,0 +1,49 @@
+using System.IO;
+using System.Linq;
+using Newtonsoft.Json;
+using WireMock.Settings;
+using WireMock.Validation;
+
+namespace WireMock.Serialization
+{
+ internal class MappingToFileSaver
+ {
+ private readonly IWireMockServerSettings _settings;
+ private readonly MappingConverter _mappingConverter;
+
+ public MappingToFileSaver(IWireMockServerSettings settings, MappingConverter mappingConverter)
+ {
+ Check.NotNull(settings, nameof(settings));
+
+ _settings = settings;
+ _mappingConverter = mappingConverter;
+ }
+
+ public void SaveMappingToFile(IMapping mapping, string folder = null)
+ {
+ if (folder == null)
+ {
+ folder = _settings.FileSystemHandler.GetMappingFolder();
+ }
+
+ if (!_settings.FileSystemHandler.FolderExists(folder))
+ {
+ _settings.FileSystemHandler.CreateFolder(folder);
+ }
+
+ var model = _mappingConverter.ToMappingModel(mapping);
+ string filename = (!string.IsNullOrEmpty(mapping.Title) ? SanitizeFileName(mapping.Title) : mapping.Guid.ToString()) + ".json";
+
+ string path = Path.Combine(folder, filename);
+
+ _settings.Logger.Info("Saving Mapping file {0}", filename);
+
+ _settings.FileSystemHandler.WriteMappingFile(path, JsonConvert.SerializeObject(model, JsonSerializationConstants.JsonSerializerSettingsDefault));
+ }
+
+ private static string SanitizeFileName(string name, char replaceChar = '_')
+ {
+ return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, replaceChar));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Server/WireMockServer.Admin.cs b/src/WireMock.Net/Server/WireMockServer.Admin.cs
index d0bd7d73..80b91e01 100644
--- a/src/WireMock.Net/Server/WireMockServer.Admin.cs
+++ b/src/WireMock.Net/Server/WireMockServer.Admin.cs
@@ -16,6 +16,7 @@ using WireMock.Http;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Matchers.Request;
+using WireMock.Proxy;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.ResponseProviders;
@@ -47,18 +48,6 @@ namespace WireMock.Server
private readonly RegexMatcher _adminMappingsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/mappings\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
private readonly RegexMatcher _adminRequestsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/requests\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
- private readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings
- {
- Formatting = Formatting.Indented,
- NullValueHandling = NullValueHandling.Ignore
- };
-
- private readonly JsonSerializerSettings _settingsIncludeNullValues = new JsonSerializerSettings
- {
- Formatting = Formatting.Indented,
- NullValueHandling = NullValueHandling.Include
- };
-
#region InitAdmin
private void InitAdmin()
{
@@ -119,7 +108,7 @@ namespace WireMock.Server
{
foreach (var mapping in Mappings.Where(m => !m.IsAdminInterface))
{
- SaveMappingToFile(mapping, folder);
+ _mappingToFileSaver.SaveMappingToFile(mapping, folder);
}
}
@@ -246,7 +235,7 @@ namespace WireMock.Server
private void InitProxyAndRecord(IWireMockServerSettings settings)
{
- _httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.ProxyAndRecordSettings);
+ _httpClientForProxy = HttpClientBuilder.Build(settings.ProxyAndRecordSettings);
var respondProvider = Given(Request.Create().WithPath("/*").UsingAnyMethod());
if (settings.StartAdminInterface == true)
@@ -263,82 +252,27 @@ namespace WireMock.Server
var proxyUri = new Uri(settings.ProxyAndRecordSettings.Url);
var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
- var responseMessage = await HttpClientHelper.SendAsync(
+ var proxyHelper = new ProxyHelper(settings);
+
+ var (responseMessage, mapping) = await proxyHelper.SendAsync(
+ _settings.ProxyAndRecordSettings,
_httpClientForProxy,
requestMessage,
- proxyUriWithRequestPathAndQuery.AbsoluteUri,
- !settings.DisableJsonBodyParsing.GetValueOrDefault(false),
- !settings.DisableRequestBodyDecompressing.GetValueOrDefault(false)
+ proxyUriWithRequestPathAndQuery.AbsoluteUri
);
- if (HttpStatusRangeParser.IsMatch(settings.ProxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
- (settings.ProxyAndRecordSettings.SaveMapping || settings.ProxyAndRecordSettings.SaveMappingToFile))
+ if (settings.ProxyAndRecordSettings.SaveMapping)
{
- var mapping = ToMapping(
- requestMessage,
- responseMessage,
- settings.ProxyAndRecordSettings.ExcludedHeaders ?? new string[] { },
- settings.ProxyAndRecordSettings.ExcludedCookies ?? new string[] { }
- );
+ _options.Mappings.TryAdd(mapping.Guid, mapping);
+ }
- if (settings.ProxyAndRecordSettings.SaveMapping)
- {
- _options.Mappings.TryAdd(mapping.Guid, mapping);
- }
-
- if (settings.ProxyAndRecordSettings.SaveMappingToFile)
- {
- SaveMappingToFile(mapping);
- }
+ if (settings.ProxyAndRecordSettings.SaveMappingToFile)
+ {
+ _mappingToFileSaver.SaveMappingToFile(mapping);
}
return responseMessage;
}
-
- private IMapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage, string[] excludedHeaders, string[] excludedCookies)
- {
- var request = Request.Create();
- request.WithPath(requestMessage.Path);
- request.UsingMethod(requestMessage.Method);
-
- requestMessage.Query.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
- requestMessage.Cookies.Loop((key, value) =>
- {
- if (!excludedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
- {
- request.WithCookie(key, value);
- }
- });
-
- var allExcludedHeaders = new List(excludedHeaders) { "Cookie" };
- requestMessage.Headers.Loop((key, value) =>
- {
- if (!allExcludedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
- {
- request.WithHeader(key, value.ToArray());
- }
- });
-
- bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
- switch (requestMessage.BodyData?.DetectedBodyType)
- {
- case BodyType.Json:
- request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson, true, throwExceptionWhenMatcherFails));
- break;
-
- case BodyType.String:
- request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, throwExceptionWhenMatcherFails, requestMessage.BodyData.BodyAsString));
- break;
-
- case BodyType.Bytes:
- request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
- break;
- }
-
- var response = Response.Create(responseMessage);
-
- return new Mapping(Guid.NewGuid(), string.Empty, null, _settings, request, response, 0, null, null, null, null);
- }
#endregion
#region Settings
@@ -446,33 +380,6 @@ namespace WireMock.Server
return ResponseMessageBuilder.Create("Mappings saved to disk");
}
- private void SaveMappingToFile(IMapping mapping, string folder = null)
- {
- if (folder == null)
- {
- folder = _settings.FileSystemHandler.GetMappingFolder();
- }
-
- if (!_settings.FileSystemHandler.FolderExists(folder))
- {
- _settings.FileSystemHandler.CreateFolder(folder);
- }
-
- var model = _mappingConverter.ToMappingModel(mapping);
- string filename = (!string.IsNullOrEmpty(mapping.Title) ? SanitizeFileName(mapping.Title) : mapping.Guid.ToString()) + ".json";
-
- string path = Path.Combine(folder, filename);
-
- _settings.Logger.Info("Saving Mapping file {0}", filename);
-
- _settings.FileSystemHandler.WriteMappingFile(path, JsonConvert.SerializeObject(model, _jsonSerializerSettings));
- }
-
- private static string SanitizeFileName(string name, char replaceChar = '_')
- {
- return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, replaceChar));
- }
-
private IEnumerable ToMappingModels()
{
return Mappings.Where(m => !m.IsAdminInterface).Select(_mappingConverter.ToMappingModel);
@@ -945,7 +852,7 @@ namespace WireMock.Server
BodyData = new BodyData
{
DetectedBodyType = BodyType.String,
- BodyAsString = JsonConvert.SerializeObject(result, keepNullValues ? _settingsIncludeNullValues : _jsonSerializerSettings)
+ BodyAsString = JsonConvert.SerializeObject(result, keepNullValues ? JsonSerializationConstants.JsonSerializerSettingsIncludeNullValues : JsonSerializationConstants.JsonSerializerSettingsDefault)
},
StatusCode = (int)HttpStatusCode.OK,
Headers = new Dictionary> { { HttpKnownHeaderNames.ContentType, new WireMockList(ContentTypeJson) } }
diff --git a/src/WireMock.Net/Server/WireMockServer.cs b/src/WireMock.Net/Server/WireMockServer.cs
index 02c51568..d5b0faa9 100644
--- a/src/WireMock.Net/Server/WireMockServer.cs
+++ b/src/WireMock.Net/Server/WireMockServer.cs
@@ -35,6 +35,7 @@ namespace WireMock.Server
private readonly IWireMockMiddlewareOptions _options = new WireMockMiddlewareOptions();
private readonly MappingConverter _mappingConverter;
private readonly MatcherMapper _matcherMapper;
+ private readonly MappingToFileSaver _mappingToFileSaver;
///
[PublicAPI]
@@ -238,6 +239,7 @@ namespace WireMock.Server
_matcherMapper = new MatcherMapper(_settings);
_mappingConverter = new MappingConverter(_matcherMapper);
+ _mappingToFileSaver = new MappingToFileSaver(_settings, _mappingConverter);
#if USE_ASPNETCORE
_httpServer = new AspNetCoreSelfHost(_options, urlOptions);
@@ -491,7 +493,7 @@ namespace WireMock.Server
if (saveToFile)
{
- SaveMappingToFile(mapping);
+ _mappingToFileSaver.SaveMappingToFile(mapping);
}
}
}
diff --git a/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs b/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs
index 04d492f8..cc797b3e 100644
--- a/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs
+++ b/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs
@@ -17,13 +17,13 @@ namespace WireMock.Settings
/// Save the mapping for each request/response to the internal Mappings.
///
[PublicAPI]
- public bool SaveMapping { get; set; } = true;
+ public bool SaveMapping { get; set; }
///
/// Save the mapping for each request/response also to a file. (Note that SaveMapping must also be set to true.)
///
[PublicAPI]
- public bool SaveMappingToFile { get; set; } = true;
+ public bool SaveMappingToFile { get; set; }
///
/// Only save request/response to the internal Mappings if the status code is included in this pattern. (Note that SaveMapping must also be set to true.)
diff --git a/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs b/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs
index 0fcc0130..f4035a5f 100644
--- a/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs
+++ b/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs
@@ -1,141 +1,250 @@
-using System;
-using System.Collections.Concurrent;
-using System.Linq.Expressions;
-using System.Threading.Tasks;
-using Moq;
-using Xunit;
-using WireMock.Models;
-using WireMock.Owin;
-using WireMock.Owin.Mappers;
-using WireMock.Util;
-using WireMock.Logging;
-using WireMock.Matchers;
-using System.Collections.Generic;
-using WireMock.Admin.Mappings;
-using WireMock.Admin.Requests;
-#if NET452
-using Microsoft.Owin;
-using IContext = Microsoft.Owin.IOwinContext;
-using IRequest = Microsoft.Owin.IOwinRequest;
-using IResponse = Microsoft.Owin.IOwinResponse;
-#else
-using Microsoft.AspNetCore.Http;
-using IContext = Microsoft.AspNetCore.Http.HttpContext;
-using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
-using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
-#endif
-
-namespace WireMock.Net.Tests.Owin
-{
- public class WireMockMiddlewareTests
- {
- private readonly WireMockMiddleware _sut;
-
- private readonly Mock _optionsMock;
- private readonly Mock _requestMapperMock;
- private readonly Mock _responseMapperMock;
- private readonly Mock _matcherMock;
- private readonly Mock _mappingMock;
- private readonly Mock _contextMock;
-
- public WireMockMiddlewareTests()
- {
- _optionsMock = new Mock();
- _optionsMock.SetupAllProperties();
- _optionsMock.Setup(o => o.Mappings).Returns(new ConcurrentDictionary());
- _optionsMock.Setup(o => o.LogEntries).Returns(new ConcurrentObservableCollection());
- _optionsMock.Setup(o => o.Scenarios).Returns(new ConcurrentDictionary());
- _optionsMock.Setup(o => o.Logger.Warn(It.IsAny(), It.IsAny