Error in RequestMessageMultiPartMatcher #608

Closed
opened 2025-12-29 15:28:09 +01:00 by adam · 3 comments
Owner

Originally created by @rmeshksar on GitHub (Jun 14, 2024).

Originally assigned to: @StefH on GitHub.

Hi,
I would like to match multipart requests.
In the request there can be several parts and I only need to match some of them and not all.
It seems when passing an array of matchers to .WithMultipart it has to be one to one associated with the request but in my case there can be different number of parts in the request and I always want to only match the first two parts based on some conditions.

In the example below request has 3 parts but how can I check if the part that has text/json content-type has specific content regardless of other parts or regardless of position of the json part.

I commented out some elements of matchers array and it fails.

	static void Main(string[] args)
	{
		// Arrange
		var server = WireMockServer.Start();

		var textPlainContent = "This is some plain text";
		var textPlainContentType = "text/plain";
		var textPlainContentTypeMatcher = new ContentTypeMatcher(textPlainContentType);
		var textPlainContentMatcher = new ExactMatcher(textPlainContent);
		var textPlainMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textPlainContentTypeMatcher, null, null, textPlainContentMatcher);

		var textJson = "{ \"Key\" : \"Value\" }";
		var textJsonContentType = "text/json";
		var textJsonContentTypeMatcher = new ContentTypeMatcher(textJsonContentType);
		var textJsonContentMatcher = new JsonMatcher(new { Key = "Value" }, true);
		var jsonMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textJsonContentTypeMatcher, null, null, textJsonContentMatcher);

		var imagePngBytes = Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC");
		var imagePngContentMatcher = new ExactObjectMatcher(imagePngBytes);
		var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, null, null, null, imagePngContentMatcher);

		var matchers = new IMatcher[]
		{
			//textPlainMatcher,
			jsonMatcher,
			//imagePngMatcher
		};

		server
			.Given(
				Request.Create()
					.UsingPost()
					.WithPath("/multipart")
					.WithMultiPart(matchers))
			.RespondWith(Response.Create());

		// Act
		var formDataContent = new MultipartFormDataContent();
		formDataContent.Add(new StringContent(textPlainContent, Encoding.UTF8, textPlainContentType), "text");
		formDataContent.Add(new StringContent(textJson, Encoding.UTF8, textJsonContentType), "json");

		var fileContent = new ByteArrayContent(imagePngBytes);
		fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
		formDataContent.Add(fileContent, "somefile", "image.png");

		var client = server.CreateClient();

		var response = client.PostAsync("/multipart", formDataContent).GetAwaiter().GetResult();

		// Assert
		Console.WriteLine(response.StatusCode);
		Console.ReadLine();

		server.Stop();
	}
Originally created by @rmeshksar on GitHub (Jun 14, 2024). Originally assigned to: @StefH on GitHub. Hi, I would like to match multipart requests. In the request there can be several parts and I only need to match some of them and not all. It seems when passing an array of matchers to .WithMultipart it has to be one to one associated with the request but in my case there can be different number of parts in the request and I always want to only match the first two parts based on some conditions. In the example below request has 3 parts but how can I check if the part that has text/json content-type has specific content regardless of other parts or regardless of position of the json part. I commented out some elements of matchers array and it fails. ```csharp static void Main(string[] args) { // Arrange var server = WireMockServer.Start(); var textPlainContent = "This is some plain text"; var textPlainContentType = "text/plain"; var textPlainContentTypeMatcher = new ContentTypeMatcher(textPlainContentType); var textPlainContentMatcher = new ExactMatcher(textPlainContent); var textPlainMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textPlainContentTypeMatcher, null, null, textPlainContentMatcher); var textJson = "{ \"Key\" : \"Value\" }"; var textJsonContentType = "text/json"; var textJsonContentTypeMatcher = new ContentTypeMatcher(textJsonContentType); var textJsonContentMatcher = new JsonMatcher(new { Key = "Value" }, true); var jsonMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textJsonContentTypeMatcher, null, null, textJsonContentMatcher); var imagePngBytes = Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC"); var imagePngContentMatcher = new ExactObjectMatcher(imagePngBytes); var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, null, null, null, imagePngContentMatcher); var matchers = new IMatcher[] { //textPlainMatcher, jsonMatcher, //imagePngMatcher }; server .Given( Request.Create() .UsingPost() .WithPath("/multipart") .WithMultiPart(matchers)) .RespondWith(Response.Create()); // Act var formDataContent = new MultipartFormDataContent(); formDataContent.Add(new StringContent(textPlainContent, Encoding.UTF8, textPlainContentType), "text"); formDataContent.Add(new StringContent(textJson, Encoding.UTF8, textJsonContentType), "json"); var fileContent = new ByteArrayContent(imagePngBytes); fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/png"); formDataContent.Add(fileContent, "somefile", "image.png"); var client = server.CreateClient(); var response = client.PostAsync("/multipart", formDataContent).GetAwaiter().GetResult(); // Assert Console.WriteLine(response.StatusCode); Console.ReadLine(); server.Stop(); } ```
adam added the bug label 2025-12-29 15:28:09 +01:00
adam closed this issue 2025-12-29 15:28:09 +01:00
Author
Owner

