Skip to content

Commit

Permalink
Use Content-Type header from PreMatching filter during media type neg…
Browse files Browse the repository at this point in the history
…otiation

Fixes: quarkusio#45058
  • Loading branch information
geoand committed Dec 12, 2024
1 parent 5df7b0e commit 85e99ff
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,11 @@ public MediaTypeMapper(List<RuntimeResource> runtimeResources) {

@Override
public void handle(ResteasyReactiveRequestContext requestContext) throws Exception {
String contentType = requestContext.serverRequest().getRequestHeader(HttpHeaders.CONTENT_TYPE);
// if there's no Content-Type it's */*
MediaType contentMediaType = contentType != null ? MediaType.valueOf(contentType) : MediaType.WILDCARD_TYPE;
// find the best matching consumes type. Note that the arguments are reversed from their definition
// of desired/provided, but we do want the result to be a media type we consume, since that's how we key
// our methods, rather than the single media type we get from the client. This way we ensure we get the
// best match.
MediaType consumes = MediaTypeHelper.getBestMatch(Collections.singletonList(contentMediaType),
consumesTypes);
MediaType consumes = MediaTypeHelper.getBestMatch(contentTypeFromRequest(requestContext), consumesTypes);
Holder selectedHolder = resourcesByConsumes.get(consumes);
// if we haven't found anything, try selecting the wildcard type, if any
if (selectedHolder == null) {
Expand Down Expand Up @@ -97,6 +93,18 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti
requestContext.restart(selectedResource);
}

private List<MediaType> contentTypeFromRequest(ResteasyReactiveRequestContext requestContext) {
List<String> contentTypeList = requestContext.getHttpHeaders().getRequestHeader(HttpHeaders.CONTENT_TYPE);
if (contentTypeList.isEmpty()) {
return Collections.singletonList(MediaType.WILDCARD_TYPE);
}
List<MediaType> result = new ArrayList<>(contentTypeList.size());
for (String s : contentTypeList) {
result.add(MediaType.valueOf(s));
}
return result;
}

public MediaType selectMediaType(ResteasyReactiveRequestContext requestContext, Holder holder) {
MediaType selected = null;
List<String> accepts = requestContext.getHttpHeaders().getRequestHeader(HttpHeaders.ACCEPT);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.jboss.resteasy.reactive.server.vertx.test.matching;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

import java.io.IOException;
import java.util.function.Supplier;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.PreMatching;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.ext.Provider;

import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

public class PreMatchContentTypeInHeaderTest {

@RegisterExtension
static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest()
.setArchiveProducer(new Supplier<>() {
@Override
public JavaArchive get() {
return ShrinkWrap.create(JavaArchive.class);
}
});

@Test
public void filterNotSettingContentType() {
given()
.header("Content-Type", "application/json")
.body("[]")
.when()
.post("/test")
.then()
.statusCode(200)
.body(is("json-[]"));

given()
.header("Content-Type", "text/plain")
.body("input")
.when()
.post("/test")
.then()
.statusCode(200)
.body(is("text-input"));
}

@Test
public void filterSettingContentTypeToText() {
given()
.header("Content-Type", "application/json")
.header("test-content-type", "text/plain")
.body("[]")
.when()
.post("/test")
.then()
.statusCode(200)
.body(is("text-[]"));
}

@Test
public void filterSettingContentTypeToJson() {
given()
.header("Content-Type", "text/plain")
.header("test-content-type", "application/json")
.body("input")
.when()
.post("/test")
.then()
.statusCode(200)
.body(is("json-input"));
}

@Path("test")
public static class TestResource {

@POST
@Consumes(MediaType.TEXT_PLAIN)
public String fromText(String input) {
return "text-" + input;
}

@POST
@Consumes(MediaType.APPLICATION_JSON)
public String fromJson(String input) {
return "json-" + input;
}
}

public record Result(String message) {

}

@Provider
@PreMatching
public static class Filter implements ContainerRequestFilter {

@Override
public void filter(ContainerRequestContext context) throws IOException {
String testContentType = context.getHeaderString("test-content-type");
if (testContentType != null) {
context.getHeaders().putSingle("Content-Type", testContentType);
}
}
}
}

0 comments on commit 85e99ff

Please sign in to comment.