Skip to content

Commit 8aecf0d

Browse files
authored
No Longer prepend uri with slash if it is a query string (#889)
* No Longer prepend uri with slash if it is a query string Fixes #887 Changes to target and uri parsing did not take into account Empty Targets or URI provided methods. In these scenarios, the target contains the entire path and the uri will be the query string only. This change takes that into account and no longer prepends a slash in these cases. * Removed unnecessary import for Spring from Target Test
1 parent f2e1226 commit 8aecf0d

File tree

3 files changed

+56
-13
lines changed

3 files changed

+56
-13
lines changed

core/src/main/java/feign/RequestTemplate.java

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import feign.template.UriTemplate;
2222
import feign.template.UriUtils;
2323
import java.io.Serializable;
24+
import java.net.URI;
2425
import java.nio.charset.Charset;
2526
import java.util.*;
2627
import java.util.AbstractMap.SimpleImmutableEntry;
@@ -400,7 +401,10 @@ public RequestTemplate uri(String uri, boolean append) {
400401

401402
if (uri == null) {
402403
uri = "/";
403-
} else if ((!uri.isEmpty() && !uri.startsWith("/") && !uri.startsWith("{"))) {
404+
} else if ((!uri.isEmpty()
405+
&& !uri.startsWith("/")
406+
&& !uri.startsWith("{")
407+
&& !uri.startsWith("?"))) {
404408
/* if the start of the url is a literal, it must begin with a slash. */
405409
uri = "/" + uri;
406410
}
@@ -448,20 +452,23 @@ public RequestTemplate target(String target) {
448452
if (target.endsWith("/")) {
449453
target = target.substring(0, target.length() - 1);
450454
}
451-
452-
/* no query strings allowed */
453-
Matcher queryStringMatcher = QUERY_STRING_PATTERN.matcher(target);
454-
if (queryStringMatcher.find()) {
455-
/*
456-
* target has a query string, we need to make sure that they are recorded as queries
457-
*/
458-
int queryStart = queryStringMatcher.start();
459-
this.extractQueryTemplates(target.substring(queryStart + 1), true);
455+
try {
456+
/* parse the target */
457+
URI targetUri = URI.create(target);
458+
459+
if (Util.isNotBlank(targetUri.getRawQuery())) {
460+
/*
461+
* target has a query string, we need to make sure that they are recorded as queries
462+
*/
463+
this.extractQueryTemplates(targetUri.getRawQuery(), true);
464+
}
460465

461466
/* strip the query string */
462-
target = target.substring(0, queryStart);
467+
this.target = targetUri.getScheme() + "://" + targetUri.getAuthority() + targetUri.getPath();
468+
} catch (IllegalArgumentException iae) {
469+
/* the uri provided is not a valid one, we can't continue */
470+
throw new IllegalArgumentException("Target is not a valid URI.", iae);
463471
}
464-
this.target = target;
465472
return this;
466473
}
467474

core/src/test/java/feign/LoggerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ public Retryer clone() {
381381
return this;
382382
}
383383
})
384-
.target(SendsStuff.class, "http://sna%fu.abc");
384+
.target(SendsStuff.class, "http://sna%25fu.abc");
385385

386386
thrown.expect(FeignException.class);
387387

core/src/test/java/feign/TargetTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import static feign.assertj.MockWebServerAssertions.assertThat;
1717

1818
import feign.Target.HardCodedTarget;
19+
import java.net.URI;
1920
import okhttp3.mockwebserver.MockResponse;
2021
import okhttp3.mockwebserver.MockWebServer;
2122
import org.junit.Rule;
@@ -70,4 +71,39 @@ public Request apply(RequestTemplate input) {
7071

7172
assertThat(server.takeRequest()).hasPath("/default/slash/foo?query=slash/bar");
7273
}
74+
75+
interface UriTarget {
76+
77+
@RequestLine("GET")
78+
Response get(URI uri);
79+
}
80+
81+
@Test
82+
public void emptyTarget() throws InterruptedException {
83+
server.enqueue(new MockResponse());
84+
85+
UriTarget uriTarget = Feign.builder().target(Target.EmptyTarget.create(UriTarget.class));
86+
87+
String host = server.getHostName();
88+
int port = server.getPort();
89+
90+
uriTarget.get(URI.create("http://" + host + ":" + port + "/path?query=param"));
91+
92+
assertThat(server.takeRequest()).hasPath("/path?query=param").hasQueryParams("query=param");
93+
}
94+
95+
@Test
96+
public void hardCodedTargetWithURI() throws InterruptedException {
97+
server.enqueue(new MockResponse());
98+
99+
String host = server.getHostName();
100+
int port = server.getPort();
101+
String base = "http://" + host + ":" + port;
102+
103+
UriTarget uriTarget = Feign.builder().target(UriTarget.class, base);
104+
105+
uriTarget.get(URI.create("http://" + host + ":" + port + "/path?query=param"));
106+
107+
assertThat(server.takeRequest()).hasPath("/path?query=param").hasQueryParams("query=param");
108+
}
73109
}

0 commit comments

Comments
 (0)