mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-17 23:14:23 +01:00
Add MultiPart/MimePart Request Matcher (#981)
* wip * . * mm * x * . * . * . * tests * . * more tests * trans * x * win * fix * . * tests
This commit is contained in:
@@ -39,14 +39,38 @@ public class MatcherModel
|
||||
/// <summary>
|
||||
/// The Operator to use when multiple patterns are defined. Optional.
|
||||
/// - null = Same as "or".
|
||||
/// - "or" = Only one pattern should match.
|
||||
/// - "or" = Only one pattern is required to match.
|
||||
/// - "and" = All patterns should match.
|
||||
/// - "average" = The average value from all patterns.
|
||||
/// </summary>
|
||||
public string? MatchOperator { get; set; }
|
||||
|
||||
#region JsonPartialMatcher and JsonPartialWildcardMatcher
|
||||
/// <summary>
|
||||
/// Support Regex, only used for JsonPartialMatcher.
|
||||
/// Support Regex.
|
||||
/// </summary>
|
||||
public bool? Regex { get; set; }
|
||||
#endregion
|
||||
|
||||
#region MimePartMatcher
|
||||
/// <summary>
|
||||
/// ContentType Matcher (image/png; name=image.png)
|
||||
/// </summary>
|
||||
public MatcherModel? ContentTypeMatcher { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ContentDisposition Matcher (attachment; filename=image.png)
|
||||
/// </summary>
|
||||
public MatcherModel? ContentDispositionMatcher { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ContentTransferEncoding Matcher (base64)
|
||||
/// </summary>
|
||||
public MatcherModel? ContentTransferEncodingMatcher { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Content Matcher
|
||||
/// </summary>
|
||||
public MatcherModel? ContentMatcher { get; set; }
|
||||
#endregion
|
||||
}
|
||||
@@ -96,32 +96,39 @@ public interface IRequestMessage
|
||||
/// <summary>
|
||||
/// The original body as string. Convenience getter for Handlebars.
|
||||
/// </summary>
|
||||
string Body { get; }
|
||||
string? Body { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The body (as JSON object). Convenience getter for Handlebars.
|
||||
/// </summary>
|
||||
object BodyAsJson { get; }
|
||||
object? BodyAsJson { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The body (as bytearray). Convenience getter for Handlebars.
|
||||
/// </summary>
|
||||
byte[] BodyAsBytes { get; }
|
||||
byte[]? BodyAsBytes { get; }
|
||||
|
||||
#if MIMEKIT
|
||||
/// <summary>
|
||||
/// The original body as MimeMessage. Convenience getter for Handlebars.
|
||||
/// </summary>
|
||||
object? BodyAsMimeMessage { get; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The detected body type. Convenience getter for Handlebars.
|
||||
/// </summary>
|
||||
string DetectedBodyType { get; }
|
||||
string? DetectedBodyType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The detected body type from the Content-Type header. Convenience getter for Handlebars.
|
||||
/// </summary>
|
||||
string DetectedBodyTypeFromContentType { get; }
|
||||
string? DetectedBodyTypeFromContentType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
|
||||
/// </summary>
|
||||
string DetectedCompression { get; }
|
||||
string? DetectedCompression { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Host
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1'" >
|
||||
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
||||
|
||||
@@ -31,21 +31,14 @@ internal static class HttpRequestMessageHelper
|
||||
MediaTypeHeaderValue.TryParse(value, out contentType);
|
||||
}
|
||||
|
||||
switch (requestMessage.BodyData?.DetectedBodyType)
|
||||
httpRequestMessage.Content = requestMessage.BodyData?.DetectedBodyType switch
|
||||
{
|
||||
case BodyType.Bytes:
|
||||
httpRequestMessage.Content = ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes!, contentType);
|
||||
break;
|
||||
|
||||
case BodyType.Json:
|
||||
httpRequestMessage.Content = StringContentHelper.Create(JsonConvert.SerializeObject(requestMessage.BodyData.BodyAsJson), contentType);
|
||||
break;
|
||||
|
||||
case BodyType.String:
|
||||
case BodyType.FormUrlEncoded:
|
||||
httpRequestMessage.Content = StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType);
|
||||
break;
|
||||
}
|
||||
BodyType.Bytes => ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes!, contentType),
|
||||
BodyType.Json => StringContentHelper.Create(JsonConvert.SerializeObject(requestMessage.BodyData.BodyAsJson), contentType),
|
||||
BodyType.String => StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType),
|
||||
BodyType.FormUrlEncoded => StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType),
|
||||
_ => httpRequestMessage.Content
|
||||
};
|
||||
|
||||
// Overwrite the host header
|
||||
httpRequestMessage.Headers.Host = new Uri(url).Authority;
|
||||
|
||||
@@ -128,7 +128,7 @@ public class GraphQLMatcher : IStringMatcher
|
||||
/// <inheritdoc />
|
||||
public MatchOperator MatchOperator { get; }
|
||||
|
||||
/// <inheritdoc cref="IMatcher.Name"/>
|
||||
/// <inheritdoc />
|
||||
public string Name => nameof(GraphQLMatcher);
|
||||
|
||||
private static ISchema BuildSchema(string schema)
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
using Stef.Validation;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Matchers.Helpers;
|
||||
|
||||
internal static class BodyDataMatchScoreCalculator
|
||||
{
|
||||
public static double CalculateMatchScore(IBodyData? requestMessage, IMatcher matcher)
|
||||
{
|
||||
Guard.NotNull(matcher);
|
||||
|
||||
if (matcher is NotNullOrEmptyMatcher notNullOrEmptyMatcher)
|
||||
{
|
||||
switch (requestMessage?.DetectedBodyType)
|
||||
{
|
||||
case BodyType.Json:
|
||||
case BodyType.String:
|
||||
case BodyType.FormUrlEncoded:
|
||||
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsString);
|
||||
|
||||
case BodyType.Bytes:
|
||||
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsBytes);
|
||||
|
||||
default:
|
||||
return MatchScores.Mismatch;
|
||||
}
|
||||
}
|
||||
|
||||
if (matcher is ExactObjectMatcher exactObjectMatcher)
|
||||
{
|
||||
// If the body is a byte array, try to match.
|
||||
var detectedBodyType = requestMessage?.DetectedBodyType;
|
||||
if (detectedBodyType is BodyType.Bytes or BodyType.String or BodyType.FormUrlEncoded)
|
||||
{
|
||||
return exactObjectMatcher.IsMatch(requestMessage?.BodyAsBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the matcher is a IObjectMatcher
|
||||
if (matcher is IObjectMatcher objectMatcher)
|
||||
{
|
||||
// If the body is a JSON object, try to match.
|
||||
if (requestMessage?.DetectedBodyType == BodyType.Json)
|
||||
{
|
||||
return objectMatcher.IsMatch(requestMessage.BodyAsJson);
|
||||
}
|
||||
|
||||
// If the body is a byte array, try to match.
|
||||
if (requestMessage?.DetectedBodyType == BodyType.Bytes)
|
||||
{
|
||||
return objectMatcher.IsMatch(requestMessage.BodyAsBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the matcher is a IStringMatcher
|
||||
if (matcher is IStringMatcher stringMatcher)
|
||||
{
|
||||
// If the body is a Json or a String, use the BodyAsString to match on.
|
||||
if (requestMessage?.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
|
||||
{
|
||||
return stringMatcher.IsMatch(requestMessage.BodyAsString);
|
||||
}
|
||||
}
|
||||
|
||||
#if MIMEKIT_XXX
|
||||
if (matcher is MultiPartMatcher multiPartMatcher)
|
||||
{
|
||||
// If the body is a String or MultiPart, use the BodyAsString to match on.
|
||||
if (requestMessage?.DetectedBodyType is BodyType.String or BodyType.MultiPart)
|
||||
{
|
||||
return multiPartMatcher.IsMatch(requestMessage.BodyAsString);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return MatchScores.Mismatch;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using AnyOfTypes;
|
||||
@@ -122,7 +121,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
|
||||
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
}
|
||||
catch (Exception e)
|
||||
catch
|
||||
{
|
||||
if (ThrowException)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace WireMock.Matchers;
|
||||
|
||||
/// <summary>
|
||||
/// MatchBehaviour
|
||||
/// MatchBehaviour (Accept or Reject)
|
||||
/// </summary>
|
||||
public enum MatchBehaviour
|
||||
{
|
||||
|
||||
125
src/WireMock.Net/Matchers/MimePartMatcher.cs
Normal file
125
src/WireMock.Net/Matchers/MimePartMatcher.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
#if MIMEKIT
|
||||
using System;
|
||||
using MimeKit;
|
||||
using WireMock.Matchers.Helpers;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Matchers;
|
||||
|
||||
/// <summary>
|
||||
/// MimePartMatcher
|
||||
/// </summary>
|
||||
public class MimePartMatcher : IMatcher
|
||||
{
|
||||
private readonly Func<MimePart, double>[] _funcs;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => nameof(MimePartMatcher);
|
||||
|
||||
/// <summary>
|
||||
/// ContentType Matcher (image/png; name=image.png.)
|
||||
/// </summary>
|
||||
public IStringMatcher? ContentTypeMatcher { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ContentDisposition Matcher (attachment; filename=image.png)
|
||||
/// </summary>
|
||||
public IStringMatcher? ContentDispositionMatcher { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ContentTransferEncoding Matcher (base64)
|
||||
/// </summary>
|
||||
public IStringMatcher? ContentTransferEncodingMatcher { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Content Matcher
|
||||
/// </summary>
|
||||
public IMatcher? ContentMatcher { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public MatchBehaviour MatchBehaviour { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ThrowException { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MimePartMatcher"/> class.
|
||||
/// </summary>
|
||||
public MimePartMatcher(
|
||||
MatchBehaviour matchBehaviour,
|
||||
IStringMatcher? contentTypeMatcher,
|
||||
IStringMatcher? contentDispositionMatcher,
|
||||
IStringMatcher? contentTransferEncodingMatcher,
|
||||
IMatcher? contentMatcher,
|
||||
bool throwException = false
|
||||
)
|
||||
{
|
||||
MatchBehaviour = matchBehaviour;
|
||||
ContentTypeMatcher = contentTypeMatcher;
|
||||
ContentDispositionMatcher = contentDispositionMatcher;
|
||||
ContentTransferEncodingMatcher = contentTransferEncodingMatcher;
|
||||
ContentMatcher = contentMatcher;
|
||||
ThrowException = throwException;
|
||||
|
||||
_funcs = new[]
|
||||
{
|
||||
mp => ContentTypeMatcher?.IsMatch(GetContentTypeAsString(mp.ContentType)) ?? MatchScores.Perfect,
|
||||
mp => ContentDispositionMatcher?.IsMatch(mp.ContentDisposition.ToString().Replace("Content-Disposition: ", string.Empty)) ?? MatchScores.Perfect,
|
||||
mp => ContentTransferEncodingMatcher?.IsMatch(mp.ContentTransferEncoding.ToString().ToLowerInvariant()) ?? MatchScores.Perfect,
|
||||
MatchOnContent
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified MimePart is match.
|
||||
/// </summary>
|
||||
/// <param name="mimePart">The MimePart.</param>
|
||||
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
|
||||
public double IsMatch(MimePart mimePart)
|
||||
{
|
||||
var match = MatchScores.Mismatch;
|
||||
|
||||
try
|
||||
{
|
||||
if (Array.TrueForAll(_funcs, func => MatchScores.IsPerfect(func(mimePart))))
|
||||
{
|
||||
match = MatchScores.Perfect;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (ThrowException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||
}
|
||||
|
||||
private double MatchOnContent(MimePart mimePart)
|
||||
{
|
||||
if (ContentMatcher == null)
|
||||
{
|
||||
return MatchScores.Perfect;
|
||||
}
|
||||
|
||||
var bodyParserSettings = new BodyParserSettings
|
||||
{
|
||||
Stream = mimePart.Content.Open(),
|
||||
ContentType = GetContentTypeAsString(mimePart.ContentType),
|
||||
DeserializeJson = true,
|
||||
ContentEncoding = null, // mimePart.ContentType.CharsetEncoding.ToString(),
|
||||
DecompressGZipAndDeflate = true
|
||||
};
|
||||
|
||||
var bodyData = BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
return BodyDataMatchScoreCalculator.CalculateMatchScore(bodyData, ContentMatcher);
|
||||
}
|
||||
|
||||
private static string? GetContentTypeAsString(ContentType? contentType)
|
||||
{
|
||||
return contentType?.ToString().Replace("Content-Type: ", string.Empty);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
using WireMock.Types;
|
||||
using WireMock.Matchers.Helpers;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Matchers.Request;
|
||||
@@ -149,69 +149,11 @@ public class RequestMessageBodyMatcher : IRequestMatcher
|
||||
return requestMatchResult.AddScore(GetType(), score);
|
||||
}
|
||||
|
||||
private static double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher)
|
||||
{
|
||||
if (matcher is NotNullOrEmptyMatcher notNullOrEmptyMatcher)
|
||||
{
|
||||
switch (requestMessage.BodyData?.DetectedBodyType)
|
||||
{
|
||||
case BodyType.Json:
|
||||
case BodyType.String:
|
||||
case BodyType.FormUrlEncoded:
|
||||
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
|
||||
|
||||
case BodyType.Bytes:
|
||||
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
|
||||
|
||||
default:
|
||||
return MatchScores.Mismatch;
|
||||
}
|
||||
}
|
||||
|
||||
if (matcher is ExactObjectMatcher exactObjectMatcher)
|
||||
{
|
||||
// If the body is a byte array, try to match.
|
||||
var detectedBodyType = requestMessage.BodyData?.DetectedBodyType;
|
||||
if (detectedBodyType is BodyType.Bytes or BodyType.String or BodyType.FormUrlEncoded)
|
||||
{
|
||||
return exactObjectMatcher.IsMatch(requestMessage.BodyData?.BodyAsBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the matcher is a IObjectMatcher
|
||||
if (matcher is IObjectMatcher objectMatcher)
|
||||
{
|
||||
// If the body is a JSON object, try to match.
|
||||
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
|
||||
{
|
||||
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsJson);
|
||||
}
|
||||
|
||||
// If the body is a byte array, try to match.
|
||||
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Bytes)
|
||||
{
|
||||
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the matcher is a IStringMatcher
|
||||
if (matcher is IStringMatcher stringMatcher)
|
||||
{
|
||||
// If the body is a Json or a String, use the BodyAsString to match on.
|
||||
if (requestMessage?.BodyData?.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
|
||||
{
|
||||
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
|
||||
}
|
||||
}
|
||||
|
||||
return MatchScores.Mismatch;
|
||||
}
|
||||
|
||||
private double CalculateMatchScore(IRequestMessage requestMessage)
|
||||
{
|
||||
if (Matchers != null)
|
||||
{
|
||||
var matchersResult = Matchers.Select(matcher => CalculateMatchScore(requestMessage, matcher)).ToArray();
|
||||
var matchersResult = Matchers.Select(matcher => BodyDataMatchScoreCalculator.CalculateMatchScore(requestMessage.BodyData, matcher)).ToArray();
|
||||
return MatchScores.ToScore(matchersResult, MatchOperator);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ public class RequestMessageGraphQLMatcher : IRequestMatcher
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Stef.Validation;
|
||||
using WireMock.Http;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Matchers.Request;
|
||||
|
||||
/// <summary>
|
||||
/// The request body MultiPart matcher.
|
||||
/// </summary>
|
||||
public class RequestMessageMultiPartMatcher : IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// The matchers.
|
||||
/// </summary>
|
||||
public IMatcher[]? Matchers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="MatchOperator"/>
|
||||
/// </summary>
|
||||
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="MatchBehaviour"/>
|
||||
/// </summary>
|
||||
public MatchBehaviour MatchBehaviour { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageMultiPartMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
public RequestMessageMultiPartMatcher(params IMatcher[] matchers)
|
||||
{
|
||||
Matchers = Guard.NotNull(matchers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageMultiPartMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
public RequestMessageMultiPartMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator, params IMatcher[] matchers)
|
||||
{
|
||||
Matchers = Guard.NotNull(matchers);
|
||||
MatchBehaviour = matchBehaviour;
|
||||
MatchOperator = matchOperator;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||
{
|
||||
#if !MIMEKIT
|
||||
throw new System.NotSupportedException("The MultiPartMatcher can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
|
||||
#else
|
||||
var match = MatchScores.Mismatch;
|
||||
|
||||
if (Matchers?.Any() != true)
|
||||
{
|
||||
return requestMatchResult.AddScore(GetType(), match);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var message = MimeKitUtils.GetMimeMessage(requestMessage.BodyData!, requestMessage.Headers![HttpKnownHeaderNames.ContentType].ToString());
|
||||
|
||||
var mimePartMatchers = Matchers.OfType<MimePartMatcher>().ToArray();
|
||||
|
||||
foreach (var mimePart in message.BodyParts.OfType<MimeKit.MimePart>())
|
||||
{
|
||||
var matchesForMimePart = new List<double> { MatchScores.Mismatch };
|
||||
matchesForMimePart.AddRange(mimePartMatchers.Select(matcher => matcher.IsMatch(mimePart)));
|
||||
|
||||
match = matchesForMimePart.Max();
|
||||
|
||||
if (MatchScores.IsPerfect(match))
|
||||
{
|
||||
if (MatchOperator == MatchOperator.Or)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match = MatchScores.Mismatch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Empty
|
||||
}
|
||||
|
||||
return requestMatchResult.AddScore(GetType(), match);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -29,17 +29,13 @@ namespace WireMock.Owin.Mappers
|
||||
|
||||
var headers = new Dictionary<string, string[]>();
|
||||
IEnumerable<string>? contentEncodingHeader = null;
|
||||
if (request.Headers.Any())
|
||||
foreach (var header in request.Headers)
|
||||
{
|
||||
headers = new Dictionary<string, string[]>();
|
||||
foreach (var header in request.Headers)
|
||||
{
|
||||
headers.Add(header.Key, header.Value);
|
||||
headers.Add(header.Key, header.Value!);
|
||||
|
||||
if (string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentEncodingHeader = header.Value;
|
||||
}
|
||||
if (string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
contentEncodingHeader = header.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.RequestBuilders;
|
||||
|
||||
/// <summary>
|
||||
/// The GraphQLRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IGraphQLRequestBuilder : IRequestMatcher
|
||||
public interface IGraphQLRequestBuilder : IMultiPartRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// WithGraphQLSchema: The GraphQL schema as a string.
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Matchers;
|
||||
|
||||
namespace WireMock.RequestBuilders;
|
||||
|
||||
34
src/WireMock.Net/RequestBuilders/IMultiPartRequestBuilder.cs
Normal file
34
src/WireMock.Net/RequestBuilders/IMultiPartRequestBuilder.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.RequestBuilders;
|
||||
|
||||
/// <summary>
|
||||
/// The MultiPartRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IMultiPartRequestBuilder : IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// WithMultiPart: IMatcher
|
||||
/// </summary>
|
||||
/// <param name="matcher">The matcher.</param>
|
||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||
IRequestBuilder WithMultiPart(IMatcher matcher);
|
||||
|
||||
/// <summary>
|
||||
/// WithMultiPart: IMatcher[], MatchBehaviour and MatchOperator
|
||||
/// </summary>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
/// <param name="matchBehaviour">The <see cref="MatchBehaviour"/> to use.</param>
|
||||
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
|
||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||
IRequestBuilder WithMultiPart(IMatcher[] matchers, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, MatchOperator matchOperator = MatchOperator.Or);
|
||||
|
||||
/// <summary>
|
||||
/// WithMultiPart: MatchBehaviour and IMatcher[]
|
||||
/// </summary>
|
||||
/// <param name="matchBehaviour">The <see cref="MatchBehaviour"/> to use.</param>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||
IRequestBuilder WithMultiPart(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, params IMatcher[] matchers);
|
||||
}
|
||||
28
src/WireMock.Net/RequestBuilders/Request.WithMultiPart.cs
Normal file
28
src/WireMock.Net/RequestBuilders/Request.WithMultiPart.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.RequestBuilders;
|
||||
|
||||
public partial class Request
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithMultiPart(IMatcher matcher)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageMultiPartMatcher(matcher));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithMultiPart(IMatcher[] matchers, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, MatchOperator matchOperator = MatchOperator.Or)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageMultiPartMatcher(matchBehaviour, matchOperator, matchers));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRequestBuilder WithMultiPart(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, params IMatcher[] matchers)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageMultiPartMatcher(matchBehaviour, MatchOperator.Or, matchers));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
#endif
|
||||
using Stef.Validation;
|
||||
using WireMock.Http;
|
||||
using WireMock.Models;
|
||||
using WireMock.Owin;
|
||||
using WireMock.Types;
|
||||
@@ -20,40 +21,40 @@ namespace WireMock;
|
||||
/// </summary>
|
||||
public class RequestMessage : IRequestMessage
|
||||
{
|
||||
/// <inheritdoc cref="IRequestMessage.ClientIP" />
|
||||
/// <inheritdoc />
|
||||
public string ClientIP { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.Url" />
|
||||
/// <inheritdoc />
|
||||
public string Url { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.AbsoluteUrl" />
|
||||
/// <inheritdoc />
|
||||
public string AbsoluteUrl { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.ProxyUrl" />
|
||||
/// <inheritdoc />
|
||||
public string? ProxyUrl { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.DateTime" />
|
||||
/// <inheritdoc />
|
||||
public DateTime DateTime { get; set; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.Path" />
|
||||
/// <inheritdoc />
|
||||
public string Path { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.AbsolutePath" />
|
||||
/// <inheritdoc />
|
||||
public string AbsolutePath { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.PathSegments" />
|
||||
/// <inheritdoc />
|
||||
public string[] PathSegments { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.AbsolutePathSegments" />
|
||||
/// <inheritdoc />
|
||||
public string[] AbsolutePathSegments { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.Method" />
|
||||
/// <inheritdoc />
|
||||
public string Method { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.Headers" />
|
||||
/// <inheritdoc />
|
||||
public IDictionary<string, WireMockList<string>>? Headers { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.Cookies" />
|
||||
/// <inheritdoc />
|
||||
public IDictionary<string, string>? Cookies { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -61,45 +62,50 @@ public class RequestMessage : IRequestMessage
|
||||
|
||||
/// <inheritdoc />
|
||||
public IDictionary<string, WireMockList<string>>? QueryIgnoreCase { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.RawQuery" />
|
||||
|
||||
/// <inheritdoc />
|
||||
public string RawQuery { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.BodyData" />
|
||||
/// <inheritdoc />
|
||||
public IBodyData? BodyData { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.Body" />
|
||||
public string Body { get; }
|
||||
/// <inheritdoc />
|
||||
public string? Body { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.BodyAsJson" />
|
||||
public object BodyAsJson { get; }
|
||||
/// <inheritdoc />
|
||||
public object? BodyAsJson { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.BodyAsBytes" />
|
||||
public byte[] BodyAsBytes { get; }
|
||||
/// <inheritdoc />
|
||||
public byte[]? BodyAsBytes { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.DetectedBodyType" />
|
||||
public string DetectedBodyType { get; }
|
||||
#if MIMEKIT
|
||||
/// <inheritdoc />
|
||||
public object? BodyAsMimeMessage { get; }
|
||||
#endif
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.DetectedBodyTypeFromContentType" />
|
||||
public string DetectedBodyTypeFromContentType { get; }
|
||||
/// <inheritdoc />
|
||||
public string? DetectedBodyType { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.DetectedCompression" />
|
||||
public string DetectedCompression { get; }
|
||||
/// <inheritdoc />
|
||||
public string? DetectedBodyTypeFromContentType { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.Host" />
|
||||
/// <inheritdoc />
|
||||
public string? DetectedCompression { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Host { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.Protocol" />
|
||||
/// <inheritdoc />
|
||||
public string Protocol { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.Port" />
|
||||
/// <inheritdoc />
|
||||
public int Port { get; }
|
||||
|
||||
/// <inheritdoc cref="IRequestMessage.Origin" />
|
||||
/// <inheritdoc />
|
||||
public string Origin { get; }
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
/// <inheritdoc cref="IRequestMessage.ClientCertificate" />
|
||||
/// <inheritdoc />
|
||||
public X509Certificate2? ClientCertificate { get; }
|
||||
#endif
|
||||
|
||||
@@ -139,11 +145,11 @@ public class RequestMessage : IRequestMessage
|
||||
#if USE_ASPNETCORE
|
||||
, X509Certificate2? clientCertificate = null
|
||||
#endif
|
||||
)
|
||||
)
|
||||
{
|
||||
Guard.NotNull(urlDetails, nameof(urlDetails));
|
||||
Guard.NotNull(method, nameof(method));
|
||||
Guard.NotNull(clientIP, nameof(clientIP));
|
||||
Guard.NotNull(urlDetails);
|
||||
Guard.NotNull(method);
|
||||
Guard.NotNull(clientIP);
|
||||
|
||||
AbsoluteUrl = urlDetails.AbsoluteUrl.ToString();
|
||||
Url = urlDetails.Url.ToString();
|
||||
@@ -166,10 +172,22 @@ public class RequestMessage : IRequestMessage
|
||||
Body = BodyData?.BodyAsString;
|
||||
BodyAsJson = BodyData?.BodyAsJson;
|
||||
BodyAsBytes = BodyData?.BodyAsBytes;
|
||||
|
||||
DetectedBodyType = BodyData?.DetectedBodyType.ToString();
|
||||
DetectedBodyTypeFromContentType = BodyData?.DetectedBodyTypeFromContentType.ToString();
|
||||
DetectedCompression = BodyData?.DetectedCompression;
|
||||
|
||||
#if MIMEKIT
|
||||
try
|
||||
{
|
||||
BodyAsMimeMessage = MimeKitUtils.GetMimeMessage(BodyData, headers![HttpKnownHeaderNames.ContentType].First());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore exception from MimeMessage.Load
|
||||
}
|
||||
#endif
|
||||
|
||||
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
|
||||
Cookies = cookies;
|
||||
RawQuery = urlDetails.Url.Query;
|
||||
|
||||
@@ -19,6 +19,7 @@ using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
using static WireMock.Util.CSharpFormatter;
|
||||
|
||||
namespace WireMock.Serialization;
|
||||
|
||||
internal class MappingConverter
|
||||
@@ -48,6 +49,7 @@ internal class MappingConverter
|
||||
var methodMatcher = request.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
|
||||
var requestMessageBodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
|
||||
var requestMessageGraphQLMatcher = request.GetRequestMessageMatcher<RequestMessageGraphQLMatcher>();
|
||||
var requestMessageMultiPartMatcher = request.GetRequestMessageMatcher<RequestMessageMultiPartMatcher>();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
@@ -114,8 +116,18 @@ internal class MappingConverter
|
||||
sb.AppendLine($" .WithGraphQLSchema({GetString(graphQLMatcher)})");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
#if MIMEKIT
|
||||
if (requestMessageMultiPartMatcher is { Matchers: { } })
|
||||
{
|
||||
if (requestMessageMultiPartMatcher.Matchers.OfType<MimePartMatcher>().Any())
|
||||
{
|
||||
sb.AppendLine(" // .WithMultiPart() is not yet supported");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (requestMessageBodyMatcher is { Matchers: { } })
|
||||
{
|
||||
if (requestMessageBodyMatcher.Matchers.OfType<WildcardMatcher>().FirstOrDefault() is { } wildcardMatcher && wildcardMatcher.GetPatterns().Any())
|
||||
@@ -185,7 +197,7 @@ internal class MappingConverter
|
||||
{
|
||||
sb.AppendLine($" .WithBody({ToCSharpStringLiteral(bodyStringValue)})");
|
||||
}
|
||||
else if(bodyData.BodyAsJson is {} jsonBody)
|
||||
else if (bodyData.BodyAsJson is { } jsonBody)
|
||||
{
|
||||
var anonymousObjectDefinition = ConvertToAnonymousObjectDefinition(jsonBody);
|
||||
sb.AppendLine($" .WithBodyAsJson({anonymousObjectDefinition})");
|
||||
@@ -228,6 +240,7 @@ internal class MappingConverter
|
||||
var methodMatcher = request.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
|
||||
var bodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
|
||||
var graphQLMatcher = request.GetRequestMessageMatcher<RequestMessageGraphQLMatcher>();
|
||||
var multiPartMatcher = request.GetRequestMessageMatcher<RequestMessageMultiPartMatcher>();
|
||||
|
||||
var mappingModel = new MappingModel
|
||||
{
|
||||
@@ -323,19 +336,20 @@ internal class MappingConverter
|
||||
mappingModel.Webhooks = mapping.Webhooks.Select(WebhookMapper.Map).ToArray();
|
||||
}
|
||||
|
||||
var graphQLOrBodyMatchers = graphQLMatcher?.Matchers ?? bodyMatcher?.Matchers;
|
||||
var matchOperator = graphQLMatcher?.MatchOperator ?? bodyMatcher?.MatchOperator;
|
||||
if (graphQLOrBodyMatchers != null && matchOperator != null)
|
||||
var bodyMatchers = multiPartMatcher?.Matchers ?? graphQLMatcher?.Matchers ?? bodyMatcher?.Matchers;
|
||||
var matchOperator = multiPartMatcher?.MatchOperator ?? graphQLMatcher?.MatchOperator ?? bodyMatcher?.MatchOperator;
|
||||
|
||||
if (bodyMatchers != null && matchOperator != null)
|
||||
{
|
||||
mappingModel.Request.Body = new BodyModel();
|
||||
|
||||
if (graphQLOrBodyMatchers.Length == 1)
|
||||
if (bodyMatchers.Length == 1)
|
||||
{
|
||||
mappingModel.Request.Body.Matcher = _mapper.Map(graphQLOrBodyMatchers[0]);
|
||||
mappingModel.Request.Body.Matcher = _mapper.Map(bodyMatchers[0]);
|
||||
}
|
||||
else if (graphQLOrBodyMatchers.Length > 1)
|
||||
else if (bodyMatchers.Length > 1)
|
||||
{
|
||||
mappingModel.Request.Body.Matchers = _mapper.Map(graphQLOrBodyMatchers);
|
||||
mappingModel.Request.Body.Matchers = _mapper.Map(bodyMatchers);
|
||||
mappingModel.Request.Body.MatchOperator = matchOperator.ToString();
|
||||
}
|
||||
}
|
||||
@@ -520,6 +534,4 @@ internal class MappingConverter
|
||||
|
||||
return newDictionary;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -75,6 +75,11 @@ internal class MatcherMapper
|
||||
case nameof(GraphQLMatcher):
|
||||
return new GraphQLMatcher(stringPatterns[0].GetPattern(), matchBehaviour, throwExceptionWhenMatcherFails, matchOperator);
|
||||
#endif
|
||||
|
||||
#if MIMEKIT
|
||||
case nameof(MimePartMatcher):
|
||||
return CreateMimePartMatcher(matchBehaviour, matcher, throwExceptionWhenMatcherFails);
|
||||
#endif
|
||||
case nameof(RegexMatcher):
|
||||
return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails, useRegexExtended, matchOperator);
|
||||
|
||||
@@ -126,12 +131,7 @@ internal class MatcherMapper
|
||||
|
||||
public MatcherModel[]? Map(IEnumerable<IMatcher>? matchers)
|
||||
{
|
||||
if (matchers == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return matchers.Where(m => m != null).Select(Map).ToArray()!;
|
||||
return matchers?.Where(m => m != null).Select(Map).ToArray();
|
||||
}
|
||||
|
||||
public MatcherModel? Map(IMatcher? matcher)
|
||||
@@ -195,6 +195,15 @@ internal class MatcherMapper
|
||||
case ExactObjectMatcher exactObjectMatcher:
|
||||
model.Pattern = exactObjectMatcher.ValueAsObject ?? exactObjectMatcher.ValueAsBytes;
|
||||
break;
|
||||
|
||||
#if MIMEKIT
|
||||
case MimePartMatcher mimePartMatcher:
|
||||
model.ContentDispositionMatcher = Map(mimePartMatcher.ContentDispositionMatcher);
|
||||
model.ContentMatcher = Map(mimePartMatcher.ContentMatcher);
|
||||
model.ContentTransferEncodingMatcher = Map(mimePartMatcher.ContentTransferEncodingMatcher);
|
||||
model.ContentTypeMatcher = Map(mimePartMatcher.ContentTypeMatcher);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return model;
|
||||
@@ -224,7 +233,7 @@ internal class MatcherMapper
|
||||
return new[] { new AnyOf<string, StringPattern>(new StringPattern { Pattern = pattern, PatternAsFile = patternAsFile }) };
|
||||
}
|
||||
|
||||
return new AnyOf<string, StringPattern>[0];
|
||||
return EmptyArray<AnyOf<string, StringPattern>>.Value;
|
||||
}
|
||||
|
||||
private static ExactObjectMatcher CreateExactObjectMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> stringPattern, bool throwException)
|
||||
@@ -241,4 +250,16 @@ internal class MatcherMapper
|
||||
|
||||
return new ExactObjectMatcher(matchBehaviour, bytePattern, throwException);
|
||||
}
|
||||
|
||||
#if MIMEKIT
|
||||
private MimePartMatcher CreateMimePartMatcher(MatchBehaviour matchBehaviour, MatcherModel? matcher, bool throwExceptionWhenMatcherFails)
|
||||
{
|
||||
var contentTypeMatcher = Map(matcher?.ContentTypeMatcher) as IStringMatcher;
|
||||
var contentDispositionMatcher = Map(matcher?.ContentDispositionMatcher) as IStringMatcher;
|
||||
var contentTransferEncodingMatcher = Map(matcher?.ContentTransferEncodingMatcher) as IStringMatcher;
|
||||
var contentMatcher = Map(matcher?.ContentMatcher);
|
||||
|
||||
return new MimePartMatcher(matchBehaviour, contentTypeMatcher, contentDispositionMatcher, contentTransferEncodingMatcher, contentMatcher, throwExceptionWhenMatcherFails);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
42
src/WireMock.Net/Util/MimeKitUtils.cs
Normal file
42
src/WireMock.Net/Util/MimeKitUtils.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
#if MIMEKIT
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using MimeKit;
|
||||
using WireMock.Http;
|
||||
using WireMock.Types;
|
||||
|
||||
namespace WireMock.Util;
|
||||
|
||||
internal static class MimeKitUtils
|
||||
{
|
||||
public static MimeMessage GetMimeMessage(IBodyData? bodyData, string contentTypeHeaderValue)
|
||||
{
|
||||
var bytes = bodyData?.DetectedBodyType switch
|
||||
{
|
||||
// If the body is bytes, use the BodyAsBytes to match on.
|
||||
BodyType.Bytes => bodyData.BodyAsBytes!,
|
||||
|
||||
// If the body is a String or MultiPart, use the BodyAsString to match on.
|
||||
BodyType.String or BodyType.MultiPart => Encoding.UTF8.GetBytes(bodyData.BodyAsString!),
|
||||
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
|
||||
var fixedBytes = FixBytes(bytes, contentTypeHeaderValue);
|
||||
return MimeMessage.Load(new MemoryStream(fixedBytes));
|
||||
}
|
||||
|
||||
private static byte[] FixBytes(byte[] bytes, WireMockList<string> contentType)
|
||||
{
|
||||
var contentTypeBytes = Encoding.UTF8.GetBytes($"{HttpKnownHeaderNames.ContentType}: {contentType}\r\n\r\n");
|
||||
|
||||
var result = new byte[contentTypeBytes.Length + bytes.Length];
|
||||
|
||||
Buffer.BlockCopy(contentTypeBytes, 0, result, 0, contentTypeBytes.Length);
|
||||
Buffer.BlockCopy(bytes, 0, result, contentTypeBytes.Length, bytes.Length);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
12
src/WireMock.Net/Util/StreamUtils.cs
Normal file
12
src/WireMock.Net/Util/StreamUtils.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace WireMock.Util;
|
||||
|
||||
internal static class StreamUtils
|
||||
{
|
||||
public static Stream CreateStream(string s)
|
||||
{
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes(s));
|
||||
}
|
||||
}
|
||||
@@ -51,10 +51,11 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
||||
<DefineConstants>$(DefineConstants);GRAPHQL</DefineConstants>
|
||||
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Matchers\MultiPartMatcher.cs" />
|
||||
<Compile Remove="Util\FileSystemWatcherExtensions.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -160,6 +161,7 @@
|
||||
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
||||
<PackageReference Include="GraphQL" Version="7.5.0" />
|
||||
<PackageReference Include="GraphQL.NewtonsoftJson" Version="7.5.0" />
|
||||
<PackageReference Include="MimeKitLite" Version="4.1.0.1" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
|
||||
|
||||
Reference in New Issue
Block a user