Fix issue with application/x-www-form-urlencoded and ExactMatcher (#907)

This commit is contained in:
Stef Heyenrath
2023-03-19 10:21:47 +01:00
committed by GitHub
parent 1221d52c69
commit b30e4faab6
11 changed files with 74 additions and 18 deletions

View File

@@ -28,7 +28,7 @@ internal static class HttpRequestMessageHelper
switch (requestMessage.BodyData?.DetectedBodyType) switch (requestMessage.BodyData?.DetectedBodyType)
{ {
case BodyType.Bytes: case BodyType.Bytes:
httpRequestMessage.Content = ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes, contentType); httpRequestMessage.Content = ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes!, contentType);
break; break;
case BodyType.Json: case BodyType.Json:
@@ -36,7 +36,8 @@ internal static class HttpRequestMessageHelper
break; break;
case BodyType.String: case BodyType.String:
httpRequestMessage.Content = StringContentHelper.Create(requestMessage.BodyData.BodyAsString, contentType); case BodyType.FormUrlEncoded:
httpRequestMessage.Content = StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType);
break; break;
} }

View File

@@ -157,6 +157,7 @@ public class RequestMessageBodyMatcher : IRequestMatcher
{ {
case BodyType.Json: case BodyType.Json:
case BodyType.String: case BodyType.String:
case BodyType.FormUrlEncoded:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsString); return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
case BodyType.Bytes: case BodyType.Bytes:
@@ -171,7 +172,7 @@ public class RequestMessageBodyMatcher : IRequestMatcher
{ {
// If the body is a byte array, try to match. // If the body is a byte array, try to match.
var detectedBodyType = requestMessage.BodyData?.DetectedBodyType; var detectedBodyType = requestMessage.BodyData?.DetectedBodyType;
if (detectedBodyType is BodyType.Bytes or BodyType.String) if (detectedBodyType is BodyType.Bytes or BodyType.String or BodyType.FormUrlEncoded)
{ {
return exactObjectMatcher.IsMatch(requestMessage.BodyData?.BodyAsBytes); return exactObjectMatcher.IsMatch(requestMessage.BodyData?.BodyAsBytes);
} }
@@ -197,7 +198,7 @@ public class RequestMessageBodyMatcher : IRequestMatcher
if (matcher is IStringMatcher stringMatcher) if (matcher is IStringMatcher stringMatcher)
{ {
// If the body is a Json or a String, use the BodyAsString to match on. // 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) if (requestMessage?.BodyData?.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
{ {
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString); return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
} }

View File

@@ -130,6 +130,7 @@ namespace WireMock.Owin.Mappers
switch (responseMessage.BodyData?.DetectedBodyType) switch (responseMessage.BodyData?.DetectedBodyType)
{ {
case BodyType.String: case BodyType.String:
case BodyType.FormUrlEncoded:
return (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(responseMessage.BodyData.BodyAsString!); return (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(responseMessage.BodyData.BodyAsString!);
case BodyType.Json: case BodyType.Json:

View File

@@ -44,6 +44,7 @@ internal class LogEntryMapper
switch (logEntry.RequestMessage.BodyData.DetectedBodyType) switch (logEntry.RequestMessage.BodyData.DetectedBodyType)
{ {
case BodyType.String: case BodyType.String:
case BodyType.FormUrlEncoded:
logRequestModel.Body = logEntry.RequestMessage.BodyData.BodyAsString; logRequestModel.Body = logEntry.RequestMessage.BodyData.BodyAsString;
break; break;
@@ -120,6 +121,7 @@ internal class LogEntryMapper
switch (logEntry.ResponseMessage.BodyData!.DetectedBodyType) switch (logEntry.ResponseMessage.BodyData!.DetectedBodyType)
{ {
case BodyType.String: case BodyType.String:
case BodyType.FormUrlEncoded:
if (!string.IsNullOrEmpty(logEntry.ResponseMessage.BodyData.IsFuncUsed) && _options.DoNotSaveDynamicResponseInLogEntry == true) if (!string.IsNullOrEmpty(logEntry.ResponseMessage.BodyData.IsFuncUsed) && _options.DoNotSaveDynamicResponseInLogEntry == true)
{ {
logResponseModel.Body = logEntry.ResponseMessage.BodyData.IsFuncUsed; logResponseModel.Body = logEntry.ResponseMessage.BodyData.IsFuncUsed;
@@ -142,6 +144,9 @@ internal class LogEntryMapper
logResponseModel.BodyAsFile = logEntry.ResponseMessage.BodyData.BodyAsFile; logResponseModel.BodyAsFile = logEntry.ResponseMessage.BodyData.BodyAsFile;
logResponseModel.BodyAsFileIsCached = logEntry.ResponseMessage.BodyData.BodyAsFileIsCached; logResponseModel.BodyAsFileIsCached = logEntry.ResponseMessage.BodyData.BodyAsFileIsCached;
break; break;
default:
break;
} }
} }

View File

@@ -131,6 +131,7 @@ internal class MappingConverter
switch (response.ResponseMessage.BodyData.DetectedBodyType) switch (response.ResponseMessage.BodyData.DetectedBodyType)
{ {
case BodyType.String: case BodyType.String:
case BodyType.FormUrlEncoded:
sb.AppendLine($" .WithBody(\"{response.ResponseMessage.BodyData.BodyAsString}\")"); sb.AppendLine($" .WithBody(\"{response.ResponseMessage.BodyData.BodyAsString}\")");
break; break;
} }
@@ -325,6 +326,7 @@ internal class MappingConverter
switch (response.ResponseMessage.BodyData?.DetectedBodyType) switch (response.ResponseMessage.BodyData?.DetectedBodyType)
{ {
case BodyType.String: case BodyType.String:
case BodyType.FormUrlEncoded:
mappingModel.Response.Body = response.ResponseMessage.BodyData.BodyAsString; mappingModel.Response.Body = response.ResponseMessage.BodyData.BodyAsString;
break; break;

View File

@@ -141,6 +141,7 @@ internal class ProxyMappingConverter
break; break;
case BodyType.String: case BodyType.String:
case BodyType.FormUrlEncoded:
newRequest.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, true, throwExceptionWhenMatcherFails, MatchOperator.Or, requestMessage.BodyData.BodyAsString!)); newRequest.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, true, throwExceptionWhenMatcherFails, MatchOperator.Or, requestMessage.BodyData.BodyAsString!));
break; break;

View File

@@ -97,6 +97,7 @@ internal static class WebhookMapper
switch (webhook.Request.BodyData.DetectedBodyType) switch (webhook.Request.BodyData.DetectedBodyType)
{ {
case BodyType.String: case BodyType.String:
case BodyType.FormUrlEncoded:
model.Request.Body = webhook.Request.BodyData.BodyAsString; model.Request.Body = webhook.Request.BodyData.BodyAsString;
break; break;

View File

@@ -767,14 +767,18 @@ public partial class WireMockServer
private static T DeserializeObject<T>(IRequestMessage requestMessage) where T : new() private static T DeserializeObject<T>(IRequestMessage requestMessage) where T : new()
{ {
return requestMessage.BodyData?.DetectedBodyType switch switch (requestMessage.BodyData?.DetectedBodyType)
{ {
BodyType.String => JsonUtils.DeserializeObject<T>(requestMessage.BodyData.BodyAsString!), case BodyType.String:
case BodyType.FormUrlEncoded:
return JsonUtils.DeserializeObject<T>(requestMessage.BodyData.BodyAsString!);
BodyType.Json when requestMessage.BodyData?.BodyAsJson != null => ((JObject)requestMessage.BodyData.BodyAsJson).ToObject<T>()!, case BodyType.Json when requestMessage.BodyData?.BodyAsJson != null:
return ((JObject)requestMessage.BodyData.BodyAsJson).ToObject<T>()!;
_ => throw new NotSupportedException() default:
}; throw new NotSupportedException();
}
} }
private static T[] DeserializeRequestMessageToArray<T>(IRequestMessage requestMessage) private static T[] DeserializeRequestMessageToArray<T>(IRequestMessage requestMessage)

View File

@@ -65,7 +65,7 @@ namespace WireMock.Server
} }
}; };
if (BytesEncodingUtils.TryGetEncoding(bytes, out Encoding encoding) && FileBodyIsString.Select(x => x.Equals(encoding)).Any()) if (BytesEncodingUtils.TryGetEncoding(bytes, out var encoding) && FileBodyIsString.Select(x => x.Equals(encoding)).Any())
{ {
response.BodyData.DetectedBodyType = BodyType.String; response.BodyData.DetectedBodyType = BodyType.String;
response.BodyData.BodyAsString = encoding.GetString(bytes); response.BodyData.BodyAsString = encoding.GetString(bytes);

View File

@@ -85,7 +85,7 @@ internal class Transformer : ITransformer
{ {
responseMessage.BodyData = TransformBodyData(transformerContext, options, model, original.BodyData, useTransformerForBodyAsFile); responseMessage.BodyData = TransformBodyData(transformerContext, options, model, original.BodyData, useTransformerForBodyAsFile);
if (original.BodyData.DetectedBodyType == BodyType.String) if (original.BodyData.DetectedBodyType is BodyType.String or BodyType.FormUrlEncoded)
{ {
responseMessage.BodyOriginal = original.BodyData.BodyAsString; responseMessage.BodyOriginal = original.BodyData.BodyAsString;
} }
@@ -123,13 +123,21 @@ internal class Transformer : ITransformer
private IBodyData? TransformBodyData(ITransformerContext transformerContext, ReplaceNodeOptions options, TransformModel model, IBodyData original, bool useTransformerForBodyAsFile) private IBodyData? TransformBodyData(ITransformerContext transformerContext, ReplaceNodeOptions options, TransformModel model, IBodyData original, bool useTransformerForBodyAsFile)
{ {
return original.DetectedBodyType switch switch (original.DetectedBodyType)
{ {
BodyType.Json => TransformBodyAsJson(transformerContext, options, model, original), case BodyType.Json:
BodyType.File => TransformBodyAsFile(transformerContext, model, original, useTransformerForBodyAsFile), return TransformBodyAsJson(transformerContext, options, model, original);
BodyType.String => TransformBodyAsString(transformerContext, model, original),
_ => null case BodyType.File:
}; return TransformBodyAsFile(transformerContext, model, original, useTransformerForBodyAsFile);
case BodyType.String:
case BodyType.FormUrlEncoded:
return TransformBodyAsString(transformerContext, model, original);
default:
return null;
}
} }
private static IDictionary<string, WireMockList<string>> TransformHeaders(ITransformerContext transformerContext, TransformModel model, IDictionary<string, WireMockList<string>>? original) private static IDictionary<string, WireMockList<string>> TransformHeaders(ITransformerContext transformerContext, TransformModel model, IDictionary<string, WireMockList<string>>? original)

View File

@@ -94,6 +94,38 @@ public partial class WireMockServerTests
server.Stop(); server.Stop();
} }
}
[Fact]
public async Task WireMockServer_WithBodyAsFormUrlEncoded_Using_PostAsync_And_WithExactMatcher()
{
// Arrange
var server = WireMockServer.Start();
server.Given(
Request.Create()
.UsingPost()
.WithPath("/foo")
.WithHeader("Content-Type", "application/x-www-form-urlencoded")
.WithBody(new ExactMatcher("name=John+Doe&email=johndoe%40example.com")
)
)
.RespondWith(
Response.Create()
);
// Act
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("name", "John Doe"),
new KeyValuePair<string, string>("email", "johndoe@example.com")
});
var response = await new HttpClient()
.PostAsync($"{server.Url}/foo", content)
.ConfigureAwait(false);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
server.Stop();
}
}
#endif #endif