From d4619c42ee5c8c54f99fa5f4ab3b73f650e1887e Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Wed, 10 Jan 2024 18:07:20 +0200 Subject: [PATCH] Use headers set in PreMatching filter during media type negotiation Fixes: #38130 --- .../server/handlers/MediaTypeMapper.java | 8 +- .../test/matching/PreMatchAcceptInHeader.java | 124 ++++++++++++++++++ 2 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeader.java diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java index 20d6749cc8299..054febcab4d5c 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/MediaTypeMapper.java @@ -17,7 +17,6 @@ import org.jboss.resteasy.reactive.common.util.ServerMediaType; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; import org.jboss.resteasy.reactive.server.mapping.RuntimeResource; -import org.jboss.resteasy.reactive.server.spi.ServerHttpRequest; import org.jboss.resteasy.reactive.server.spi.ServerRestHandler; /** @@ -100,12 +99,13 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti public MediaType selectMediaType(ResteasyReactiveRequestContext requestContext, Holder holder) { MediaType selected = null; - ServerHttpRequest httpServerRequest = requestContext.serverRequest(); - if (httpServerRequest.containsRequestHeader(HttpHeaders.ACCEPT)) { + List accepts = requestContext.getHttpHeaders().getRequestHeader(HttpHeaders.ACCEPT); + for (String accept : accepts) { Map.Entry entry = holder.serverMediaType - .negotiateProduces(requestContext.serverRequest().getRequestHeader(HttpHeaders.ACCEPT), null); + .negotiateProduces(accept, null); if (entry.getValue() != null) { selected = entry.getValue(); + break; } } if (selected == null) { diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeader.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeader.java new file mode 100644 index 0000000000000..cfbd44a4795fc --- /dev/null +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/matching/PreMatchAcceptInHeader.java @@ -0,0 +1,124 @@ +package org.jboss.resteasy.reactive.server.vertx.test.matching; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; + +import java.util.function.Supplier; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerRequestFilter; +import jakarta.ws.rs.container.PreMatching; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +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 PreMatchAcceptInHeader { + + @RegisterExtension + static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest() + .setArchiveProducer(new Supplier<>() { + @Override + public JavaArchive get() { + return ShrinkWrap.create(JavaArchive.class) + .addClass(PathSegmentTest.Resource.class); + } + }); + + @Test + void browserDefault() { + given().accept("text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8") + .when() + .get("test") + .then() + .statusCode(200) + .body(containsString("")); + } + + @Test + void text() { + given().accept("text/plain") + .when() + .get("test") + .then() + .statusCode(200) + .body(equalTo("test")); + } + + @Test + void html() { + given().accept("text/html") + .when() + .get("test") + .then() + .statusCode(200) + .body(equalTo("test")); + } + + @Test + void json() { + given().accept("application/json") + .when() + .get("test") + .then() + .statusCode(404); + } + + @Test + void setAcceptToTextInFilter() { + given().accept("application/json") + .header("x-set-accept-to-text", "true") + .when() + .get("test") + .then() + .statusCode(200) + .body(equalTo("test")); + } + + @Path("/test") + public static class Resource { + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String text() { + return "text"; + } + + @GET + @Produces(MediaType.TEXT_HTML) + public String html() { + return """ + + + + + Hello World + + + """; + } + } + + @PreMatching + @Provider + public static class SetAcceptHeaderFilter implements ContainerRequestFilter { + + @Override + public void filter(ContainerRequestContext requestContext) { + MultivaluedMap headers = requestContext.getHeaders(); + if ("true".equals(headers.getFirst("x-set-accept-to-text"))) { + headers.putSingle(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN); + } + } + } +}