ProxySettings : Add logic to not save some requests depending on HttpMethods (#900)

* Add ExcludedHttpMethods to ProxySettings

* tst

* fix

* SaveMappingSettings

* .
This commit is contained in:
Stef Heyenrath
2023-03-09 15:28:52 +01:00
committed by GitHub
parent 61cdc13fae
commit 674fa89c3e
9 changed files with 140 additions and 12 deletions

View File

@@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
namespace WireMock.Matchers; namespace WireMock.Matchers;

View File

@@ -1,8 +1,10 @@
using System; using System;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Stef.Validation; using Stef.Validation;
using WireMock.Http; using WireMock.Http;
using WireMock.Matchers;
using WireMock.Serialization; using WireMock.Serialization;
using WireMock.Settings; using WireMock.Settings;
using WireMock.Util; using WireMock.Util;
@@ -47,12 +49,33 @@ internal class ProxyHelper
var responseMessage = await HttpResponseMessageHelper.CreateAsync(httpResponseMessage, requiredUri, originalUri, deserializeJson, decompressGzipAndDeflate).ConfigureAwait(false); var responseMessage = await HttpResponseMessageHelper.CreateAsync(httpResponseMessage, requiredUri, originalUri, deserializeJson, decompressGzipAndDeflate).ConfigureAwait(false);
IMapping? newMapping = null; IMapping? newMapping = null;
if (HttpStatusRangeParser.IsMatch(proxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
(proxyAndRecordSettings.SaveMapping || proxyAndRecordSettings.SaveMappingToFile)) var saveMappingSettings = proxyAndRecordSettings.SaveMappingSettings;
bool save = true;
if (saveMappingSettings != null)
{
save &= Check(saveMappingSettings.StatusCodePattern,
() => HttpStatusRangeParser.IsMatch(saveMappingSettings.StatusCodePattern, responseMessage.StatusCode)
);
save &= Check(saveMappingSettings.HttpMethods,
() => saveMappingSettings.HttpMethods.Value.Contains(requestMessage.Method, StringComparer.OrdinalIgnoreCase)
);
}
if (save && (proxyAndRecordSettings.SaveMapping || proxyAndRecordSettings.SaveMappingToFile))
{ {
newMapping = _proxyMappingConverter.ToMapping(mapping, proxyAndRecordSettings, requestMessage, responseMessage); newMapping = _proxyMappingConverter.ToMapping(mapping, proxyAndRecordSettings, requestMessage, responseMessage);
} }
return (responseMessage, newMapping); return (responseMessage, newMapping);
} }
private static bool Check<T>(ProxySaveMappingSetting<T>? saveMappingSetting, Func<bool> action)
{
var isMatch = saveMappingSetting is null || action();
var matchBehaviour = saveMappingSetting?.MatchBehaviour ?? MatchBehaviour.AcceptOnMatch;
return isMatch == (matchBehaviour == MatchBehaviour.AcceptOnMatch);
}
} }

View File

