Skip to content

Commit

Permalink
fix: when setting any content header after setting the HttpContent wi…
Browse files Browse the repository at this point in the history
…th JsonBody (or any other custom IResponseBehavior) it would reset the HttpContent to an empty content. (#99)
  • Loading branch information
skwasjer authored Jan 31, 2024
1 parent 48dd275 commit cf3f387
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 10 deletions.
19 changes: 19 additions & 0 deletions src/MockHttp/Language/Flow/Response/EnsureHttpContentBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using MockHttp.Responses;

namespace MockHttp.Language.Flow.Response;

internal sealed class EnsureHttpContentBehavior
: IResponseBehavior
{
public Task HandleAsync
(
MockHttpRequestContext requestContext,
HttpResponseMessage responseMessage,
ResponseHandlerDelegate next,
CancellationToken cancellationToken)
{
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
responseMessage.Content ??= new EmptyContent();
return next(requestContext, responseMessage, cancellationToken);
}
}
15 changes: 5 additions & 10 deletions src/MockHttp/Language/Flow/Response/ResponseBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ internal sealed class ResponseBuilder
IWithContentResult,
IWithHeadersResult
{
private static readonly Func<CancellationToken, Task<HttpContent>> EmptyHttpContentFactory = _ => Task.FromResult<HttpContent>(new EmptyContent());

/// <inheritdoc />
public IList<IResponseBehavior> Behaviors { get; } = new List<IResponseBehavior>();
public IList<IResponseBehavior> Behaviors { get; } = new List<IResponseBehavior>
{
// We're adding this default behavior as the first step, to ensure HttpContent is not null initially.
new EnsureHttpContentBehavior()
};

/// <inheritdoc />
public IWithStatusCodeResult StatusCode(HttpStatusCode statusCode, string? reasonPhrase = null)
Expand Down Expand Up @@ -56,12 +58,6 @@ public IWithHeadersResult Headers(IEnumerable<KeyValuePair<string, IEnumerable<s
throw new ArgumentException("At least one header must be specified.", nameof(headers));
}

// If no content when adding headers, we force empty content so that content headers can still be set.
if (!Behaviors.OfType<HttpContentBehavior>().Any())
{
Body(EmptyHttpContentFactory);
}

Behaviors.Add(new HttpHeaderBehavior(headerList));
return this;
}
Expand Down Expand Up @@ -157,4 +153,3 @@ int CompareOtherWayAround(int result)
}
}
}

45 changes: 45 additions & 0 deletions test/MockHttp.Json.Tests/Issues/Issue98.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Net;
using System.Text;
using MockHttp.FluentAssertions;
using Newtonsoft.Json;

namespace MockHttp.Json.Issues;

public class Issue98
{
[Fact]
public async Task When_setting_content_header_after_setting_jsonBody_it_should_return_expected_response()
{
using var mockHttp = new MockHttpHandler();
mockHttp
.When(m => m
.Method(HttpMethod.Post)
.RequestUri("api/login")
.ContentType("application/json; charset=utf-8")
.JsonBody(new { username = @"corp\user", password = "Super.Mari0.Bro$$" })
)
.Respond(r => r
.StatusCode(HttpStatusCode.OK)
.JsonBody(new { username = "user@corp" }, Encoding.UTF8)
.Header("Set-Cookie",
"session=abcdefghi==; Expires=Tue, 01 Feb 2024 01:01:01 GMT; Secure; HttpOnly; Path=/")
)
.Verifiable();

var client = new HttpClient(mockHttp)
{
BaseAddress = new Uri("http://localhost")
};
// Act
HttpResponseMessage? response = await client.PostAsJsonAsync("api/login", new { username = @"corp\user", password = @"Super.Mari0.Bro$$" });

// Assert
response.Should().HaveStatusCode(HttpStatusCode.OK);
response.Headers.Should()
.ContainKey("Set-Cookie",
"session=abcdefghi==; Expires=Tue, 01 Feb 2024 01:01:01 GMT; Secure; HttpOnly; Path=/");
response.Should().HaveContentType("application/json; charset=utf-8");
await response.Should().HaveContentAsync(JsonConvert.SerializeObject(new { username = "user@corp" }), Encoding.UTF8);
mockHttp.Verify();
}
}

0 comments on commit cf3f387

Please sign in to comment.