diff --git a/reference/rest/src/main/java/io/a2a/server/rest/quarkus/A2AServerRoutes.java b/reference/rest/src/main/java/io/a2a/server/rest/quarkus/A2AServerRoutes.java index 19399c18a..11f5ab299 100644 --- a/reference/rest/src/main/java/io/a2a/server/rest/quarkus/A2AServerRoutes.java +++ b/reference/rest/src/main/java/io/a2a/server/rest/quarkus/A2AServerRoutes.java @@ -346,7 +346,7 @@ public void getTask(RoutingContext rc) { */ @Route(regex = "^\\/(?[^\\/]*\\/?)tasks\\/(?[^/]+):cancel$", order = 1, methods = {Route.HttpMethod.POST}, type = Route.HandlerType.BLOCKING) public void cancelTask(@Body String body, RoutingContext rc) { - if (!validateContentType(rc)) { + if (!validateContentTypeForOptionalBody(rc, body)) { return; } String taskId = rc.pathParam("taskId"); @@ -624,6 +624,25 @@ private boolean validateContentType(RoutingContext rc) { return true; } + /** + * Check if the request content type is application/json when body content is present. + * Per RFC 9110 ยง8.3, Content-Type is only meaningful when a message body is present. + * Use this for endpoints where the body is optional. + * + * @param rc the routing context + * @param body the request body (may be null or empty) + * @return true if validation passes, false if Content-Type error should be returned + */ + private boolean validateContentTypeForOptionalBody(RoutingContext rc, @Nullable String body) { + // If body is null or empty, Content-Type is not required + if (body == null || body.isBlank()) { + return true; + } + + // Body has content - validate Content-Type + return validateContentType(rc); + } + /** * Retrieves the public agent card for agent discovery. *