@@ -26,8 +26,12 @@ internal class ProxyMappingConverter
_dateTimeUtils = Guard.NotNull(dateTimeUtils); _dateTimeUtils = Guard.NotNull(dateTimeUtils);
} }
public IMapping ToMapping(IMapping? mapping, ProxyAndRecordSettings proxyAndRecordSettings, IRequestMessage requestMessage, ResponseMessage responseMessage) public IMapping? ToMapping(IMapping? mapping, ProxyAndRecordSettings proxyAndRecordSettings, IRequestMessage requestMessage, ResponseMessage responseMessage)
{ {
var useDefinedRequestMatchers = proxyAndRecordSettings.UseDefinedRequestMatchers;
var excludedHeaders = new List<string>(proxyAndRecordSettings.ExcludedHeaders ?? new string[] { }) { "Cookie" };
var excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? new string[0];
var request = (Request?)mapping?.RequestMatcher; var request = (Request?)mapping?.RequestMatcher;
var clientIPMatcher = request?.GetRequestMessageMatcher<RequestMessageClientIPMatcher>(); var clientIPMatcher = request?.GetRequestMessageMatcher<RequestMessageClientIPMatcher>();
var pathMatcher = request?.GetRequestMessageMatcher<RequestMessagePathMatcher>(); var pathMatcher = request?.GetRequestMessageMatcher<RequestMessagePathMatcher>();
@@ -37,11 +41,6 @@ internal class ProxyMappingConverter
var methodMatcher = request?.GetRequestMessageMatcher<RequestMessageMethodMatcher>(); var methodMatcher = request?.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
var bodyMatcher = request?.GetRequestMessageMatcher<RequestMessageBodyMatcher>(); var bodyMatcher = request?.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
var useDefinedRequestMatchers = proxyAndRecordSettings.UseDefinedRequestMatchers;
var excludedHeaders = new List<string>(proxyAndRecordSettings.ExcludedHeaders ?? new string[] { }) { "Cookie" };
var excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? new string[] { };
var newRequest = Request.Create(); var newRequest = Request.Create();
// ClientIP // ClientIP

View File

@@ -28,9 +28,28 @@ public class ProxyAndRecordSettings : HttpClientSettings
/// <summary> /// <summary>
/// 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.) /// 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.)
/// The pattern can contain a single value like "200", but also ranges like "2xx", "100,300,600" or "100-299,6xx" are supported. /// The pattern can contain a single value like "200", but also ranges like "2xx", "100,300,600" or "100-299,6xx" are supported.
///
/// Deprecated : use SaveMappingSettings.
/// </summary> /// </summary>
[PublicAPI] [PublicAPI]
public string SaveMappingForStatusCodePattern { get; set; } = "*"; public string SaveMappingForStatusCodePattern
{
set
{
if (SaveMappingSettings is null)
{
SaveMappingSettings = new ProxySaveMappingSettings();
}
SaveMappingSettings.StatusCodePattern = value;
}
}
/// <summary>
/// Additional SaveMappingSettings.
/// </summary>
[PublicAPI]
public ProxySaveMappingSettings? SaveMappingSettings { get; set; }
/// <summary> /// <summary>
/// Defines a list from headers which will be excluded from the saved mappings. /// Defines a list from headers which will be excluded from the saved mappings.

View File

@@ -0,0 +1,20 @@
using WireMock.Matchers;
namespace WireMock.Settings;
public class ProxySaveMappingSetting<T>
{
public MatchBehaviour MatchBehaviour { get; } = MatchBehaviour.AcceptOnMatch;
public T Value { get; private set; }
public ProxySaveMappingSetting(T value, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
Value = value;
MatchBehaviour = matchBehaviour;
}
public static implicit operator ProxySaveMappingSetting<T>(T value) => new ProxySaveMappingSetting<T>(value);
public static implicit operator T(ProxySaveMappingSetting<T> @this) => @this.Value;
}

View File

@@ -0,0 +1,22 @@
using JetBrains.Annotations;
namespace WireMock.Settings;
/// <summary>
/// ProxySaveMappingSettings
/// </summary>
public class ProxySaveMappingSettings
{
/// <summary>
/// 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.)
/// The pattern can contain a single value like "200", but also ranges like "2xx", "100,300,600" or "100-299,6xx" are supported.
/// </summary>
[PublicAPI]
public ProxySaveMappingSetting<string>? StatusCodePattern { get; set; } = "*";
/// <summary>
/// Only save these Http Methods. (Note that SaveMapping must also be set to true.)
/// </summary>
[PublicAPI]
public ProxySaveMappingSetting<string[]>? HttpMethods { get; set; }
}

View File

@@ -4,6 +4,7 @@ using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Stef.Validation; using Stef.Validation;
using WireMock.Logging; using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Types; using WireMock.Types;
using WireMock.Util; using WireMock.Util;
@@ -111,7 +112,12 @@ public static class WireMockServerSettingsParser
SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"), SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
UseDefinedRequestMatchers = parser.GetBoolValue(nameof(ProxyAndRecordSettings.UseDefinedRequestMatchers)), UseDefinedRequestMatchers = parser.GetBoolValue(nameof(ProxyAndRecordSettings.UseDefinedRequestMatchers)),
AppendGuidToSavedMappingFile = parser.GetBoolValue(nameof(ProxyAndRecordSettings.AppendGuidToSavedMappingFile)), AppendGuidToSavedMappingFile = parser.GetBoolValue(nameof(ProxyAndRecordSettings.AppendGuidToSavedMappingFile)),
Url = proxyUrl! Url = proxyUrl!,
SaveMappingSettings = new ProxySaveMappingSettings
{
StatusCodePattern = parser.GetStringValue("SaveMappingForStatusCodePattern", "*"),
// HttpMethods = new ProxySaveMappingSetting<string[]>(parser.GetValues("DoNotSaveMappingForHttpMethods", new string[0]), MatchBehaviour.RejectOnMatch)
}
}; };
string? proxyAddress = parser.GetStringValue("WebProxyAddress"); string? proxyAddress = parser.GetStringValue("WebProxyAddress");

View File

@@ -1,6 +1,7 @@
#if !(NET452 || NET461 || NETCOREAPP3_1) #if !(NET452 || NET461 || NETCOREAPP3_1)
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions;
using Moq; using Moq;
using VerifyTests; using VerifyTests;
using VerifyXunit; using VerifyXunit;
@@ -70,7 +71,7 @@ public class ProxyMappingConverterTests
var responseMessage = new ResponseMessage(); var responseMessage = new ResponseMessage();
// Act // Act
var proxyMapping = _sut.ToMapping(mappingMock.Object, proxyAndRecordSettings, requestMessageMock.Object, responseMessage); var proxyMapping = _sut.ToMapping(mappingMock.Object, proxyAndRecordSettings, requestMessageMock.Object, responseMessage)!;
// Assert // Assert
var model = _mappingConverter.ToMappingModel(proxyMapping); var model = _mappingConverter.ToMappingModel(proxyMapping);

View File

@@ -248,6 +248,45 @@ public class WireMockServerProxyTests
fileSystemHandlerMock.Verify(f => f.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Never); fileSystemHandlerMock.Verify(f => f.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
} }
[Fact]
public async Task WireMockServer_Proxy_With_DoNotSaveMappingForHttpMethod_Should_Not_SaveMapping()
{
// Assign
var fileSystemHandlerMock = new Mock<IFileSystemHandler>();
fileSystemHandlerMock.Setup(f => f.GetMappingFolder()).Returns("m");
var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
Url = "http://www.google.com",
SaveMapping = true,
SaveMappingToFile = true,
SaveMappingSettings = new ProxySaveMappingSettings
{
HttpMethods = new ProxySaveMappingSetting<string[]>(new string[] { "GET" }, MatchBehaviour.RejectOnMatch) // To make sure that we don't want this mapping
}
},
FileSystemHandler = fileSystemHandlerMock.Object
};
var server = WireMockServer.Start(settings);
// Act
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(server.Urls[0])
};
var httpClientHandler = new HttpClientHandler { AllowAutoRedirect = false };
await new HttpClient(httpClientHandler).SendAsync(requestMessage).ConfigureAwait(false);
// Assert
server.Mappings.Should().HaveCount(1);
// Verify
fileSystemHandlerMock.Verify(f => f.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
}
[Fact] [Fact]
public async Task WireMockServer_Proxy_Should_log_proxied_requests() public async Task WireMockServer_Proxy_Should_log_proxied_requests()
{ {