Skip to content

Commit 2703853

Browse files
authored
Merge pull request #2054 from ClickHouse/fix_user_agent
[client-v2] Fix user agent
2 parents 5f3e7fd + 262251c commit 2703853

File tree

24 files changed

+372
-106
lines changed

24 files changed

+372
-106
lines changed

clickhouse-client/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@
6969
</dependencies>
7070

7171
<build>
72+
<resources>
73+
<resource>
74+
<directory>src/main/resources</directory>
75+
<filtering>true</filtering>
76+
</resource>
77+
</resources>
7278
<plugins>
7379
<plugin>
7480
<groupId>org.apache.maven.plugins</groupId>

clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseClientOption.java

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.clickhouse.client.config;
22

3+
import java.io.InputStream;
34
import java.io.Serializable;
45
import java.net.InetAddress;
56
import java.net.UnknownHostException;
67
import java.util.Collections;
78
import java.util.HashMap;
89
import java.util.Map;
10+
import java.util.Properties;
911

1012
import com.clickhouse.config.ClickHouseOption;
1113
import com.clickhouse.data.ClickHouseChecker;
@@ -491,19 +493,8 @@ public enum ClickHouseClientOption implements ClickHouseOption {
491493
}
492494
options = Collections.unmodifiableMap(map);
493495

494-
// <artifact-id> <version> (revision: <revision>)
495-
String ver = ClickHouseClientOption.class.getPackage().getImplementationVersion();
496-
String[] parts = ver == null || ver.isEmpty() ? null : ver.split("\\s");
497-
if (parts != null && parts.length == 4 && parts[1].length() > 0 && parts[3].length() > 1
498-
&& ver.charAt(ver.length() - 1) == ')') {
499-
PRODUCT_VERSION = parts[1];
500-
ver = parts[3];
501-
PRODUCT_REVISION = ver.substring(0, ver.length() - 1);
502-
} else { // perhaps try harder by checking version from pom.xml?
503-
PRODUCT_VERSION = LATEST_KNOWN_VERSION;
504-
PRODUCT_REVISION = UNKNOWN;
505-
}
506-
496+
PRODUCT_VERSION = readVersionFromResource("clickhouse-client-version.properties");
497+
PRODUCT_REVISION = UNKNOWN;
507498

508499
CLIENT_OS_INFO = new StringBuilder().append(getSystemConfig("os.name", "O/S")).append('/')
509500
.append(getSystemConfig("os.version", UNKNOWN)).toString();
@@ -514,12 +505,31 @@ public enum ClickHouseClientOption implements ClickHouseOption {
514505
CLIENT_JVM_INFO = new StringBuilder().append(getSystemConfig("java.vm.name", "Java")).append('/')
515506
.append(javaVersion).toString();
516507
CLIENT_USER = getSystemConfig("user.name", UNKNOWN);
508+
509+
String host = null;
517510
try {
518-
ver = InetAddress.getLocalHost().getHostName();
511+
host = InetAddress.getLocalHost().getHostName();
519512
} catch (UnknownHostException e1) {
520513
// ignore
521514
}
522-
CLIENT_HOST = ver == null || ver.isEmpty() ? UNKNOWN : ver;
515+
CLIENT_HOST = host == null || host.isEmpty() ? UNKNOWN : host;
516+
}
517+
518+
public static String readVersionFromResource(String resourceFilePath) {
519+
// TODO: move to client-v2 when client-v1 is deprecated completely
520+
String tmpVersion = "unknown";
521+
try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceFilePath)) {
522+
Properties p = new Properties();
523+
p.load(in);
524+
525+
String tmp = p.getProperty("version");
526+
if (tmp != null && !tmp.isEmpty() && !tmp.equals("${revision}")) {
527+
tmpVersion = tmp;
528+
}
529+
} catch (Exception e) {
530+
// ignore
531+
}
532+
return tmpVersion;
523533
}
524534

