Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Bunkum.Core/Endpoints/Middlewares/MainMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ private Response GenerateResponseFromEndpoint(object? val, EndpointAttribute att
return new Response([], ContentType.Plaintext, HttpStatusCode.BadRequest);
}

if (!this.TryGetBodyParameter(attribute, paramType, body, out arg))
// Don't try to deserialize/inject empty bodies if the endpoint explicitly allows them.
if (context.HasBody && !this.TryGetBodyParameter(attribute, paramType, body, out arg))
{
return new Response([], ContentType.Plaintext, HttpStatusCode.BadRequest);
}
Expand Down
20 changes: 20 additions & 0 deletions BunkumTests.HttpServer/Endpoints/BodyEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,32 @@ public Serializable Json(RequestContext context, Serializable body)
return body;
}

[AllowEmptyBody]
[HttpEndpoint("/body/json/optional", HttpMethods.Post, ContentType.Json)]
public Serializable OptionalJson(RequestContext context, Serializable? body)
{
return body ?? new()
{
Field = "had no body",
};
}

[HttpEndpoint("/body/xml", HttpMethods.Post, ContentType.Xml)]
public Serializable Xml(RequestContext context, Serializable body)
{
return body;
}

[AllowEmptyBody]
[HttpEndpoint("/body/xml/optional", HttpMethods.Post, ContentType.Xml)]
public Serializable OptionalXml(RequestContext context, Serializable? body)
{
return body ?? new()
{
Field = "had no body",
};
}

[HttpEndpoint("/body/byteArray", HttpMethods.Post)]
public string ByteArray(RequestContext context, byte[] body)
{
Expand Down
82 changes: 82 additions & 0 deletions BunkumTests.HttpServer/Tests/BodyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,86 @@ public async Task ReturnsBadRequestOnNoData()
HttpResponseMessage msg = await client.PostAsync("/body/string", null);
Assert.That(msg.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
}

[Test]
public async Task RejectsEmptyJsonBodyIfRequired()
{
(BunkumServer server, HttpClient client) = this.Setup();
server.AddEndpointGroup<BodyEndpoints>();

// empty bodies are rejected
HttpResponseMessage msg = await client.PostAsync("/body/json", null);
Assert.That(msg.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));

// but valid bodies are accepted
string requestBody = "{\"Field\":\"has body\"}";
msg = await client.PostAsync("/body/json", new StringContent(requestBody));
Assert.That(msg.StatusCode, Is.EqualTo(HttpStatusCode.OK));

string text = await msg.Content.ReadAsStringAsync();
Assert.That(text, Is.EqualTo(requestBody));
}

[Test]
public async Task AcceptsEmptyJsonBodyIfOptional()
{
(BunkumServer server, HttpClient client) = this.Setup();
server.AddEndpointGroup<BodyEndpoints>();

// empty bodies are accepted
HttpResponseMessage msg = await client.PostAsync("/body/json/optional", null);
Assert.That(msg.StatusCode, Is.EqualTo(HttpStatusCode.OK));

string text = await msg.Content.ReadAsStringAsync();
Assert.That(text, Is.EqualTo("{\"Field\":\"had no body\"}"));

// and valid bodies are also accepted
string requestBody = "{\"Field\":\"has body\"}";
msg = await client.PostAsync("/body/json/optional", new StringContent(requestBody));
Assert.That(msg.StatusCode, Is.EqualTo(HttpStatusCode.OK));

text = await msg.Content.ReadAsStringAsync();
Assert.That(text, Is.EqualTo(requestBody));
}

[Test]
public async Task RejectsEmptyXmlBodyIfRequired()
{
(BunkumServer server, HttpClient client) = this.Setup();
server.AddEndpointGroup<BodyEndpoints>();

// empty bodies are rejected
HttpResponseMessage msg = await client.PostAsync("/body/xml", null);
Assert.That(msg.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));

// but valid bodies are accepted
string requestBody = "<Serializable><Field>has body</Field></Serializable>";
msg = await client.PostAsync("/body/xml", new StringContent(requestBody));
Assert.That(msg.StatusCode, Is.EqualTo(HttpStatusCode.OK));

string text = await msg.Content.ReadAsStringAsync();
Assert.That(text, Is.EqualTo(requestBody));
}

[Test]
public async Task AcceptsEmptyXmlBodyIfOptional()
{
(BunkumServer server, HttpClient client) = this.Setup();
server.AddEndpointGroup<BodyEndpoints>();

// empty bodies are accepted
HttpResponseMessage msg = await client.PostAsync("/body/xml/optional", null);
Assert.That(msg.StatusCode, Is.EqualTo(HttpStatusCode.OK));

string text = await msg.Content.ReadAsStringAsync();
Assert.That(text, Is.EqualTo("<Serializable><Field>had no body</Field></Serializable>"));

// and valid bodies are also accepted
string requestBody = "<Serializable><Field>has body</Field></Serializable>";
msg = await client.PostAsync("/body/xml/optional", new StringContent(requestBody));
Assert.That(msg.StatusCode, Is.EqualTo(HttpStatusCode.OK));

text = await msg.Content.ReadAsStringAsync();
Assert.That(text, Is.EqualTo(requestBody));
}
}