Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
package com.exonum.client;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Objects.requireNonNull;

import com.exonum.binding.common.hash.HashCode;
import com.exonum.binding.common.message.TransactionMessage;
Expand Down Expand Up @@ -213,11 +212,12 @@ public Builder setHttpClient(OkHttpClient client) {
}

/**
* Optionally, sets prefix url to be applied to all requests made by the client.
* Sets an optional URL prefix to be applied to all requests made by the client.
* Can be helpful in case of using middleware routing proxy on the blockchain node side.
* There is no prefix by default.
*/
public Builder setPrefix(String prefix) {
this.prefix = requireNonNull(prefix);
this.prefix = checkNotNull(prefix);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@

package com.exonum.client;

import static java.util.Objects.requireNonNull;
import static com.google.common.base.Preconditions.checkNotNull;

import java.net.URI;
import java.net.URL;
import java.util.Map;
import okhttp3.HttpUrl;
Expand All @@ -26,18 +27,18 @@
final class HttpUrlHelper {

static HttpUrl getFullUrl(URL host, String prefix, String relativeUrl,
Map<String, String> query) {
requireNonNull(query);
Builder builder = urlHostBuilder(host)
.addPathSegments(normalize(prefix))
.addPathSegments(normalize(relativeUrl));
query.forEach(builder::addEncodedQueryParameter);

return builder.build();
Map<String, String> encodedQueryParameters) {
checkNotNull(encodedQueryParameters);
Builder urlBuilder = urlHostBuilder(host)
.addPathSegments(prefix)
.addPathSegments(relativeUrl);
encodedQueryParameters.forEach(urlBuilder::addEncodedQueryParameter);

return normalize(urlBuilder.build());
}

private static HttpUrl.Builder urlHostBuilder(URL host) {
requireNonNull(host);
checkNotNull(host);
HttpUrl.Builder builder = new HttpUrl.Builder()
.scheme(host.getProtocol())
.host(host.getHost());
Expand All @@ -48,16 +49,13 @@ private static HttpUrl.Builder urlHostBuilder(URL host) {
}

/**
* Removes heading slash from the path.
* Useful because underlying OkHttp applies slashes when constructing paths.
* Normalized the given URL to the canonical form.
* Doesn't modify letters case in the URL.
* Also see {@link URI#normalize()}.
*/
private static String normalize(String path) {
requireNonNull(path);
if (path.startsWith("/")) {
return path.substring(1);
} else {
return path;
}
private static HttpUrl normalize(HttpUrl url) {
URI normalized = url.uri().normalize();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is no longer a naïve approach 🙃 Shall we add more tests specific to this normalization algorithm to exercise that?

return HttpUrl.get(normalized);
}

private HttpUrlHelper() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import static java.util.Collections.emptyMap;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.params.provider.Arguments.of;
import static org.junit.jupiter.params.provider.Arguments.arguments;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
Expand Down Expand Up @@ -49,22 +49,23 @@ void getFullUrl(String expectedUrl,
* - port is optional
* - prefix is optional
* - paths can start either with or without heading slash
* - query params is optional.
* - query params are optional.
*/
private static List<Arguments> source() {
Map<String, String> noQuery = emptyMap();
return ImmutableList.of(
of("http://localhost/path/to/source",
arguments("http://localhost/path/to/source",
"http://localhost", "", "/path/to/source", noQuery),
of("http://localhost/prefix/path/to/source",
arguments("http://localhost/prefix/path/to/source",
"http://localhost", "prefix", "path/to/source", noQuery),
of("http://localhost:8080/prefix/path/to/source",
arguments("http://localhost/pre%20fix/path/to/source",
"http://localhost", "pre fix", "path/to/source", noQuery),
arguments("http://localhost:8080/prefix/path/to/source",
"http://localhost:8080", "/prefix", "/path/to/source", noQuery),
of("http://localhost:8080/pre/fix/path/to/source",
arguments("http://localhost:8080/pre/fix/path/to/source",
"http://localhost:8080", "/pre/fix", "/path/to/source", noQuery),
of("http://localhost:8080/pre/fix/path/to/source?key=value",
arguments("http://localhost:8080/pre/fix/path/to/source?key=value",
"http://localhost:8080", "/pre/fix", "/path/to/source", ImmutableMap.of("key", "value"))
);
}

}