Skip to content

Commit 3397eb2

Browse files
authored
Merge pull request #2484 from enqueue/dbname-dash
Database names with dashes
2 parents 60ae503 + f02e181 commit 3397eb2

File tree

5 files changed

+440
-148
lines changed

5 files changed

+440
-148
lines changed

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

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
package com.clickhouse.client.api.internal;
22

33
import com.clickhouse.client.ClickHouseSslContextProvider;
4-
import com.clickhouse.client.api.*;
4+
import com.clickhouse.client.api.ClickHouseException;
5+
import com.clickhouse.client.api.Client;
6+
import com.clickhouse.client.api.ClientConfigProperties;
7+
import com.clickhouse.client.api.ClientException;
8+
import com.clickhouse.client.api.ClientFaultCause;
9+
import com.clickhouse.client.api.ClientMisconfigurationException;
10+
import com.clickhouse.client.api.ConnectionInitiationException;
11+
import com.clickhouse.client.api.ConnectionReuseStrategy;
12+
import com.clickhouse.client.api.DataTransferException;
13+
import com.clickhouse.client.api.ServerException;
514
import com.clickhouse.client.api.enums.ProxyType;
615
import com.clickhouse.client.api.http.ClickHouseHttpProto;
716
import com.clickhouse.client.api.transport.Endpoint;
@@ -63,6 +72,7 @@
6372
import java.net.SocketTimeoutException;
6473
import java.net.URI;
6574
import java.net.URISyntaxException;
75+
import java.net.URLEncoder;
6676
import java.net.UnknownHostException;
6777
import java.nio.charset.StandardCharsets;
6878
import java.security.NoSuchAlgorithmException;
@@ -79,12 +89,16 @@
7989
import java.util.concurrent.TimeUnit;
8090
import java.util.concurrent.atomic.AtomicLong;
8191
import java.util.function.Function;
92+
import java.util.regex.Pattern;
8293

