Skip to content
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
30 changes: 3 additions & 27 deletions src/WireMock.Net.Minimal/Http/WebhookSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,17 @@
using WireMock.Models;
using WireMock.Settings;
using WireMock.Transformers;
using WireMock.Transformers.Handlebars;
using WireMock.Transformers.Scriban;
using WireMock.Types;
using WireMock.Util;

namespace WireMock.Http;

internal class WebhookSender
internal class WebhookSender(WireMockServerSettings settings)
{
private const string ClientIp = "::1";
private static readonly ThreadLocal<Random> Random = new(() => new Random(DateTime.UtcNow.Millisecond));

private readonly WireMockServerSettings _settings;

public WebhookSender(WireMockServerSettings settings)
{
_settings = Guard.NotNull(settings);
}
private readonly WireMockServerSettings _settings = Guard.NotNull(settings);

public async Task<HttpResponseMessage> SendAsync(
HttpClient client,
Expand All @@ -49,24 +42,7 @@ IResponseMessage originalResponseMessage
string requestUrl;
if (webhookRequest.UseTransformer == true)
{
ITransformer transformer;
switch (webhookRequest.TransformerType)
{
case TransformerType.Handlebars:
var factoryHandlebars = new HandlebarsContextFactory(_settings);
transformer = new Transformer(_settings, factoryHandlebars);
break;

case TransformerType.Scriban:
case TransformerType.ScribanDotLiquid:
var factoryDotLiquid = new ScribanContextFactory(_settings.FileSystemHandler, webhookRequest.TransformerType);
transformer = new Transformer(_settings, factoryDotLiquid);
break;

default:
throw new NotImplementedException($"TransformerType '{webhookRequest.TransformerType}' is not supported.");
}

var transformer = TransformerFactory.Create(webhookRequest.TransformerType, _settings);
bodyData = transformer.TransformBody(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.BodyData, webhookRequest.TransformerReplaceNodeOptions);
headers = transformer.TransformHeaders(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Headers);
requestUrl = transformer.TransformString(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Url);
Expand Down
25 changes: 4 additions & 21 deletions src/WireMock.Net.Minimal/Proxy/ProxyHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,10 @@

namespace WireMock.Proxy;

internal class ProxyHelper
internal class ProxyHelper(WireMockServerSettings settings)
{
private readonly WireMockServerSettings _settings;
private readonly ProxyMappingConverter _proxyMappingConverter;

public ProxyHelper(WireMockServerSettings settings)
{
_settings = Guard.NotNull(settings);
_proxyMappingConverter = new ProxyMappingConverter(settings, new GuidUtils(), new DateTimeUtils());
}
private readonly WireMockServerSettings _settings = Guard.NotNull(settings);
private readonly ProxyMappingConverter _proxyMappingConverter = new(settings, new GuidUtils(), new DateTimeUtils());

public async Task<(IResponseMessage Message, IMapping? Mapping)> SendAsync(
IMapping? mapping,
Expand All @@ -39,18 +33,7 @@ public ProxyHelper(WireMockServerSettings settings)
var requiredUri = new Uri(url);

// Create HttpRequestMessage
var replaceSettings = proxyAndRecordSettings.ReplaceSettings;
string proxyUrl;
if (replaceSettings is not null)
{
var stringComparison = replaceSettings.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
proxyUrl = url.Replace(replaceSettings.OldValue, replaceSettings.NewValue, stringComparison);
}
else
{
proxyUrl = url;
}

var proxyUrl = proxyAndRecordSettings.ReplaceSettings != null ? ProxyUrlTransformer.Transform(_settings, proxyAndRecordSettings.ReplaceSettings, url) : url;
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, proxyUrl);

// Call the URL
Expand Down
21 changes: 21 additions & 0 deletions src/WireMock.Net.Minimal/Proxy/ProxyUrlTransformer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright © WireMock.Net

using System;
using WireMock.Settings;
using WireMock.Transformers;

namespace WireMock.Proxy;

internal static class ProxyUrlTransformer
{
internal static string Transform(WireMockServerSettings settings, ProxyUrlReplaceSettings replaceSettings, string url)
{
if (!replaceSettings.UseTransformer)
{
return url.Replace(replaceSettings.OldValue, replaceSettings.NewValue, replaceSettings.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
}

var transformer = TransformerFactory.Create(replaceSettings.TransformerType, settings);
return transformer.Transform(replaceSettings.TransformTemplate, url);
}
}
21 changes: 2 additions & 19 deletions src/WireMock.Net.Minimal/ResponseBuilders/Response.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,25 +272,8 @@ string RemoveFirstOccurrence(string source, string find)
}
}

ITransformer responseMessageTransformer;
switch (TransformerType)
{
case TransformerType.Handlebars:
var factoryHandlebars = new HandlebarsContextFactory(settings);
responseMessageTransformer = new Transformer(settings, factoryHandlebars);
break;

case TransformerType.Scriban:
case TransformerType.ScribanDotLiquid:
var factoryDotLiquid = new ScribanContextFactory(settings.FileSystemHandler, TransformerType);
responseMessageTransformer = new Transformer(settings, factoryDotLiquid);
break;

default:
throw new NotSupportedException($"TransformerType '{TransformerType}' is not supported.");
}

return (responseMessageTransformer.Transform(mapping, requestMessage, responseMessage, UseTransformerForBodyAsFile, TransformerReplaceNodeOptions), null);
var transformer = TransformerFactory.Create(TransformerType, settings);
return (transformer.Transform(mapping, requestMessage, responseMessage, UseTransformerForBodyAsFile, TransformerReplaceNodeOptions), null);
}

if (!UseTransformer && ResponseMessage.BodyData?.BodyAsFileIsCached == true && responseMessage.BodyData?.BodyAsFile is not null)
Expand Down
4 changes: 3 additions & 1 deletion src/WireMock.Net.Minimal/Transformers/ITransformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace WireMock.Transformers;

interface ITransformer
internal interface ITransformer
{
ResponseMessage Transform(IMapping mapping, IRequestMessage requestMessage, IResponseMessage original, bool useTransformerForBodyAsFile, ReplaceNodeOptions options);

Expand All @@ -15,4 +15,6 @@ interface ITransformer
IDictionary<string, WireMockList<string>> TransformHeaders(IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, IDictionary<string, WireMockList<string>>? headers);

string TransformString(IMapping mapping, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage, string? value);

string Transform(string template, object? model);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Copyright © WireMock.Net

namespace WireMock.Transformers
namespace WireMock.Transformers;

internal interface ITransformerContextFactory
{
interface ITransformerContextFactory
{
ITransformerContext Create();
}
ITransformerContext Create();
}
5 changes: 5 additions & 0 deletions src/WireMock.Net.Minimal/Transformers/Transformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ public string TransformString(
return transformerContext.ParseAndRender(value, model);
}

public string Transform(string template, object? model)
{
return model is null ? string.Empty : _factory.Create().ParseAndRender(template, model);
}

public ResponseMessage Transform(IMapping mapping, IRequestMessage requestMessage, IResponseMessage original, bool useTransformerForBodyAsFile, ReplaceNodeOptions options)
{
var responseMessage = new ResponseMessage();
Expand Down
30 changes: 30 additions & 0 deletions src/WireMock.Net.Minimal/Transformers/TransformerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright © WireMock.Net

using System;
using WireMock.Settings;
using WireMock.Transformers.Handlebars;
using WireMock.Transformers.Scriban;
using WireMock.Types;

namespace WireMock.Transformers;

internal static class TransformerFactory
{
internal static ITransformer Create(TransformerType transformerType, WireMockServerSettings settings)
{
switch (transformerType)
{
case TransformerType.Handlebars:
var factoryHandlebars = new HandlebarsContextFactory(settings);
return new Transformer(settings, factoryHandlebars);

case TransformerType.Scriban:
case TransformerType.ScribanDotLiquid:
var factoryDotLiquid = new ScribanContextFactory(settings.FileSystemHandler, transformerType);
return new Transformer(settings, factoryDotLiquid);

default:
throw new NotSupportedException($"{nameof(TransformerType)} '{transformerType}' is not supported.");
}
}
}
29 changes: 25 additions & 4 deletions src/WireMock.Net.Shared/Settings/ProxyUrlReplaceSettings.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// Copyright © WireMock.Net

using System.Diagnostics.CodeAnalysis;
using WireMock.Types;

namespace WireMock.Settings;

/// <summary>
Expand All @@ -8,17 +11,35 @@ namespace WireMock.Settings;
public class ProxyUrlReplaceSettings
{
/// <summary>
/// The old path value to be replaced by the new path value
/// The old path value to be replaced by the new path value.
/// </summary>
public string OldValue { get; set; } = null!;
public string? OldValue { get; set; }

/// <summary>
/// The new path value to replace the old value with
/// The new path value to replace the old value with.
/// </summary>
public string NewValue { get; set; } = null!;
public string? NewValue { get; set; }

/// <summary>
/// Defines if the case should be ignored when replacing.
/// </summary>
public bool IgnoreCase { get; set; }

/// <summary>
/// Holds the transformation template used when <see cref="UseTransformer"/> is true.
/// </summary>
public string? TransformTemplate { get; set; }

/// <summary>
/// Use Transformer.
/// </summary>
[MemberNotNullWhen(true, nameof(TransformTemplate))]
[MemberNotNullWhen(false, nameof(OldValue))]
[MemberNotNullWhen(false, nameof(NewValue))]
public bool UseTransformer => !string.IsNullOrEmpty(TransformTemplate);

/// <summary>
/// The transformer type, in case <see cref="UseTransformer"/> is set to <c>true</c>.
/// </summary>
public TransformerType TransformerType { get; set; } = TransformerType.Handlebars;
}
98 changes: 98 additions & 0 deletions test/WireMock.Net.Tests/Proxy/ProxyUrlTransformerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System.Globalization;
using Moq;
using WireMock.Handlers;
using WireMock.Proxy;
using WireMock.Settings;
using WireMock.Types;
using Xunit;

namespace WireMock.Net.Tests.Proxy;

public class ProxyUrlTransformerTests
{
private readonly Mock<IFileSystemHandler> _fileSystemHandlerMock = new();

[Fact]
public void Transform_WithUseTransformerFalse_PerformsSimpleReplace_CaseSensitive()
{
// Arrange
var settings = new WireMockServerSettings
{
FileSystemHandler = _fileSystemHandlerMock.Object,
Culture = CultureInfo.InvariantCulture
};

var replaceSettings = new ProxyUrlReplaceSettings
{
TransformTemplate = null,
OldValue = "/old",
NewValue = "/new",
IgnoreCase = false
};

var url = "http://example.com/old/path";
var expected = "http://example.com/new/path";

// Act
var actual = ProxyUrlTransformer.Transform(settings, replaceSettings, url);

// Assert
Assert.Equal(expected, actual);
}

[Fact]
public void Transform_WithUseTransformerFalse_PerformsSimpleReplace_IgnoreCase()
{
// Arrange
var settings = new WireMockServerSettings
{
FileSystemHandler = _fileSystemHandlerMock.Object,
Culture = CultureInfo.InvariantCulture
};

var replaceSettings = new ProxyUrlReplaceSettings
{
TransformTemplate = null, // UseTransformer == false
OldValue = "/OLD",
NewValue = "/new",
IgnoreCase = true
};

var url = "http://example.com/old/path"; // lowercase 'old' but OldValue is uppercase
var expected = "http://example.com/new/path";

// Act
var actual = ProxyUrlTransformer.Transform(settings, replaceSettings, url);

// Assert
Assert.Equal(expected, actual);
}

[Fact]
public void Transform_WithUseTransformerTrue_UsesTransformer_ToTransformUrl()
{
// Arrange
var settings = new WireMockServerSettings
{
FileSystemHandler = _fileSystemHandlerMock.Object,
Culture = CultureInfo.InvariantCulture
};

// Handlebars is the default TransformerType; the TransformTemplate uses the model directly.
var replaceSettings = new ProxyUrlReplaceSettings
{
TransformTemplate = "{{this}}-transformed",
// TransformerType defaults to Handlebars but set explicitly for clarity.
TransformerType = TransformerType.Handlebars
};

var url = "http://example.com/path";
var expected = "http://example.com/path-transformed";

// Act
var actual = ProxyUrlTransformer.Transform(settings, replaceSettings, url);

// Assert
Assert.Equal(expected, actual);
}
}
Loading