Skip to content

Commit bc2d310

Browse files
committed
fix: Return 400 for malformed request bodies
An unparseable request body (e.g. a double comma in JSON) made the body mapper throw its library-specific runtime exception, which fell through to the default 500 branch of the exception handler. Convert any parse failure at the single mapper.readFrom call site into a ValidationException so it renders as a 400 application/problem+json response, consistent with the other body-validation errors. Covers all body mappers. HCC-14723
1 parent e9cfa18 commit bc2d310

2 files changed

Lines changed: 40 additions & 1 deletion

File tree

src/main/java/com/retailsvc/http/internal/RequestPreparationFilter.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,18 @@ private ParsedBody validateAndParseBody(HttpExchange exchange, Operation op, byt
243243
new ValidationError(
244244
BODY_POINTER, "content-type", "unsupported content type: " + mediaType, null));
245245
}
246-
Object parsed = mapper.readFrom(body, header);
246+
Object parsed;
247+
try {
248+
parsed = mapper.readFrom(body, header);
249+
} catch (ValidationException e) {
250+
throw e;
251+
} catch (RuntimeException e) {
252+
// Body could not be parsed (e.g. malformed JSON). Untrusted input -> 400, not 500.
253+
LOG.debug("Failed to parse request body", e);
254+
throw new ValidationException(
255+
new ValidationError(
256+
BODY_POINTER, "malformed", "request body is not valid " + mediaType, null));
257+
}
247258
if (mediaType.equals("application/x-www-form-urlencoded") && parsed instanceof Map<?, ?> map) {
248259
@SuppressWarnings("unchecked")
249260
Map<String, Object> typed = (Map<String, Object>) map;

src/test/java/com/retailsvc/http/OpenApiServerIT.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,34 @@ void postDataShouldReturnJsonBody() {
127127
}
128128
}
129129

130+
@Test
131+
void postDataShouldReturnBadRequestOnMalformedJson() {
132+
try (var server = newServer(Map.of("post-data", new EchoHandler()));
133+
var client = httpClient()) {
134+
135+
// Double comma after a property is invalid JSON; must be 400, not 500 (HCC-14723).
136+
var body = "{\"id\":\"some-id\",,\"age\":42}";
137+
var headers = Map.of("correlation-id", UUID.randomUUID().toString());
138+
var request = newRequest(server, path, "POST", ofString(body), headers);
139+
140+
var response = client.send(request, BodyHandlers.ofString());
141+
var statusCode = response.statusCode();
142+
var contentType = response.headers().firstValue("Content-Type").orElse("");
143+
var responseBody = response.body();
144+
145+
assertThat(statusCode).isEqualTo(400);
146+
assertThat(contentType).contains("application/problem+json");
147+
assertThat(responseBody).contains("keyword");
148+
assertThat(responseBody).contains("pointer");
149+
150+
} catch (IOException e) {
151+
fail(e);
152+
} catch (InterruptedException e) {
153+
Thread.currentThread().interrupt();
154+
fail(e);
155+
}
156+
}
157+
130158
@Test
131159
void postDataShouldReturnBadRequestOnMissingRequiredProperties() {
132160
Map<String, RequestHandler> handlers = Map.of("post-data", new EchoHandler());

0 commit comments

Comments
 (0)