525535
/**
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
version=${revision}
2+
build.date=${build_timestamp}

clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseConfigTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import java.util.Collections;
1313
import java.util.HashMap;
1414
import java.util.Map;
15+
import java.util.regex.Matcher;
16+
import java.util.regex.Pattern;
1517

1618
public class ClickHouseConfigTest {
1719
@Test(groups = { "unit" })
@@ -74,7 +76,8 @@ public void testCustomValues() {
7476
@Test(groups = { "unit" })
7577
public void testClientInfo() throws UnknownHostException {
7678
ClickHouseConfig config = new ClickHouseConfig();
77-
Assert.assertEquals(config.getProductVersion(), ClickHouseClientOption.LATEST_KNOWN_VERSION);
79+
Matcher versioMatcher = Pattern.compile("(^|\\\\.[\\\\d]+)+.*").matcher(config.getProductVersion());
80+
Assert.assertTrue(versioMatcher.matches());
7881
Assert.assertEquals(config.getProductRevision(), "unknown");
7982
Assert.assertEquals(config.getClientOsInfo(),
8083
System.getProperty("os.name") + "/" + System.getProperty("os.version"));
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
version=${revision}
2+
build.date=${build_timestamp}

client-v2/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,12 @@
138138
</dependencies>
139139

140140
<build>
141+
<resources>
142+
<resource>
143+
<directory>src/main/resources</directory>
144+
<filtering>true</filtering>
145+
</resource>
146+
</resources>
141147
<plugins>
142148
<plugin>
143149
<groupId>org.apache.maven.plugins</groupId>

client-v2/src/main/java/com/clickhouse/client/api/Client.java

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@
2626
import com.clickhouse.client.api.internal.ClickHouseLZ4OutputStream;
2727
import com.clickhouse.client.api.internal.ClientStatisticsHolder;
2828
import com.clickhouse.client.api.internal.ClientV1AdaptorHelper;
29-
import com.clickhouse.client.api.internal.EnvUtils;
3029
import com.clickhouse.client.api.internal.HttpAPIClientHelper;
3130
import com.clickhouse.client.api.internal.MapUtils;
32-
import com.clickhouse.client.api.internal.ServerSettings;
3331
import com.clickhouse.client.api.internal.SettingsConverter;
3432
import com.clickhouse.client.api.internal.TableSchemaParser;
3533
import com.clickhouse.client.api.internal.ValidationUtils;
@@ -76,8 +74,8 @@
7674
import java.util.HashSet;
7775
import java.util.LinkedHashMap;
7876
import java.util.List;
79-
import java.util.Locale;
8077
import java.util.Map;
78+
import java.util.Properties;
8179
import java.util.Set;
8280
import java.util.StringJoiner;
8381
import java.util.TimeZone;
@@ -186,6 +184,7 @@ private Client(Set<String> endpoints, Map<String,String> configuration, boolean
186184
}
187185
this.columnToMethodMatchingStrategy = columnToMethodMatchingStrategy;
188186

187+
189188
updateServerContext();
190189
}
191190

@@ -359,6 +358,9 @@ public Builder addEndpoint(Protocol protocol, String host, int port, boolean sec
359358
*/
360359
public Builder setOption(String key, String value) {
361360
this.configuration.put(key, value);
361+
if (key.equals(ClientConfigProperties.PRODUCT_NAME.getKey())) {
362+
setClientName(value);
363+
}
362364
return this;
363365
}
364366

@@ -817,7 +819,7 @@ public Builder setSharedOperationExecutor(ExecutorService executorService) {
817819
/**
818820
* Set size of a buffers that are used to read/write data from the server. It is mainly used to copy data from
819821
* a socket to application memory and visa-versa. Setting is applied for both read and write operations.
820-
* Default is 8192 bytes.
822+
* Default is 300,000 bytes.
821823
*
822824
* @param size - size in bytes
823825
* @return
@@ -977,7 +979,9 @@ public Builder setClientName(String clientName) {
977979
* @return same instance of the builder
978980
*/
979981
public Builder setOptions(Map<String, String> options) {
980-
this.configuration.putAll(options);
982+
for (Map.Entry<String, String> entry : options.entrySet()) {
983+
setOption(entry.getKey(), entry.getValue());
984+
}
981985
return this;
982986
}
983987

@@ -1147,41 +1151,7 @@ private void setDefaults() {
11471151
if (!configuration.containsKey(ClientConfigProperties.USE_HTTP_COMPRESSION.getKey())) {
11481152
useHttpCompression(false);
11491153
}
1150-
1151-
String userAgent = configuration.getOrDefault(ClientConfigProperties.HTTP_HEADER_PREFIX + HttpHeaders.USER_AGENT.toUpperCase(Locale.US), "");
1152-
String clientName = configuration.getOrDefault(ClientConfigProperties.CLIENT_NAME.getKey(), "");
1153-
httpHeader(HttpHeaders.USER_AGENT, buildUserAgent(userAgent.isEmpty() ? clientName : userAgent));
1154-
}
1155-
1156-
private static String buildUserAgent(String customUserAgent) {
1157-
1158-
StringBuilder userAgent = new StringBuilder();
1159-
if (customUserAgent != null && !customUserAgent.isEmpty()) {
1160-
userAgent.append(customUserAgent).append(" ");
1161-
}
1162-
1163-
userAgent.append(CLIENT_USER_AGENT);
1164-
1165-
String clientVersion = Client.class.getPackage().getImplementationVersion();
1166-
if (clientVersion == null) {
1167-
clientVersion = LATEST_ARTIFACT_VERSION;
1168-
}
1169-
userAgent.append(clientVersion);
1170-
1171-
userAgent.append(" (");
1172-
userAgent.append(System.getProperty("os.name"));
1173-
userAgent.append("; ");
1174-
userAgent.append("jvm:").append(System.getProperty("java.version"));
1175-
userAgent.append("; ");
1176-
1177-
userAgent.setLength(userAgent.length() - 2);
1178-
userAgent.append(')');
1179-
1180-
return userAgent.toString();
11811154
}
1182-
1183-
public static final String LATEST_ARTIFACT_VERSION = "0.7.1-patch1";
1184-
public static final String CLIENT_USER_AGENT = "clickhouse-java-v2/";
11851155
}
11861156

