diff --git a/src/WireMock.Net.StandAlone/StandAloneApp.cs b/src/WireMock.Net.StandAlone/StandAloneApp.cs index a2f79c44..fa4e098c 100644 --- a/src/WireMock.Net.StandAlone/StandAloneApp.cs +++ b/src/WireMock.Net.StandAlone/StandAloneApp.cs @@ -56,6 +56,7 @@ namespace WireMock.Net.StandAlone MaxRequestLogCount = parser.GetIntValue("MaxRequestLogCount"), RequestLogExpirationDuration = parser.GetIntValue("RequestLogExpirationDuration"), AllowCSharpCodeMatcher = parser.GetBoolValue("AllowCSharpCodeMatcher"), + AllowBodyForAllHttpMethods = parser.GetBoolValue("AllowBodyForAllHttpMethods") }; if (logger != null) diff --git a/src/WireMock.Net/Admin/Settings/SettingsModel.cs b/src/WireMock.Net/Admin/Settings/SettingsModel.cs index 1a5a77d4..2b421d03 100644 --- a/src/WireMock.Net/Admin/Settings/SettingsModel.cs +++ b/src/WireMock.Net/Admin/Settings/SettingsModel.cs @@ -24,5 +24,10 @@ /// Gets or sets the MaxRequestLog count. /// public int? MaxRequestLogCount { get; set; } + + /// + /// Gets or sets wether to allow a body for all HTTP methods. + /// + public bool? AllowBodyForAllHttpMethods { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs b/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs index 882164f0..3d948847 100644 --- a/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs +++ b/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs @@ -20,7 +20,7 @@ namespace WireMock.Owin IStringMatcher AuthorizationMatcher { get; set; } - bool AllowPartialMapping { get; set; } + bool? AllowPartialMapping { get; set; } ConcurrentDictionary Mappings { get; } @@ -37,5 +37,7 @@ namespace WireMock.Owin Action PostWireMockMiddlewareInit { get; set; } IFileSystemHandler FileSystemHandler { get; set; } + + bool? AllowBodyForAllHttpMethods { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/Owin/Mappers/IOwinRequestMapper.cs b/src/WireMock.Net/Owin/Mappers/IOwinRequestMapper.cs index d6ea8f33..efe8c0ad 100644 --- a/src/WireMock.Net/Owin/Mappers/IOwinRequestMapper.cs +++ b/src/WireMock.Net/Owin/Mappers/IOwinRequestMapper.cs @@ -16,7 +16,8 @@ namespace WireMock.Owin.Mappers /// MapAsync IRequest to RequestMessage /// /// The OwinRequest/HttpRequest + /// The WireMockMiddlewareOptions /// RequestMessage - Task MapAsync(IRequest request); + Task MapAsync(IRequest request, IWireMockMiddlewareOptions options); } } \ No newline at end of file diff --git a/src/WireMock.Net/Owin/Mappers/OwinRequestMapper.cs b/src/WireMock.Net/Owin/Mappers/OwinRequestMapper.cs index 6c0e1342..c9ff92e6 100644 --- a/src/WireMock.Net/Owin/Mappers/OwinRequestMapper.cs +++ b/src/WireMock.Net/Owin/Mappers/OwinRequestMapper.cs @@ -20,7 +20,7 @@ namespace WireMock.Owin.Mappers internal class OwinRequestMapper : IOwinRequestMapper { /// - public async Task MapAsync(IRequest request) + public async Task MapAsync(IRequest request, IWireMockMiddlewareOptions options) { (UrlDetails urldetails, string clientIP) = ParseRequest(request); @@ -47,7 +47,7 @@ namespace WireMock.Owin.Mappers } BodyData body = null; - if (request.Body != null && BodyParser.ShouldParseBody(method)) + if (request.Body != null && BodyParser.ShouldParseBody(method, options.AllowBodyForAllHttpMethods == true)) { body = await BodyParser.Parse(request.Body, request.ContentType); } diff --git a/src/WireMock.Net/Owin/MappingMatcher.cs b/src/WireMock.Net/Owin/MappingMatcher.cs index c5b26e80..e6f15398 100644 --- a/src/WireMock.Net/Owin/MappingMatcher.cs +++ b/src/WireMock.Net/Owin/MappingMatcher.cs @@ -37,7 +37,7 @@ namespace WireMock.Owin } } - if (_options.AllowPartialMapping) + if (_options.AllowPartialMapping == true) { var partialMappings = mappings .Where(pm => (pm.Mapping.IsAdminInterface && pm.RequestMatchResult.IsPerfectMatch) || !pm.Mapping.IsAdminInterface) diff --git a/src/WireMock.Net/Owin/WireMockMiddleware.cs b/src/WireMock.Net/Owin/WireMockMiddleware.cs index 2f9bf948..b572e24e 100644 --- a/src/WireMock.Net/Owin/WireMockMiddleware.cs +++ b/src/WireMock.Net/Owin/WireMockMiddleware.cs @@ -69,7 +69,7 @@ namespace WireMock.Owin private async Task InvokeInternal(IContext ctx) { - var request = await _requestMapper.MapAsync(ctx.Request); + var request = await _requestMapper.MapAsync(ctx.Request, _options); bool logRequest = false; ResponseMessage response = null; diff --git a/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs b/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs index fa3c3ed6..9a8b1da7 100644 --- a/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs +++ b/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs @@ -21,7 +21,7 @@ namespace WireMock.Owin public IStringMatcher AuthorizationMatcher { get; set; } - public bool AllowPartialMapping { get; set; } + public bool? AllowPartialMapping { get; set; } public ConcurrentDictionary Mappings { get; } = new ConcurrentDictionary(); @@ -39,5 +39,8 @@ namespace WireMock.Owin /// public IFileSystemHandler FileSystemHandler { get; set; } + + /// + public bool? AllowBodyForAllHttpMethods { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs index c5d034aa..78ef8795 100644 --- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs +++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs @@ -339,7 +339,8 @@ namespace WireMock.Server AllowPartialMapping = _options.AllowPartialMapping, MaxRequestLogCount = _options.MaxRequestLogCount, RequestLogExpirationDuration = _options.RequestLogExpirationDuration, - GlobalProcessingDelay = (int?)_options.RequestProcessingDelay?.TotalMilliseconds + GlobalProcessingDelay = (int?)_options.RequestProcessingDelay?.TotalMilliseconds, + AllowBodyForAllHttpMethods = _options.AllowBodyForAllHttpMethods }; return ToJson(model); @@ -361,6 +362,11 @@ namespace WireMock.Server _options.RequestProcessingDelay = TimeSpan.FromMilliseconds(settings.GlobalProcessingDelay.Value); } + if (settings.AllowBodyForAllHttpMethods != null) + { + _options.AllowBodyForAllHttpMethods = settings.AllowBodyForAllHttpMethods.Value; + } + return ResponseMessageBuilder.Create("Settings updated"); } #endregion Settings diff --git a/src/WireMock.Net/Server/FluentMockServer.cs b/src/WireMock.Net/Server/FluentMockServer.cs index 63e36bc3..8ca4c17a 100644 --- a/src/WireMock.Net/Server/FluentMockServer.cs +++ b/src/WireMock.Net/Server/FluentMockServer.cs @@ -1,11 +1,11 @@ -using JetBrains.Annotations; -using Newtonsoft.Json; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; +using JetBrains.Annotations; +using Newtonsoft.Json; using WireMock.Admin.Mappings; using WireMock.Exceptions; using WireMock.Handlers; @@ -257,6 +257,12 @@ namespace WireMock.Server } } + if (settings.AllowBodyForAllHttpMethods == true) + { + _options.AllowBodyForAllHttpMethods = _settings.AllowBodyForAllHttpMethods; + _settings.Logger.Info("AllowBodyForAllHttpMethods is set to {0}", _settings.AllowBodyForAllHttpMethods == true); + } + if (settings.AllowPartialMapping == true) { AllowPartialMapping(); diff --git a/src/WireMock.Net/Settings/FluentMockServerSettings.cs b/src/WireMock.Net/Settings/FluentMockServerSettings.cs index 7758109b..b3035984 100644 --- a/src/WireMock.Net/Settings/FluentMockServerSettings.cs +++ b/src/WireMock.Net/Settings/FluentMockServerSettings.cs @@ -94,5 +94,9 @@ namespace WireMock.Settings /// [PublicAPI] public bool? AllowCSharpCodeMatcher { get; set; } + + /// + [PublicAPI] + public bool? AllowBodyForAllHttpMethods { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/Settings/IFluentMockServerSettings.cs b/src/WireMock.Net/Settings/IFluentMockServerSettings.cs index b6ae621e..7c10a367 100644 --- a/src/WireMock.Net/Settings/IFluentMockServerSettings.cs +++ b/src/WireMock.Net/Settings/IFluentMockServerSettings.cs @@ -124,6 +124,13 @@ namespace WireMock.Settings /// /// Allow the usage of CSharpCodeMatcher (default is not allowed). /// + [PublicAPI] bool? AllowCSharpCodeMatcher { get; set; } + + /// + /// Allow a Body for all HTTP Methods. (default set to false). + /// + [PublicAPI] + bool? AllowBodyForAllHttpMethods { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/Util/BodyParser.cs b/src/WireMock.Net/Util/BodyParser.cs index d4dda286..46534560 100644 --- a/src/WireMock.Net/Util/BodyParser.cs +++ b/src/WireMock.Net/Util/BodyParser.cs @@ -59,14 +59,19 @@ namespace WireMock.Util private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None }; - public static bool ShouldParseBody([CanBeNull] string method) + public static bool ShouldParseBody([CanBeNull] string httpMethod, bool allowBodyForAllHttpMethods) { - if (string.IsNullOrEmpty(method)) + if (string.IsNullOrEmpty(httpMethod)) { return false; } - if (BodyAllowedForMethods.TryGetValue(method.ToUpper(), out bool allowed)) + if (allowBodyForAllHttpMethods) + { + return true; + } + + if (BodyAllowedForMethods.TryGetValue(httpMethod.ToUpper(), out bool allowed)) { return allowed; } diff --git a/test/WireMock.Net.Tests/FluentMockServerTests.Settings.cs b/test/WireMock.Net.Tests/FluentMockServerTests.Settings.cs index b819a397..d04b98da 100644 --- a/test/WireMock.Net.Tests/FluentMockServerTests.Settings.cs +++ b/test/WireMock.Net.Tests/FluentMockServerTests.Settings.cs @@ -116,7 +116,25 @@ namespace WireMock.Net.Tests // Assert var options = server.GetPrivateFieldValue("_options"); - Check.That(options.AllowPartialMapping).IsTrue(); + Check.That(options.AllowPartialMapping).Equals(true); + + // Verify + _loggerMock.Verify(l => l.Info(It.IsAny(), It.IsAny())); + } + + [Fact] + public void FluentMockServer_FluentMockServerSettings_AllowBodyForAllHttpMethods() + { + // Assign and Act + var server = FluentMockServer.Start(new FluentMockServerSettings + { + Logger = _loggerMock.Object, + AllowBodyForAllHttpMethods = true + }); + + // Assert + var options = server.GetPrivateFieldValue("_options"); + Check.That(options.AllowBodyForAllHttpMethods).Equals(true); // Verify _loggerMock.Verify(l => l.Info(It.IsAny(), It.IsAny())); diff --git a/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs b/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs index dfdcae3e..26da3474 100644 --- a/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs +++ b/test/WireMock.Net.Tests/Owin/WireMockMiddlewareTests.cs @@ -52,7 +52,7 @@ namespace WireMock.Net.Tests.Owin _requestMapperMock = new Mock(); _requestMapperMock.SetupAllProperties(); var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1"); - _requestMapperMock.Setup(m => m.MapAsync(It.IsAny())).ReturnsAsync(request); + _requestMapperMock.Setup(m => m.MapAsync(It.IsAny(), It.IsAny())).ReturnsAsync(request); _responseMapperMock = new Mock(); _responseMapperMock.SetupAllProperties(); @@ -87,7 +87,7 @@ namespace WireMock.Net.Tests.Owin { // Assign var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary()); - _requestMapperMock.Setup(m => m.MapAsync(It.IsAny())).ReturnsAsync(request); + _requestMapperMock.Setup(m => m.MapAsync(It.IsAny(), It.IsAny())).ReturnsAsync(request); _optionsMock.SetupGet(o => o.AuthorizationMatcher).Returns(new ExactMatcher()); _mappingMock.SetupGet(m => m.IsAdminInterface).Returns(true); @@ -108,7 +108,7 @@ namespace WireMock.Net.Tests.Owin { // Assign var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary { { "h", new[] { "x" } } }); - _requestMapperMock.Setup(m => m.MapAsync(It.IsAny())).ReturnsAsync(request); + _requestMapperMock.Setup(m => m.MapAsync(It.IsAny(), It.IsAny())).ReturnsAsync(request); _optionsMock.SetupGet(o => o.AuthorizationMatcher).Returns(new ExactMatcher()); _mappingMock.SetupGet(m => m.IsAdminInterface).Returns(true); diff --git a/test/WireMock.Net.Tests/Util/BodyParserTests.cs b/test/WireMock.Net.Tests/Util/BodyParserTests.cs index d64374cd..70369e0f 100644 --- a/test/WireMock.Net.Tests/Util/BodyParserTests.cs +++ b/test/WireMock.Net.Tests/Util/BodyParserTests.cs @@ -1,168 +1,185 @@ -using NFluent; -using System.IO; -using System.Text; -using System.Threading.Tasks; -using WireMock.Util; -using Xunit; - -namespace WireMock.Net.Tests.Util -{ - public class BodyParserTests - { - [Theory] - [InlineData("application/json", "{ \"x\": 1 }", BodyType.Json, BodyType.Json)] - [InlineData("application/json; charset=utf-8", "{ \"x\": 1 }", BodyType.Json, BodyType.Json)] - [InlineData("application/json; odata.metadata=minimal", "{ \"x\": 1 }", BodyType.Json, BodyType.Json)] - [InlineData("application/vnd.api+json", "{ \"x\": 1 }", BodyType.Json, BodyType.Json)] - [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) - { - // Arrange - var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsJson)); - - // Act - var body = await BodyParser.Parse(memoryStream, contentType); - - // Assert - Check.That(body.BodyAsBytes).IsNotNull(); - Check.That(body.BodyAsJson).IsNotNull(); - Check.That(body.BodyAsString).Equals(bodyAsJson); - Check.That(body.DetectedBodyType).IsEqualTo(detectedBodyType); - Check.That(body.DetectedBodyTypeFromContentType).IsEqualTo(detectedBodyTypeFromContentType); - } - - [Theory] - [InlineData("application/xml", "hello", BodyType.String, BodyType.String)] - [InlineData("something", "hello", BodyType.String, BodyType.Bytes)] - public async Task BodyParser_Parse_ContentTypeString(string contentType, string bodyAsString, BodyType detectedBodyType, BodyType detectedBodyTypeFromContentType) - { - // Arrange - var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsString)); - - // Act - var body = await BodyParser.Parse(memoryStream, contentType); - - // Assert - Check.That(body.BodyAsBytes).IsNotNull(); - Check.That(body.BodyAsJson).IsNull(); - Check.That(body.BodyAsString).Equals(bodyAsString); - Check.That(body.DetectedBodyType).IsEqualTo(detectedBodyType); - 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] - public async Task BodyParser_Parse_WithUTF8EncodingAndContentTypeMultipart_DetectedBodyTypeEqualsString() - { - // 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.String); - Check.That(result.DetectedBodyTypeFromContentType).IsEqualTo(BodyType.MultiPart); - Check.That(result.BodyAsBytes).IsNotNull(); - Check.That(result.BodyAsJson).IsNull(); - Check.That(result.BodyAsString).IsNotNull(); - } - - [Fact] - public async Task BodyParser_Parse_WithUTF16EncodingAndContentTypeMultipart_DetectedBodyTypeEqualsString() - { - // Arrange - string contentType = "multipart/form-data"; - string body = char.ConvertFromUtf32(0x1D161); //U+1D161 = MUSICAL SYMBOL SIXTEENTH NOTE - - var memoryStream = new MemoryStream(Encoding.UTF32.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) - { - // Arrange - var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsString)); - - // Act - var body = await BodyParser.Parse(memoryStream, contentType); - - // Assert - Check.That(body.BodyAsBytes).IsNotNull(); - Check.That(body.BodyAsJson).IsNull(); - Check.That(body.BodyAsString).Equals(bodyAsString); - Check.That(body.DetectedBodyType).IsEqualTo(detectedBodyType); - Check.That(body.DetectedBodyTypeFromContentType).IsEqualTo(detectedBodyTypeFromContentType); - } - - [Theory] - [InlineData("HEAD", false)] - [InlineData("GET", false)] - [InlineData("PUT", true)] - [InlineData("POST", true)] +using NFluent; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using WireMock.Util; +using Xunit; + +namespace WireMock.Net.Tests.Util +{ + public class BodyParserTests + { + [Theory] + [InlineData("application/json", "{ \"x\": 1 }", BodyType.Json, BodyType.Json)] + [InlineData("application/json; charset=utf-8", "{ \"x\": 1 }", BodyType.Json, BodyType.Json)] + [InlineData("application/json; odata.metadata=minimal", "{ \"x\": 1 }", BodyType.Json, BodyType.Json)] + [InlineData("application/vnd.api+json", "{ \"x\": 1 }", BodyType.Json, BodyType.Json)] + [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) + { + // Arrange + var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsJson)); + + // Act + var body = await BodyParser.Parse(memoryStream, contentType); + + // Assert + Check.That(body.BodyAsBytes).IsNotNull(); + Check.That(body.BodyAsJson).IsNotNull(); + Check.That(body.BodyAsString).Equals(bodyAsJson); + Check.That(body.DetectedBodyType).IsEqualTo(detectedBodyType); + Check.That(body.DetectedBodyTypeFromContentType).IsEqualTo(detectedBodyTypeFromContentType); + } + + [Theory] + [InlineData("application/xml", "hello", BodyType.String, BodyType.String)] + [InlineData("something", "hello", BodyType.String, BodyType.Bytes)] + public async Task BodyParser_Parse_ContentTypeString(string contentType, string bodyAsString, BodyType detectedBodyType, BodyType detectedBodyTypeFromContentType) + { + // Arrange + var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsString)); + + // Act + var body = await BodyParser.Parse(memoryStream, contentType); + + // Assert + Check.That(body.BodyAsBytes).IsNotNull(); + Check.That(body.BodyAsJson).IsNull(); + Check.That(body.BodyAsString).Equals(bodyAsString); + Check.That(body.DetectedBodyType).IsEqualTo(detectedBodyType); + 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] + public async Task BodyParser_Parse_WithUTF8EncodingAndContentTypeMultipart_DetectedBodyTypeEqualsString() + { + // 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.String); + Check.That(result.DetectedBodyTypeFromContentType).IsEqualTo(BodyType.MultiPart); + Check.That(result.BodyAsBytes).IsNotNull(); + Check.That(result.BodyAsJson).IsNull(); + Check.That(result.BodyAsString).IsNotNull(); + } + + [Fact] + public async Task BodyParser_Parse_WithUTF16EncodingAndContentTypeMultipart_DetectedBodyTypeEqualsString() + { + // Arrange + string contentType = "multipart/form-data"; + string body = char.ConvertFromUtf32(0x1D161); //U+1D161 = MUSICAL SYMBOL SIXTEENTH NOTE + + var memoryStream = new MemoryStream(Encoding.UTF32.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) + { + // Arrange + var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(bodyAsString)); + + // Act + var body = await BodyParser.Parse(memoryStream, contentType); + + // Assert + Check.That(body.BodyAsBytes).IsNotNull(); + Check.That(body.BodyAsJson).IsNull(); + Check.That(body.BodyAsString).Equals(bodyAsString); + Check.That(body.DetectedBodyType).IsEqualTo(detectedBodyType); + Check.That(body.DetectedBodyTypeFromContentType).IsEqualTo(detectedBodyTypeFromContentType); + } + + [Theory] + [InlineData("HEAD", false)] + [InlineData("GET", false)] + [InlineData("PUT", true)] + [InlineData("POST", true)] [InlineData("DELETE", false)] [InlineData("TRACE", false)] [InlineData("OPTIONS", true)] [InlineData("CONNECT", false)] - [InlineData("PATCH", true)] - public void BodyParser_ShouldParseBody_ExpectedResultForKnownMethods(string method, bool resultShouldBe) + [InlineData("PATCH", true)] + public void BodyParser_ShouldParseBodyForMethodAndAllowAllIsFalse_ExpectedResultForKnownMethods(string method, bool resultShouldBe) { - Check.That(BodyParser.ShouldParseBody(method)).Equals(resultShouldBe); + Check.That(BodyParser.ShouldParseBody(method, false)).Equals(resultShouldBe); } - [Theory] - [InlineData("REPORT")] - [InlineData("SOME-UNKNOWN-METHOD")] + [Theory] + [InlineData("HEAD")] + [InlineData("GET")] + [InlineData("PUT")] + [InlineData("POST")] + [InlineData("DELETE")] + [InlineData("TRACE")] + [InlineData("OPTIONS")] + [InlineData("CONNECT")] + [InlineData("PATCH")] + [InlineData("REPORT")] + [InlineData("SOME-UNKNOWN-METHOD")] + public void BodyParser_ShouldParseBodyForMethodAndAllowAllIsTrue_ExpectedResultShouldBeTrue(string method) + { + Check.That(BodyParser.ShouldParseBody(method, true)).IsTrue(); + } + + [Theory] + [InlineData("REPORT")] + [InlineData("SOME-UNKNOWN-METHOD")] public void BodyParser_ShouldParseBody_DefaultIsTrueForUnknownMethods(string method) { - Check.That(BodyParser.ShouldParseBody(method)).IsTrue(); - } - } + Check.That(BodyParser.ShouldParseBody(method, false)).IsTrue(); + } + } } \ No newline at end of file