Skip to content

Commit 272c882

Browse files
Kay WerndliVerKWer
authored andcommitted
4.x: Fix resolved URI query params (#8566)
The ClientRequestBase class did not properly resolve URIs when path- and query parameters were mixed. More specifically, the query parameters were stripped if the URI template was absolute.
1 parent e7ad9de commit 272c882

File tree

3 files changed

+135
-3
lines changed

3 files changed

+135
-3
lines changed

webclient/api/src/main/java/io/helidon/webclient/api/ClientRequestBase.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import io.helidon.common.tls.Tls;
3838
import io.helidon.common.uri.UriEncoding;
3939
import io.helidon.common.uri.UriFragment;
40+
import io.helidon.common.uri.UriQuery;
4041
import io.helidon.http.ClientRequestHeaders;
4142
import io.helidon.http.Header;
4243
import io.helidon.http.HeaderNames;
@@ -437,10 +438,19 @@ protected MediaContext mediaContext() {
437438
protected ClientUri resolveUri(ClientUri toResolve) {
438439
if (uriTemplate != null) {
439440
String resolved = resolvePathParams(uriTemplate);
441+
URI uri;
440442
if (skipUriEncoding) {
441-
toResolve.resolve(URI.create(resolved));
443+
uri = URI.create(resolved);
442444
} else {
443-
toResolve.resolve(URI.create(UriEncoding.encodeUri(resolved)));
445+
uri = URI.create(UriEncoding.encodeUri(resolved));
446+
}
447+
toResolve.resolve(uri);
448+
449+
if (uri.isAbsolute()) { // query parameters are cleared when resolving against absolute URIs
450+
UriQuery query = clientUri.query();
451+
if (!query.isEmpty()) {
452+
toResolve.writeableQuery().from(query);
453+
}
444454
}
445455
}
446456
return toResolve;
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright (c) 2024 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.helidon.webclient.api;
18+
19+
import io.helidon.common.uri.UriPath;
20+
import io.helidon.http.Method;
21+
import org.junit.jupiter.api.Test;
22+
23+
import java.util.Collections;
24+
25+
import static org.hamcrest.CoreMatchers.is;
26+
import static org.hamcrest.MatcherAssert.assertThat;
27+
28+
class ClientRequestBaseTest {
29+
30+
/**
31+
* Verify that query parameters are preserved when resolving URI templates (cf. issue #8566).
32+
* Make sure to test both absolute and relative URIs as they are handled differently when resolving.
33+
*/
34+
@Test
35+
public void resolvedUriTest() {
36+
ClientUri uri = new FakeClientRequest()
37+
.uri("https://www.example.com/")
38+
.queryParam("k", "v").resolvedUri();
39+
assertThat(uri.authority(), is("www.example.com:443"));
40+
assertThat(uri.host(), is("www.example.com"));
41+
assertThat(uri.path(), is(UriPath.root()));
42+
assertThat(uri.port(), is(443));
43+
assertThat(uri.scheme(), is("https"));
44+
assertThat(uri.query().get("k"), is("v"));
45+
46+
uri = new FakeClientRequest()
47+
.uri("https://www.example.com/{path}")
48+
.pathParam("path", "p")
49+
.queryParam("k", "v").resolvedUri();
50+
assertThat(uri.authority(), is("www.example.com:443"));
51+
assertThat(uri.host(), is("www.example.com"));
52+
assertThat(uri.path(), is(UriPath.create("/p")));
53+
assertThat(uri.port(), is(443));
54+
assertThat(uri.scheme(), is("https"));
55+
assertThat(uri.query().get("k"), is("v"));
56+
57+
uri = new FakeClientRequest()
58+
.uri("example/{path}")
59+
.pathParam("path", "p")
60+
.queryParam("k", "v").resolvedUri();
61+
assertThat(uri.authority(), is("localhost:80"));
62+
assertThat(uri.host(), is("localhost"));
63+
assertThat(uri.path(), is(UriPath.create("/example/p")));
64+
assertThat(uri.port(), is(80));
65+
assertThat(uri.scheme(), is("http"));
66+
assertThat(uri.query().get("k"), is("v"));
67+
68+
uri = new FakeClientRequest()
69+
.uri("https://www.example.com/p?k={k}")
70+
.pathParam("k", "v")
71+
.queryParam("k", "v").resolvedUri();
72+
assertThat(uri.authority(), is("www.example.com:443"));
73+
assertThat(uri.host(), is("www.example.com"));
74+
assertThat(uri.path(), is(UriPath.create("/p%3Fk=v")));
75+
assertThat(uri.port(), is(443));
76+
assertThat(uri.scheme(), is("https"));
77+
assertThat(uri.query().get("k"), is("v"));
78+
}
79+
80+
81+
private static final class FakeClientRequest extends ClientRequestBase<FakeClientRequest, HttpClientResponse> {
82+
private FakeClientRequest() {
83+
super(WebClientConfig.create(), null, "fake", Method.GET, ClientUri.create(), Collections.emptyMap());
84+
}
85+
86+
@Override
87+
protected HttpClientResponse doSubmit(Object entity) {
88+
return null;
89+
}
90+
91+
@Override
92+
protected HttpClientResponse doOutputStream(OutputStreamHandler outputStreamHandler) {
93+
return null;
94+
}
95+
}
96+
}

webclient/api/src/test/java/io/helidon/webclient/api/ClientUriTest.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,30 @@ void testResolveQuery() {
131131
assertThat(clientUri.query().get("filter"), is("a b c"));
132132
assertThat(clientUri.query().getRaw("filter"), is("a%20b%20c"));
133133
}
134-
}
134+
135+
/**
136+
* Verifies that {@link ClientUri#resolve(ClientUri)} retains query parameters but {@link ClientUri#resolve(URI)}
137+
* doesn't (which is the same behaviour as {@link URI#resolve(URI)}).
138+
*/
139+
@Test
140+
void testResolveQueryParameter() {
141+
ClientUri helper = ClientUri.create(URI.create("http://localhost:8080/?k=v"));
142+
URI uri = URI.create("https://www.example.com:80");
143+
helper.resolve(uri);
144+
assertThat(helper.authority(), is("www.example.com:80"));
145+
assertThat(helper.host(), is("www.example.com"));
146+
assertThat(helper.path(), is(UriPath.root()));
147+
assertThat(helper.port(), is(80));
148+
assertThat(helper.scheme(), is("https"));
149+
assertThat("unexpected query parameter: 'k'", !helper.query().contains("k"));
150+
151+
helper = ClientUri.create(URI.create("http://localhost:8080/?k=v"));
152+
helper.resolve(ClientUri.create(uri));
153+
assertThat(helper.authority(), is("www.example.com:80"));
154+
assertThat(helper.host(), is("www.example.com"));
155+
assertThat(helper.path(), is(UriPath.root()));
156+
assertThat(helper.port(), is(80));
157+
assertThat(helper.scheme(), is("https"));
158+
assertThat(helper.query().get("k"), is("v"));
159+
}
160+
}

0 commit comments

Comments
 (0)