mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-27 19:27:42 +02:00
Fix issues with Proxy mode and Binary Request Bodies (#334)
* Add Test for Proxy with binary request * Fix binary parsing in BodyParser * Fix binary Matching in RequestMessageBodyMatcher * Improved Binary Matching in RequestMessageBodyMatcher * BodyParser: Add test for Content Autodetection * RequestMessageBodyMatcherTests: Make Code more pretty :) * BodyParserChanges: Revert white space changes * Fixed test for different behavior in request matching
This commit is contained in:
@@ -145,17 +145,17 @@ namespace WireMock.Matchers.Request
|
|||||||
|
|
||||||
if (Func != null)
|
if (Func != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(requestMessage?.BodyData?.DetectedBodyType == BodyType.String && Func(requestMessage.BodyData.BodyAsString));
|
return MatchScores.ToScore(Func(requestMessage?.BodyData?.BodyAsString));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JsonFunc != null)
|
if (JsonFunc != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(requestMessage?.BodyData?.DetectedBodyType == BodyType.Json && JsonFunc(requestMessage.BodyData.BodyAsJson));
|
return MatchScores.ToScore(JsonFunc(requestMessage?.BodyData?.BodyAsJson));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DataFunc != null)
|
if (DataFunc != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(requestMessage?.BodyData?.DetectedBodyType == BodyType.Bytes && DataFunc(requestMessage.BodyData.BodyAsBytes));
|
return MatchScores.ToScore(DataFunc(requestMessage?.BodyData?.BodyAsBytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
return MatchScores.Mismatch;
|
return MatchScores.Mismatch;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ namespace WireMock.Util
|
|||||||
{
|
{
|
||||||
internal static class BodyParser
|
internal static class BodyParser
|
||||||
{
|
{
|
||||||
private static readonly Encoding DefaultEncoding = Encoding.UTF8;
|
private static readonly Encoding DefaultEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
|
||||||
private static readonly Encoding[] SupportedBodyAsStringEncodingForMultipart = { Encoding.UTF8, Encoding.ASCII };
|
private static readonly Encoding[] SupportedBodyAsStringEncodingForMultipart = { DefaultEncoding, Encoding.ASCII };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
HEAD - No defined body semantics.
|
HEAD - No defined body semantics.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Net.Http;
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using FluentAssertions;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
using WireMock.RequestBuilders;
|
using WireMock.RequestBuilders;
|
||||||
using WireMock.ResponseBuilders;
|
using WireMock.ResponseBuilders;
|
||||||
@@ -308,6 +309,43 @@ namespace WireMock.Net.Tests
|
|||||||
Check.That(receivedRequest.Cookies).ContainsPair("name", "value");
|
Check.That(receivedRequest.Cookies).ContainsPair("name", "value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send some binary content in a request through the proxy and check that the same content
|
||||||
|
/// arrived at the target. As example a JPEG/JIFF header is used, which is not representable
|
||||||
|
/// in UTF8 and breaks if it is not treated as binary content.
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public async Task FluentMockServer_Proxy_Should_preserve_binary_request_content()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var jpegHeader = new byte[] {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00};
|
||||||
|
var brokenJpegHeader = new byte[]
|
||||||
|
{0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00};
|
||||||
|
|
||||||
|
bool HasCorrectHeader(byte[] bytes) => bytes.SequenceEqual(jpegHeader);
|
||||||
|
bool HasBrokenHeader(byte[] bytes) => bytes.SequenceEqual(brokenJpegHeader);
|
||||||
|
|
||||||
|
var serverForProxyForwarding = FluentMockServer.Start();
|
||||||
|
serverForProxyForwarding
|
||||||
|
.Given(Request.Create().WithBody(HasCorrectHeader))
|
||||||
|
.RespondWith(Response.Create().WithSuccess());
|
||||||
|
|
||||||
|
serverForProxyForwarding
|
||||||
|
.Given(Request.Create().WithBody(HasBrokenHeader))
|
||||||
|
.RespondWith(Response.Create().WithStatusCode(HttpStatusCode.InternalServerError));
|
||||||
|
|
||||||
|
var server = FluentMockServer.Start();
|
||||||
|
server
|
||||||
|
.Given(Request.Create())
|
||||||
|
.RespondWith(Response.Create().WithProxy(serverForProxyForwarding.Urls[0]));
|
||||||
|
|
||||||
|
// act
|
||||||
|
var response = await new HttpClient().PostAsync(server.Urls[0], new ByteArrayContent(jpegHeader));
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Check.That(response.StatusCode).IsEqualTo(HttpStatusCode.OK);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task FluentMockServer_Proxy_Should_set_BodyAsJson_in_proxied_response()
|
public async Task FluentMockServer_Proxy_Should_set_BodyAsJson_in_proxied_response()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ namespace WireMock.Net.Tests
|
|||||||
var server = FluentMockServer.Start();
|
var server = FluentMockServer.Start();
|
||||||
|
|
||||||
server
|
server
|
||||||
.Given(Request.Create().WithBody(b => true))
|
.Given(Request.Create().WithBody((byte[] bodyBytes) => bodyBytes != null))
|
||||||
.AtPriority(0)
|
.AtPriority(0)
|
||||||
.RespondWith(Response.Create().WithStatusCode(400));
|
.RespondWith(Response.Create().WithStatusCode(400));
|
||||||
server
|
server
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
using System.Linq;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using NFluent;
|
using NFluent;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
@@ -208,5 +213,74 @@ namespace WireMock.Net.Tests.RequestMatchers
|
|||||||
// Verify
|
// Verify
|
||||||
objectMatcherMock.Verify(m => m.IsMatch(It.IsAny<byte[]>()), Times.Once);
|
objectMatcherMock.Verify(m => m.IsMatch(It.IsAny<byte[]>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(MatchingScoreData))]
|
||||||
|
public async Task RequestMessageBodyMatcher_GetMatchingScore_Funcs_Matching(object body, RequestMessageBodyMatcher matcher, bool shouldMatch)
|
||||||
|
{
|
||||||
|
// assign
|
||||||
|
BodyData bodyData;
|
||||||
|
if (body is byte[] b)
|
||||||
|
bodyData = await BodyParser.Parse(new MemoryStream(b), null);
|
||||||
|
else if (body is string s)
|
||||||
|
bodyData = await BodyParser.Parse(new MemoryStream(Encoding.UTF8.GetBytes(s)), null);
|
||||||
|
else
|
||||||
|
throw new Exception();
|
||||||
|
|
||||||
|
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.1", bodyData);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = new RequestMatchResult();
|
||||||
|
var score = matcher.GetMatchingScore(requestMessage, result);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Check.That(score).IsEqualTo(shouldMatch ? 1d : 0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TheoryData<object, RequestMessageBodyMatcher, bool> MatchingScoreData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var json = "{'a':'b'}";
|
||||||
|
var str = "HelloWorld";
|
||||||
|
var bytes = new byte[] {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00};
|
||||||
|
|
||||||
|
return new TheoryData<object, RequestMessageBodyMatcher, bool>
|
||||||
|
{
|
||||||
|
// JSON match +++
|
||||||
|
{json, new RequestMessageBodyMatcher((object o) => ((dynamic) o).a == "b"), true},
|
||||||
|
{json, new RequestMessageBodyMatcher((string s) => s == json), true},
|
||||||
|
{json, new RequestMessageBodyMatcher((byte[] b) => b.SequenceEqual(Encoding.UTF8.GetBytes(json))), true},
|
||||||
|
|
||||||
|
// JSON no match ---
|
||||||
|
{json, new RequestMessageBodyMatcher((object o) => false), false},
|
||||||
|
{json, new RequestMessageBodyMatcher((string s) => false), false},
|
||||||
|
{json, new RequestMessageBodyMatcher((byte[] b) => false), false},
|
||||||
|
{json, new RequestMessageBodyMatcher(), false },
|
||||||
|
|
||||||
|
// string match +++
|
||||||
|
{str, new RequestMessageBodyMatcher((object o) => o == null), true},
|
||||||
|
{str, new RequestMessageBodyMatcher((string s) => s == str), true},
|
||||||
|
{str, new RequestMessageBodyMatcher((byte[] b) => b.SequenceEqual(Encoding.UTF8.GetBytes(str))), true},
|
||||||
|
|
||||||
|
// string no match ---
|
||||||
|
{str, new RequestMessageBodyMatcher((object o) => false), false},
|
||||||
|
{str, new RequestMessageBodyMatcher((string s) => false), false},
|
||||||
|
{str, new RequestMessageBodyMatcher((byte[] b) => false), false},
|
||||||
|
{str, new RequestMessageBodyMatcher(), false },
|
||||||
|
|
||||||
|
// binary match +++
|
||||||
|
{bytes, new RequestMessageBodyMatcher((object o) => o == null), true},
|
||||||
|
{bytes, new RequestMessageBodyMatcher((string s) => s == null), true},
|
||||||
|
{bytes, new RequestMessageBodyMatcher((byte[] b) => b.SequenceEqual(bytes)), true},
|
||||||
|
|
||||||
|
// binary no match ---
|
||||||
|
{bytes, new RequestMessageBodyMatcher((object o) => false), false},
|
||||||
|
{bytes, new RequestMessageBodyMatcher((string s) => false), false},
|
||||||
|
{bytes, new RequestMessageBodyMatcher((byte[] b) => false), false},
|
||||||
|
{bytes, new RequestMessageBodyMatcher(), false },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,22 @@ namespace WireMock.Net.Tests.Util
|
|||||||
Check.That(body.DetectedBodyTypeFromContentType).IsEqualTo(detectedBodyTypeFromContentType);
|
Check.That(body.DetectedBodyTypeFromContentType).IsEqualTo(detectedBodyTypeFromContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(new byte[] {34, 97, 34}, BodyType.Json)]
|
||||||
|
[InlineData(new byte[] {97}, BodyType.String)]
|
||||||
|
[InlineData(new byte[] {0xFF, 0xD8, 0xFF, 0xE0}, BodyType.Bytes)]
|
||||||
|
public async Task BodyParser_Parse_DetectedBodyType(byte[] content, BodyType detectedBodyType)
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var memoryStream = new MemoryStream(content);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var body = await BodyParser.Parse(memoryStream, null);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Check.That(body.DetectedBodyType).IsEqualTo(detectedBodyType);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task BodyParser_Parse_WithUTF8EncodingAndContentTypeMultipart_DetectedBodyTypeEqualsString()
|
public async Task BodyParser_Parse_WithUTF8EncodingAndContentTypeMultipart_DetectedBodyTypeEqualsString()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user