diff --git a/Directory.Build.props b/Directory.Build.props index b6c806f2..059e75a5 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ - 1.0.6 + 1.0.6.1 diff --git a/GitHubReleaseNotes.txt b/GitHubReleaseNotes.txt index a39f929e..f4b7a6d2 100644 --- a/GitHubReleaseNotes.txt +++ b/GitHubReleaseNotes.txt @@ -1,3 +1,3 @@ https://github.com/StefH/GitHubReleaseNotes -GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --version 1.0.6 \ No newline at end of file +GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --version 1.0.6.1 \ No newline at end of file diff --git a/src/WireMock.Net/Util/BodyParser.cs b/src/WireMock.Net/Util/BodyParser.cs index 66b80127..7bd98f74 100644 --- a/src/WireMock.Net/Util/BodyParser.cs +++ b/src/WireMock.Net/Util/BodyParser.cs @@ -1,11 +1,11 @@ -using System; +using JetBrains.Annotations; +using MimeKit; +using Newtonsoft.Json; +using System; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; -using JetBrains.Annotations; -using MimeKit; -using Newtonsoft.Json; using WireMock.Matchers; using WireMock.Validation; @@ -28,6 +28,10 @@ namespace WireMock.Util */ private static readonly string[] AllowedBodyParseMethods = { "PUT", "POST", "OPTIONS", "PATCH" }; + private static readonly IStringMatcher[] MultipartContentTypesMatchers = { + new WildcardMatcher("multipart/*", true) + }; + private static readonly IStringMatcher[] JsonContentTypesMatchers = { new WildcardMatcher("application/json", true), new WildcardMatcher("application/vnd.*+json", true) @@ -68,6 +72,11 @@ namespace WireMock.Util return BodyType.Json; } + if (MultipartContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MimeType)))) + { + return BodyType.MultiPart; + } + return BodyType.Bytes; } @@ -82,6 +91,12 @@ namespace WireMock.Util DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(contentType) }; + // In case of MultiPart: never try to read as String but keep as-is + if (data.DetectedBodyTypeFromContentType == BodyType.MultiPart) + { + return data; + } + // Try to get the body as String try { diff --git a/src/WireMock.Net/Util/BodyType.cs b/src/WireMock.Net/Util/BodyType.cs index 9bc53019..6c8d2e05 100644 --- a/src/WireMock.Net/Util/BodyType.cs +++ b/src/WireMock.Net/Util/BodyType.cs @@ -28,6 +28,11 @@ /// /// Body is a File /// - File + File, + + /// + /// Body is a MultiPart + /// + MultiPart } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Util/BodyParserTests.cs b/test/WireMock.Net.Tests/Util/BodyParserTests.cs index a6e2da14..a5425b2a 100644 --- a/test/WireMock.Net.Tests/Util/BodyParserTests.cs +++ b/test/WireMock.Net.Tests/Util/BodyParserTests.cs @@ -1,7 +1,7 @@ -using System.IO; +using NFluent; +using System.IO; using System.Text; using System.Threading.Tasks; -using NFluent; using WireMock.Util; using Xunit; @@ -17,7 +17,7 @@ namespace WireMock.Net.Tests.Util [InlineData("application/vnd.test+json", "{ \"x\": 1 }", BodyType.Json, BodyType.Json)] public async Task BodyParser_Parse_ContentTypeJson(string contentType, string bodyAsJson, BodyType detectedBodyType, BodyType detectedBodyTypeFromContentType) { - // Assign + // Arrange var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsJson)); // Act @@ -36,7 +36,7 @@ namespace WireMock.Net.Tests.Util [InlineData("something", "hello", BodyType.String, BodyType.Bytes)] public async Task BodyParser_Parse_ContentTypeString(string contentType, string bodyAsString, BodyType detectedBodyType, BodyType detectedBodyTypeFromContentType) { - // Assign + // Arrange var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsString)); // Act @@ -50,11 +50,49 @@ namespace WireMock.Net.Tests.Util Check.That(body.DetectedBodyTypeFromContentType).IsEqualTo(detectedBodyTypeFromContentType); } + [Fact] + public async Task BodyParser_Parse_ContentTypeMultipart() + { + // Arrange + string contentType = "multipart/form-data"; + string body = @" + +-----------------------------9051914041544843365972754266 +Content-Disposition: form-data; name=""text"" + +text default +-----------------------------9051914041544843365972754266 +Content-Disposition: form-data; name=""file1""; filename=""a.txt"" +Content-Type: text/plain + +Content of a txt + +-----------------------------9051914041544843365972754266 +Content-Disposition: form-data; name=""file2""; filename=""a.html"" +Content-Type: text/html + +Content of a.html. + +-----------------------------9051914041544843365972754266--"; + + var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(body)); + + // Act + var result = await BodyParser.Parse(memoryStream, contentType); + + // Assert + Check.That(result.DetectedBodyType).IsEqualTo(BodyType.Bytes); + Check.That(result.DetectedBodyTypeFromContentType).IsEqualTo(BodyType.MultiPart); + Check.That(result.BodyAsBytes).IsNotNull(); + Check.That(result.BodyAsJson).IsNull(); + Check.That(result.BodyAsString).IsNull(); + } + [Theory] [InlineData(null, "hello", BodyType.String, BodyType.Bytes)] public async Task BodyParser_Parse_ContentTypeIsNull(string contentType, string bodyAsString, BodyType detectedBodyType, BodyType detectedBodyTypeFromContentType) { - // Assign + // Arrange var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsString)); // Act