@rmeshksar commented on GitHub (Jun 14, 2024):

I think it is a bug.
in the file ~\Matchers\Request\RequestMessageMultiPartMatcher.cs, the logic of GetMatchingScore method should be changed to have two loops with the outer loop to be matchers and inner loop each part.

I tried the following and it worked but there might be better ways to implement it:

    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 score = MatchScores.Mismatch;
        Exception? exception = null;

        if (Matchers?.Any() != true)
        {
            return requestMatchResult.AddScore(GetType(), score, null);
        }

        if (!MimeKitUtils.TryGetMimeMessage(requestMessage, out var message))
        {
            return requestMatchResult.AddScore(GetType(), score, null);
        }

        try
        {
            foreach (var mimePartMatcher in Matchers.OfType<MimePartMatcher>().ToArray())
            {
                score = MatchScores.Mismatch;
                foreach (var mimeBodyPart in message.BodyParts.OfType<MimeKit.MimePart>())
                {
                    var matchResult = mimePartMatcher.IsMatch(mimeBodyPart);
                    if (matchResult.IsPerfect())
                    {
                        score = MatchScores.Perfect;
                        break;
                    }
                }
                if ((MatchOperator == MatchOperator.Or && MatchScores.IsPerfect(score))
                    || (MatchOperator == MatchOperator.And && !MatchScores.IsPerfect(score)))
                {
                    break;
                }
            }
        }
        catch (Exception ex)
        {
            exception = ex;
        }

        return requestMatchResult.AddScore(GetType(), score, exception);
#endif
    }
@rmeshksar commented on GitHub (Jun 14, 2024): I think it is a bug. in the file ~\Matchers\Request\RequestMessageMultiPartMatcher.cs, the logic of GetMatchingScore method should be changed to have two loops with the outer loop to be matchers and inner loop each part. I tried the following and it worked but there might be better ways to implement it: ```csharp 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 score = MatchScores.Mismatch; Exception? exception = null; if (Matchers?.Any() != true) { return requestMatchResult.AddScore(GetType(), score, null); } if (!MimeKitUtils.TryGetMimeMessage(requestMessage, out var message)) { return requestMatchResult.AddScore(GetType(), score, null); } try { foreach (var mimePartMatcher in Matchers.OfType<MimePartMatcher>().ToArray()) { score = MatchScores.Mismatch; foreach (var mimeBodyPart in message.BodyParts.OfType<MimeKit.MimePart>()) { var matchResult = mimePartMatcher.IsMatch(mimeBodyPart); if (matchResult.IsPerfect()) { score = MatchScores.Perfect; break; } } if ((MatchOperator == MatchOperator.Or && MatchScores.IsPerfect(score)) || (MatchOperator == MatchOperator.And && !MatchScores.IsPerfect(score))) { break; } } } catch (Exception ex) { exception = ex; } return requestMatchResult.AddScore(GetType(), score, exception); #endif } ```
Author
Owner

@StefH commented on GitHub (Jun 29, 2024):

@rmeshksar
Can you please create a fix PR which also includes a unit-test?

@StefH commented on GitHub (Jun 29, 2024): @rmeshksar Can you please create a fix PR which also includes a unit-test?
Author
Owner

@rmeshksar commented on GitHub (Jul 4, 2024):

I will do it in this week. Thanks

@rmeshksar commented on GitHub (Jul 4, 2024): I will do it in this week. Thanks
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net-wiremock#608