Skip to content

Bug fixes #299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.eventstore.dbclient;


import io.grpc.ClientInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -15,6 +14,7 @@
* Utility to create client settings programmatically.
*/
public class ConnectionSettingsBuilder {

private static final Logger logger = LoggerFactory.getLogger(ConnectionSettingsBuilder.class);
private boolean _dnsDiscover = false;
private int _maxDiscoverAttempts = 3;
Expand All @@ -33,10 +33,12 @@ public class ConnectionSettingsBuilder {
private String _tlsCaFile = null;
private Set<String> _features = new HashSet<>();

ConnectionSettingsBuilder() {}
ConnectionSettingsBuilder() {
}

/**
* Returns configured connection settings.
*
* @see EventStoreDBClientSettings
* @return configured settings.
*/
Expand Down Expand Up @@ -76,7 +78,8 @@ public ConnectionSettingsBuilder maxDiscoverAttempts(int maxDiscoverAttempts) {
}

/**
* How long to wait before retrying a new discovery process (in milliseconds).
* How long to wait before retrying a new discovery process (in
* milliseconds).
*/
public ConnectionSettingsBuilder discoveryInterval(int discoveryInterval) {
this._discoveryInterval = discoveryInterval;
Expand Down Expand Up @@ -163,31 +166,35 @@ public ConnectionSettingsBuilder addHost(InetSocketAddress host) {
}

/**
* The amount of time (in milliseconds) the sender of the keepalive ping waits for an acknowledgement.
* The amount of time (in milliseconds) the sender of the keepalive ping
* waits for an acknowledgement.
*/
public ConnectionSettingsBuilder keepAliveTimeout(long value) {
if (value >= 0 && value < Consts.DEFAULT_KEEP_ALIVE_TIMEOUT_IN_MS) {
logger.warn("Specified keepAliveTimeout of {} is less than recommended {}", value, Consts.DEFAULT_KEEP_ALIVE_TIMEOUT_IN_MS);
}

if (value == -1)
if (value == -1) {
value = Long.MAX_VALUE;
}

this._keepAliveTimeout = value;

return this;
}

/**
* The amount of time (in milliseconds) to wait after which a keepalive ping is sent on the transport.
* The amount of time (in milliseconds) to wait after which a keepalive ping
* is sent on the transport.
*/
public ConnectionSettingsBuilder keepAliveInterval(long value) {
if (value >= 0 && value < Consts.DEFAULT_KEEP_ALIVE_INTERVAL_IN_MS) {
logger.warn("Specified keepAliveInterval of {} is less than recommended {}", value, Consts.DEFAULT_KEEP_ALIVE_INTERVAL_IN_MS);
}

if (value == -1)
if (value == -1) {
value = Long.MAX_VALUE;
}

this._keepAliveInterval = value;

Expand All @@ -204,6 +211,7 @@ public ConnectionSettingsBuilder defaultDeadline(long value) {

/**
* Register a gRPC interceptor every time a new gRPC channel is created.
*
* @param interceptor
*/
public ConnectionSettingsBuilder addInterceptor(ClientInterceptor interceptor) {
Expand All @@ -212,8 +220,10 @@ public ConnectionSettingsBuilder addInterceptor(ClientInterceptor interceptor) {
}

/**
* Client certificate for secure connection. Not required for enabling secure connection. Useful for self-signed
* certificate that are not installed on the system trust store.
* Client certificate for secure connection. Not required for enabling
* secure connection. Useful for self-signed certificate that are not
* installed on the system trust store.
*
* @param filepath path to a certificate file.
*/
public ConnectionSettingsBuilder tlsCaFile(String filepath) {
Expand Down Expand Up @@ -246,7 +256,11 @@ void parseGossipSeed(String host) {
break;
case 2:
try {
addHost(hostParts[0], Short.parseShort(hostParts[1]));
int port = Integer.parseInt(hostParts[1]);
if (port > 65535) {
throw new RuntimeException(new IllegalArgumentException(String.format("Invalid port number format: %s. Post cannot be higher than 65535.", hostParts[1])));
}
addHost(hostParts[0], port);
} catch (NumberFormatException e) {
throw new RuntimeException(String.format("Invalid port number format: %s", hostParts[1]));
}
Expand All @@ -257,8 +271,9 @@ void parseGossipSeed(String host) {
}

static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder, URL url) {
if (!url.getProtocol().equals("esdb") && !url.getProtocol().equals("esdb+discover"))
if (!url.getProtocol().equals("esdb") && !url.getProtocol().equals("esdb+discover")) {
throw new RuntimeException(String.format("Unknown URL scheme: %s", url.getProtocol()));
}

builder.dnsDiscover(url.getProtocol().equals("esdb+discover"));

Expand All @@ -271,16 +286,18 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
else
} else {
builder.defaultCredentials(splits[0], "");
}
}

if (builder._hosts.isEmpty() && !url.getPath().isEmpty() && !url.getPath().equals("/"))
if (builder._hosts.isEmpty() && !url.getPath().isEmpty() && !url.getPath().equals("/")) {
throw new RuntimeException(String.format("Unsupported URL path: %s", url.getPath()));
}

if (builder._hosts.isEmpty() && url.getHost().isEmpty())
if (builder._hosts.isEmpty() && url.getHost().isEmpty()) {
throw new RuntimeException("Connection string doesn't have an host");
}

if (builder._hosts.isEmpty()) {
if (!url.getHost().contains(",")) {
Expand All @@ -292,16 +309,18 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
}
}

if (url.getQuery() == null)
if (url.getQuery() == null) {
return builder.buildConnectionSettings();
}

String userCertFile = null;
String userKeyFile = null;
for (String param : url.getQuery().split("&")) {
String[] entry = param.split("=");

if (entry.length <= 1)
if (entry.length <= 1) {
continue;
}

String value = entry[1].toLowerCase();
switch (entry[0].toLowerCase()) {
Expand All @@ -328,8 +347,9 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
try {
int parsedValue = Integer.parseInt(value);

if (parsedValue < 0)
if (parsedValue < 0) {
invalidParamFormat(entry[0], value);
}

builder._maxDiscoverAttempts = parsedValue;
} catch (NumberFormatException e) {
Expand All @@ -341,8 +361,9 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
try {
int parsedValue = Integer.parseInt(value);

if (parsedValue < 0)
if (parsedValue < 0) {
invalidParamFormat(entry[0], value);
}

builder._discoveryInterval = parsedValue;
} catch (NumberFormatException e) {
Expand All @@ -354,8 +375,9 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
try {
int parsedValue = Integer.parseInt(value);

if (parsedValue < 0)
if (parsedValue < 0) {
invalidParamFormat(entry[0], value);
}

builder._gossipTimeout = parsedValue;
} catch (NumberFormatException e) {
Expand All @@ -364,37 +386,43 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
break;

case "dnsdiscover":
if (!value.equals("true") && !value.equals("false"))
if (!value.equals("true") && !value.equals("false")) {
invalidParamFormat(entry[0], value);
}

builder._dnsDiscover = value.equals("true");
break;

case "tls":
if (!value.equals("true") && !value.equals("false"))
if (!value.equals("true") && !value.equals("false")) {
invalidParamFormat(entry[0], value);
}

builder._tls = value.equals("true");
break;

case "tlsverifycert":
if (!value.equals("true") && !value.equals("false"))
if (!value.equals("true") && !value.equals("false")) {
invalidParamFormat(entry[0], value);
}

builder._tlsVerifyCert = value.equals("true");
break;

case "keepalivetimeout":
try {
long parsedValue = Long.parseLong(value);
if (parsedValue >= 0 && parsedValue < Consts.DEFAULT_KEEP_ALIVE_TIMEOUT_IN_MS)
if (parsedValue >= 0 && parsedValue < Consts.DEFAULT_KEEP_ALIVE_TIMEOUT_IN_MS) {
logger.warn("Specified keepAliveTimeout of {} is less than recommended {}", parsedValue, Consts.DEFAULT_KEEP_ALIVE_TIMEOUT_IN_MS);
}

if (parsedValue < -1)
if (parsedValue < -1) {
invalidParamFormat(entry[0], value);
}

if (parsedValue == -1)
if (parsedValue == -1) {
parsedValue = Long.MAX_VALUE;
}

builder._keepAliveTimeout = parsedValue;
} catch (NumberFormatException e) {
Expand All @@ -405,14 +433,17 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
case "keepaliveinterval":
try {
long parsedValue = Long.parseLong(value);
if (parsedValue >= 0 && parsedValue < Consts.DEFAULT_KEEP_ALIVE_INTERVAL_IN_MS)
if (parsedValue >= 0 && parsedValue < Consts.DEFAULT_KEEP_ALIVE_INTERVAL_IN_MS) {
logger.warn("Specified keepAliveInterval of {} is less than recommended {}", parsedValue, Consts.DEFAULT_KEEP_ALIVE_INTERVAL_IN_MS);
}

if (parsedValue < -1)
if (parsedValue < -1) {
invalidParamFormat(entry[0], value);
}

if (parsedValue == -1)
if (parsedValue == -1) {
parsedValue = Long.MAX_VALUE;
}

builder._keepAliveInterval = parsedValue;
} catch (NumberFormatException e) {
Expand All @@ -424,8 +455,9 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
try {
long parsedValue = Long.parseLong(value);

if (parsedValue <= 0)
if (parsedValue <= 0) {
invalidParamFormat(entry[0], value);
}

builder._defaultDeadline = parsedValue;
} catch (NumberFormatException e) {
Expand All @@ -434,22 +466,25 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
break;

case "tlscafile":
if (entry[1].isEmpty())
if (entry[1].isEmpty()) {
invalidParamFormat(entry[0], entry[1]);
}

builder._tlsCaFile = entry[1];
break;

case "usercertfile":
if (entry[1].isEmpty())
if (entry[1].isEmpty()) {
invalidParamFormat(entry[0], entry[1]);
}

userCertFile = entry[1];
break;

case "userkeyfile":
if (entry[1].isEmpty())
if (entry[1].isEmpty()) {
invalidParamFormat(entry[0], entry[1]);
}

userKeyFile = entry[1];
break;
Expand All @@ -464,11 +499,13 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
}
}

if (userCertFile != null ^ userKeyFile != null)
if (userCertFile != null ^ userKeyFile != null) {
throw new RuntimeException("Invalid user certificate settings. Both 'userCertFile' and 'userKeyFile' must be provided.");
}

if (userCertFile != null)
if (userCertFile != null) {
builder.defaultClientCertificate(userCertFile, userKeyFile);
}

return builder.buildConnectionSettings();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.eventstore.dbclient.resolution;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

Expand All @@ -13,6 +14,6 @@ public FixedSeedsNodeResolution(InetSocketAddress[] seeds) {

@Override
public List<InetSocketAddress> resolve() {
return Arrays.asList(seeds);
return new ArrayList<>(Arrays.asList(seeds));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import com.eventstore.dbclient.ConnectionStringParsingException;
import com.eventstore.dbclient.EventStoreDBConnectionString;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;


public class ParseInvalidConnectionStringTests {
public static Stream<Arguments> invalidConnectionStrings() {
return Stream.of(
Expand All @@ -27,7 +29,8 @@ public static Stream<Arguments> invalidConnectionStrings() {
Arguments.of("esdb://localhost?keepAliveTimeout=-3"),
Arguments.of("esdb://localhost?nodePreference=read_only_replica"),
Arguments.of("esdb://localhost?userCertFile=/path/to/cert"),
Arguments.of("esdb://localhost?userKeyFile=/path/to/key")
Arguments.of("esdb://localhost?userKeyFile=/path/to/key"),
Arguments.of("esdb://localhost:65536,localhost:2113")
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.json.JsonMapper;

import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
Expand Down Expand Up @@ -234,4 +236,12 @@ private EventStoreDBClientSettings parseJson(String input) throws JsonProcessing

return builder.buildConnectionSettings();
}

@Test
public void testPortNumbers() {
//Test gossip seeds with port numbers higher than 32000.
EventStoreDBClientSettings settings = EventStoreDBConnectionString.parseOrThrow("esdb://localhost:4500,localhost:50000?feature=foobar&feature=baz");
Assertions.assertNotNull(settings);
Assertions.assertEquals(2,settings.getHosts().length);
}
}
Loading