11871157
private ClickHouseNode getServerNode() {
@@ -2170,6 +2140,10 @@ public String getServerVersion() {
21702140
return this.serverVersion;
21712141
}
21722142

2143+
public String getClientVersion() {
2144+
return clientVersion;
2145+
}
2146+
21732147
/**
21742148
* Sets list of DB roles that should be applied to each query.
21752149
*
@@ -2186,6 +2160,10 @@ public void updateClientName(String name) {
21862160
this.configuration.put(ClientConfigProperties.CLIENT_NAME.getKey(), name);
21872161
}
21882162

2163+
public static final String clientVersion =
2164+
ClickHouseClientOption.readVersionFromResource("client-v2-version.properties");
2165+
public static final String CLIENT_USER_AGENT = "clickhouse-java-v2/";
2166+
21892167
private Collection<String> unmodifiableDbRolesView = Collections.emptyList();
21902168

21912169
/**

client-v2/src/main/java/com/clickhouse/client/api/ClientConfigProperties.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,16 @@ public enum ClientConfigProperties {
115115

116116
CLIENT_RETRY_ON_FAILURE("client_retry_on_failures"),
117117

118-
CLIENT_NAME("client_name");
118+
CLIENT_NAME("client_name"),
119+
120+
/**
121+
* An old alias to {@link ClientConfigProperties#CLIENT_NAME}. Using the last one is preferred.
122+
*/
123+
@Deprecated
124+
PRODUCT_NAME("product_name"),
125+
126+
127+
;
119128

120129
private String key;
121130

client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,12 @@ public Object getOption(String option) {
4848
* @param option - configuration option name
4949
* @param value - configuration option value
5050
*/
51-
public void setOption(String option, Object value) {
51+
public InsertSettings setOption(String option, Object value) {
5252
rawSettings.put(option, value);
53+
if (option.equals(ClientConfigProperties.PRODUCT_NAME.getKey())) {
54+
rawSettings.put(ClientConfigProperties.CLIENT_NAME.getKey(), value);
55+
}
56+
return this;
5357
}
5458

5559
/**

client-v2/src/main/java/com/clickhouse/client/api/internal/HttpAPIClientHelper.java

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.apache.hc.core5.http.HttpEntity;
3535
import org.apache.hc.core5.http.HttpHeaders;
3636
import org.apache.hc.core5.http.HttpHost;
37+
import org.apache.hc.core5.http.HttpRequest;
3738
import org.apache.hc.core5.http.HttpStatus;
3839
import org.apache.hc.core5.http.NoHttpResponseException;
3940
import org.apache.hc.core5.http.config.CharCodingConfig;
@@ -73,9 +74,6 @@
7374
import java.util.Set;
7475
import java.util.concurrent.TimeUnit;
7576
import java.util.function.Function;
76-
import java.util.function.Supplier;
77-
78-
import static com.clickhouse.client.api.ClientConfigProperties.SOCKET_TCP_NO_DELAY_OPT;
7977

8078
public class HttpAPIClientHelper {
8179
private static final Logger LOG = LoggerFactory.getLogger(Client.class);
@@ -92,14 +90,12 @@ public class HttpAPIClientHelper {
9290

9391
private final Set<ClientFaultCause> defaultRetryCauses;
9492

95-
private String httpClientUserAgentPart;
93+
private String defaultUserAgent;
9694

9795
public HttpAPIClientHelper(Map<String, String> configuration) {
9896
this.chConfiguration = configuration;
9997
this.httpClient = createHttpClient();
10098

101-
this.httpClientUserAgentPart = this.httpClient.getClass().getPackage().getImplementationTitle() + "/" + this.httpClient.getClass().getPackage().getImplementationVersion();
102-
10399
RequestConfig.Builder reqConfBuilder = RequestConfig.custom();
104100
MapUtils.applyLong(chConfiguration, "connection_request_timeout",
105101
(t) -> reqConfBuilder
@@ -116,6 +112,8 @@ public HttpAPIClientHelper(Map<String, String> configuration) {
116112
if (defaultRetryCauses.contains(ClientFaultCause.None)) {
117113
defaultRetryCauses.removeIf(c -> c != ClientFaultCause.None);
118114
}
115+
116+
this.defaultUserAgent = buildDefaultUserAgent();
119117
}
120118

121119
/**
@@ -472,9 +470,9 @@ private void addHeaders(HttpPost req, Map<String, String> chConfig, Map<String,
472470
}
473471

474472
// -- keep last
475-
Header userAgent = req.getFirstHeader(HttpHeaders.USER_AGENT);
476-
req.setHeader(HttpHeaders.USER_AGENT, userAgent == null ? httpClientUserAgentPart : userAgent.getValue() + " " + httpClientUserAgentPart);
473+
correctUserAgentHeader(req, requestConfig);
477474
}
475+
478476
private void addQueryParams(URIBuilder req, Map<String, String> chConfig, Map<String, Object> requestConfig) {
479477
for (Map.Entry<String, String> entry : chConfig.entrySet()) {
480478
if (entry.getKey().startsWith(ClientConfigProperties.SERVER_SETTING_PREFIX)) {
@@ -646,6 +644,54 @@ public static Map<String, String> parseUrlParameters(URL url) {
646644
return params;
647645
}
648646

647+
648+
private void correctUserAgentHeader(HttpRequest request, Map<String, Object> requestConfig) {
649+
//TODO: implement cache for user-agent
650+
Header userAgentHeader = request.getLastHeader(HttpHeaders.USER_AGENT);
651+
request.removeHeaders(HttpHeaders.USER_AGENT);
652+
653+
String clientName = chConfiguration.getOrDefault(ClientConfigProperties.CLIENT_NAME.getKey(), "");
654+
if (requestConfig != null) {
655+
String reqClientName = (String) requestConfig.get(ClientConfigProperties.CLIENT_NAME.getKey());
656+
if (reqClientName != null && !reqClientName.isEmpty()) {
657+
clientName = reqClientName;
658+
}
659+
}
660+
String userAgentValue = defaultUserAgent;
661+
if (userAgentHeader == null && clientName != null && !clientName.isEmpty()) {
662+
userAgentValue = clientName + " " + defaultUserAgent;
663+
} else if (userAgentHeader != null) {
664+
userAgentValue = userAgentHeader.getValue() + " " + defaultUserAgent;
665+
}
666+
667+
request.setHeader(HttpHeaders.USER_AGENT, userAgentValue);
668+
}
669+
670+
private String buildDefaultUserAgent() {
671+
StringBuilder userAgent = new StringBuilder();
672+
userAgent.append(Client.CLIENT_USER_AGENT);
673+
674+
String clientVersion = Client.clientVersion;
675+
676+
userAgent.append(clientVersion);
677+
678+
userAgent.append(" (");
679+
userAgent.append(System.getProperty("os.name"));
680+
userAgent.append("; ");
681+
userAgent.append("jvm:").append(System.getProperty("java.version"));
682+
userAgent.append("; ");
683+
684+
userAgent.setLength(userAgent.length() - 2);
685+
userAgent.append(')');
686+
687+
userAgent.append(" ")
688+
.append(this.httpClient.getClass().getPackage().getImplementationTitle().replaceAll(" ", "-"))
689+
.append('/')
690+
.append(this.httpClient.getClass().getPackage().getImplementationVersion());
691+
692+
return userAgent.toString();
693+
}
694+
649695
public void close() {
650696
httpClient.close(CloseMode.IMMEDIATE);
651697
}

0 commit comments

Comments
 (0)