mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-28 03:37:45 +02:00
Version 2.x (#1359)
* Version 2.x * Setup .NET 9 * 12 * cleanup some #if for NETSTANDARD1_3 * cleanup + fix tests for net8 * openapi * NO ConfigureAwait(false) + cleanup * . * #endif * HashSet * WireMock.Net.NUnit * HttpContext * Add WebSockets (#1423) * Add WebSockets * Add tests * fix * more tests * Add tests * ... * remove IOwin * - * tests * fluent * ok * match * . * byte[] * x * func * func * byte * trans * ... * frameworks......... * jmes * xxx * sc * using var httpClient = new HttpClient(); * usings * maxRetries * up * xunit v3 * ct * --- * ct * ct2 * T Unit * WireMock.Net.TUnitTests / 10 * t unit first * --project * no tunit * t2 * --project * --project * ci - --project * publish ./test/wiremock-coverage.xml * windows * . * log * ... * log * goed * BodyType * . * . * --scenario * ... * pact * ct * . * WireMock.Net.RestClient.AwesomeAssertions (#1427) * WireMock.Net.RestClient.AwesomeAssertions * ok * atpath * fix test * sonar fixes * ports * proxy test * FIX? * --- * await Task.Delay(100, _ct); * ? * --project * Aspire: use IDistributedApplicationEventingSubscriber (#1428) * broadcast * ok * more tsts * . * Collection * up * . * 2 * remove nfluent * <VersionPrefix>2.0.0-preview-02</VersionPrefix> * ... * . * nuget icon * . * <PackageReference Include="JmesPath.Net" Version="1.1.0" /> * x * 500 * . * fix some warnings * ws
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if !NETSTANDARD1_3
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -111,5 +109,4 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
|
||||
tenant = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using WireMock.Matchers;
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if NET451 || NET452 || NET46 || NET451 || NET461 || NETSTANDARD1_3 || NETSTANDARD2_0
|
||||
using System.Text.RegularExpressions;
|
||||
using WireMock.Constants;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace System;
|
||||
|
||||
internal static class StringExtensions
|
||||
{
|
||||
public static string Replace(this string text, string oldValue, string newValue, StringComparison stringComparison)
|
||||
{
|
||||
var options = stringComparison == StringComparison.OrdinalIgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;
|
||||
return Regex.Replace(text, oldValue, newValue, options, RegexConstants.DefaultTimeout);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if NETSTANDARD1_3
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace System.Net;
|
||||
|
||||
internal class WebProxy : IWebProxy
|
||||
{
|
||||
private readonly string _proxy;
|
||||
public ICredentials? Credentials { get; set; }
|
||||
|
||||
public WebProxy(string proxy)
|
||||
{
|
||||
_proxy = proxy;
|
||||
}
|
||||
|
||||
public Uri GetProxy(Uri destination)
|
||||
{
|
||||
return new Uri(_proxy);
|
||||
}
|
||||
|
||||
public bool IsBypassed(Uri host)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using WireMock.Models;
|
||||
|
||||
namespace WireMock.Extensions;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using WireMock.Util;
|
||||
using Stef.Validation;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Authentication;
|
||||
using WireMock.HttpsCertificate;
|
||||
using WireMock.Settings;
|
||||
|
||||
@@ -11,29 +12,21 @@ internal static class HttpClientBuilder
|
||||
{
|
||||
public static HttpClient Build(HttpClientSettings settings)
|
||||
{
|
||||
#if NETSTANDARD || NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||
#if NET8_0_OR_GREATER
|
||||
|
||||
var handler = new HttpClientHandler
|
||||
{
|
||||
CheckCertificateRevocationList = false,
|
||||
#if NET5_0_OR_GREATER
|
||||
SslProtocols = System.Security.Authentication.SslProtocols.Tls13 | System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
|
||||
#else
|
||||
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
|
||||
#endif
|
||||
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
|
||||
|
||||
#pragma warning disable SYSLIB0039 // Type or member is obsolete
|
||||
SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
|
||||
#pragma warning restore SYSLIB0039 // Type or member is obsolete
|
||||
ServerCertificateCustomValidationCallback = (_, _, _, _) => true,
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
|
||||
};
|
||||
#elif NET46
|
||||
#else
|
||||
var handler = new HttpClientHandler
|
||||
{
|
||||
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
|
||||
};
|
||||
#else
|
||||
var handler = new WebRequestHandler
|
||||
{
|
||||
ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
|
||||
ServerCertificateCustomValidationCallback = (_, _, _, _) => true,
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
|
||||
};
|
||||
#endif
|
||||
@@ -67,13 +60,12 @@ internal static class HttpClientBuilder
|
||||
}
|
||||
}
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
#if NET8_0_OR_GREATER
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
|
||||
ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) => true;
|
||||
#elif !NETSTANDARD1_3
|
||||
#else
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
|
||||
ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) => true;
|
||||
#endif
|
||||
ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) => true;
|
||||
|
||||
return HttpClientFactory2.Create(handler);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ internal static class HttpClientFactory2
|
||||
|
||||
var next = handler;
|
||||
|
||||
foreach (var delegatingHandler in delegatingHandlers.Reverse())
|
||||
foreach (var delegatingHandler in Enumerable.Reverse(delegatingHandlers))
|
||||
{
|
||||
delegatingHandler.InnerHandler = next;
|
||||
next = delegatingHandler;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
@@ -9,7 +7,6 @@ using Newtonsoft.Json;
|
||||
using Stef.Validation;
|
||||
using WireMock.Constants;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Http;
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Http;
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Stef.Validation;
|
||||
using WireMock.Models;
|
||||
using WireMock.Settings;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
#if NET5_0_OR_GREATER
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using WireMock.Server;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using WireMock.Owin;
|
||||
|
||||
@@ -43,20 +41,17 @@ internal static class CertificateLoader
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if NETSTANDARD || NET46
|
||||
certStore.Dispose();
|
||||
#else
|
||||
certStore.Close();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(options.X509CertificateFilePath))
|
||||
{
|
||||
if (options.X509CertificateFilePath.EndsWith(ExtensionPem, StringComparison.OrdinalIgnoreCase))
|
||||
if (options.X509CertificateFilePath!.EndsWith(ExtensionPem, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// PEM logic based on: https://www.scottbrady91.com/c-sharp/pem-loading-in-dotnet-core-and-dotnet
|
||||
#if NET5_0_OR_GREATER
|
||||
#if NET8_0_OR_GREATER
|
||||
if (!string.IsNullOrEmpty(options.X509CertificatePassword))
|
||||
{
|
||||
var certPem = File.ReadAllText(options.X509CertificateFilePath);
|
||||
@@ -66,18 +61,8 @@ internal static class CertificateLoader
|
||||
return new X509Certificate2(cert.Export(X509ContentType.Pfx, defaultPasswordPem), defaultPasswordPem);
|
||||
}
|
||||
return X509Certificate2.CreateFromPemFile(options.X509CertificateFilePath);
|
||||
|
||||
#elif NETCOREAPP3_1
|
||||
var cert = new X509Certificate2(options.X509CertificateFilePath);
|
||||
if (!string.IsNullOrEmpty(options.X509CertificatePassword))
|
||||
{
|
||||
var key = System.Security.Cryptography.ECDsa.Create()!;
|
||||
key.ImportECPrivateKey(System.Text.Encoding.UTF8.GetBytes(options.X509CertificatePassword), out _);
|
||||
return cert.CopyWithPrivateKey(key);
|
||||
}
|
||||
return cert;
|
||||
#else
|
||||
throw new InvalidOperationException("Loading a PEM Certificate is only supported for .NET Core App 3.1, .NET 5.0 and higher.");
|
||||
throw new InvalidOperationException("Loading a PEM Certificate is only supported for .NET 8.0 and higher.");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -123,11 +108,8 @@ internal static class CertificateLoader
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if NETSTANDARD || NET46
|
||||
certStore.Dispose();
|
||||
#else
|
||||
certStore.Close();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace WireMock.HttpsCertificate;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Server;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.Logging;
|
||||
@@ -14,13 +13,13 @@ public class LogEntry : ILogEntry
|
||||
public Guid Guid { get; set; }
|
||||
|
||||
/// <inheritdoc cref="ILogEntry.RequestMessage" />
|
||||
public IRequestMessage RequestMessage { get; set; } = null!;
|
||||
public IRequestMessage? RequestMessage { get; set; }
|
||||
|
||||
/// <inheritdoc cref="ILogEntry.ResponseMessage" />
|
||||
public IResponseMessage ResponseMessage { get; set; } = null!;
|
||||
public IResponseMessage? ResponseMessage { get; set; }
|
||||
|
||||
/// <inheritdoc cref="ILogEntry.RequestMatchResult" />
|
||||
public IRequestMatchResult RequestMatchResult { get; set; } = null!;
|
||||
public IRequestMatchResult? RequestMatchResult { get; set; }
|
||||
|
||||
/// <inheritdoc cref="ILogEntry.MappingGuid" />
|
||||
public Guid? MappingGuid { get; set; }
|
||||
@@ -35,5 +34,5 @@ public class LogEntry : ILogEntry
|
||||
public string? PartialMappingTitle { get; set; }
|
||||
|
||||
/// <inheritdoc cref="ILogEntry.PartialMatchResult" />
|
||||
public IRequestMatchResult PartialMatchResult { get; set; } = null!;
|
||||
public IRequestMatchResult? PartialMatchResult { get; set; }
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using WireMock.Admin.Requests;
|
||||
|
||||
namespace WireMock.Logging;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using WireMock.Admin.Requests;
|
||||
|
||||
namespace WireMock.Logging;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Stef.Validation;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Models;
|
||||
@@ -145,9 +144,9 @@ public class Mapping : IMapping
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage)
|
||||
public Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(HttpContext context, IRequestMessage requestMessage)
|
||||
{
|
||||
return Provider.ProvideResponseAsync(this, requestMessage, Settings);
|
||||
return Provider.ProvideResponseAsync(this, context, requestMessage, Settings);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Stef.Validation;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using WireMock.Util;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
|
||||
namespace WireMock.Matchers;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AnyOfTypes;
|
||||
using Stef.Validation;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AnyOfTypes;
|
||||
using Stef.Validation;
|
||||
|
||||
85
src/WireMock.Net.Minimal/Matchers/FuncMatcher.cs
Normal file
85
src/WireMock.Net.Minimal/Matchers/FuncMatcher.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using Stef.Validation;
|
||||
using WireMock.Extensions;
|
||||
|
||||
namespace WireMock.Matchers;
|
||||
|
||||
/// <summary>
|
||||
/// FuncMatcher - matches using a custom function
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="IFuncMatcher"/>
|
||||
public class FuncMatcher : IFuncMatcher
|
||||
{
|
||||
private readonly Func<string?, bool>? _stringFunc;
|
||||
private readonly Func<byte[]?, bool>? _bytesFunc;
|
||||
|
||||
/// <inheritdoc />
|
||||
public MatchBehaviour MatchBehaviour { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FuncMatcher"/> class for string matching.
|
||||
/// </summary>
|
||||
/// <param name="func">The function to check if a string is a match.</param>
|
||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||
public FuncMatcher(Func<string?, bool> func, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||
{
|
||||
_stringFunc = Guard.NotNull(func);
|
||||
MatchBehaviour = matchBehaviour;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FuncMatcher"/> class for byte array matching.
|
||||
/// </summary>
|
||||
/// <param name="func">The function to check if a byte[] is a match.</param>
|
||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||
public FuncMatcher(Func<byte[]?, bool> func, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||
{
|
||||
_bytesFunc = Guard.NotNull(func);
|
||||
MatchBehaviour = matchBehaviour;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public MatchResult IsMatch(object? value)
|
||||
{
|
||||
if (value is string stringValue && _stringFunc != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return MatchResult.From(Name, MatchBehaviour, _stringFunc(stringValue));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return MatchResult.From(Name, ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (value is byte[] bytesValue && _bytesFunc != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return MatchResult.From(Name, MatchBehaviour, _bytesFunc(bytesValue));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return MatchResult.From(Name, ex);
|
||||
}
|
||||
}
|
||||
|
||||
return MatchResult.From(Name, MatchScores.Mismatch);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => nameof(FuncMatcher);
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetCSharpCodeArguments()
|
||||
{
|
||||
var funcType = _stringFunc != null ? "Func<string?, bool>" : "Func<byte[]?, bool>";
|
||||
return $"new {Name}" +
|
||||
$"(" +
|
||||
$"/* {funcType} function */, " +
|
||||
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}" +
|
||||
$")";
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AnyOfTypes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -71,7 +70,7 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
|
||||
{
|
||||
try
|
||||
{
|
||||
var jToken = JToken.Parse(input);
|
||||
var jToken = JToken.Parse(input!);
|
||||
score = IsMatch(jToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AnyOfTypes;
|
||||
using DevLab.JmesPath;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Stef.Validation;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace WireMock.Matchers.Request;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
using WireMock.Matchers.Helpers;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Stef.Validation;
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AnyOfTypes;
|
||||
using Stef.Validation;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using Stef.Validation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace WireMock.Matchers.Request;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
using WireMock.Types;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
using WireMock.Util;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
using WireMock.Types;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AnyOfTypes;
|
||||
using Stef.Validation;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AnyOfTypes;
|
||||
using Stef.Validation;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.XPath;
|
||||
@@ -11,9 +9,7 @@ using WireMock.Models;
|
||||
using Stef.Validation;
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Util;
|
||||
#if !NETSTANDARD1_3
|
||||
using Wmhelp.XPath2;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Matchers;
|
||||
|
||||
@@ -135,7 +131,7 @@ public class XPathMatcher : IStringMatcher
|
||||
}
|
||||
catch
|
||||
{
|
||||
_xmlDocument = default;
|
||||
_xmlDocument = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,25 +147,17 @@ public class XPathMatcher : IStringMatcher
|
||||
var xmlNamespaceManager = GetXmlNamespaceManager(xmlNamespaceMap);
|
||||
if (xmlNamespaceManager == null)
|
||||
{
|
||||
#if NETSTANDARD1_3
|
||||
return navigator.Evaluate(xpath);
|
||||
#else
|
||||
return navigator.XPath2Evaluate(xpath);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETSTANDARD1_3
|
||||
return navigator.Evaluate(xpath, xmlNamespaceManager);
|
||||
#else
|
||||
return navigator.XPath2Evaluate(xpath, xmlNamespaceManager);
|
||||
#endif
|
||||
}
|
||||
|
||||
private XmlNamespaceManager? GetXmlNamespaceManager(IEnumerable<XmlNamespace>? xmlNamespaceMap)
|
||||
{
|
||||
if (_xpathNavigator == null || xmlNamespaceMap == null)
|
||||
{
|
||||
return default;
|
||||
return null;
|
||||
}
|
||||
|
||||
var nsManager = new XmlNamespaceManager(_xpathNavigator.NameTable);
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading;
|
||||
|
||||
namespace WireMock.Models;
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
|
||||
namespace WireMock.Models;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using Stef.Validation;
|
||||
|
||||
namespace WireMock.Models;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if ACTIVITY_TRACING_SUPPORTED
|
||||
|
||||
namespace WireMock.Owin.ActivityTracing;
|
||||
|
||||
/// <summary>
|
||||
/// Options for controlling activity tracing in WireMock.Net middleware.
|
||||
/// These options control the creation of System.Diagnostics.Activity objects
|
||||
/// but do not require any OpenTelemetry exporter dependencies.
|
||||
/// </summary>
|
||||
public class ActivityTracingOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to exclude admin interface requests from tracing.
|
||||
/// Default is <c>true</c>.
|
||||
/// </summary>
|
||||
public bool ExcludeAdminRequests { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to record request body in trace attributes.
|
||||
/// Default is <c>false</c> due to potential PII concerns.
|
||||
/// </summary>
|
||||
public bool RecordRequestBody { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to record response body in trace attributes.
|
||||
/// Default is <c>false</c> due to potential PII concerns.
|
||||
/// </summary>
|
||||
public bool RecordResponseBody { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to record mapping match details in trace attributes.
|
||||
/// Default is <c>true</c>.
|
||||
/// </summary>
|
||||
public bool RecordMatchDetails { get; set; } = true;
|
||||
}
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if !ACTIVITY_TRACING_SUPPORTED
|
||||
using System;
|
||||
#endif
|
||||
using WireMock.Settings;
|
||||
|
||||
namespace WireMock.Owin.ActivityTracing;
|
||||
|
||||
/// <summary>
|
||||
/// Validator for Activity Tracing configuration.
|
||||
/// </summary>
|
||||
internal static class ActivityTracingValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates that Activity Tracing is supported on the current framework.
|
||||
/// Throws an exception if ActivityTracingOptions is configured on an unsupported framework.
|
||||
/// </summary>
|
||||
/// <param name="settings">The WireMock server settings to validate.</param>
|
||||
/// <exception cref="System.InvalidOperationException">
|
||||
/// Thrown when ActivityTracingOptions is configured but the current framework does not support System.Diagnostics.Activity.
|
||||
/// </exception>
|
||||
public static void ValidateActivityApiPresence(WireMockServerSettings settings)
|
||||
{
|
||||
#if !ACTIVITY_TRACING_SUPPORTED
|
||||
if (settings.ActivityTracingOptions is not null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Activity Tracing is not supported on this target framework. " +
|
||||
"It requires .NET 5.0 or higher which includes System.Diagnostics.Activity support.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if ACTIVITY_TRACING_SUPPORTED
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net.WebSockets;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Settings;
|
||||
using WireMock.WebSockets;
|
||||
|
||||
namespace WireMock.Owin.ActivityTracing;
|
||||
|
||||
/// <summary>
|
||||
/// Provides an ActivitySource for WireMock.Net distributed tracing.
|
||||
/// </summary>
|
||||
public static class WireMockActivitySource
|
||||
internal static class WireMockActivitySource
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the ActivitySource used by WireMock.Net.
|
||||
@@ -103,11 +104,11 @@ public static class WireMockActivitySource
|
||||
// Set status based on HTTP status code (using standard otel.status_code tag)
|
||||
if (statusCodeInt.Value >= 400)
|
||||
{
|
||||
activity.SetTag("otel.status_code", "ERROR");
|
||||
activity.SetTag(WireMockSemanticConventions.OtelStatusCode, "ERROR");
|
||||
}
|
||||
else
|
||||
{
|
||||
activity.SetTag("otel.status_code", "OK");
|
||||
activity.SetTag(WireMockSemanticConventions.OtelStatusCode, "OK");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,11 +191,65 @@ public static class WireMockActivitySource
|
||||
}
|
||||
|
||||
// Use standard OpenTelemetry exception semantic conventions
|
||||
activity.SetTag("otel.status_code", "ERROR");
|
||||
activity.SetTag(WireMockSemanticConventions.OtelStatusCode, "ERROR");
|
||||
activity.SetTag("otel.status_description", exception.Message);
|
||||
activity.SetTag("exception.type", exception.GetType().FullName);
|
||||
activity.SetTag("exception.message", exception.Message);
|
||||
activity.SetTag("exception.stacktrace", exception.ToString());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new activity for a WebSocket message.
|
||||
/// </summary>
|
||||
/// <param name="direction">The direction of the message.</param>
|
||||
/// <param name="mappingGuid">The GUID of the mapping handling the WebSocket.</param>
|
||||
/// <returns>The started activity, or null if tracing is not enabled.</returns>
|
||||
internal static Activity? StartWebSocketMessageActivity(WebSocketMessageDirection direction, Guid mappingGuid)
|
||||
{
|
||||
if (!Source.HasListeners())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var activity = Source.StartActivity(
|
||||
$"WireMock WebSocket {direction.ToString().ToLowerInvariant()}",
|
||||
ActivityKind.Server
|
||||
);
|
||||
|
||||
if (activity != null)
|
||||
{
|
||||
activity.SetTag(WireMockSemanticConventions.MappingGuid, mappingGuid.ToString());
|
||||
}
|
||||
|
||||
return activity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enriches an activity with WebSocket message information.
|
||||
/// </summary>
|
||||
internal static void EnrichWithWebSocketMessage(
|
||||
Activity? activity,
|
||||
WebSocketMessageType messageType,
|
||||
int messageSize,
|
||||
bool endOfMessage,
|
||||
string? textContent = null,
|
||||
ActivityTracingOptions? options = null)
|
||||
{
|
||||
if (activity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
activity.SetTag(WireMockSemanticConventions.WebSocketMessageType, messageType.ToString());
|
||||
activity.SetTag(WireMockSemanticConventions.WebSocketMessageSize, messageSize);
|
||||
activity.SetTag(WireMockSemanticConventions.WebSocketEndOfMessage, endOfMessage);
|
||||
|
||||
// Record message content if enabled and it's text
|
||||
if (options?.RecordRequestBody == true && messageType == WebSocketMessageType.Text && textContent != null)
|
||||
{
|
||||
activity.SetTag(WireMockSemanticConventions.WebSocketMessageContent, textContent);
|
||||
}
|
||||
|
||||
activity.SetTag(WireMockSemanticConventions.OtelStatusCode, "OK");
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ namespace WireMock.Owin.ActivityTracing;
|
||||
/// </summary>
|
||||
internal static class WireMockSemanticConventions
|
||||
{
|
||||
public const string OtelStatusCode = "otel.status_code";
|
||||
|
||||
// Standard HTTP semantic conventions (OpenTelemetry)
|
||||
public const string HttpMethod = "http.request.method";
|
||||
public const string HttpUrl = "url.full";
|
||||
@@ -25,4 +27,10 @@ internal static class WireMockSemanticConventions
|
||||
public const string RequestGuid = "wiremock.request.guid";
|
||||
public const string RequestBody = "wiremock.request.body";
|
||||
public const string ResponseBody = "wiremock.response.body";
|
||||
|
||||
// WebSocket-specific attributes
|
||||
public const string WebSocketMessageType = "wiremock.websocket.message.type";
|
||||
public const string WebSocketMessageSize = "wiremock.websocket.message.size";
|
||||
public const string WebSocketEndOfMessage = "wiremock.websocket.message.end_of_message";
|
||||
public const string WebSocketMessageContent = "wiremock.websocket.message.content";
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||
#if NET8_0
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WireMock.Types;
|
||||
@@ -9,6 +9,8 @@ namespace WireMock.Owin;
|
||||
|
||||
internal partial class AspNetCoreSelfHost
|
||||
{
|
||||
private const string CorsPolicyName = "WireMock.Net - Policy";
|
||||
|
||||
public void AddCors(IServiceCollection services)
|
||||
{
|
||||
if (_wireMockMiddlewareOptions.CorsPolicyOptions > CorsPolicyOptions.None)
|
||||
@@ -1,12 +1,8 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if USE_ASPNETCORE && !NETSTANDARD1_3
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using CertificateLoader = WireMock.HttpsCertificate.CertificateLoader;
|
||||
@@ -38,7 +34,7 @@ internal partial class AspNetCoreSelfHost
|
||||
options.ServerCertificate = CertificateLoader.LoadCertificate(wireMockMiddlewareOptions, urlDetail.Host);
|
||||
}
|
||||
|
||||
options.ClientCertificateMode = (ClientCertificateMode)wireMockMiddlewareOptions.ClientCertificateMode;
|
||||
options.ClientCertificateMode = wireMockMiddlewareOptions.ClientCertificateMode;
|
||||
if (wireMockMiddlewareOptions.AcceptAnyClientCertificate)
|
||||
{
|
||||
options.ClientCertificateValidation = (_, _, _) => true;
|
||||
@@ -47,7 +43,7 @@ internal partial class AspNetCoreSelfHost
|
||||
|
||||
if (urlDetail.IsHttp2)
|
||||
{
|
||||
listenOptions.Protocols = HttpProtocols.Http2;
|
||||
SetHttp2AsProtocolsOnListenOptions(listenOptions);
|
||||
}
|
||||
});
|
||||
continue;
|
||||
@@ -55,10 +51,7 @@ internal partial class AspNetCoreSelfHost
|
||||
|
||||
if (urlDetail.IsHttp2)
|
||||
{
|
||||
Listen(kestrelOptions, urlDetail, listenOptions =>
|
||||
{
|
||||
listenOptions.Protocols = HttpProtocols.Http2;
|
||||
});
|
||||
Listen(kestrelOptions, urlDetail, SetHttp2AsProtocolsOnListenOptions);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -66,6 +59,15 @@ internal partial class AspNetCoreSelfHost
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetHttp2AsProtocolsOnListenOptions(ListenOptions listenOptions)
|
||||
{
|
||||
#if NET8_0_OR_GREATER
|
||||
listenOptions.Protocols = HttpProtocols.Http2;
|
||||
#else
|
||||
throw new NotSupportedException("HTTP/2 is only supported in .NET 8 or greater.");
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void Listen(KestrelServerOptions kestrelOptions, HostUrlDetails urlDetail, Action<ListenOptions> configure)
|
||||
{
|
||||
// Listens on any IP with the given port.
|
||||
@@ -111,5 +113,4 @@ internal static class IWebHostBuilderExtensions
|
||||
services.Configure<KestrelServerOptions>(context.Configuration.GetSection("Kestrel"));
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if USE_ASPNETCORE && NETSTANDARD1_3
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Server.Kestrel;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WireMock.HttpsCertificate;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
|
||||
internal partial class AspNetCoreSelfHost
|
||||
{
|
||||
private static void SetKestrelOptionsLimits(KestrelServerOptions options)
|
||||
{
|
||||
options.Limits.MaxRequestBufferSize = null;
|
||||
options.Limits.MaxRequestHeaderCount = 100;
|
||||
options.Limits.MaxResponseBufferSize = null;
|
||||
}
|
||||
|
||||
private static void SetHttpsAndUrls(KestrelServerOptions options, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
|
||||
{
|
||||
foreach (var urlDetail in urlDetails)
|
||||
{
|
||||
if (urlDetail.IsHttps)
|
||||
{
|
||||
options.UseHttps(new HttpsConnectionFilterOptions
|
||||
{
|
||||
ServerCertificate = wireMockMiddlewareOptions.CustomCertificateDefined ? CertificateLoader.LoadCertificate(wireMockMiddlewareOptions, urlDetail.Host) : PublicCertificateHelper.GetX509Certificate2(),
|
||||
ClientCertificateMode = (ClientCertificateMode) wireMockMiddlewareOptions.ClientCertificateMode,
|
||||
ClientCertificateValidation = wireMockMiddlewareOptions.AcceptAnyClientCertificate ? (_, _, _) => true : null
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class IWebHostBuilderExtensions
|
||||
{
|
||||
internal static IWebHostBuilder ConfigureAppConfigurationUsingEnvironmentVariables(this IWebHostBuilder builder) => builder;
|
||||
|
||||
internal static IWebHostBuilder ConfigureKestrelServerOptions(this IWebHostBuilder builder)
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddEnvironmentVariables()
|
||||
.Build();
|
||||
|
||||
return builder.ConfigureServices(services =>
|
||||
{
|
||||
services.Configure<KestrelServerOptions>(configuration.GetSection("Kestrel"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,42 +1,34 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Stef.Validation;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Owin.Mappers;
|
||||
using WireMock.Serialization;
|
||||
using WireMock.Services;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
|
||||
internal partial class AspNetCoreSelfHost : IOwinSelfHost
|
||||
internal partial class AspNetCoreSelfHost
|
||||
{
|
||||
private const string CorsPolicyName = "WireMock.Net - Policy";
|
||||
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
private readonly IWireMockMiddlewareOptions _wireMockMiddlewareOptions;
|
||||
private readonly IWireMockLogger _logger;
|
||||
private readonly HostUrlOptions _urlOptions;
|
||||
|
||||
private Exception _runningException;
|
||||
private IWebHost _host;
|
||||
private IWebHost _host = null!;
|
||||
|
||||
public bool IsStarted { get; private set; }
|
||||
|
||||
public List<string> Urls { get; } = new();
|
||||
public List<string> Urls { get; } = [];
|
||||
|
||||
public List<int> Ports { get; } = new();
|
||||
public List<int> Ports { get; } = [];
|
||||
|
||||
public Exception RunningException => _runningException;
|
||||
public Exception? RunningException { get; private set; }
|
||||
|
||||
public AspNetCoreSelfHost(IWireMockMiddlewareOptions wireMockMiddlewareOptions, HostUrlOptions urlOptions)
|
||||
{
|
||||
@@ -73,8 +65,11 @@ internal partial class AspNetCoreSelfHost : IOwinSelfHost
|
||||
services.AddSingleton<IOwinRequestMapper, OwinRequestMapper>();
|
||||
services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>();
|
||||
services.AddSingleton<IGuidUtils, GuidUtils>();
|
||||
services.AddSingleton<IDateTimeUtils, DateTimeUtils>();
|
||||
services.AddSingleton<LogEntryMapper>();
|
||||
services.AddSingleton<IWireMockMiddlewareLogger, WireMockMiddlewareLogger>();
|
||||
|
||||
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||
#if NET8_0_OR_GREATER
|
||||
AddCors(services);
|
||||
#endif
|
||||
_wireMockMiddlewareOptions.AdditionalServiceRegistration?.Invoke(services);
|
||||
@@ -83,8 +78,16 @@ internal partial class AspNetCoreSelfHost : IOwinSelfHost
|
||||
{
|
||||
appBuilder.UseMiddleware<GlobalExceptionMiddleware>();
|
||||
|
||||
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||
#if NET8_0_OR_GREATER
|
||||
UseCors(appBuilder);
|
||||
|
||||
var webSocketOptions = new WebSocketOptions();
|
||||
if (_wireMockMiddlewareOptions.WebSocketSettings?.KeepAliveIntervalSeconds != null)
|
||||
{
|
||||
webSocketOptions.KeepAliveInterval = TimeSpan.FromSeconds(_wireMockMiddlewareOptions.WebSocketSettings.KeepAliveIntervalSeconds);
|
||||
}
|
||||
|
||||
appBuilder.UseWebSockets(webSocketOptions);
|
||||
#endif
|
||||
_wireMockMiddlewareOptions.PreWireMockMiddlewareInit?.Invoke(appBuilder);
|
||||
|
||||
@@ -99,73 +102,76 @@ internal partial class AspNetCoreSelfHost : IOwinSelfHost
|
||||
SetHttpsAndUrls(options, _wireMockMiddlewareOptions, _urlOptions.GetDetails());
|
||||
})
|
||||
.ConfigureKestrelServerOptions()
|
||||
|
||||
#if NETSTANDARD1_3
|
||||
.UseUrls(_urlOptions.GetDetails().Select(u => u.Url).ToArray())
|
||||
#endif
|
||||
.Build();
|
||||
|
||||
return RunHost(_cts.Token);
|
||||
}
|
||||
|
||||
private Task RunHost(CancellationToken token)
|
||||
private Task RunHost(CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||
var appLifetime = _host.Services.GetRequiredService<Microsoft.Extensions.Hosting.IHostApplicationLifetime>();
|
||||
#if NET8_0_OR_GREATER
|
||||
var appLifetime = _host.Services.GetRequiredService<Microsoft.Extensions.Hosting.IHostApplicationLifetime>();
|
||||
#else
|
||||
var appLifetime = _host.Services.GetRequiredService<IApplicationLifetime>();
|
||||
var appLifetime = _host.Services.GetRequiredService<IApplicationLifetime>();
|
||||
#endif
|
||||
appLifetime.ApplicationStarted.Register(() =>
|
||||
{
|
||||
var addresses = _host.ServerFeatures
|
||||
.Get<Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature>()!
|
||||
.Addresses;
|
||||
appLifetime.ApplicationStarted.Register(() =>
|
||||
{
|
||||
var addresses = _host.ServerFeatures
|
||||
.Get<Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature>()!
|
||||
.Addresses
|
||||
.ToArray();
|
||||
|
||||
if (_urlOptions.Urls == null)
|
||||
{
|
||||
foreach (var address in addresses)
|
||||
{
|
||||
Urls.Add(address.Replace("0.0.0.0", "localhost").Replace("[::]", "localhost"));
|
||||
PortUtils.TryExtract(address, out _, out _, out var scheme, out var host, out var port);
|
||||
|
||||
PortUtils.TryExtract(address, out _, out _, out _, out _, out var port);
|
||||
var replacedHost = ReplaceHostWithLocalhost(host!);
|
||||
var newUrl = $"{scheme}://{replacedHost}:{port}";
|
||||
Urls.Add(newUrl);
|
||||
Ports.Add(port);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var urlOptions = _urlOptions.Urls?.ToArray() ?? [];
|
||||
|
||||
for (int i = 0; i < urlOptions.Length; i++)
|
||||
{
|
||||
PortUtils.TryExtract(urlOptions[i], out _, out _, out var originalScheme, out _, out _);
|
||||
if (originalScheme!.StartsWith("grpc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Always replace "grpc" with "http" in the scheme because GrpcChannel needs http or https.
|
||||
originalScheme = originalScheme.Replace("grpc", "http", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
PortUtils.TryExtract(addresses[i], out _, out _, out _, out var realHost, out var realPort);
|
||||
|
||||
var replacedHost = ReplaceHostWithLocalhost(realHost!);
|
||||
var newUrl = $"{originalScheme}://{replacedHost}:{realPort}";
|
||||
|
||||
Urls.Add(newUrl);
|
||||
Ports.Add(realPort);
|
||||
}
|
||||
}
|
||||
|
||||
IsStarted = true;
|
||||
});
|
||||
|
||||
#if NETSTANDARD1_3
|
||||
_logger.Info("Server using netstandard1.3");
|
||||
#elif NETSTANDARD2_0
|
||||
_logger.Info("Server using netstandard2.0");
|
||||
#elif NETSTANDARD2_1
|
||||
_logger.Info("Server using netstandard2.1");
|
||||
#elif NETCOREAPP3_1
|
||||
_logger.Info("Server using .NET Core App 3.1");
|
||||
#elif NET5_0
|
||||
_logger.Info("Server using .NET 5.0");
|
||||
#elif NET6_0
|
||||
_logger.Info("Server using .NET 6.0");
|
||||
#elif NET7_0
|
||||
_logger.Info("Server using .NET 7.0");
|
||||
#elif NET8_0
|
||||
#if NET8_0
|
||||
_logger.Info("Server using .NET 8.0");
|
||||
#elif NET46
|
||||
_logger.Info("Server using .NET Framework 4.6.1 or higher");
|
||||
#else
|
||||
_logger.Info("Server using .NET Standard 2.0");
|
||||
#endif
|
||||
|
||||
#if NETSTANDARD1_3
|
||||
return Task.Run(() =>
|
||||
{
|
||||
_host.Run(token);
|
||||
});
|
||||
#else
|
||||
return _host.RunAsync(token);
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_runningException = e;
|
||||
RunningException = e;
|
||||
_logger.Error(e.ToString());
|
||||
|
||||
IsStarted = false;
|
||||
@@ -179,11 +185,11 @@ internal partial class AspNetCoreSelfHost : IOwinSelfHost
|
||||
_cts.Cancel();
|
||||
|
||||
IsStarted = false;
|
||||
#if NETSTANDARD1_3
|
||||
return Task.CompletedTask;
|
||||
#else
|
||||
return _host.StopAsync();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private static string ReplaceHostWithLocalhost(string host)
|
||||
{
|
||||
return host.Replace("0.0.0.0", "localhost").Replace("[::]", "localhost");
|
||||
}
|
||||
}
|
||||
@@ -1,70 +1,41 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Newtonsoft.Json;
|
||||
#if !USE_ASPNETCORE
|
||||
using Microsoft.Owin;
|
||||
using IContext = Microsoft.Owin.IOwinContext;
|
||||
using OwinMiddleware = Microsoft.Owin.OwinMiddleware;
|
||||
using Next = Microsoft.Owin.OwinMiddleware;
|
||||
#else
|
||||
using OwinMiddleware = System.Object;
|
||||
using IContext = Microsoft.AspNetCore.Http.HttpContext;
|
||||
using Next = Microsoft.AspNetCore.Http.RequestDelegate;
|
||||
#endif
|
||||
using WireMock.Owin.Mappers;
|
||||
using Stef.Validation;
|
||||
using WireMock.Owin.Mappers;
|
||||
|
||||
namespace WireMock.Owin
|
||||
namespace WireMock.Owin;
|
||||
|
||||
internal class GlobalExceptionMiddleware
|
||||
{
|
||||
internal class GlobalExceptionMiddleware : OwinMiddleware
|
||||
private readonly IWireMockMiddlewareOptions _options;
|
||||
private readonly IOwinResponseMapper _responseMapper;
|
||||
|
||||
public GlobalExceptionMiddleware(RequestDelegate next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper)
|
||||
{
|
||||
private readonly IWireMockMiddlewareOptions _options;
|
||||
private readonly IOwinResponseMapper _responseMapper;
|
||||
Next = next;
|
||||
_options = Guard.NotNull(options);
|
||||
_responseMapper = Guard.NotNull(responseMapper);
|
||||
}
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
public GlobalExceptionMiddleware(Next next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper) : base(next)
|
||||
public RequestDelegate Next { get; }
|
||||
|
||||
public Task Invoke(HttpContext ctx)
|
||||
{
|
||||
return InvokeInternalAsync(ctx);
|
||||
}
|
||||
|
||||
private async Task InvokeInternalAsync(HttpContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
_options = Guard.NotNull(options);
|
||||
_responseMapper = Guard.NotNull(responseMapper);;
|
||||
await Next.Invoke(ctx).ConfigureAwait(false);
|
||||
}
|
||||
#else
|
||||
public GlobalExceptionMiddleware(Next next, IWireMockMiddlewareOptions options, IOwinResponseMapper responseMapper)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Next = next;
|
||||
_options = Guard.NotNull(options);
|
||||
_responseMapper = Guard.NotNull(responseMapper);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
public Next Next { get; }
|
||||
#endif
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
public override Task Invoke(IContext ctx)
|
||||
#else
|
||||
public Task Invoke(IContext ctx)
|
||||
#endif
|
||||
{
|
||||
return InvokeInternalAsync(ctx);
|
||||
}
|
||||
|
||||
private async Task InvokeInternalAsync(IContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Next != null)
|
||||
{
|
||||
await Next.Invoke(ctx).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_options.Logger.Error("HttpStatusCode set to 500 {0}", ex);
|
||||
await _responseMapper.MapAsync(ResponseMessageBuilder.Create(500, JsonConvert.SerializeObject(ex)), ctx.Response).ConfigureAwait(false);
|
||||
}
|
||||
_options.Logger.Error("HttpStatusCode set to 500 {0}", ex);
|
||||
await _responseMapper.MapAsync(ResponseMessageBuilder.Create(500, JsonConvert.SerializeObject(ex)), ctx.Response).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
@@ -23,20 +22,34 @@ internal class HostUrlOptions
|
||||
var list = new List<HostUrlDetails>();
|
||||
if (Urls == null)
|
||||
{
|
||||
if (HostingScheme is HostingScheme.Http or HostingScheme.Https)
|
||||
if (HostingScheme is not HostingScheme.None)
|
||||
{
|
||||
var port = Port > 0 ? Port.Value : FindFreeTcpPort();
|
||||
var scheme = HostingScheme == HostingScheme.Https ? "https" : "http";
|
||||
list.Add(new HostUrlDetails { IsHttps = HostingScheme == HostingScheme.Https, IsHttp2 = UseHttp2 == true, Url = $"{scheme}://{Star}:{port}", Scheme = scheme, Host = Star, Port = port });
|
||||
var scheme = GetSchemeAsString(HostingScheme);
|
||||
var port = Port > 0 ? Port.Value : 0;
|
||||
var isHttps = HostingScheme == HostingScheme.Https || HostingScheme == HostingScheme.Wss;
|
||||
list.Add(new HostUrlDetails { IsHttps = isHttps, IsHttp2 = UseHttp2 == true, Url = $"{scheme}://{Star}:{port}", Scheme = scheme, Host = Star, Port = port });
|
||||
}
|
||||
|
||||
if (HostingScheme == HostingScheme.HttpAndHttps)
|
||||
{
|
||||
var httpPort = Port > 0 ? Port.Value : FindFreeTcpPort();
|
||||
list.Add(new HostUrlDetails { IsHttps = false, IsHttp2 = UseHttp2 == true, Url = $"http://{Star}:{httpPort}", Scheme = "http", Host = Star, Port = httpPort });
|
||||
var port = Port > 0 ? Port.Value : 0;
|
||||
var scheme = GetSchemeAsString(HostingScheme.Http);
|
||||
list.Add(new HostUrlDetails { IsHttps = false, IsHttp2 = UseHttp2 == true, Url = $"{scheme}://{Star}:{port}", Scheme = scheme, Host = Star, Port = port });
|
||||
|
||||
var httpsPort = FindFreeTcpPort(); // In this scenario, always get a free port for https.
|
||||
list.Add(new HostUrlDetails { IsHttps = true, IsHttp2 = UseHttp2 == true, Url = $"https://{Star}:{httpsPort}", Scheme = "https", Host = Star, Port = httpsPort });
|
||||
var securePort = 0; // In this scenario, always get a free port for https.
|
||||
var secureScheme = GetSchemeAsString(HostingScheme.Https);
|
||||
list.Add(new HostUrlDetails { IsHttps = true, IsHttp2 = UseHttp2 == true, Url = $"{secureScheme}://{Star}:{securePort}", Scheme = secureScheme, Host = Star, Port = securePort });
|
||||
}
|
||||
|
||||
if (HostingScheme == HostingScheme.WsAndWss)
|
||||
{
|
||||
var port = Port > 0 ? Port.Value : 0;
|
||||
var scheme = GetSchemeAsString(HostingScheme.Ws);
|
||||
list.Add(new HostUrlDetails { IsHttps = false, IsHttp2 = UseHttp2 == true, Url = $"{scheme}://{Star}:{port}", Scheme = scheme, Host = Star, Port = port });
|
||||
|
||||
var securePort = 0; // In this scenario, always get a free port for https.
|
||||
var secureScheme = GetSchemeAsString(HostingScheme.Wss);
|
||||
list.Add(new HostUrlDetails { IsHttps = true, IsHttp2 = UseHttp2 == true, Url = $"{secureScheme}://{Star}:{securePort}", Scheme = secureScheme, Host = Star, Port = securePort });
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -53,12 +66,19 @@ internal class HostUrlOptions
|
||||
return list;
|
||||
}
|
||||
|
||||
private static int FindFreeTcpPort()
|
||||
private string GetSchemeAsString(HostingScheme scheme)
|
||||
{
|
||||
#if USE_ASPNETCORE || NETSTANDARD2_0 || NETSTANDARD2_1
|
||||
return 0;
|
||||
#else
|
||||
return PortUtils.FindFreeTcpPort();
|
||||
#endif
|
||||
return scheme switch
|
||||
{
|
||||
HostingScheme.Http => "http",
|
||||
HostingScheme.Https => "https",
|
||||
HostingScheme.HttpAndHttps => "http", // Default to http when both are specified, since the https URL will be added separately with a free port.
|
||||
|
||||
HostingScheme.Ws => "ws",
|
||||
HostingScheme.Wss => "wss",
|
||||
HostingScheme.WsAndWss => "ws", // Default to ws when both are specified, since the wss URL will be added separately with a free port.
|
||||
|
||||
_ => throw new NotSupportedException($"Unsupported hosting scheme: {HostingScheme}")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
|
||||
interface IOwinSelfHost
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this server is started.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this server is started; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
bool IsStarted { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the urls.
|
||||
/// </summary>
|
||||
List<string> Urls { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ports.
|
||||
/// </summary>
|
||||
List<int> Ports { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The exception occurred when the host is running.
|
||||
/// </summary>
|
||||
Exception? RunningException { get; }
|
||||
|
||||
Task StartAsync();
|
||||
|
||||
Task StopAsync();
|
||||
}
|
||||
13
src/WireMock.Net.Minimal/Owin/IWireMockMiddlewareLogger.cs
Normal file
13
src/WireMock.Net.Minimal/Owin/IWireMockMiddlewareLogger.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Diagnostics;
|
||||
using WireMock.Logging;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
|
||||
internal interface IWireMockMiddlewareLogger
|
||||
{
|
||||
void LogRequestAndResponse(bool logRequest, RequestMessage request, IResponseMessage? response, MappingMatcherResult? match, MappingMatcherResult? partialMatch, Activity? activity);
|
||||
|
||||
void LogLogEntry(LogEntry entry, bool addRequest);
|
||||
}
|
||||
@@ -1,23 +1,17 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Owin.ActivityTracing;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
using JetBrains.Annotations;
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
using Owin;
|
||||
#else
|
||||
using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
#endif
|
||||
using WireMock.WebSockets;
|
||||
using ClientCertificateMode = Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
|
||||
@@ -41,11 +35,10 @@ internal interface IWireMockMiddlewareOptions
|
||||
|
||||
int? MaxRequestLogCount { get; set; }
|
||||
|
||||
Action<IAppBuilder>? PreWireMockMiddlewareInit { get; set; }
|
||||
Action<IApplicationBuilder>? PreWireMockMiddlewareInit { get; set; }
|
||||
|
||||
Action<IAppBuilder>? PostWireMockMiddlewareInit { get; set; }
|
||||
Action<IApplicationBuilder>? PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
|
||||
|
||||
CorsPolicyOptions? CorsPolicyOptions { get; set; }
|
||||
@@ -53,7 +46,6 @@ internal interface IWireMockMiddlewareOptions
|
||||
ClientCertificateMode ClientCertificateMode { get; set; }
|
||||
|
||||
bool AcceptAnyClientCertificate { get; set; }
|
||||
#endif
|
||||
|
||||
IFileSystemHandler? FileSystemHandler { get; set; }
|
||||
|
||||
@@ -90,13 +82,21 @@ internal interface IWireMockMiddlewareOptions
|
||||
|
||||
QueryParameterMultipleValueSupport? QueryParameterMultipleValueSupport { get; set; }
|
||||
|
||||
public bool ProxyAll { get; set; }
|
||||
bool ProxyAll { get; set; }
|
||||
|
||||
#if ACTIVITY_TRACING_SUPPORTED
|
||||
/// <summary>
|
||||
/// Gets or sets the activity tracing options.
|
||||
/// When set, System.Diagnostics.Activity objects are created for request tracing.
|
||||
/// </summary>
|
||||
ActivityTracingOptions? ActivityTracingOptions { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The WebSocket connection registries per mapping (used for broadcast).
|
||||
/// </summary>
|
||||
ConcurrentDictionary<Guid, WebSocketConnectionRegistry> WebSocketRegistries { get; }
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket settings.
|
||||
/// </summary>
|
||||
WebSocketSettings? WebSocketSettings { get; set; }
|
||||
}
|
||||
@@ -1,25 +1,19 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Threading.Tasks;
|
||||
#if !USE_ASPNETCORE
|
||||
using IRequest = Microsoft.Owin.IOwinRequest;
|
||||
#else
|
||||
using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
|
||||
#endif
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace WireMock.Owin.Mappers
|
||||
namespace WireMock.Owin.Mappers;
|
||||
|
||||
/// <summary>
|
||||
/// IOwinRequestMapper
|
||||
/// </summary>
|
||||
internal interface IOwinRequestMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// IOwinRequestMapper
|
||||
/// MapAsync IRequest to RequestMessage
|
||||
/// </summary>
|
||||
internal interface IOwinRequestMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// MapAsync IRequest to RequestMessage
|
||||
/// </summary>
|
||||
/// <param name="request">The OwinRequest/HttpRequest</param>
|
||||
/// <param name="options">The WireMockMiddlewareOptions</param>
|
||||
/// <returns>RequestMessage</returns>
|
||||
Task<RequestMessage> MapAsync(IRequest request, IWireMockMiddlewareOptions options);
|
||||
}
|
||||
/// <param name="context">The HttpContext</param>
|
||||
/// <param name="options">The WireMockMiddlewareOptions</param>
|
||||
/// <returns>RequestMessage</returns>
|
||||
Task<RequestMessage> MapAsync(HttpContext context, IWireMockMiddlewareOptions options);
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Threading.Tasks;
|
||||
#if !USE_ASPNETCORE
|
||||
using IResponse = Microsoft.Owin.IOwinResponse;
|
||||
#else
|
||||
using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
|
||||
#endif
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace WireMock.Owin.Mappers;
|
||||
|
||||
@@ -18,6 +13,6 @@ internal interface IOwinResponseMapper
|
||||
/// Map ResponseMessage to IResponse.
|
||||
/// </summary>
|
||||
/// <param name="responseMessage">The ResponseMessage</param>
|
||||
/// <param name="response">The OwinResponse/HttpResponse</param>
|
||||
Task MapAsync(IResponseMessage? responseMessage, IResponse response);
|
||||
}
|
||||
/// <param name="response">The HttpResponse</param>
|
||||
Task MapAsync(IResponseMessage? responseMessage, HttpResponse response);
|
||||
}
|
||||
@@ -1,18 +1,11 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using WireMock.Http;
|
||||
using WireMock.Models;
|
||||
using WireMock.Util;
|
||||
#if !USE_ASPNETCORE
|
||||
using IRequest = Microsoft.Owin.IOwinRequest;
|
||||
#else
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using IRequest = Microsoft.AspNetCore.Http.HttpRequest;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin.Mappers;
|
||||
|
||||
@@ -22,8 +15,9 @@ namespace WireMock.Owin.Mappers;
|
||||
internal class OwinRequestMapper : IOwinRequestMapper
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<RequestMessage> MapAsync(IRequest request, IWireMockMiddlewareOptions options)
|
||||
public async Task<RequestMessage> MapAsync(HttpContext context, IWireMockMiddlewareOptions options)
|
||||
{
|
||||
var request = context.Request;
|
||||
var (urlDetails, clientIP) = ParseRequest(request);
|
||||
|
||||
var method = request.Method;
|
||||
@@ -73,22 +67,16 @@ internal class OwinRequestMapper : IOwinRequestMapper
|
||||
body,
|
||||
headers,
|
||||
cookies,
|
||||
httpVersion
|
||||
#if USE_ASPNETCORE
|
||||
, await request.HttpContext.Connection.GetClientCertificateAsync()
|
||||
#endif
|
||||
)
|
||||
httpVersion,
|
||||
await request.HttpContext.Connection.GetClientCertificateAsync()
|
||||
)
|
||||
{
|
||||
DateTime = DateTime.UtcNow
|
||||
};
|
||||
}
|
||||
|
||||
private static (UrlDetails UrlDetails, string ClientIP) ParseRequest(IRequest request)
|
||||
private static (UrlDetails UrlDetails, string ClientIP) ParseRequest(HttpRequest request)
|
||||
{
|
||||
#if !USE_ASPNETCORE
|
||||
var urlDetails = UrlUtils.Parse(request.Uri, request.PathBase);
|
||||
var clientIP = request.RemoteIpAddress;
|
||||
#else
|
||||
var urlDetails = UrlUtils.Parse(new Uri(request.GetEncodedUrl()), request.PathBase);
|
||||
|
||||
var connection = request.HttpContext.Connection;
|
||||
@@ -105,7 +93,7 @@ internal class OwinRequestMapper : IOwinRequestMapper
|
||||
{
|
||||
clientIP = connection.RemoteIpAddress.ToString();
|
||||
}
|
||||
#endif
|
||||
|
||||
return (urlDetails, clientIP);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,21 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Newtonsoft.Json;
|
||||
using RandomDataGenerator.FieldOptions;
|
||||
using RandomDataGenerator.Randomizers;
|
||||
using Stef.Validation;
|
||||
using WireMock.Http;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.ResponseProviders;
|
||||
using WireMock.Types;
|
||||
using Stef.Validation;
|
||||
using WireMock.Util;
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
using IResponse = Microsoft.Owin.IOwinResponse;
|
||||
#else
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using IResponse = Microsoft.AspNetCore.Http.HttpResponse;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin.Mappers
|
||||
{
|
||||
/// <summary>
|
||||
@@ -37,8 +29,8 @@ namespace WireMock.Owin.Mappers
|
||||
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/78h415ay(v=vs.110).aspx
|
||||
private static readonly IDictionary<string, Action<IResponse, bool, WireMockList<string>>> ResponseHeadersToFix =
|
||||
new Dictionary<string, Action<IResponse, bool, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase)
|
||||
private static readonly IDictionary<string, Action<HttpResponse, bool, WireMockList<string>>> ResponseHeadersToFix =
|
||||
new Dictionary<string, Action<HttpResponse, bool, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ HttpKnownHeaderNames.ContentType, (r, _, v) => r.ContentType = v.FirstOrDefault() },
|
||||
{ HttpKnownHeaderNames.ContentLength, (r, hasBody, v) =>
|
||||
@@ -62,9 +54,9 @@ namespace WireMock.Owin.Mappers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task MapAsync(IResponseMessage? responseMessage, IResponse response)
|
||||
public async Task MapAsync(IResponseMessage? responseMessage, HttpResponse response)
|
||||
{
|
||||
if (responseMessage == null)
|
||||
if (responseMessage == null || responseMessage is WebSocketHandledResponse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -128,7 +120,7 @@ namespace WireMock.Owin.Mappers
|
||||
SetResponseTrailingHeaders(responseMessage, response);
|
||||
}
|
||||
|
||||
private static async Task HandleSseStringAsync(IResponseMessage responseMessage, IResponse response, IBodyData bodyData)
|
||||
private static async Task HandleSseStringAsync(IResponseMessage responseMessage, HttpResponse response, IBodyData bodyData)
|
||||
{
|
||||
if (bodyData.SseStringQueue == null)
|
||||
{
|
||||
@@ -202,7 +194,7 @@ namespace WireMock.Owin.Mappers
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void SetResponseHeaders(IResponseMessage responseMessage, bool hasBody, IResponse response)
|
||||
private static void SetResponseHeaders(IResponseMessage responseMessage, bool hasBody, HttpResponse response)
|
||||
{
|
||||
// Force setting the Date header (#577)
|
||||
AppendResponseHeader(
|
||||
@@ -218,7 +210,7 @@ namespace WireMock.Owin.Mappers
|
||||
var value = item.Value;
|
||||
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
|
||||
{
|
||||
action?.Invoke(response, hasBody, value);
|
||||
action.Invoke(response, hasBody, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -231,7 +223,7 @@ namespace WireMock.Owin.Mappers
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetResponseTrailingHeaders(IResponseMessage responseMessage, IResponse response)
|
||||
private static void SetResponseTrailingHeaders(IResponseMessage responseMessage, HttpResponse response)
|
||||
{
|
||||
if (responseMessage.TrailingHeaders == null)
|
||||
{
|
||||
@@ -239,13 +231,11 @@ namespace WireMock.Owin.Mappers
|
||||
}
|
||||
|
||||
#if TRAILINGHEADERS
|
||||
foreach (var item in responseMessage.TrailingHeaders)
|
||||
foreach (var (headerName, value) in responseMessage.TrailingHeaders)
|
||||
{
|
||||
var headerName = item.Key;
|
||||
var value = item.Value;
|
||||
if (ResponseHeadersToFix.TryGetValue(headerName, out var action))
|
||||
{
|
||||
action?.Invoke(response, false, value);
|
||||
action.Invoke(response, false, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -259,13 +249,9 @@ namespace WireMock.Owin.Mappers
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void AppendResponseHeader(IResponse response, string headerName, string[] values)
|
||||
private static void AppendResponseHeader(HttpResponse response, string headerName, string[] values)
|
||||
{
|
||||
#if !USE_ASPNETCORE
|
||||
response.Headers.AppendValues(headerName, values);
|
||||
#else
|
||||
response.Headers.Append(headerName, values);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
using WireMock.Extensions;
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
using Microsoft.Owin.Hosting;
|
||||
using Owin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Owin.Mappers;
|
||||
using Stef.Validation;
|
||||
using WireMock.Services;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
|
||||
internal class OwinSelfHost : IOwinSelfHost
|
||||
{
|
||||
private readonly IWireMockMiddlewareOptions _options;
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
private readonly IWireMockLogger _logger;
|
||||
|
||||
private Exception? _runningException;
|
||||
|
||||
public OwinSelfHost(IWireMockMiddlewareOptions options, HostUrlOptions urlOptions)
|
||||
{
|
||||
Guard.NotNull(urlOptions);
|
||||
|
||||
_options = Guard.NotNull(options);
|
||||
_logger = options.Logger ?? new WireMockConsoleLogger();
|
||||
|
||||
foreach (var detail in urlOptions.GetDetails())
|
||||
{
|
||||
Urls.Add(detail.Url);
|
||||
Ports.Add(detail.Port);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsStarted { get; private set; }
|
||||
|
||||
public List<string> Urls { get; } = new();
|
||||
|
||||
public List<int> Ports { get; } = new();
|
||||
|
||||
public Exception? RunningException => _runningException;
|
||||
|
||||
[PublicAPI]
|
||||
public Task StartAsync()
|
||||
{
|
||||
return Task.Run(StartServers, _cts.Token);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public Task StopAsync()
|
||||
{
|
||||
_cts.Cancel();
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void StartServers()
|
||||
{
|
||||
#if NET46
|
||||
_logger.Info("Server using .net 4.6");
|
||||
#else
|
||||
_logger.Info("Server using .net 4.5.x");
|
||||
#endif
|
||||
var servers = new List<IDisposable>();
|
||||
|
||||
try
|
||||
{
|
||||
var requestMapper = new OwinRequestMapper();
|
||||
var responseMapper = new OwinResponseMapper(_options);
|
||||
var matcher = new MappingMatcher(_options, new RandomizerDoubleBetween0And1());
|
||||
var guidUtils = new GuidUtils();
|
||||
|
||||
Action<IAppBuilder> startup = app =>
|
||||
{
|
||||
app.Use<GlobalExceptionMiddleware>(_options, responseMapper);
|
||||
_options.PreWireMockMiddlewareInit?.Invoke(app);
|
||||
app.Use<WireMockMiddleware>(_options, requestMapper, responseMapper, matcher, guidUtils);
|
||||
_options.PostWireMockMiddlewareInit?.Invoke(app);
|
||||
};
|
||||
|
||||
foreach (var url in Urls)
|
||||
{
|
||||
servers.Add(WebApp.Start(url, startup));
|
||||
}
|
||||
|
||||
IsStarted = true;
|
||||
|
||||
// WaitHandle is signaled when the token is cancelled,
|
||||
// which will be more efficient than Thread.Sleep in while loop
|
||||
_cts.Token.WaitHandle.WaitOne();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Expose exception of starting host, otherwise it's hard to be troubleshooting if keeping quiet
|
||||
// For example, WebApp.Start will fail with System.MissingMemberException if Microsoft.Owin.Host.HttpListener.dll is being located
|
||||
// https://stackoverflow.com/questions/25090211/owin-httplistener-not-located/31369857
|
||||
_runningException = e;
|
||||
_logger.Error(e.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsStarted = false;
|
||||
// Dispose all servers in finally block to make sure clean up allocated resource on error happening
|
||||
servers.ForEach(s => s.Dispose());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,415 +1,252 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using Stef.Validation;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Http;
|
||||
using WireMock.Owin.Mappers;
|
||||
using WireMock.Serialization;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Settings;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using WireMock.Constants;
|
||||
using WireMock.Exceptions;
|
||||
using WireMock.Util;
|
||||
#if ACTIVITY_TRACING_SUPPORTED
|
||||
using System.Diagnostics;
|
||||
using WireMock.Http;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Owin.ActivityTracing;
|
||||
#endif
|
||||
#if !USE_ASPNETCORE
|
||||
using IContext = Microsoft.Owin.IOwinContext;
|
||||
using OwinMiddleware = Microsoft.Owin.OwinMiddleware;
|
||||
using Next = Microsoft.Owin.OwinMiddleware;
|
||||
#else
|
||||
using OwinMiddleware = System.Object;
|
||||
using IContext = Microsoft.AspNetCore.Http.HttpContext;
|
||||
using Next = Microsoft.AspNetCore.Http.RequestDelegate;
|
||||
#endif
|
||||
using WireMock.Owin.Mappers;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Serialization;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Owin
|
||||
namespace WireMock.Owin;
|
||||
|
||||
internal class WireMockMiddleware(
|
||||
#pragma warning disable CS9113 // Parameter is unread.
|
||||
RequestDelegate next,
|
||||
#pragma warning restore CS9113 // Parameter is unread.
|
||||
IWireMockMiddlewareOptions options,
|
||||
IOwinRequestMapper requestMapper,
|
||||
IOwinResponseMapper responseMapper,
|
||||
IMappingMatcher mappingMatcher,
|
||||
IWireMockMiddlewareLogger logger,
|
||||
IGuidUtils guidUtils,
|
||||
IDateTimeUtils dateTimeUtils
|
||||
)
|
||||
{
|
||||
internal class WireMockMiddleware : OwinMiddleware
|
||||
private readonly object _lock = new();
|
||||
|
||||
public Task Invoke(HttpContext ctx)
|
||||
{
|
||||
private readonly object _lock = new();
|
||||
private static readonly Task CompletedTask = Task.FromResult(false);
|
||||
|
||||
private readonly IWireMockMiddlewareOptions _options;
|
||||
private readonly IOwinRequestMapper _requestMapper;
|
||||
private readonly IOwinResponseMapper _responseMapper;
|
||||
private readonly IMappingMatcher _mappingMatcher;
|
||||
private readonly LogEntryMapper _logEntryMapper;
|
||||
private readonly IGuidUtils _guidUtils;
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
public WireMockMiddleware(
|
||||
Next next,
|
||||
IWireMockMiddlewareOptions options,
|
||||
IOwinRequestMapper requestMapper,
|
||||
IOwinResponseMapper responseMapper,
|
||||
IMappingMatcher mappingMatcher,
|
||||
IGuidUtils guidUtils
|
||||
) : base(next)
|
||||
if (options.HandleRequestsSynchronously.GetValueOrDefault(false))
|
||||
{
|
||||
_options = Guard.NotNull(options);
|
||||
_requestMapper = Guard.NotNull(requestMapper);
|
||||
_responseMapper = Guard.NotNull(responseMapper);
|
||||
_mappingMatcher = Guard.NotNull(mappingMatcher);
|
||||
_logEntryMapper = new LogEntryMapper(options);
|
||||
_guidUtils = Guard.NotNull(guidUtils);
|
||||
}
|
||||
#else
|
||||
public WireMockMiddleware(
|
||||
Next next,
|
||||
IWireMockMiddlewareOptions options,
|
||||
IOwinRequestMapper requestMapper,
|
||||
IOwinResponseMapper responseMapper,
|
||||
IMappingMatcher mappingMatcher,
|
||||
IGuidUtils guidUtils
|
||||
)
|
||||
{
|
||||
_options = Guard.NotNull(options);
|
||||
_requestMapper = Guard.NotNull(requestMapper);
|
||||
_responseMapper = Guard.NotNull(responseMapper);
|
||||
_mappingMatcher = Guard.NotNull(mappingMatcher);
|
||||
_logEntryMapper = new LogEntryMapper(options);
|
||||
_guidUtils = Guard.NotNull(guidUtils);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
public override Task Invoke(IContext ctx)
|
||||
#else
|
||||
public Task Invoke(IContext ctx)
|
||||
#endif
|
||||
{
|
||||
if (_options.HandleRequestsSynchronously.GetValueOrDefault(false))
|
||||
lock (_lock)
|
||||
{
|
||||
lock (_lock)
|
||||
return InvokeInternalAsync(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
return InvokeInternalAsync(ctx);
|
||||
}
|
||||
|
||||
private async Task InvokeInternalAsync(HttpContext ctx)
|
||||
{
|
||||
// Store options in HttpContext for providers to access (e.g., WebSocketResponseProvider)
|
||||
ctx.Items[nameof(IWireMockMiddlewareOptions)] = options;
|
||||
ctx.Items[nameof(IWireMockMiddlewareLogger)] = logger;
|
||||
ctx.Items[nameof(IGuidUtils)] = guidUtils;
|
||||
ctx.Items[nameof(IDateTimeUtils)] = dateTimeUtils;
|
||||
|
||||
var request = await requestMapper.MapAsync(ctx, options).ConfigureAwait(false);
|
||||
|
||||
var logRequest = false;
|
||||
IResponseMessage? response = null;
|
||||
(MappingMatcherResult? Match, MappingMatcherResult? Partial) result = (null, null);
|
||||
|
||||
var tracingEnabled = options.ActivityTracingOptions is not null;
|
||||
var excludeAdmin = options.ActivityTracingOptions?.ExcludeAdminRequests ?? true;
|
||||
Activity? activity = null;
|
||||
|
||||
// Check if we should trace this request (optionally exclude admin requests)
|
||||
var shouldTrace = tracingEnabled && !(excludeAdmin && request.Path.StartsWith("/__admin/"));
|
||||
|
||||
if (shouldTrace)
|
||||
{
|
||||
activity = WireMockActivitySource.StartRequestActivity(request.Method, request.Path);
|
||||
WireMockActivitySource.EnrichWithRequest(activity, request, options.ActivityTracingOptions);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var mapping in options.Mappings.Values)
|
||||
{
|
||||
if (mapping.Scenario is null)
|
||||
{
|
||||
return InvokeInternalAsync(ctx);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set scenario start
|
||||
if (!options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
|
||||
{
|
||||
options.Scenarios.TryAdd(mapping.Scenario, new ScenarioState
|
||||
{
|
||||
Name = mapping.Scenario
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return InvokeInternalAsync(ctx);
|
||||
}
|
||||
result = mappingMatcher.FindBestMatch(request);
|
||||
|
||||
private async Task InvokeInternalAsync(IContext ctx)
|
||||
{
|
||||
var request = await _requestMapper.MapAsync(ctx.Request, _options).ConfigureAwait(false);
|
||||
|
||||
#if ACTIVITY_TRACING_SUPPORTED
|
||||
// Start activity if ActivityTracingOptions is configured
|
||||
var tracingEnabled = _options.ActivityTracingOptions is not null;
|
||||
var excludeAdmin = _options.ActivityTracingOptions?.ExcludeAdminRequests ?? true;
|
||||
Activity? activity = null;
|
||||
|
||||
// Check if we should trace this request (optionally exclude admin requests)
|
||||
var shouldTrace = tracingEnabled && !(excludeAdmin && request.Path.StartsWith("/__admin/"));
|
||||
|
||||
if (shouldTrace)
|
||||
var targetMapping = result.Match?.Mapping;
|
||||
if (targetMapping == null)
|
||||
{
|
||||
activity = WireMockActivitySource.StartRequestActivity(request.Method, request.Path);
|
||||
WireMockActivitySource.EnrichWithRequest(activity, request, _options.ActivityTracingOptions);
|
||||
logRequest = true;
|
||||
options.Logger.Warn("HttpStatusCode set to 404 : No matching mapping found");
|
||||
response = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await InvokeInternalCoreAsync(ctx, request, activity).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
activity?.Dispose();
|
||||
}
|
||||
#else
|
||||
await InvokeInternalCoreAsync(ctx, request).ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
logRequest = targetMapping.LogMapping;
|
||||
|
||||
#if ACTIVITY_TRACING_SUPPORTED
|
||||
private async Task InvokeInternalCoreAsync(IContext ctx, RequestMessage request, Activity? activity)
|
||||
#else
|
||||
private async Task InvokeInternalCoreAsync(IContext ctx, RequestMessage request)
|
||||
#endif
|
||||
{
|
||||
var logRequest = false;
|
||||
IResponseMessage? response = null;
|
||||
(MappingMatcherResult? Match, MappingMatcherResult? Partial) result = (null, null);
|
||||
|
||||
try
|
||||
if (targetMapping.IsAdminInterface && options.AuthenticationMatcher != null && request.Headers != null)
|
||||
{
|
||||
foreach (var mapping in _options.Mappings.Values)
|
||||
var authorizationHeaderPresent = request.Headers.TryGetValue(HttpKnownHeaderNames.Authorization, out var authorization);
|
||||
if (!authorizationHeaderPresent)
|
||||
{
|
||||
if (mapping.Scenario is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set scenario start
|
||||
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
|
||||
{
|
||||
_options.Scenarios.TryAdd(mapping.Scenario, new ScenarioState
|
||||
{
|
||||
Name = mapping.Scenario
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
result = _mappingMatcher.FindBestMatch(request);
|
||||
|
||||
var targetMapping = result.Match?.Mapping;
|
||||
if (targetMapping == null)
|
||||
{
|
||||
logRequest = true;
|
||||
_options.Logger.Warn("HttpStatusCode set to 404 : No matching mapping found");
|
||||
response = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound);
|
||||
options.Logger.Error("HttpStatusCode set to 401, authorization header is missing.");
|
||||
response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null);
|
||||
return;
|
||||
}
|
||||
|
||||
logRequest = targetMapping.LogMapping;
|
||||
|
||||
if (targetMapping.IsAdminInterface && _options.AuthenticationMatcher != null && request.Headers != null)
|
||||
var authorizationHeaderMatchResult = options.AuthenticationMatcher.IsMatch(authorization!.ToString());
|
||||
if (!MatchScores.IsPerfect(authorizationHeaderMatchResult.Score))
|
||||
{
|
||||
var authorizationHeaderPresent = request.Headers.TryGetValue(HttpKnownHeaderNames.Authorization, out var authorization);
|
||||
if (!authorizationHeaderPresent)
|
||||
{
|
||||
_options.Logger.Error("HttpStatusCode set to 401, authorization header is missing.");
|
||||
response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null);
|
||||
return;
|
||||
}
|
||||
options.Logger.Error("HttpStatusCode set to 401, authentication failed.", authorizationHeaderMatchResult.Exception ?? throw new WireMockException("Authentication failed"));
|
||||
response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var authorizationHeaderMatchResult = _options.AuthenticationMatcher.IsMatch(authorization!.ToString());
|
||||
if (!MatchScores.IsPerfect(authorizationHeaderMatchResult.Score))
|
||||
{
|
||||
_options.Logger.Error("HttpStatusCode set to 401, authentication failed.", authorizationHeaderMatchResult.Exception ?? throw new WireMockException("Authentication failed"));
|
||||
response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null);
|
||||
return;
|
||||
}
|
||||
if (!targetMapping.IsAdminInterface && options.RequestProcessingDelay > TimeSpan.Zero)
|
||||
{
|
||||
await Task.Delay(options.RequestProcessingDelay.Value).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var (theResponse, theOptionalNewMapping) = await targetMapping.ProvideResponseAsync(ctx, request).ConfigureAwait(false);
|
||||
response = theResponse;
|
||||
|
||||
if (targetMapping.Provider is Response responseBuilder && !targetMapping.IsAdminInterface && theOptionalNewMapping != null)
|
||||
{
|
||||
if (responseBuilder?.ProxyAndRecordSettings?.SaveMapping == true || targetMapping.Settings.ProxyAndRecordSettings?.SaveMapping == true)
|
||||
{
|
||||
options.Mappings.TryAdd(theOptionalNewMapping.Guid, theOptionalNewMapping);
|
||||
}
|
||||
|
||||
if (!targetMapping.IsAdminInterface && _options.RequestProcessingDelay > TimeSpan.Zero)
|
||||
if (responseBuilder?.ProxyAndRecordSettings?.SaveMappingToFile == true || targetMapping.Settings.ProxyAndRecordSettings?.SaveMappingToFile == true)
|
||||
{
|
||||
await Task.Delay(_options.RequestProcessingDelay.Value).ConfigureAwait(false);
|
||||
var matcherMapper = new MatcherMapper(targetMapping.Settings);
|
||||
var mappingConverter = new MappingConverter(matcherMapper);
|
||||
var mappingToFileSaver = new MappingToFileSaver(targetMapping.Settings, mappingConverter);
|
||||
|
||||
mappingToFileSaver.SaveMappingToFile(theOptionalNewMapping);
|
||||
}
|
||||
}
|
||||
|
||||
var (theResponse, theOptionalNewMapping) = await targetMapping.ProvideResponseAsync(request).ConfigureAwait(false);
|
||||
response = theResponse;
|
||||
if (targetMapping.Scenario != null)
|
||||
{
|
||||
UpdateScenarioState(targetMapping);
|
||||
}
|
||||
|
||||
var responseBuilder = targetMapping.Provider as Response;
|
||||
if (!targetMapping.IsAdminInterface && targetMapping.Webhooks?.Length > 0)
|
||||
{
|
||||
await SendToWebhooksAsync(targetMapping, request, response).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
options.Logger.Error($"Providing a Response for Mapping '{result.Match?.Mapping.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}");
|
||||
WireMockActivitySource.RecordException(activity, ex);
|
||||
|
||||
if (!targetMapping.IsAdminInterface && theOptionalNewMapping != null)
|
||||
{
|
||||
if (responseBuilder?.ProxyAndRecordSettings?.SaveMapping == true || targetMapping.Settings.ProxyAndRecordSettings?.SaveMapping == true)
|
||||
{
|
||||
_options.Mappings.TryAdd(theOptionalNewMapping.Guid, theOptionalNewMapping);
|
||||
}
|
||||
response = ResponseMessageBuilder.Create(500, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
logger.LogRequestAndResponse(logRequest, request, response, result.Match, result.Partial, activity);
|
||||
|
||||
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(theOptionalNewMapping);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetMapping.Scenario != null)
|
||||
{
|
||||
UpdateScenarioState(targetMapping);
|
||||
}
|
||||
|
||||
if (!targetMapping.IsAdminInterface && targetMapping.Webhooks?.Length > 0)
|
||||
{
|
||||
await SendToWebhooksAsync(targetMapping, request, response).ConfigureAwait(false);
|
||||
}
|
||||
try
|
||||
{
|
||||
await responseMapper.MapAsync(response, ctx.Response).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_options.Logger.Error($"Providing a Response for Mapping '{result.Match?.Mapping.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}");
|
||||
response = ResponseMessageBuilder.Create(500, ex.Message);
|
||||
options.Logger.Error("HttpStatusCode set to 404 : No matching mapping found", ex);
|
||||
|
||||
#if ACTIVITY_TRACING_SUPPORTED
|
||||
WireMockActivitySource.RecordException(activity, ex);
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
{
|
||||
var log = new LogEntry
|
||||
{
|
||||
Guid = _guidUtils.NewGuid(),
|
||||
RequestMessage = request,
|
||||
ResponseMessage = response,
|
||||
|
||||
MappingGuid = result.Match?.Mapping?.Guid,
|
||||
MappingTitle = result.Match?.Mapping?.Title,
|
||||
RequestMatchResult = result.Match?.RequestMatchResult,
|
||||
|
||||
PartialMappingGuid = result.Partial?.Mapping?.Guid,
|
||||
PartialMappingTitle = result.Partial?.Mapping?.Title,
|
||||
PartialMatchResult = result.Partial?.RequestMatchResult
|
||||
};
|
||||
|
||||
#if ACTIVITY_TRACING_SUPPORTED
|
||||
// Enrich activity with response and mapping info
|
||||
WireMockActivitySource.EnrichWithLogEntry(activity, log, _options.ActivityTracingOptions);
|
||||
#endif
|
||||
|
||||
LogRequest(log, logRequest);
|
||||
|
||||
try
|
||||
{
|
||||
if (_options.SaveUnmatchedRequests == true && result.Match?.RequestMatchResult is not { IsPerfectMatch: true })
|
||||
{
|
||||
var filename = $"{log.Guid}.LogEntry.json";
|
||||
_options.FileSystemHandler?.WriteUnmatchedRequest(filename, JsonUtils.Serialize(log));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Empty catch
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _responseMapper.MapAsync(response, ctx.Response).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_options.Logger.Error("HttpStatusCode set to 404 : No matching mapping found", ex);
|
||||
|
||||
var notFoundResponse = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound);
|
||||
await _responseMapper.MapAsync(notFoundResponse, ctx.Response).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
await CompletedTask.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task SendToWebhooksAsync(IMapping mapping, IRequestMessage request, IResponseMessage response)
|
||||
{
|
||||
var tasks = new List<Func<Task>>();
|
||||
for (int index = 0; index < mapping.Webhooks?.Length; index++)
|
||||
{
|
||||
var httpClientForWebhook = HttpClientBuilder.Build(mapping.Settings.WebhookSettings ?? new WebhookSettings());
|
||||
var webhookSender = new WebhookSender(mapping.Settings);
|
||||
var webhookRequest = mapping.Webhooks[index].Request;
|
||||
var webHookIndex = index;
|
||||
|
||||
tasks.Add(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await webhookSender.SendAsync(httpClientForWebhook, mapping, webhookRequest, request, response).ConfigureAwait(false);
|
||||
if (!result.IsSuccessStatusCode)
|
||||
{
|
||||
var content = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
_options.Logger.Warn($"Sending message to Webhook [{webHookIndex}] from Mapping '{mapping.Guid}' failed. HttpStatusCode: {result.StatusCode} Content: {content}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_options.Logger.Error($"Sending message to Webhook [{webHookIndex}] from Mapping '{mapping.Guid}' failed. Exception: {ex}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (mapping.UseWebhooksFireAndForget == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Do not wait
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Task.WhenAll(tasks.Select(async task => await task.Invoke())).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.WhenAll(tasks.Select(async task => await task.Invoke())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateScenarioState(IMapping mapping)
|
||||
{
|
||||
var scenario = _options.Scenarios[mapping.Scenario!];
|
||||
|
||||
// Increase the number of times this state has been executed
|
||||
scenario.Counter++;
|
||||
|
||||
// Only if the number of times this state is executed equals the required StateTimes, proceed to next state and reset the counter to 0
|
||||
if (scenario.Counter == (mapping.TimesInSameState ?? 1))
|
||||
{
|
||||
scenario.NextState = mapping.NextState;
|
||||
scenario.Counter = 0;
|
||||
}
|
||||
|
||||
// Else just update Started and Finished
|
||||
scenario.Started = true;
|
||||
scenario.Finished = mapping.NextState == null;
|
||||
}
|
||||
|
||||
private void LogRequest(LogEntry entry, bool addRequest)
|
||||
{
|
||||
_options.Logger.DebugRequestResponse(_logEntryMapper.Map(entry), entry.RequestMessage.Path.StartsWith("/__admin/"));
|
||||
|
||||
// If addRequest is set to true and MaxRequestLogCount is null or does have a value greater than 0, try to add a new request log.
|
||||
if (addRequest && _options.MaxRequestLogCount is null or > 0)
|
||||
{
|
||||
TryAddLogEntry(entry);
|
||||
}
|
||||
|
||||
// In case MaxRequestLogCount has a value greater than 0, try to delete existing request logs based on the count.
|
||||
if (_options.MaxRequestLogCount is > 0)
|
||||
{
|
||||
var logEntries = _options.LogEntries.ToList();
|
||||
foreach (var logEntry in logEntries.OrderBy(le => le.RequestMessage.DateTime).Take(logEntries.Count - _options.MaxRequestLogCount.Value))
|
||||
{
|
||||
TryRemoveLogEntry(logEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// In case RequestLogExpirationDuration has a value greater than 0, try to delete existing request logs based on the date.
|
||||
if (_options.RequestLogExpirationDuration is > 0)
|
||||
{
|
||||
var checkTime = DateTime.UtcNow.AddHours(-_options.RequestLogExpirationDuration.Value);
|
||||
foreach (var logEntry in _options.LogEntries.ToList().Where(le => le.RequestMessage.DateTime < checkTime))
|
||||
{
|
||||
TryRemoveLogEntry(logEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TryAddLogEntry(LogEntry logEntry)
|
||||
{
|
||||
try
|
||||
{
|
||||
_options.LogEntries.Add(logEntry);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore exception (can happen during stress testing)
|
||||
}
|
||||
}
|
||||
|
||||
private void TryRemoveLogEntry(LogEntry logEntry)
|
||||
{
|
||||
try
|
||||
{
|
||||
_options.LogEntries.Remove(logEntry);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore exception (can happen during stress testing)
|
||||
var notFoundResponse = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound);
|
||||
await responseMapper.MapAsync(notFoundResponse, ctx.Response).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendToWebhooksAsync(IMapping mapping, IRequestMessage request, IResponseMessage response)
|
||||
{
|
||||
var tasks = new List<Func<Task>>();
|
||||
for (int index = 0; index < mapping.Webhooks?.Length; index++)
|
||||
{
|
||||
var httpClientForWebhook = HttpClientBuilder.Build(mapping.Settings.WebhookSettings ?? new WebhookSettings());
|
||||
var webhookSender = new WebhookSender(mapping.Settings);
|
||||
var webhookRequest = mapping.Webhooks[index].Request;
|
||||
var webHookIndex = index;
|
||||
|
||||
tasks.Add(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await webhookSender.SendAsync(httpClientForWebhook, mapping, webhookRequest, request, response).ConfigureAwait(false);
|
||||
if (!result.IsSuccessStatusCode)
|
||||
{
|
||||
var content = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
options.Logger.Warn($"Sending message to Webhook [{webHookIndex}] from Mapping '{mapping.Guid}' failed. HttpStatusCode: {result.StatusCode} Content: {content}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
options.Logger.Error($"Sending message to Webhook [{webHookIndex}] from Mapping '{mapping.Guid}' failed. Exception: {ex}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (mapping.UseWebhooksFireAndForget == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Do not wait
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Task.WhenAll(tasks.Select(async task => await task.Invoke())).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.WhenAll(tasks.Select(async task => await task.Invoke())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateScenarioState(IMapping mapping)
|
||||
{
|
||||
var scenario = options.Scenarios[mapping.Scenario!];
|
||||
|
||||
// Increase the number of times this state has been executed
|
||||
scenario.Counter++;
|
||||
|
||||
// Only if the number of times this state is executed equals the required StateTimes, proceed to next state and reset the counter to 0
|
||||
if (scenario.Counter == (mapping.TimesInSameState ?? 1))
|
||||
{
|
||||
scenario.NextState = mapping.NextState;
|
||||
scenario.Counter = 0;
|
||||
}
|
||||
|
||||
// Else just update Started and Finished
|
||||
scenario.Started = true;
|
||||
scenario.Finished = mapping.NextState == null;
|
||||
}
|
||||
}
|
||||
114
src/WireMock.Net.Minimal/Owin/WireMockMiddlewareLogger.cs
Normal file
114
src/WireMock.Net.Minimal/Owin/WireMockMiddlewareLogger.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Owin.ActivityTracing;
|
||||
using WireMock.Serialization;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
|
||||
internal class WireMockMiddlewareLogger(
|
||||
IWireMockMiddlewareOptions _options,
|
||||
LogEntryMapper _logEntryMapper,
|
||||
IGuidUtils _guidUtils
|
||||
) : IWireMockMiddlewareLogger
|
||||
{
|
||||
public void LogRequestAndResponse(bool logRequest, RequestMessage request, IResponseMessage? response, MappingMatcherResult? match, MappingMatcherResult? partialMatch, Activity? activity)
|
||||
{
|
||||
var logEntry = new LogEntry
|
||||
{
|
||||
Guid = _guidUtils.NewGuid(),
|
||||
RequestMessage = request,
|
||||
ResponseMessage = response,
|
||||
|
||||
MappingGuid = match?.Mapping?.Guid,
|
||||
MappingTitle = match?.Mapping?.Title,
|
||||
RequestMatchResult = match?.RequestMatchResult,
|
||||
|
||||
PartialMappingGuid = partialMatch?.Mapping?.Guid,
|
||||
PartialMappingTitle = partialMatch?.Mapping?.Title,
|
||||
PartialMatchResult = partialMatch?.RequestMatchResult
|
||||
};
|
||||
|
||||
WireMockActivitySource.EnrichWithLogEntry(activity, logEntry, _options.ActivityTracingOptions);
|
||||
activity?.Dispose();
|
||||
|
||||
LogLogEntry(logEntry, logRequest);
|
||||
|
||||
try
|
||||
{
|
||||
if (_options.SaveUnmatchedRequests == true && match?.RequestMatchResult is not { IsPerfectMatch: true })
|
||||
{
|
||||
var filename = $"{logEntry.Guid}.LogEntry.json";
|
||||
_options.FileSystemHandler?.WriteUnmatchedRequest(filename, JsonUtils.Serialize(logEntry));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Empty catch
|
||||
}
|
||||
}
|
||||
|
||||
public void LogLogEntry(LogEntry entry, bool addRequest)
|
||||
{
|
||||
_options.Logger.DebugRequestResponse(_logEntryMapper.Map(entry), entry.RequestMessage?.Path.StartsWith("/__admin/") == true);
|
||||
|
||||
// If addRequest is set to true and MaxRequestLogCount is null or does have a value greater than 0, try to add a new request log.
|
||||
if (addRequest && _options.MaxRequestLogCount is null or > 0)
|
||||
{
|
||||
TryAddLogEntry(entry);
|
||||
}
|
||||
|
||||
|
||||
// In case MaxRequestLogCount has a value greater than 0, try to delete existing request logs based on the count.
|
||||
if (_options.MaxRequestLogCount is > 0)
|
||||
{
|
||||
var logEntries = _options.LogEntries.ToList();
|
||||
|
||||
foreach (var logEntry in logEntries
|
||||
.OrderBy(le => le.RequestMessage?.DateTime ?? le.ResponseMessage?.DateTime)
|
||||
.Take(logEntries.Count - _options.MaxRequestLogCount.Value))
|
||||
{
|
||||
TryRemoveLogEntry(logEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// In case RequestLogExpirationDuration has a value greater than 0, try to delete existing request logs based on the date.
|
||||
if (_options.RequestLogExpirationDuration is > 0)
|
||||
{
|
||||
var logEntries = _options.LogEntries.ToList();
|
||||
|
||||
var checkTime = DateTime.UtcNow.AddHours(-_options.RequestLogExpirationDuration.Value);
|
||||
foreach (var logEntry in logEntries.Where(le => le.RequestMessage?.DateTime < checkTime || le.ResponseMessage?.DateTime < checkTime))
|
||||
{
|
||||
TryRemoveLogEntry(logEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TryAddLogEntry(LogEntry logEntry)
|
||||
{
|
||||
try
|
||||
{
|
||||
_options.LogEntries.Add(logEntry);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore exception (can happen during stress testing)
|
||||
}
|
||||
}
|
||||
|
||||
private void TryRemoveLogEntry(LogEntry logEntry)
|
||||
{
|
||||
try
|
||||
{
|
||||
_options.LogEntries.Remove(logEntry);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore exception (can happen during stress testing)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,23 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Owin.ActivityTracing;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
#if !USE_ASPNETCORE
|
||||
using Owin;
|
||||
#else
|
||||
using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
#endif
|
||||
using WireMock.WebSockets;
|
||||
using ClientCertificateMode = Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
|
||||
internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
|
||||
{
|
||||
public IWireMockLogger Logger { get; set; }
|
||||
public IWireMockLogger Logger { get; set; } = new WireMockConsoleLogger();
|
||||
|
||||
public TimeSpan? RequestProcessingDelay { get; set; }
|
||||
|
||||
@@ -39,11 +35,10 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
|
||||
|
||||
public int? MaxRequestLogCount { get; set; }
|
||||
|
||||
public Action<IAppBuilder>? PreWireMockMiddlewareInit { get; set; }
|
||||
public Action<IApplicationBuilder>? PreWireMockMiddlewareInit { get; set; }
|
||||
|
||||
public Action<IAppBuilder>? PostWireMockMiddlewareInit { get; set; }
|
||||
public Action<IApplicationBuilder>? PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
public Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
|
||||
|
||||
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
|
||||
@@ -52,7 +47,6 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool AcceptAnyClientCertificate { get; set; }
|
||||
#endif
|
||||
|
||||
/// <inheritdoc cref="IWireMockMiddlewareOptions.FileSystemHandler"/>
|
||||
public IFileSystemHandler? FileSystemHandler { get; set; }
|
||||
@@ -108,8 +102,11 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
|
||||
/// <inheritdoc />
|
||||
public bool ProxyAll { get; set; }
|
||||
|
||||
#if ACTIVITY_TRACING_SUPPORTED
|
||||
/// <inheritdoc />
|
||||
public ActivityTracingOptions? ActivityTracingOptions { get; set; }
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConcurrentDictionary<Guid, WebSocketConnectionRegistry> WebSocketRegistries { get; } = new();
|
||||
|
||||
public WebSocketSettings? WebSocketSettings { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using Stef.Validation;
|
||||
using WireMock.Owin.ActivityTracing;
|
||||
using WireMock.Settings;
|
||||
|
||||
namespace WireMock.Owin;
|
||||
@@ -19,6 +17,7 @@ internal static class WireMockMiddlewareOptionsHelper
|
||||
|
||||
options ??= new WireMockMiddlewareOptions();
|
||||
|
||||
options.ActivityTracingOptions = settings.ActivityTracingOptions;
|
||||
options.AllowBodyForAllHttpMethods = settings.AllowBodyForAllHttpMethods;
|
||||
options.AllowOnlyDefinedHttpStatusCodeInResponse = settings.AllowOnlyDefinedHttpStatusCodeInResponse;
|
||||
options.AllowPartialMapping = settings.AllowPartialMapping;
|
||||
@@ -35,20 +34,6 @@ internal static class WireMockMiddlewareOptionsHelper
|
||||
options.RequestLogExpirationDuration = settings.RequestLogExpirationDuration;
|
||||
options.SaveUnmatchedRequests = settings.SaveUnmatchedRequests;
|
||||
|
||||
// Validate and configure activity tracing
|
||||
ActivityTracingValidator.ValidateActivityApiPresence(settings);
|
||||
#if ACTIVITY_TRACING_SUPPORTED
|
||||
if (settings.ActivityTracingOptions is not null)
|
||||
{
|
||||
options.ActivityTracingOptions = new Owin.ActivityTracing.ActivityTracingOptions
|
||||
{
|
||||
ExcludeAdminRequests = settings.ActivityTracingOptions.ExcludeAdminRequests,
|
||||
RecordRequestBody = settings.ActivityTracingOptions.RecordRequestBody,
|
||||
RecordResponseBody = settings.ActivityTracingOptions.RecordResponseBody,
|
||||
RecordMatchDetails = settings.ActivityTracingOptions.RecordMatchDetails
|
||||
};
|
||||
}
|
||||
#endif
|
||||
#if USE_ASPNETCORE
|
||||
options.AdditionalServiceRegistration = settings.AdditionalServiceRegistration;
|
||||
options.CorsPolicyOptions = settings.CorsPolicyOptions;
|
||||
|
||||
@@ -5,11 +5,11 @@ namespace WireMock.Pact.Models.V2;
|
||||
|
||||
public class Interaction
|
||||
{
|
||||
public string? Description { get; set; }
|
||||
public required string Description { get; set; }
|
||||
|
||||
public string? ProviderState { get; set; }
|
||||
|
||||
public PactRequest Request { get; set; } = new();
|
||||
public required PactRequest Request { get; set; }
|
||||
|
||||
public PactResponse Response { get; set; } = new();
|
||||
public required PactResponse Response { get; set; }
|
||||
}
|
||||
@@ -8,20 +8,20 @@ public class MatchingRule
|
||||
/// <summary>
|
||||
/// type or regex
|
||||
/// </summary>
|
||||
public string Match { get; set; } = "type";
|
||||
public required string Match { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used for Match = "type"
|
||||
/// </summary>
|
||||
public string Min { get; set; }
|
||||
public string? Min { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used for Match = "type"
|
||||
/// </summary>
|
||||
public string Max { get; set; }
|
||||
public string? Max { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used for Match = "regex"
|
||||
/// </summary>
|
||||
public string Regex { get; set; }
|
||||
public string? Regex { get; set; }
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace WireMock.Pact.Models.V2;
|
||||
|
||||
public class Metadata
|
||||
{
|
||||
public string PactSpecificationVersion { get; set; }
|
||||
public required string PactSpecificationVersion { get; set; }
|
||||
|
||||
public PactSpecification PactSpecification { get; set; } = new PactSpecification();
|
||||
public required PactSpecification PactSpecification { get; set; }
|
||||
}
|
||||
@@ -1,17 +1,15 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#pragma warning disable CS1591
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WireMock.Pact.Models.V2;
|
||||
|
||||
public class Pact
|
||||
{
|
||||
public Pacticipant Consumer { get; set; }
|
||||
public required Pacticipant Consumer { get; set; }
|
||||
|
||||
public List<Interaction> Interactions { get; set; } = new List<Interaction>();
|
||||
public required List<Interaction> Interactions { get; set; } = [];
|
||||
|
||||
public Metadata Metadata { get; set; }
|
||||
public Metadata? Metadata { get; set; }
|
||||
|
||||
public Pacticipant Provider { get; set; }
|
||||
public required Pacticipant Provider { get; set; }
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#pragma warning disable CS1591
|
||||
using System.Collections.Generic;
|
||||
using WireMock.Constants;
|
||||
|
||||
namespace WireMock.Pact.Models.V2;
|
||||
@@ -10,9 +9,9 @@ public class PactRequest
|
||||
{
|
||||
public IDictionary<string, string>? Headers { get; set; }
|
||||
|
||||
public string Method { get; set; } = HttpRequestMethod.GET;
|
||||
public required string Method { get; set; } = HttpRequestMethod.GET;
|
||||
|
||||
public string? Path { get; set; } = "/";
|
||||
public required string Path { get; set; } = "/";
|
||||
|
||||
public string? Query { get; set; }
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#pragma warning disable CS1591
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WireMock.Pact.Models.V2;
|
||||
|
||||
public class PactResponse
|
||||
@@ -11,5 +9,5 @@ public class PactResponse
|
||||
|
||||
public IDictionary<string, string>? Headers { get; set; }
|
||||
|
||||
public int Status { get; set; } = 200;
|
||||
public required int Status { get; set; }
|
||||
}
|
||||
@@ -5,9 +5,9 @@ namespace WireMock.Pact.Models.V2;
|
||||
|
||||
public class PactRust
|
||||
{
|
||||
public string Ffi { get; set; }
|
||||
public required string Ffi { get; set; }
|
||||
|
||||
public string Mockserver { get; set; }
|
||||
public required string Mockserver { get; set; }
|
||||
|
||||
public string Models { get; set; }
|
||||
public required string Models { get; set; }
|
||||
}
|
||||
@@ -5,5 +5,5 @@ namespace WireMock.Pact.Models.V2;
|
||||
|
||||
public class PactSpecification
|
||||
{
|
||||
public string Version { get; set; } = "2.0";
|
||||
public required string Version { get; set; } = "2.0";
|
||||
}
|
||||
@@ -5,5 +5,5 @@ namespace WireMock.Pact.Models.V2;
|
||||
|
||||
public class Pacticipant
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public required string Name { get; set; }
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
#pragma warning disable CS1591
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WireMock.Pact.Models.V2;
|
||||
|
||||
public class ProviderState
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public required string Name { get; set; }
|
||||
|
||||
public IDictionary<string, string> Params { get; set; }
|
||||
public IDictionary<string, string>? Params { get; set; }
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Stef.Validation;
|
||||
using WireMock.Http;
|
||||
using WireMock.Matchers;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Transformers;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using Stef.Validation;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using Stef.Validation;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using Stef.Validation;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using Stef.Validation;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Types;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using Stef.Validation;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using Stef.Validation;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Linq;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.RequestBuilders;
|
||||
|
||||
public partial class Request
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public bool IsWebSocket { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithWebSocketUpgrade(params string[] protocols)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageHeaderMatcher(
|
||||
MatchBehaviour.AcceptOnMatch,
|
||||
MatchOperator.Or,
|
||||
"Upgrade",
|
||||
true,
|
||||
new ExactMatcher(true, "websocket")
|
||||
));
|
||||
|
||||
_requestMatchers.Add(new RequestMessageHeaderMatcher(
|
||||
MatchBehaviour.AcceptOnMatch,
|
||||
MatchOperator.Or,
|
||||
"Connection",
|
||||
true,
|
||||
new WildcardMatcher("*Upgrade*", true)
|
||||
));
|
||||
|
||||
if (protocols.Length > 0)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageHeaderMatcher(
|
||||
MatchBehaviour.AcceptOnMatch,
|
||||
MatchOperator.Or,
|
||||
"Sec-WebSocket-Protocol",
|
||||
true,
|
||||
protocols.Select(p => new ExactMatcher(true, p)).ToArray()
|
||||
));
|
||||
}
|
||||
|
||||
IsWebSocket = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
|
||||
// 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
#if USE_ASPNETCORE
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
#endif
|
||||
using System.Text.Json.Serialization;
|
||||
using Stef.Validation;
|
||||
using WireMock.Models;
|
||||
using WireMock.Owin;
|
||||
@@ -82,11 +79,10 @@ public class RequestMessage : IRequestMessage
|
||||
/// <inheritdoc />
|
||||
public byte[]? BodyAsBytes { get; }
|
||||
|
||||
#if MIMEKIT
|
||||
/// <inheritdoc />
|
||||
[Newtonsoft.Json.JsonIgnore] // Issue 1001
|
||||
[JsonIgnore]
|
||||
public Models.Mime.IMimeMessageData? BodyAsMimeMessage { get; }
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? DetectedBodyType { get; }
|
||||
@@ -109,10 +105,8 @@ public class RequestMessage : IRequestMessage
|
||||
/// <inheritdoc />
|
||||
public string Origin { get; }
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
/// <inheritdoc />
|
||||
public X509Certificate2? ClientCertificate { get; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Used for Unit Testing
|
||||
@@ -135,10 +129,8 @@ public class RequestMessage : IRequestMessage
|
||||
IBodyData? bodyData = null,
|
||||
IDictionary<string, string[]>? headers = null,
|
||||
IDictionary<string, string>? cookies = null,
|
||||
string httpVersion = "1.1"
|
||||
#if USE_ASPNETCORE
|
||||
, X509Certificate2? clientCertificate = null
|
||||
#endif
|
||||
string httpVersion = "1.1",
|
||||
X509Certificate2? clientCertificate = null
|
||||
)
|
||||
{
|
||||
Guard.NotNull(urlDetails);
|
||||
@@ -178,16 +170,11 @@ public class RequestMessage : IRequestMessage
|
||||
Query = QueryStringParser.Parse(RawQuery, options?.QueryParameterMultipleValueSupport);
|
||||
QueryIgnoreCase = new Dictionary<string, WireMockList<string>>(Query, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
ClientCertificate = clientCertificate;
|
||||
#endif
|
||||
|
||||
#if MIMEKIT
|
||||
if (TypeLoader.TryLoadStaticInstance<IMimeKitUtils>(out var mimeKitUtils) && mimeKitUtils.TryGetMimeMessage(this, out var mimeMessage))
|
||||
{
|
||||
BodyAsMimeMessage = mimeMessage;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -199,7 +186,6 @@ public class RequestMessage : IRequestMessage
|
||||
}
|
||||
|
||||
var query = !ignoreCase ? Query : new Dictionary<string, WireMockList<string>>(Query, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
return query.ContainsKey(key) ? query[key] : null;
|
||||
return query.TryGetValue(key, out var value) ? value : null;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JsonConverter.Abstractions;
|
||||
using Stef.Validation;
|
||||
using WireMock.Models;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
using Stef.Validation;
|
||||
|
||||
namespace WireMock.ResponseBuilders;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
using WireMock.Types;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using WireMock.Types;
|
||||
|
||||
namespace WireMock.ResponseBuilders;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using WireMock.Settings;
|
||||
using WireMock.WebSockets;
|
||||
|
||||
namespace WireMock.ResponseBuilders;
|
||||
|
||||
public partial class Response
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal property to store WebSocket builder configuration
|
||||
/// </summary>
|
||||
internal WebSocketBuilder? WebSocketBuilder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Configure WebSocket response behavior
|
||||
/// </summary>
|
||||
public IResponseBuilder WithWebSocket(Action<IWebSocketBuilder> configure)
|
||||
{
|
||||
var builder = new WebSocketBuilder(this);
|
||||
configure(builder);
|
||||
|
||||
WebSocketBuilder = builder;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Proxy WebSocket to another server
|
||||
/// </summary>
|
||||
public IResponseBuilder WithWebSocketProxy(string targetUrl)
|
||||
{
|
||||
return WithWebSocketProxy(new ProxyAndRecordSettings { Url = targetUrl });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Proxy WebSocket to another server with settings
|
||||
/// </summary>
|
||||
public IResponseBuilder WithWebSocketProxy(ProxyAndRecordSettings settings)
|
||||
{
|
||||
var builder = new WebSocketBuilder(this);
|
||||
builder.WithProxy(settings);
|
||||
|
||||
WebSocketBuilder = builder;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,14 @@
|
||||
|
||||
// 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 System;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Stef.Validation;
|
||||
using WireMock.Proxy;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Transformers;
|
||||
using WireMock.Transformers.Handlebars;
|
||||
using WireMock.Transformers.Scriban;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
@@ -187,8 +183,10 @@ public partial class Response : IResponseBuilder
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IMapping mapping, IRequestMessage requestMessage, WireMockServerSettings settings)
|
||||
public async Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IMapping mapping, HttpContext context, IRequestMessage requestMessage, WireMockServerSettings settings)
|
||||
{
|
||||
Guard.NotNull(mapping);
|
||||
Guard.NotNull(context);
|
||||
Guard.NotNull(requestMessage);
|
||||
Guard.NotNull(settings);
|
||||
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
// 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 System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
using Stef.Validation;
|
||||
|
||||
namespace WireMock;
|
||||
|
||||
@@ -40,6 +39,12 @@ public class ResponseMessage : IResponseMessage
|
||||
/// <inheritdoc cref="IResponseMessage.FaultPercentage" />
|
||||
public double? FaultPercentage { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime DateTime { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? Method { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AddHeader(string name, string value)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Constants;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Stef.Validation;
|
||||
using WireMock.Settings;
|
||||
|
||||
@@ -9,15 +8,16 @@ namespace WireMock.ResponseProviders;
|
||||
|
||||
internal class DynamicAsyncResponseProvider : IResponseProvider
|
||||
{
|
||||
private readonly Func<IRequestMessage, Task<IResponseMessage>> _responseMessageFunc;
|
||||
private readonly Func<HttpContext, IRequestMessage, Task<IResponseMessage>> _responseMessageFunc;
|
||||
|
||||
public DynamicAsyncResponseProvider(Func<IRequestMessage, Task<IResponseMessage>> responseMessageFunc)
|
||||
public DynamicAsyncResponseProvider(Func<HttpContext, IRequestMessage, Task<IResponseMessage>> responseMessageFunc)
|
||||
{
|
||||
_responseMessageFunc = Guard.NotNull(responseMessageFunc);
|
||||
}
|
||||
|
||||
public async Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IMapping mapping, IRequestMessage requestMessage, WireMockServerSettings settings)
|
||||
/// <inheritdoc />
|
||||
public async Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IMapping mapping, HttpContext context, IRequestMessage requestMessage, WireMockServerSettings settings)
|
||||
{
|
||||
return (await _responseMessageFunc(requestMessage).ConfigureAwait(false), null);
|
||||
return (await _responseMessageFunc(context, requestMessage).ConfigureAwait(false), null);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user