2626import com .clickhouse .client .api .internal .ClickHouseLZ4OutputStream ;
2727import com .clickhouse .client .api .internal .ClientStatisticsHolder ;
2828import com .clickhouse .client .api .internal .ClientV1AdaptorHelper ;
29+ import com .clickhouse .client .api .internal .EnvUtils ;
2930import com .clickhouse .client .api .internal .HttpAPIClientHelper ;
3031import com .clickhouse .client .api .internal .MapUtils ;
3132import com .clickhouse .client .api .internal .SettingsConverter ;
4950import org .apache .hc .core5 .concurrent .DefaultThreadFactory ;
5051import org .apache .hc .core5 .http .ClassicHttpResponse ;
5152import org .apache .hc .core5 .http .ConnectionRequestTimeoutException ;
53+ import org .apache .hc .core5 .http .HttpHeaders ;
5254import org .apache .hc .core5 .http .HttpStatus ;
5355import org .apache .hc .core5 .http .NoHttpResponseException ;
5456import org .slf4j .Logger ;
7274import java .util .HashSet ;
7375import java .util .LinkedHashMap ;
7476import java .util .List ;
77+ import java .util .Locale ;
7578import java .util .Map ;
7679import java .util .Set ;
7780import java .util .StringJoiner ;
@@ -828,7 +831,7 @@ public Builder allowBinaryReaderToReuseBuffers(boolean reuse) {
828831 * @return same instance of the builder
829832 */
830833 public Builder httpHeader (String key , String value ) {
831- this .configuration .put (ClientConfigProperties .HTTP_HEADER_PREFIX + key , value );
834+ this .configuration .put (ClientConfigProperties .HTTP_HEADER_PREFIX + key . toUpperCase ( Locale . US ) , value );
832835 return this ;
833836 }
834837
@@ -839,7 +842,7 @@ public Builder httpHeader(String key, String value) {
839842 * @return same instance of the builder
840843 */
841844 public Builder httpHeader (String key , Collection <String > values ) {
842- this .configuration .put (ClientConfigProperties .HTTP_HEADER_PREFIX + key , ClientConfigProperties .commaSeparated (values ));
845+ this .configuration .put (ClientConfigProperties .HTTP_HEADER_PREFIX + key . toUpperCase ( Locale . US ) , ClientConfigProperties .commaSeparated (values ));
843846 return this ;
844847 }
845848
@@ -897,12 +900,28 @@ public Builder columnToMethodMatchingStrategy(ColumnToMethodMatchingStrategy str
897900 * Whether to use HTTP basic authentication. Default value is true.
898901 * Password that contain UTF8 characters may not be passed through http headers and BASIC authentication
899902 * is the only option here.
903+ * @param useBasicAuth - indicates if basic authentication should be used
904+ * @return same instance of the builder
900905 */
901906 public Builder useHTTPBasicAuth (boolean useBasicAuth ) {
902907 this .configuration .put (ClientConfigProperties .HTTP_USE_BASIC_AUTH .getKey (), String .valueOf (useBasicAuth ));
903908 return this ;
904909 }
905910
911+ /**
912+ * Sets additional information about calling application. This string will be passed to server as a client name.
913+ * In case of HTTP protocol it will be passed as a {@code User-Agent} header.
914+ * Warn: If custom value of User-Agent header is set it will override this value for HTTP transport
915+ * Client name is used by server to identify client application when investigating {@code system.query_log}. In case of HTTP
916+ * transport this value will be in the {@code system.query_log.http_user_agent} column. Currently only HTTP transport is used.
917+ *
918+ * @param clientName - client application display name.
919+ * @return same instance of the builder
920+ */
921+ public Builder setClientName (String clientName ) {
922+ this .configuration .put (ClientConfigProperties .CLIENT_NAME .getKey (), clientName );
923+ return this ;
924+ }
906925
907926 public Client build () {
908927 setDefaults ();
@@ -1042,7 +1061,41 @@ private void setDefaults() {
10421061 if (!configuration .containsKey (ClientConfigProperties .HTTP_USE_BASIC_AUTH .getKey ())) {
10431062 useHTTPBasicAuth (true );
10441063 }
1064+
1065+ String userAgent = configuration .getOrDefault (ClientConfigProperties .HTTP_HEADER_PREFIX + HttpHeaders .USER_AGENT .toUpperCase (Locale .US ), "" );
1066+ String clientName = configuration .getOrDefault (ClientConfigProperties .CLIENT_NAME .getKey (), "" );
1067+ httpHeader (HttpHeaders .USER_AGENT , buildUserAgent (userAgent .isEmpty () ? clientName : userAgent ));
10451068 }
1069+
1070+ private static String buildUserAgent (String customUserAgent ) {
1071+
1072+ StringBuilder userAgent = new StringBuilder ();
1073+ if (customUserAgent != null && !customUserAgent .isEmpty ()) {
1074+ userAgent .append (customUserAgent ).append (" " );
1075+ }
1076+
1077+ userAgent .append (CLIENT_USER_AGENT );
1078+
1079+ String clientVersion = Client .class .getPackage ().getImplementationVersion ();
1080+ if (clientVersion == null ) {
1081+ clientVersion = LATEST_ARTIFACT_VERSION ;
1082+ }
1083+ userAgent .append (clientVersion );
1084+
1085+ userAgent .append (" (" );
1086+ userAgent .append (System .getProperty ("os.name" ));
1087+ userAgent .append ("; " );
1088+ userAgent .append ("jvm:" ).append (System .getProperty ("java.version" ));
1089+ userAgent .append ("; " );
1090+
1091+ userAgent .setLength (userAgent .length () - 2 );
1092+ userAgent .append (')' );
1093+
1094+ return userAgent .toString ();
1095+ }
1096+
1097+ public static final String LATEST_ARTIFACT_VERSION = "0.7.1-patch1" ;
1098+ public static final String CLIENT_USER_AGENT = "clickhouse-java-v2/" ;
10461099 }
10471100
10481101 private ClickHouseNode getServerNode () {
0 commit comments