8394
public class HttpAPIClientHelper {
8495
private static final Logger LOG = LoggerFactory.getLogger(Client.class);
8596

8697
private static final int ERROR_BODY_BUFFER_SIZE = 1024; // Error messages are usually small
8798

99+
private static final Pattern PATTERN_HEADER_VALUE_ASCII = Pattern.compile(
100+
"\\p{Graph}+(?:[ ]\\p{Graph}+)*");
101+
88102
private final CloseableHttpClient httpClient;
89103

90104
private final RequestConfig baseRequestConfig;
@@ -287,7 +301,7 @@ public CloseableHttpClient createHttpClient(boolean initSslContext, Map<String,
287301
SocketConfig socketConfig = soCfgBuilder.build();
288302

289303
// Connection manager
290-
if (ClientConfigProperties.CONNECTION_POOL_ENABLED.getOrDefault(configuration)) {
304+
if (ClientConfigProperties.CONNECTION_POOL_ENABLED.<Boolean>getOrDefault(configuration)) {
291305
clientBuilder.setConnectionManager(poolConnectionManager(sslConnectionSocketFactory, socketConfig, configuration));
292306
} else {
293307
clientBuilder.setConnectionManager(basicConnectionManager(sslConnectionSocketFactory, socketConfig, configuration));
@@ -430,36 +444,55 @@ public ClassicHttpResponse executeRequest(Endpoint server, Map<String, Object> r
430444
private static final ContentType CONTENT_TYPE = ContentType.create(ContentType.TEXT_PLAIN.getMimeType(), "UTF-8");
431445

432446
private void addHeaders(HttpPost req, Map<String, Object> requestConfig) {
433-
req.addHeader(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE.getMimeType());
447+
addHeader(req, HttpHeaders.CONTENT_TYPE, CONTENT_TYPE.getMimeType());
434448
if (requestConfig.containsKey(ClientConfigProperties.INPUT_OUTPUT_FORMAT.getKey())) {
435-
req.addHeader(ClickHouseHttpProto.HEADER_FORMAT, requestConfig.get(ClientConfigProperties.INPUT_OUTPUT_FORMAT.getKey()));
449+
addHeader(
450+
req,
451+
ClickHouseHttpProto.HEADER_FORMAT,
452+
requestConfig.get(ClientConfigProperties.INPUT_OUTPUT_FORMAT.getKey()));
436453
}
437-
438454
if (requestConfig.containsKey(ClientConfigProperties.QUERY_ID.getKey())) {
439-
req.addHeader(ClickHouseHttpProto.HEADER_QUERY_ID, requestConfig.get(ClientConfigProperties.QUERY_ID.getKey()).toString());
440-
}
441-
442-
443-
req.addHeader(ClickHouseHttpProto.HEADER_DATABASE, ClientConfigProperties.DATABASE.getOrDefault(requestConfig));
444-
445-
446-
if (ClientConfigProperties.SSL_AUTH.getOrDefault(requestConfig)) {
447-
req.addHeader(ClickHouseHttpProto.HEADER_DB_USER, ClientConfigProperties.USER.getOrDefault(requestConfig));
448-
req.addHeader(ClickHouseHttpProto.HEADER_SSL_CERT_AUTH, "on");
449-
} else if (ClientConfigProperties.HTTP_USE_BASIC_AUTH.getOrDefault(requestConfig)) {
455+
addHeader(
456+
req,
457+
ClickHouseHttpProto.HEADER_QUERY_ID,
458+
requestConfig.get(ClientConfigProperties.QUERY_ID.getKey()));
459+
}
460+
addHeader(
461+
req,
462+
ClickHouseHttpProto.HEADER_DATABASE,
463+
ClientConfigProperties.DATABASE.getOrDefault(requestConfig));
464+
465+
if (ClientConfigProperties.SSL_AUTH.<Boolean>getOrDefault(requestConfig).booleanValue()) {
466+
addHeader(
467+
req,
468+
ClickHouseHttpProto.HEADER_DB_USER,
469+
ClientConfigProperties.USER.getOrDefault(requestConfig));
470+
addHeader(
471+
req,
472+
ClickHouseHttpProto.HEADER_SSL_CERT_AUTH,
473+
"on");
474+
} else if (ClientConfigProperties.HTTP_USE_BASIC_AUTH.<Boolean>getOrDefault(requestConfig).booleanValue()) {
450475
String user = ClientConfigProperties.USER.getOrDefault(requestConfig);
451476
String password = ClientConfigProperties.PASSWORD.getOrDefault(requestConfig);
452-
453-
req.addHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString(
454-
(user + ":" + password).getBytes(StandardCharsets.UTF_8))
455-
);
477+
// Use as-is, no encoding allowed
478+
req.addHeader(
479+
HttpHeaders.AUTHORIZATION,
480+
"Basic " + Base64.getEncoder().encodeToString(
481+
(user + ":" + password).getBytes(StandardCharsets.UTF_8)));
456482
} else {
457-
req.addHeader(ClickHouseHttpProto.HEADER_DB_USER, ClientConfigProperties.USER.getOrDefault(requestConfig));
458-
req.addHeader(ClickHouseHttpProto.HEADER_DB_PASSWORD, ClientConfigProperties.PASSWORD.getOrDefault(requestConfig));
459-
483+
addHeader(
484+
req,
485+
ClickHouseHttpProto.HEADER_DB_USER,
486+
ClientConfigProperties.USER.getOrDefault(requestConfig));
487+
addHeader(
488+
req,
489+
ClickHouseHttpProto.HEADER_DB_PASSWORD,
490+
ClientConfigProperties.PASSWORD.getOrDefault(requestConfig));
460491
}
461492
if (proxyAuthHeaderValue != null) {
462-
req.addHeader(HttpHeaders.PROXY_AUTHORIZATION, proxyAuthHeaderValue);
493+
req.addHeader(
494+
HttpHeaders.PROXY_AUTHORIZATION,
495+
proxyAuthHeaderValue);
463496
}
464497

465498
boolean clientCompression = ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getOrDefault(requestConfig);
@@ -469,26 +502,30 @@ private void addHeaders(HttpPost req, Map<String, Object> requestConfig) {
469502

470503
if (useHttpCompression) {
471504
if (serverCompression) {
472-
req.addHeader(HttpHeaders.ACCEPT_ENCODING, "lz4");
505+
addHeader(req, HttpHeaders.ACCEPT_ENCODING, "lz4");
473506
}
474507
if (clientCompression && !appCompressedData) {
475-
req.addHeader(HttpHeaders.CONTENT_ENCODING, "lz4");
508+
addHeader(req, HttpHeaders.CONTENT_ENCODING, "lz4");
476509
}
477510
}
478511

479512
for (String key : requestConfig.keySet()) {
480513
if (key.startsWith(ClientConfigProperties.HTTP_HEADER_PREFIX)) {
481514
Object val = requestConfig.get(key);
482515
if (val != null) {
483-
req.setHeader(key.substring(ClientConfigProperties.HTTP_HEADER_PREFIX.length()), String.valueOf(val));
516+
addHeader(
517+
req,
518+
key.substring(ClientConfigProperties.HTTP_HEADER_PREFIX.length()),
519+
String.valueOf(val));
484520
}
485521
}
486522
}
487523

488-
489524
// Special cases
490-
if (req.containsHeader(HttpHeaders.AUTHORIZATION) && (req.containsHeader(ClickHouseHttpProto.HEADER_DB_USER) ||
491-
req.containsHeader(ClickHouseHttpProto.HEADER_DB_PASSWORD))) {
525+
if (req.containsHeader(HttpHeaders.AUTHORIZATION)
526+
&& (req.containsHeader(ClickHouseHttpProto.HEADER_DB_USER) ||
527+
req.containsHeader(ClickHouseHttpProto.HEADER_DB_PASSWORD)))
528+
{
492529
// user has set auth header for purpose, lets remove ours
493530
req.removeHeaders(ClickHouseHttpProto.HEADER_DB_USER);
494531
req.removeHeaders(ClickHouseHttpProto.HEADER_DB_PASSWORD);
@@ -668,7 +705,6 @@ private void correctUserAgentHeader(HttpRequest request, Map<String, Object> req
668705
} else if (userAgentHeader != null) {
669706
userAgentValue = userAgentHeader.getValue() + " " + defaultUserAgent;
670707
}
671-
672708
request.setHeader(HttpHeaders.USER_AGENT, userAgentValue);
673709
}
674710

@@ -720,6 +756,25 @@ public void close() {
720756
httpClient.close(CloseMode.IMMEDIATE);
721757
}
722758

759+
private static <T> void addHeader(HttpRequest req, String headerName,
760+
T value)
761+
{
762+
if (value == null) {
763+
return;
764+
}
765+
String tString = value.toString();
766+
if (tString.isBlank()) {
767+
return;
768+
}
769+
if (PATTERN_HEADER_VALUE_ASCII.matcher(tString).matches()) {
770+
req.addHeader(headerName, tString);
771+
} else {
772+
req.addHeader(
773+
headerName + "*",
774+
"UTF-8''" + URLEncoder.encode(tString, StandardCharsets.UTF_8));
775+
}
776+
}
777+
723778
/**
724779
* This factory is used only when no ssl connections are required (no https endpoints).
725780
* Internally http client would create factory and spend time if no supplied.

0 commit comments

Comments
 (0)