diff --git a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs index 95b6075d..01d45bf9 100644 --- a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs +++ b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs @@ -137,7 +137,6 @@ message HelloReply { public static void Run() { RunOnLocal(); - return; var mappingBuilder = new MappingBuilder(); mappingBuilder @@ -308,17 +307,6 @@ message HelloReply { .RespondWith(Response.Create() .WithBody("GraphQL is ok") ); - - //server - // .AddGraphQLSchema("my-graphql", TestSchema, customScalars) - // .Given(Request.Create() - // .WithPath("/graphql2") - // .UsingPost() - // ) - // .WithGraphQLSchema("my-graphql") - // .RespondWith(Response.Create() - // .WithBody("GraphQL is ok") - // ); #endif #if MIMEKIT @@ -377,6 +365,15 @@ message HelloReply { .WithHeader("Content-Type", "text/plain") ); + server + .Given(Request.Create() + .UsingHead() + .WithPath("/cl") + ) + .RespondWith(Response.Create() + .WithHeader("Content-Length", "42") + ); + server .Given(Request.Create() .UsingMethod("GET") diff --git a/src/WireMock.Net/Http/HttpKnownHeaderNames.cs b/src/WireMock.Net/Http/HttpKnownHeaderNames.cs index 955308c8..fdb13ecf 100644 --- a/src/WireMock.Net/Http/HttpKnownHeaderNames.cs +++ b/src/WireMock.Net/Http/HttpKnownHeaderNames.cs @@ -14,12 +14,12 @@ namespace WireMock.Http; /// internal static class HttpKnownHeaderNames { - // https://docs.microsoft.com/en-us/dotnet/api/system.net.webheadercollection.isrestricted + // - https://docs.microsoft.com/en-us/dotnet/api/system.net.webheadercollection.isrestricted + // - ContentLength is allowed per #720 private static readonly string[] RestrictedResponseHeaders = { Accept, Connection, - ContentLength, ContentType, Date, // RFC1123Pattern Expect, diff --git a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs index d36ae030..694ab2a1 100644 --- a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs +++ b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs @@ -37,13 +37,20 @@ namespace WireMock.Owin.Mappers private readonly Encoding _utf8NoBom = new UTF8Encoding(false); // https://msdn.microsoft.com/en-us/library/78h415ay(v=vs.110).aspx -#if !USE_ASPNETCORE - private static readonly IDictionary>> ResponseHeadersToFix = new Dictionary>>(StringComparer.OrdinalIgnoreCase) { -#else - private static readonly IDictionary>> ResponseHeadersToFix = new Dictionary>>(StringComparer.OrdinalIgnoreCase) { -#endif - { HttpKnownHeaderNames.ContentType, (r, v) => r.ContentType = v.FirstOrDefault() } - }; + private static readonly IDictionary>> ResponseHeadersToFix = + new Dictionary>>(StringComparer.OrdinalIgnoreCase) + { + { HttpKnownHeaderNames.ContentType, (r, _, v) => r.ContentType = v.FirstOrDefault() }, + { HttpKnownHeaderNames.ContentLength, (r, hasBody, v) => + { + // Only set the Content-Length header if the response does not have a body + if (!hasBody && long.TryParse(v.FirstOrDefault(), out var contentLength)) + { + r.ContentLength = contentLength; + } + } + } + }; /// /// Constructor @@ -83,23 +90,21 @@ namespace WireMock.Owin.Mappers } var statusCodeType = responseMessage.StatusCode?.GetType(); - switch (statusCodeType) + if (statusCodeType != null) { - case { } when statusCodeType == typeof(int) || statusCodeType == typeof(int?) || statusCodeType.GetTypeInfo().IsEnum: + if (statusCodeType == typeof(int) || statusCodeType == typeof(int?) || statusCodeType.GetTypeInfo().IsEnum) + { response.StatusCode = MapStatusCode((int)responseMessage.StatusCode!); - break; - - case { } when statusCodeType == typeof(string): - // Note: this case will also match on null - int.TryParse(responseMessage.StatusCode as string, out var result); - response.StatusCode = MapStatusCode(result); - break; - - default: - break; + } + else if (statusCodeType == typeof(string)) + { + // Note: this case will also match on null + int.TryParse(responseMessage.StatusCode as string, out var statusCodeTypeAsInt); + response.StatusCode = MapStatusCode(statusCodeTypeAsInt); + } } - SetResponseHeaders(responseMessage, response); + SetResponseHeaders(responseMessage, bytes, response); if (bytes != null) { @@ -160,7 +165,7 @@ namespace WireMock.Owin.Mappers return null; } - private static void SetResponseHeaders(IResponseMessage responseMessage, IResponse response) + private static void SetResponseHeaders(IResponseMessage responseMessage, byte[]? bytes, IResponse response) { // Force setting the Date header (#577) AppendResponseHeader( @@ -179,11 +184,11 @@ namespace WireMock.Owin.Mappers var value = item.Value; if (ResponseHeadersToFix.TryGetValue(headerName, out var action)) { - action?.Invoke(response, value); + action?.Invoke(response, bytes != null, value); } else { - // Check if this response header can be added (#148 and #227) + // Check if this response header can be added (#148, #227 and #720) if (!HttpKnownHeaderNames.IsRestrictedResponseHeader(headerName)) { AppendResponseHeader(response, headerName, value.ToArray()); @@ -206,7 +211,7 @@ namespace WireMock.Owin.Mappers var value = item.Value; if (ResponseHeadersToFix.TryGetValue(headerName, out var action)) { - action?.Invoke(response, value); + action?.Invoke(response, false, value); } else { diff --git a/test/WireMock.Net.Tests/Owin/Mappers/OwinResponseMapperTests.cs b/test/WireMock.Net.Tests/Owin/Mappers/OwinResponseMapperTests.cs index 6988d2e8..73674d98 100644 --- a/test/WireMock.Net.Tests/Owin/Mappers/OwinResponseMapperTests.cs +++ b/test/WireMock.Net.Tests/Owin/Mappers/OwinResponseMapperTests.cs @@ -25,278 +25,277 @@ using Response = Microsoft.AspNetCore.Http.HttpResponse; using Microsoft.Extensions.Primitives; #endif -namespace WireMock.Net.Tests.Owin.Mappers +namespace WireMock.Net.Tests.Owin.Mappers; + +public class OwinResponseMapperTests { - public class OwinResponseMapperTests + private static readonly Task CompletedTask = Task.FromResult(true); + private readonly OwinResponseMapper _sut; + private readonly Mock _responseMock; + private readonly Mock _stream; + private readonly Mock _headers; + private readonly Mock _fileSystemHandlerMock; + private readonly Mock _optionsMock; + + public OwinResponseMapperTests() { - private static readonly Task CompletedTask = Task.FromResult(true); - private readonly OwinResponseMapper _sut; - private readonly Mock _responseMock; - private readonly Mock _stream; - private readonly Mock _headers; - private readonly Mock _fileSystemHandlerMock; - private readonly Mock _optionsMock; + _stream = new Mock(); + _stream.SetupAllProperties(); + _stream.Setup(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(CompletedTask); - public OwinResponseMapperTests() - { - _stream = new Mock(); - _stream.SetupAllProperties(); - _stream.Setup(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(CompletedTask); + _fileSystemHandlerMock = new Mock(); + _fileSystemHandlerMock.SetupAllProperties(); - _fileSystemHandlerMock = new Mock(); - _fileSystemHandlerMock.SetupAllProperties(); + _optionsMock = new Mock(); + _optionsMock.SetupAllProperties(); + _optionsMock.SetupGet(o => o.FileSystemHandler).Returns(_fileSystemHandlerMock.Object); - _optionsMock = new Mock(); - _optionsMock.SetupAllProperties(); - _optionsMock.SetupGet(o => o.FileSystemHandler).Returns(_fileSystemHandlerMock.Object); - - _headers = new Mock(); - _headers.SetupAllProperties(); + _headers = new Mock(); + _headers.SetupAllProperties(); #if NET452 - _headers.Setup(h => h.AppendValues(It.IsAny(), It.IsAny())); + _headers.Setup(h => h.AppendValues(It.IsAny(), It.IsAny())); #else - _headers.Setup(h => h.Add(It.IsAny(), It.IsAny())); + _headers.Setup(h => h.Add(It.IsAny(), It.IsAny())); #endif - _responseMock = new Mock(); - _responseMock.SetupAllProperties(); - _responseMock.SetupGet(r => r.Body).Returns(_stream.Object); - _responseMock.SetupGet(r => r.Headers).Returns(_headers.Object); + _responseMock = new Mock(); + _responseMock.SetupAllProperties(); + _responseMock.SetupGet(r => r.Body).Returns(_stream.Object); + _responseMock.SetupGet(r => r.Headers).Returns(_headers.Object); - _sut = new OwinResponseMapper(_optionsMock.Object); - } + _sut = new OwinResponseMapper(_optionsMock.Object); + } - [Fact] - public async Task OwinResponseMapper_MapAsync_Null() + [Fact] + public async Task OwinResponseMapper_MapAsync_Null() + { + // Act + await _sut.MapAsync(null, _responseMock.Object).ConfigureAwait(false); + } + + [Theory] + [InlineData(300, 300)] + [InlineData(500, 500)] + public async Task OwinResponseMapper_MapAsync_Valid_StatusCode(object code, int expected) + { + // Arrange + var responseMessage = new ResponseMessage { - // Act - await _sut.MapAsync(null, _responseMock.Object).ConfigureAwait(false); - } + StatusCode = code + }; - [Theory] - [InlineData(300, 300)] - [InlineData(500, 500)] - public async Task OwinResponseMapper_MapAsync_Valid_StatusCode(object code, int expected) + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + + // Assert + _responseMock.VerifySet(r => r.StatusCode = expected, Times.Once); + } + + [Theory] + [InlineData(0, 200)] + [InlineData(-1, 200)] + [InlineData(10000, 200)] + [InlineData(300, 300)] + public async Task OwinResponseMapper_MapAsync_Invalid_StatusCode_When_AllowOnlyDefinedHttpStatusCodeInResponseSet_Is_True(object code, int expected) + { + // Arrange + _optionsMock.SetupGet(o => o.AllowOnlyDefinedHttpStatusCodeInResponse).Returns(true); + var responseMessage = new ResponseMessage { - // Arrange - var responseMessage = new ResponseMessage - { - StatusCode = code - }; + StatusCode = code + }; - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - // Assert - _responseMock.VerifySet(r => r.StatusCode = expected, Times.Once); - } + // Assert + _responseMock.VerifySet(r => r.StatusCode = expected, Times.Once); + } - [Theory] - [InlineData(0, 200)] - [InlineData(-1, 200)] - [InlineData(10000, 200)] - [InlineData(300, 300)] - public async Task OwinResponseMapper_MapAsync_Invalid_StatusCode_When_AllowOnlyDefinedHttpStatusCodeInResponseSet_Is_True(object code, int expected) + [Fact] + public async Task OwinResponseMapper_MapAsync_StatusCode_Is_Null() + { + // Arrange + var responseMessage = new ResponseMessage { - // Arrange - _optionsMock.SetupGet(o => o.AllowOnlyDefinedHttpStatusCodeInResponse).Returns(true); - var responseMessage = new ResponseMessage - { - StatusCode = code - }; + StatusCode = null + }; - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - // Assert - _responseMock.VerifySet(r => r.StatusCode = expected, Times.Once); - } + // Assert + _responseMock.VerifySet(r => r.StatusCode = It.IsAny(), Times.Never); + } - [Fact] - public async Task OwinResponseMapper_MapAsync_StatusCode_Is_Null() + [Theory] + [InlineData(0, 0)] + [InlineData(-1, -1)] + [InlineData(10000, 10000)] + [InlineData(300, 300)] + public async Task OwinResponseMapper_MapAsync_StatusCode_Is_NotInEnumRange(object code, int expected) + { + // Arrange + var responseMessage = new ResponseMessage { - // Arrange - var responseMessage = new ResponseMessage - { - StatusCode = null - }; + StatusCode = code + }; - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - // Assert - _responseMock.VerifySet(r => r.StatusCode = It.IsAny(), Times.Never); - } + // Assert + _responseMock.VerifySet(r => r.StatusCode = expected, Times.Once); + } - [Theory] - [InlineData(0, 0)] - [InlineData(-1, -1)] - [InlineData(10000, 10000)] - [InlineData(300, 300)] - public async Task OwinResponseMapper_MapAsync_StatusCode_Is_NotInEnumRange(object code, int expected) + [Fact] + public async Task OwinResponseMapper_MapAsync_NoBody() + { + // Arrange + var responseMessage = new ResponseMessage { - // Arrange - var responseMessage = new ResponseMessage - { - StatusCode = code - }; + Headers = new Dictionary>() + }; - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - // Assert - _responseMock.VerifySet(r => r.StatusCode = expected, Times.Once); - } + // Assert + _stream.Verify(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } - [Fact] - public async Task OwinResponseMapper_MapAsync_NoBody() + [Fact] + public async Task OwinResponseMapper_MapAsync_Body() + { + // Arrange + string body = "abcd"; + var responseMessage = new ResponseMessage { - // Arrange - var responseMessage = new ResponseMessage - { - Headers = new Dictionary>() - }; + Headers = new Dictionary>(), + BodyData = new BodyData { DetectedBodyType = BodyType.String, BodyAsString = body } + }; - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - // Assert - _stream.Verify(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - } + // Assert + _stream.Verify(s => s.WriteAsync(new byte[] { 97, 98, 99, 100 }, 0, 4, It.IsAny()), Times.Once); + } - [Fact] - public async Task OwinResponseMapper_MapAsync_Body() + [Fact] + public async Task OwinResponseMapper_MapAsync_BodyAsBytes() + { + // Arrange + var bytes = new byte[] { 48, 49 }; + var responseMessage = new ResponseMessage { - // Arrange - string body = "abcd"; - var responseMessage = new ResponseMessage - { - Headers = new Dictionary>(), - BodyData = new BodyData { DetectedBodyType = BodyType.String, BodyAsString = body } - }; + Headers = new Dictionary>(), + BodyData = new BodyData { DetectedBodyType = BodyType.Bytes, BodyAsBytes = bytes } + }; - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - // Assert - _stream.Verify(s => s.WriteAsync(new byte[] { 97, 98, 99, 100 }, 0, 4, It.IsAny()), Times.Once); - } + // Assert + _stream.Verify(s => s.WriteAsync(bytes, 0, bytes.Length, It.IsAny()), Times.Once); + } - [Fact] - public async Task OwinResponseMapper_MapAsync_BodyAsBytes() + [Fact] + public async Task OwinResponseMapper_MapAsync_BodyAsJson() + { + // Arrange + var json = new { t = "x", i = (string?)null }; + var responseMessage = new ResponseMessage { - // Arrange - var bytes = new byte[] { 48, 49 }; - var responseMessage = new ResponseMessage - { - Headers = new Dictionary>(), - BodyData = new BodyData { DetectedBodyType = BodyType.Bytes, BodyAsBytes = bytes } - }; + Headers = new Dictionary>(), + BodyData = new BodyData { DetectedBodyType = BodyType.Json, BodyAsJson = json, BodyAsJsonIndented = false } + }; - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - // Assert - _stream.Verify(s => s.WriteAsync(bytes, 0, bytes.Length, It.IsAny()), Times.Once); - } + // Assert + _stream.Verify(s => s.WriteAsync(new byte[] { 123, 34, 116, 34, 58, 34, 120, 34, 125 }, 0, 9, It.IsAny()), Times.Once); + } - [Fact] - public async Task OwinResponseMapper_MapAsync_BodyAsJson() + [Fact] + public async Task OwinResponseMapper_MapAsync_SetResponseHeaders() + { + // Arrange + var responseMessage = new ResponseMessage { - // Arrange - var json = new { t = "x", i = (string?)null }; - var responseMessage = new ResponseMessage - { - Headers = new Dictionary>(), - BodyData = new BodyData { DetectedBodyType = BodyType.Json, BodyAsJson = json, BodyAsJsonIndented = false } - }; + Headers = new Dictionary> { { "h", new WireMockList("x", "y") } } + }; - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - // Assert - _stream.Verify(s => s.WriteAsync(new byte[] { 123, 34, 116, 34, 58, 34, 120, 34, 125 }, 0, 9, It.IsAny()), Times.Once); - } - - [Fact] - public async Task OwinResponseMapper_MapAsync_SetResponseHeaders() - { - // Arrange - var responseMessage = new ResponseMessage - { - Headers = new Dictionary> { { "h", new WireMockList("x", "y") } } - }; - - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - - // Assert + // Assert #if NET452 - _headers.Verify(h => h.AppendValues("h", new string[] { "x", "y" }), Times.Once); + _headers.Verify(h => h.AppendValues("h", new string[] { "x", "y" }), Times.Once); #else - var v = new StringValues(); - _headers.Verify(h => h.TryGetValue("h", out v), Times.Once); + var v = new StringValues(); + _headers.Verify(h => h.TryGetValue("h", out v), Times.Once); #endif - } + } - [Fact] - public void OwinResponseMapper_MapAsync_BodyAsFile_ThrowsException() + [Fact] + public void OwinResponseMapper_MapAsync_BodyAsFile_ThrowsException() + { + // Arrange + var responseMessage = new ResponseMessage { - // Arrange - var responseMessage = new ResponseMessage - { - Headers = new Dictionary>(), - BodyData = new BodyData { DetectedBodyType = BodyType.File, BodyAsFile = string.Empty } - }; - _fileSystemHandlerMock.Setup(f => f.ReadResponseBodyAsFile(It.IsAny())).Throws(); + Headers = new Dictionary>(), + BodyData = new BodyData { DetectedBodyType = BodyType.File, BodyAsFile = string.Empty } + }; + _fileSystemHandlerMock.Setup(f => f.ReadResponseBodyAsFile(It.IsAny())).Throws(); - // Act - Func action = () => _sut.MapAsync(responseMessage, _responseMock.Object); + // Act + Func action = () => _sut.MapAsync(responseMessage, _responseMock.Object); - // Assert - action.Should().ThrowAsync(); - } + // Assert + action.Should().ThrowAsync(); + } - [Fact] - public async Task OwinResponseMapper_MapAsync_WithFault_EMPTY_RESPONSE() + [Fact] + public async Task OwinResponseMapper_MapAsync_WithFault_EMPTY_RESPONSE() + { + // Arrange + string body = "abc"; + var responseMessage = new ResponseMessage { - // Arrange - string body = "abc"; - var responseMessage = new ResponseMessage - { - Headers = new Dictionary>(), - BodyData = new BodyData { DetectedBodyType = BodyType.String, BodyAsString = body }, - FaultType = FaultType.EMPTY_RESPONSE - }; + Headers = new Dictionary>(), + BodyData = new BodyData { DetectedBodyType = BodyType.String, BodyAsString = body }, + FaultType = FaultType.EMPTY_RESPONSE + }; - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - // Assert - _stream.Verify(s => s.WriteAsync(EmptyArray.Value, 0, 0, It.IsAny()), Times.Once); - } + // Assert + _stream.Verify(s => s.WriteAsync(EmptyArray.Value, 0, 0, It.IsAny()), Times.Once); + } - [Theory] - [InlineData("abcd", BodyType.String)] - [InlineData("", BodyType.String)] - [InlineData(null, BodyType.None)] - public async Task OwinResponseMapper_MapAsync_WithFault_MALFORMED_RESPONSE_CHUNK(string body, BodyType detected) + [Theory] + [InlineData("abcd", BodyType.String)] + [InlineData("", BodyType.String)] + [InlineData(null, BodyType.None)] + public async Task OwinResponseMapper_MapAsync_WithFault_MALFORMED_RESPONSE_CHUNK(string body, BodyType detected) + { + // Arrange + var responseMessage = new ResponseMessage { - // Arrange - var responseMessage = new ResponseMessage - { - Headers = new Dictionary>(), - BodyData = new BodyData { DetectedBodyType = detected, BodyAsString = body }, - StatusCode = 100, - FaultType = FaultType.MALFORMED_RESPONSE_CHUNK - }; + Headers = new Dictionary>(), + BodyData = new BodyData { DetectedBodyType = detected, BodyAsString = body }, + StatusCode = 100, + FaultType = FaultType.MALFORMED_RESPONSE_CHUNK + }; - // Act - await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); + // Act + await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); - // Assert - _responseMock.VerifySet(r => r.StatusCode = 100, Times.Once); - _stream.Verify(s => s.WriteAsync(It.IsAny(), 0, It.Is(count => count >= 0), It.IsAny()), Times.Once); - } + // Assert + _responseMock.VerifySet(r => r.StatusCode = 100, Times.Once); + _stream.Verify(s => s.WriteAsync(It.IsAny(), 0, It.Is(count => count >= 0), It.IsAny()), Times.Once); } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/WireMockServerTests.cs b/test/WireMock.Net.Tests/WireMockServerTests.cs index 4e85d0f1..c53a7aa3 100644 --- a/test/WireMock.Net.Tests/WireMockServerTests.cs +++ b/test/WireMock.Net.Tests/WireMockServerTests.cs @@ -14,6 +14,7 @@ using FluentAssertions; using Newtonsoft.Json; using NFluent; using WireMock.Admin.Mappings; +using WireMock.Http; using WireMock.Matchers; using WireMock.Net.Tests.Serialization; using WireMock.Net.Xunit; @@ -351,7 +352,7 @@ public partial class WireMockServerTests //} [Fact] - public async Task WireMockServer_Should_exclude_restrictedResponseHeader() + public async Task WireMockServer_Should_Exclude_RestrictedResponseHeader() { // Assign string path = $"/foo_{Guid.NewGuid()}"; @@ -371,6 +372,26 @@ public partial class WireMockServerTests server.Stop(); } + [Fact] // #720 + public async Task WireMockServer_Should_AllowResponseHeaderContentLength_For_HEAD() + { + // Assign + const string length = "42"; + var path = $"/cl_{Guid.NewGuid()}"; + using var server = WireMockServer.Start(); + + server + .Given(Request.Create().WithPath(path).UsingHead()) + .RespondWith(Response.Create().WithHeader(HttpKnownHeaderNames.ContentLength, length)); + + // Act + var httpRequestMessage = new HttpRequestMessage(HttpMethod.Head, path); + var response = await server.CreateClient().SendAsync(httpRequestMessage).ConfigureAwait(false); + + // Assert + response.Content.Headers.GetValues(HttpKnownHeaderNames.ContentLength).Should().Contain(length); + } + #if !NET452 && !NET461 [Theory] [InlineData("TRACE")]