Skip to content

Commit c0b6dba

Browse files
author
Kay Werndli
committed
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 33c7b97 commit c0b6dba

File tree

3 files changed

+136
-4
lines changed

3 files changed

+136
-4
lines changed

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023 Oracle and/or its affiliates.
2+
* Copyright (c) 2023, 2024 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -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;
@@ -426,10 +427,19 @@ protected MediaContext mediaContext() {
426427
protected ClientUri resolveUri(ClientUri toResolve) {
427428
if (uriTemplate != null) {
428429
String resolved = resolvePathParams(uriTemplate);
430+
URI uri;
429431
if (skipUriEncoding) {
430-
toResolve.resolve(URI.create(resolved));
432+
uri = URI.create(resolved);
431433
} else {
432-
toResolve.resolve(URI.create(UriEncoding.encodeUri(resolved)));
434+
uri = URI.create(UriEncoding.encodeUri(resolved));
435+
}
436+
toResolve.resolve(uri);
437+
438+
if (uri.isAbsolute()) { // query parameters are cleared when resolving against absolute URIs
439+
UriQuery query = clientUri.query();
440+
if (!query.isEmpty()) {
441+
toResolve.writeableQuery().from(query);
442+
}
433443
}
434444
}
435445
return toResolve;
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright (c) 2023, 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
@@ -117,4 +117,30 @@ void testResolveQuery() {
117117
assertThat(clientUri.query().get("filter"), is("a b c"));
118118
assertThat(clientUri.query().getRaw("filter"), is("a%20b%20c"));
119119
}
120-
}
120+
121+
/**
122+
* Verifies that {@link ClientUri#resolve(ClientUri)} retains query parameters but {@link ClientUri#resolve(URI)}
123+
* doesn't (which is the same behaviour as {@link URI#resolve(URI)}).
124+
*/
125+
@Test
126+
void testResolveQueryParameter() {
127+
ClientUri helper = ClientUri.create(URI.create("http://localhost:8080/?k=v"));
128+
URI uri = URI.create("https://www.example.com:80");
129+
helper.resolve(uri);
130+
assertThat(helper.authority(), is("www.example.com:80"));
131+
assertThat(helper.host(), is("www.example.com"));
132+
assertThat(helper.path(), is(UriPath.root()));
133+
assertThat(helper.port(), is(80));
134+
assertThat(helper.scheme(), is("https"));
135+
assertThat("unexpected query parameter: 'k'", !helper.query().contains("k"));
136+
137+
helper = ClientUri.create(URI.create("http://localhost:8080/?k=v"));
138+
helper.resolve(ClientUri.create(uri));
139+
assertThat(helper.authority(), is("www.example.com:80"));
140+
assertThat(helper.host(), is("www.example.com"));
141+
assertThat(helper.path(), is(UriPath.root()));
142+
assertThat(helper.port(), is(80));
143+
assertThat(helper.scheme(), is("https"));
144+
assertThat(helper.query().get("k"), is("v"));
145+
}
146+
}

0 commit comments

Comments
 (0)