Skip to content

Commit 858f867

Browse files
committed
Introduce bolt_agent and update the default user_agent (#1410)
* Introduce `bolt_agent` and update the default `user_agent` This update introduces support for the new `HELLO` message `bolt_agent` field that is mandatory in the Bolt protocol version 5.3. The `bolt_agent` value is non-configurable and follows a common format among the official drivers. Java driver `bolt_agent` sample: ``` neo4j-java/5.7.0-bf6c5444e19cef8b6cb7aa7e0cecf80b7f8a19a9 (Linux; 5.15.49-linuxkit; aarch64) Java/17.0.6 (Eclipse Adoptium; OpenJDK 64-Bit Server VM; 17.0.6+10) ``` This update also brings support for the Bolt protocol version 5.3. The user agent remains a configurable value, but its default value has been updated to match the new `bolt_agent` value. * Update IT tests
1 parent b19edb9 commit 858f867

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1388
-83
lines changed

driver/src/main/java/org/neo4j/driver/Config.java

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
*/
1919
package org.neo4j.driver;
2020

21-
import static java.lang.String.format;
2221
import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING;
22+
import static org.neo4j.driver.internal.util.DriverInfoUtil.boltAgent;
2323

2424
import java.io.File;
2525
import java.io.Serial;
@@ -345,7 +345,7 @@ public static final class ConfigBuilder {
345345
private long idleTimeBeforeConnectionTest = PoolSettings.DEFAULT_IDLE_TIME_BEFORE_CONNECTION_TEST;
346346
private long maxConnectionLifetimeMillis = PoolSettings.DEFAULT_MAX_CONNECTION_LIFETIME;
347347
private long connectionAcquisitionTimeoutMillis = PoolSettings.DEFAULT_CONNECTION_ACQUISITION_TIMEOUT;
348-
private String userAgent = format("neo4j-java/%s", driverVersion());
348+
private String userAgent = boltAgent();
349349
private final SecuritySettings.SecuritySettingsBuilder securitySettingsBuilder =
350350
new SecuritySettings.SecuritySettingsBuilder();
351351
private long routingTablePurgeDelayMillis = RoutingSettings.STALE_ROUTING_TABLE_PURGE_DELAY_MS;
@@ -748,23 +748,6 @@ public ConfigBuilder withNotificationConfig(NotificationConfig notificationConfi
748748
return this;
749749
}
750750

751-
/**
752-
* Extracts the driver version from the driver jar MANIFEST.MF file.
753-
*/
754-
private static String driverVersion() {
755-
// "Session" is arbitrary - the only thing that matters is that the class we use here is in the
756-
// 'org.neo4j.driver' package, because that is where the jar manifest specifies the version.
757-
// This is done as part of the build, adding a MANIFEST.MF file to the generated jarfile.
758-
Package pkg = Session.class.getPackage();
759-
if (pkg != null && pkg.getImplementationVersion() != null) {
760-
return pkg.getImplementationVersion();
761-
}
762-
763-
// If there is no version, we're not running from a jar file, but from raw compiled class files.
764-
// This should only happen during development, so call the version 'dev'.
765-
return "dev";
766-
}
767-
768751
/**
769752
* Create a config instance from this builder.
770753
*

driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import org.neo4j.driver.internal.security.StaticAuthTokenManager;
6262
import org.neo4j.driver.internal.spi.ConnectionPool;
6363
import org.neo4j.driver.internal.spi.ConnectionProvider;
64+
import org.neo4j.driver.internal.util.DriverInfoUtil;
6465
import org.neo4j.driver.internal.util.Futures;
6566
import org.neo4j.driver.net.ServerAddressResolver;
6667

@@ -141,7 +142,8 @@ protected ConnectionPool createConnectionPool(
141142
Clock clock = createClock();
142143
ConnectionSettings settings =
143144
new ConnectionSettings(authTokenManager, config.userAgent(), config.connectionTimeoutMillis());
144-
ChannelConnector connector = createConnector(settings, securityPlan, config, clock, routingContext);
145+
var boltAgent = DriverInfoUtil.boltAgent();
146+
ChannelConnector connector = createConnector(settings, securityPlan, config, clock, routingContext, boltAgent);
145147
PoolSettings poolSettings = new PoolSettings(
146148
config.maxConnectionPoolSize(),
147149
config.connectionAcquisitionTimeoutMillis(),
@@ -179,15 +181,17 @@ protected ChannelConnector createConnector(
179181
SecurityPlan securityPlan,
180182
Config config,
181183
Clock clock,
182-
RoutingContext routingContext) {
184+
RoutingContext routingContext,
185+
String boltAgent) {
183186
return new ChannelConnectorImpl(
184187
settings,
185188
securityPlan,
186189
config.logging(),
187190
clock,
188191
routingContext,
189192
getDomainNameResolver(),
190-
config.notificationConfig());
193+
config.notificationConfig(),
194+
boltAgent);
191195
}
192196

193197
private InternalDriver createDriver(

driver/src/main/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtil.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42;
3030
import org.neo4j.driver.internal.messaging.v44.BoltProtocolV44;
3131
import org.neo4j.driver.internal.messaging.v5.BoltProtocolV5;
32-
import org.neo4j.driver.internal.messaging.v52.BoltProtocolV52;
32+
import org.neo4j.driver.internal.messaging.v53.BoltProtocolV53;
3333

3434
public final class BoltProtocolUtil {
3535
public static final int BOLT_MAGIC_PREAMBLE = 0x6060B017;
@@ -41,7 +41,7 @@ public final class BoltProtocolUtil {
4141

4242
private static final ByteBuf HANDSHAKE_BUF = unreleasableBuffer(copyInt(
4343
BOLT_MAGIC_PREAMBLE,
44-
BoltProtocolV52.VERSION.toIntRange(BoltProtocolV5.VERSION),
44+
BoltProtocolV53.VERSION.toIntRange(BoltProtocolV5.VERSION),
4545
BoltProtocolV44.VERSION.toIntRange(BoltProtocolV42.VERSION),
4646
BoltProtocolV41.VERSION.toInt(),
4747
BoltProtocolV3.VERSION.toInt()))

driver/src/main/java/org/neo4j/driver/internal/async/connection/ChannelConnectorImpl.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
public class ChannelConnectorImpl implements ChannelConnector {
4444
private final String userAgent;
45+
private final String boltAgent;
4546
private final AuthTokenManager authTokenManager;
4647
private final RoutingContext routingContext;
4748
private final SecurityPlan securityPlan;
@@ -60,7 +61,8 @@ public ChannelConnectorImpl(
6061
Clock clock,
6162
RoutingContext routingContext,
6263
DomainNameResolver domainNameResolver,
63-
NotificationConfig notificationConfig) {
64+
NotificationConfig notificationConfig,
65+
String boltAgent) {
6466
this(
6567
connectionSettings,
6668
securityPlan,
@@ -69,7 +71,8 @@ public ChannelConnectorImpl(
6971
clock,
7072
routingContext,
7173
domainNameResolver,
72-
notificationConfig);
74+
notificationConfig,
75+
boltAgent);
7376
}
7477

7578
public ChannelConnectorImpl(
@@ -80,8 +83,10 @@ public ChannelConnectorImpl(
8083
Clock clock,
8184
RoutingContext routingContext,
8285
DomainNameResolver domainNameResolver,
83-
NotificationConfig notificationConfig) {
86+
NotificationConfig notificationConfig,
87+
String boltAgent) {
8488
this.userAgent = connectionSettings.userAgent();
89+
this.boltAgent = requireNonNull(boltAgent);
8590
this.authTokenManager = connectionSettings.authTokenProvider();
8691
this.routingContext = routingContext;
8792
this.connectTimeoutMillis = connectionSettings.connectTimeoutMillis();
@@ -145,6 +150,6 @@ private void installHandshakeCompletedListeners(
145150
// add listener that sends an INIT message. connection is now fully established. channel pipeline if fully
146151
// set to send/receive messages for a selected protocol version
147152
handshakeCompleted.addListener(new HandshakeCompletedListener(
148-
userAgent, routingContext, connectionInitialized, notificationConfig, clock));
153+
userAgent, boltAgent, routingContext, connectionInitialized, notificationConfig, clock));
149154
}
150155
}

driver/src/main/java/org/neo4j/driver/internal/async/connection/HandshakeCompletedListener.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,22 @@
3232

3333
public class HandshakeCompletedListener implements ChannelFutureListener {
3434
private final String userAgent;
35+
private final String boltAgent;
3536
private final RoutingContext routingContext;
3637
private final ChannelPromise connectionInitializedPromise;
3738
private final NotificationConfig notificationConfig;
3839
private final Clock clock;
3940

4041
public HandshakeCompletedListener(
4142
String userAgent,
43+
String boltAgent,
4244
RoutingContext routingContext,
4345
ChannelPromise connectionInitializedPromise,
4446
NotificationConfig notificationConfig,
4547
Clock clock) {
4648
requireNonNull(clock, "clock must not be null");
4749
this.userAgent = requireNonNull(userAgent);
50+
this.boltAgent = requireNonNull(boltAgent);
4851
this.routingContext = routingContext;
4952
this.connectionInitializedPromise = requireNonNull(connectionInitializedPromise);
5053
this.notificationConfig = notificationConfig;
@@ -71,6 +74,7 @@ public void operationComplete(ChannelFuture future) {
7174
authContext.setValidToken(authToken);
7275
protocol.initializeChannel(
7376
userAgent,
77+
boltAgent,
7478
authToken,
7579
routingContext,
7680
connectionInitializedPromise,
@@ -81,7 +85,13 @@ public void operationComplete(ChannelFuture future) {
8185
channel.eventLoop());
8286
} else {
8387
protocol.initializeChannel(
84-
userAgent, null, routingContext, connectionInitializedPromise, notificationConfig, clock);
88+
userAgent,
89+
boltAgent,
90+
null,
91+
routingContext,
92+
connectionInitializedPromise,
93+
notificationConfig,
94+
clock);
8595
}
8696
} else {
8797
connectionInitializedPromise.setFailure(future.cause());

driver/src/main/java/org/neo4j/driver/internal/messaging/BoltProtocol.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.neo4j.driver.internal.messaging.v5.BoltProtocolV5;
4848
import org.neo4j.driver.internal.messaging.v51.BoltProtocolV51;
4949
import org.neo4j.driver.internal.messaging.v52.BoltProtocolV52;
50+
import org.neo4j.driver.internal.messaging.v53.BoltProtocolV53;
5051
import org.neo4j.driver.internal.spi.Connection;
5152

5253
public interface BoltProtocol {
@@ -61,14 +62,16 @@ public interface BoltProtocol {
6162
* Initialize channel after it is connected and handshake selected this protocol version.
6263
*
6364
* @param userAgent the user agent string.
65+
* @param boltAgent the bolt agent
6466
* @param authToken the authentication token.
6567
* @param routingContext the configured routing context
6668
* @param channelInitializedPromise the promise to be notified when initialization is completed.
67-
* @param notificationConfig the notification configuration
68-
* @param clock the clock to use
69+
* @param notificationConfig the notification configuration
70+
* @param clock the clock to use
6971
*/
7072
void initializeChannel(
7173
String userAgent,
74+
String boltAgent,
7275
AuthToken authToken,
7376
RoutingContext routingContext,
7477
ChannelPromise channelInitializedPromise,
@@ -189,6 +192,8 @@ static BoltProtocol forVersion(BoltProtocolVersion version) {
189192
return BoltProtocolV51.INSTANCE;
190193
} else if (BoltProtocolV52.VERSION.equals(version)) {
191194
return BoltProtocolV52.INSTANCE;
195+
} else if (BoltProtocolV53.VERSION.equals(version)) {
196+
return BoltProtocolV53.INSTANCE;
192197
}
193198
throw new ClientException("Unknown protocol version: " + version);
194199
}

driver/src/main/java/org/neo4j/driver/internal/messaging/request/HelloMessage.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,20 @@ public class HelloMessage extends MessageWithMetadata {
3232
public static final byte SIGNATURE = 0x01;
3333

3434
private static final String USER_AGENT_METADATA_KEY = "user_agent";
35+
private static final String BOLT_AGENT_METADATA_KEY = "bolt_agent";
3536
private static final String ROUTING_CONTEXT_METADATA_KEY = "routing";
3637
private static final String PATCH_BOLT_METADATA_KEY = "patch_bolt";
3738

3839
private static final String DATE_TIME_UTC_PATCH_VALUE = "utc";
3940

4041
public HelloMessage(
4142
String userAgent,
43+
String boltAgent,
4244
Map<String, Value> authToken,
4345
Map<String, String> routingContext,
4446
boolean includeDateTimeUtc,
4547
NotificationConfig notificationConfig) {
46-
super(buildMetadata(userAgent, authToken, routingContext, includeDateTimeUtc, notificationConfig));
48+
super(buildMetadata(userAgent, boltAgent, authToken, routingContext, includeDateTimeUtc, notificationConfig));
4749
}
4850

4951
@Override
@@ -77,12 +79,18 @@ public String toString() {
7779

7880
private static Map<String, Value> buildMetadata(
7981
String userAgent,
82+
String boltAgent,
8083
Map<String, Value> authToken,
8184
Map<String, String> routingContext,
8285
boolean includeDateTimeUtc,
8386
NotificationConfig notificationConfig) {
8487
Map<String, Value> result = new HashMap<>(authToken);
85-
result.put(USER_AGENT_METADATA_KEY, value(userAgent));
88+
if (userAgent != null) {
89+
result.put(USER_AGENT_METADATA_KEY, value(userAgent));
90+
}
91+
if (boltAgent != null) {
92+
result.put(BOLT_AGENT_METADATA_KEY, value(boltAgent));
93+
}
8694
if (routingContext != null) {
8795
result.put(ROUTING_CONTEXT_METADATA_KEY, value(routingContext));
8896
}

driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ public MessageFormat createMessageFormat() {
8181
@Override
8282
public void initializeChannel(
8383
String userAgent,
84+
String boltAgent,
8485
AuthToken authToken,
8586
RoutingContext routingContext,
8687
ChannelPromise channelInitializedPromise,
@@ -97,13 +98,15 @@ public void initializeChannel(
9798
if (routingContext.isServerRoutingEnabled()) {
9899
message = new HelloMessage(
99100
userAgent,
101+
null,
100102
((InternalAuthToken) authToken).toMap(),
101103
routingContext.toMap(),
102104
includeDateTimeUtcPatchInHello(),
103105
notificationConfig);
104106
} else {
105107
message = new HelloMessage(
106108
userAgent,
109+
null,
107110
((InternalAuthToken) authToken).toMap(),
108111
null,
109112
includeDateTimeUtcPatchInHello(),

driver/src/main/java/org/neo4j/driver/internal/messaging/v51/BoltProtocolV51.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class BoltProtocolV51 extends BoltProtocolV5 {
4242
@Override
4343
public void initializeChannel(
4444
String userAgent,
45+
String boltAgent,
4546
AuthToken authToken,
4647
RoutingContext routingContext,
4748
ChannelPromise channelInitializedPromise,
@@ -57,9 +58,9 @@ public void initializeChannel(
5758

5859
if (routingContext.isServerRoutingEnabled()) {
5960
message = new HelloMessage(
60-
userAgent, Collections.emptyMap(), routingContext.toMap(), false, notificationConfig);
61+
userAgent, null, Collections.emptyMap(), routingContext.toMap(), false, notificationConfig);
6162
} else {
62-
message = new HelloMessage(userAgent, Collections.emptyMap(), null, false, notificationConfig);
63+
message = new HelloMessage(userAgent, null, Collections.emptyMap(), null, false, notificationConfig);
6364
}
6465

6566
var helloFuture = new CompletableFuture<Void>();

0 commit comments

Comments
 (0)