diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/java/io/quarkus/resteasy/reactive/server/servlet/runtime/ServletRequestContext.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/java/io/quarkus/resteasy/reactive/server/servlet/runtime/ServletRequestContext.java index 6788338a6e444..43f562f444e85 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/java/io/quarkus/resteasy/reactive/server/servlet/runtime/ServletRequestContext.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-servlet/runtime/src/main/java/io/quarkus/resteasy/reactive/server/servlet/runtime/ServletRequestContext.java @@ -34,6 +34,7 @@ import org.jboss.resteasy.reactive.spi.ThreadSetupAction; import io.netty.channel.EventLoop; +import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.util.concurrent.ScheduledFuture; import io.quarkus.arc.Arc; import io.quarkus.arc.impl.LazyValue; @@ -44,6 +45,7 @@ import io.undertow.server.HttpServerExchange; import io.undertow.server.ResponseCommitListener; import io.vertx.core.Handler; +import io.vertx.core.MultiMap; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; import io.vertx.core.net.impl.ConnectionBase; @@ -112,6 +114,16 @@ public ServerHttpResponse serverResponse() { return this; } + @Override + protected void setQueryParamsFrom(String uri) { + MultiMap map = context.queryParams(); + map.clear(); + Map> decodedParams = new QueryStringDecoder(uri).parameters(); + for (Map.Entry> entry : decodedParams.entrySet()) { + map.add(entry.getKey(), entry.getValue()); + } + } + protected void handleRequestScopeActivation() { super.handleRequestScopeActivation(); QuarkusHttpUser user = (QuarkusHttpUser) context.user(); diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java index 74333c9ad1c63..f309df5d6ad4b 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ResteasyReactiveRequestContext.java @@ -28,6 +28,7 @@ import javax.ws.rs.ext.ReaderInterceptor; import javax.ws.rs.ext.WriterInterceptor; +import org.jboss.resteasy.reactive.common.NotImplementedYet; import org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext; import org.jboss.resteasy.reactive.common.util.Encode; import org.jboss.resteasy.reactive.common.util.PathSegmentImpl; @@ -470,13 +471,17 @@ public ResteasyReactiveRequestContext setRequestUri(URI requestURI) { this.path = requestURI.getPath(); this.authority = requestURI.getRawAuthority(); this.scheme = requestURI.getScheme(); - // FIXME: it's possible we may have to also update the query part + setQueryParamsFrom(requestURI.toString()); // invalidate those this.uriInfo = null; this.absoluteUri = null; return this; } + protected void setQueryParamsFrom(String uri) { + throw new NotImplementedYet(); + } + /** * Returns the current response content type. If a response has been set and has an * explicit content type then this is used, otherwise it returns any content type diff --git a/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxResteasyReactiveRequestContext.java b/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxResteasyReactiveRequestContext.java index 7540644cabff5..084c6cf9f6153 100644 --- a/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxResteasyReactiveRequestContext.java +++ b/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxResteasyReactiveRequestContext.java @@ -28,10 +28,12 @@ import io.netty.buffer.Unpooled; import io.netty.channel.EventLoop; import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.util.concurrent.ScheduledFuture; import io.vertx.core.AsyncResult; import io.vertx.core.Context; import io.vertx.core.Handler; +import io.vertx.core.MultiMap; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpServerRequest; @@ -106,6 +108,16 @@ public ServerHttpResponse serverResponse() { return this; } + @Override + protected void setQueryParamsFrom(String uri) { + MultiMap map = context.queryParams(); + map.clear(); + Map> decodedParams = new QueryStringDecoder(uri).parameters(); + for (Map.Entry> entry : decodedParams.entrySet()) { + map.add(entry.getKey(), entry.getValue()); + } + } + @Override protected EventLoop getEventLoop() { return ((ConnectionBase) context.request().connection()).channel().eventLoop(); diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/resource/basic/RequestFilterQueryParamsTest.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/resource/basic/RequestFilterQueryParamsTest.java new file mode 100644 index 0000000000000..130f8c79598bf --- /dev/null +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/resource/basic/RequestFilterQueryParamsTest.java @@ -0,0 +1,66 @@ +package org.jboss.resteasy.reactive.server.vertx.test.resource.basic; + +import static io.restassured.RestAssured.get; + +import java.io.IOException; +import java.net.URI; + +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.ext.Provider; + +import org.hamcrest.Matchers; +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 RequestFilterQueryParamsTest { + + @RegisterExtension + static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(BlockingHelloResource.class, ReplacePathAndQueryParamsFilter.class)); + + @Test + public void test() { + get("/dummy") + .then() + .statusCode(200) + .body(Matchers.equalTo("Hello filter")); + } + + @Path("hello") + public static class BlockingHelloResource { + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello(@QueryParam("name") @DefaultValue("world") String name) { + return "Hello " + name; + } + } + + @Provider + @PreMatching + public static class ReplacePathAndQueryParamsFilter implements ContainerRequestFilter { + + @Override + public void filter(ContainerRequestContext requestContext) + throws IOException { + UriBuilder builder = requestContext.getUriInfo().getRequestUriBuilder(); + builder.replacePath("/hello"); + builder.replaceQueryParam("name", "filter"); + URI uri = builder.build(); + requestContext.setRequestUri(uri); + } + } +}