Skip to content

Commit bcf7e56

Browse files
authored
Merge pull request #49726 from janscheidegger/do-not-decode-query-params
Do not decode query params in request filter
2 parents 3f48984 + 90c18c4 commit bcf7e56

File tree

7 files changed

+92
-2
lines changed

7 files changed

+92
-2
lines changed

extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/stork/HelloClient.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import jakarta.ws.rs.POST;
66
import jakarta.ws.rs.Path;
77
import jakarta.ws.rs.PathParam;
8+
import jakarta.ws.rs.QueryParam;
89
import jakarta.ws.rs.core.MediaType;
910

1011
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
@@ -23,4 +24,8 @@ public interface HelloClient {
2324
@GET
2425
@Path("/{name}")
2526
public String helloWithPathParam(@PathParam("name") String name);
27+
28+
@GET
29+
@Path("/query")
30+
public String helloWithQueryParam(@QueryParam("foo") String foo);
2631
}

extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/stork/HelloResource.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import jakarta.ws.rs.Path;
66
import jakarta.ws.rs.PathParam;
77
import jakarta.ws.rs.Produces;
8+
import jakarta.ws.rs.QueryParam;
89
import jakarta.ws.rs.core.Context;
910
import jakarta.ws.rs.core.MediaType;
1011
import jakarta.ws.rs.core.Request;
@@ -26,6 +27,12 @@ public String invoke(@PathParam("name") String name) {
2627
return "Hello, " + name;
2728
}
2829

30+
@GET
31+
@Path("/query")
32+
public String helloWithQueryParam(@QueryParam("foo") String foo) {
33+
return "Hello, this is your query parameter: " + foo;
34+
}
35+
2936
@POST
3037
public String echo(String name, @Context Request request) {
3138
return "hello, " + name;

extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/stork/PassThroughResource.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import jakarta.ws.rs.GET;
66
import jakarta.ws.rs.Path;
77
import jakarta.ws.rs.PathParam;
8+
import jakarta.ws.rs.QueryParam;
89

910
import org.eclipse.microprofile.rest.client.RestClientBuilder;
1011
import org.eclipse.microprofile.rest.client.inject.RestClient;
@@ -29,6 +30,12 @@ public String invokeClientWithPathParamContainingSlash(@PathParam("name") String
2930
return client.helloWithPathParam(name + "/" + name);
3031
}
3132

33+
@Path("/v2/query")
34+
@GET
35+
public String invokeClientWithQueryParam(@QueryParam("foo") String foo) {
36+
return client.helloWithQueryParam(foo);
37+
}
38+
3239
@Path("/{name}")
3340
@GET
3441
public String invokeClientWithPathParam(@PathParam("name") String name) {

extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/stork/StorkDevModeTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ void shouldSayHelloNameWithSlash() {
7979

8080
}
8181

82+
@Test
83+
void shouldEncodeQueryCorrectly() {
84+
when()
85+
.get("/helper/v2/query?foo=cigüeña")
86+
.then()
87+
.statusCode(200)
88+
.body(equalTo("Hello, this is your query parameter: cigüeña"));
89+
90+
}
91+
8292
@Test
8393
void shouldSayHelloNameWithBlank() {
8494
when()

independent-projects/resteasy-reactive/client/runtime/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@
6363
<artifactId>junit-jupiter</artifactId>
6464
<scope>test</scope>
6565
</dependency>
66+
<dependency>
67+
<groupId>org.mockito</groupId>
68+
<artifactId>mockito-core</artifactId>
69+
<scope>test</scope>
70+
</dependency>
6671

6772
<dependency>
6873
<groupId>org.jboss.logging</groupId>

independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/StorkClientRequestFilter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ public void filter(ResteasyReactiveClientRequestContext requestContext) {
9090
//To avoid the path double encoding we create uri with path=null and set the path after
9191
URI newUri = new URI(scheme,
9292
uri.getUserInfo(), host, port,
93-
null, uri.getQuery(), uri.getFragment());
94-
URI build = UriBuilder.fromUri(newUri).path(actualPath).build();
93+
null, null, uri.getFragment());
94+
URI build = UriBuilder.fromUri(newUri).path(actualPath).replaceQuery(uri.getRawQuery()).build();
9595
requestContext.setUri(build);
9696
if (measureTime && instance.gatherStatistics()) {
9797
requestContext.setCallStatsCollector(instance);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.jboss.resteasy.reactive.client.impl;
2+
3+
import static org.mockito.Mockito.anyBoolean;
4+
import static org.mockito.Mockito.anyString;
5+
import static org.mockito.Mockito.argThat;
6+
import static org.mockito.Mockito.mock;
7+
import static org.mockito.Mockito.mockStatic;
8+
import static org.mockito.Mockito.verify;
9+
import static org.mockito.Mockito.when;
10+
11+
import java.net.URI;
12+
13+
import jakarta.ws.rs.core.GenericType;
14+
15+
import org.jboss.resteasy.reactive.client.spi.ResteasyReactiveClientRequestContext;
16+
import org.junit.jupiter.api.Test;
17+
import org.mockito.MockedStatic;
18+
19+
import io.smallrye.mutiny.Multi;
20+
import io.smallrye.mutiny.Uni;
21+
import io.smallrye.stork.Stork;
22+
import io.smallrye.stork.api.Service;
23+
import io.smallrye.stork.api.ServiceInstance;
24+
25+
class StorkClientRequestFilterTest {
26+
@Test
27+
void testQueryEncoding() {
28+
// Given
29+
Stork mockStork = mock(Stork.class);
30+
try (MockedStatic<Stork> storkStatic = mockStatic(Stork.class)) {
31+
storkStatic.when(Stork::getInstance).thenReturn(mockStork);
32+
Service mockedService = mock(Service.class);
33+
ServiceInstance mockedServiceInstance = mock(ServiceInstance.class);
34+
when(mockStork.getService(anyString())).thenReturn(mockedService);
35+
when(mockedService.selectInstanceAndRecordStart(anyBoolean()))
36+
.thenReturn(Uni.createFrom().item(mockedServiceInstance));
37+
StorkClientRequestFilter filter = new StorkClientRequestFilter();
38+
ResteasyReactiveClientRequestContext context = mock(ResteasyReactiveClientRequestContext.class);
39+
40+
URI originalUri = URI
41+
.create("stork://my-service/some/path?foo=bar%20baz&special=%26%3D&ae=%C3%A4&oe=%C3%B6&ue=%C3%BC");
42+
when(context.getUri()).thenReturn(originalUri);
43+
when(context.getResponseType()).thenReturn(new GenericType<>(Multi.class));
44+
45+
// When
46+
filter.filter(context);
47+
48+
// Then
49+
verify(context).setUri(argThat(uri -> {
50+
// Query should be preserved and properly encoded
51+
return "http://localhost:80/some/path?foo=bar%20baz&special=%26%3D&ae=%C3%A4&oe=%C3%B6&ue=%C3%BC"
52+
.equals(uri.toString());
53+
}));
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)