Date: Fri, 11 Sep 2026 20:11:12 +0300
Subject: [PATCH 8/9] nao-it suggestions
---
.../redis/RedisProtocolConnectSelfTest.java | 50 ++++++---
.../server/GridRedisClientCommandHandler.java | 100 +++++++++++-------
.../tcp/redis/GridRedisNioListener.java | 2 +-
3 files changed, 102 insertions(+), 50 deletions(-)
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolConnectSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolConnectSelfTest.java
index b22f823042fb6..16c0e76ee8030 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolConnectSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/RedisProtocolConnectSelfTest.java
@@ -18,9 +18,11 @@
package org.apache.ignite.internal.processors.rest.protocols.tcp.redis;
import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.ignite.testframework.GridTestUtils;
import org.junit.Assert;
import org.junit.Test;
import redis.clients.jedis.Jedis;
+import redis.clients.jedis.exceptions.JedisDataException;
import static org.apache.ignite.internal.util.IgniteUtils.KB;
@@ -28,31 +30,25 @@
* Tests for Connection commands of Redis protocol.
*/
public class RedisProtocolConnectSelfTest extends RedisCommonAbstractTest {
- /**
- * @throws Exception If failed.
- */
+ /** */
@Test
- public void testPing() throws Exception {
+ public void testPing() {
try (Jedis jedis = pool.getResource()) {
Assert.assertEquals("PONG", jedis.ping());
}
}
- /**
- * @throws Exception If failed.
- */
+ /** */
@Test
- public void testEcho() throws Exception {
+ public void testEcho() {
try (Jedis jedis = pool.getResource()) {
Assert.assertEquals("Hello, grid!", jedis.echo("Hello, grid!"));
}
}
- /**
- * @throws Exception If failed.
- */
+ /** */
@Test
- public void testSelect() throws Exception {
+ public void testSelect() {
try (Jedis jedis = pool.getResource()) {
// connected to cache with index 0
jedis.set("k0", "v0");
@@ -78,6 +74,36 @@ public void testSelect() throws Exception {
}
}
+ /** */
+ @Test
+ public void testClient() {
+ try (Jedis jedis = pool.getResource()) {
+ Assert.assertNull(jedis.clientGetname());
+
+ Assert.assertEquals("OK", jedis.clientSetname("test-client"));
+ Assert.assertEquals("test-client", jedis.clientGetname());
+
+ // The name is connection-scoped.
+ try (Jedis jedis2 = pool.getResource()) {
+ Assert.assertNull(jedis2.clientGetname());
+ }
+
+ Assert.assertEquals("test-client", jedis.clientGetname());
+ }
+ }
+
+ /** */
+ @Test
+ public void testClientUnknownSubcommand() {
+ try (Jedis jedis = pool.getResource()) {
+ GridTestUtils.assertThrows(log, () -> jedis.clientUnpause(), JedisDataException.class,
+ "Unknown subcommand 'UNPAUSE' for 'client' command");
+
+ // The connection is still usable.
+ Assert.assertEquals("PONG", jedis.ping());
+ }
+ }
+
/** */
@Test
public void testSetGetLongString() {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/server/GridRedisClientCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/server/GridRedisClientCommandHandler.java
index e9cfd928d58c3..80745b7865179 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/server/GridRedisClientCommandHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/server/GridRedisClientCommandHandler.java
@@ -17,44 +17,35 @@
package org.apache.ignite.internal.processors.rest.handlers.redis.server;
-import java.nio.ByteBuffer;
import java.util.Collection;
-import java.util.List;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.IgniteLogger;
-import org.apache.ignite.internal.GridKernalContext;
-import org.apache.ignite.internal.processors.rest.GridRestCommand;
-import org.apache.ignite.internal.processors.rest.GridRestProtocolHandler;
-import org.apache.ignite.internal.processors.rest.GridRestResponse;
-import org.apache.ignite.internal.processors.rest.handlers.redis.GridRedisRestCommandHandler;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.processors.rest.handlers.redis.GridRedisCommandHandler;
import org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisCommand;
import org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisMessage;
import org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisProtocolParser;
-import org.apache.ignite.internal.processors.rest.request.GridRestCacheRequest;
-import org.apache.ignite.internal.processors.rest.request.GridRestRequest;
+import org.apache.ignite.internal.util.future.GridFinishedFuture;
+import org.apache.ignite.internal.util.nio.GridNioSession;
+import org.apache.ignite.internal.util.nio.GridNioSessionMetaKey;
+import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.U;
import static org.apache.ignite.internal.processors.rest.protocols.tcp.redis.GridRedisCommand.CLIENT;
/**
* Redis CLIENT command handler.
+ *
+ * CLIENT is a connection-scoped command container, so it is handled locally, without a REST round trip.
+ * Only the subcommands that carry no cluster-wide state are supported, the rest are answered with an error.
*/
-public class GridRedisClientCommandHandler extends GridRedisRestCommandHandler {
+public class GridRedisClientCommandHandler implements GridRedisCommandHandler {
/** Supported commands. */
- private static final Collection SUPPORTED_COMMANDS = U.sealList(
- CLIENT
- );
-
- /**
- * Handler constructor.
- *
- * @param log Logger to use.
- * @param hnd Rest handler.
- * @param ctx Kernal context.
- */
- public GridRedisClientCommandHandler(IgniteLogger log, GridRestProtocolHandler hnd, GridKernalContext ctx) {
- super(log, hnd, ctx);
- }
+ private static final Collection SUPPORTED_COMMANDS = U.sealList(CLIENT);
+
+ /** Session metadata key for the name set by CLIENT SETNAME. */
+ private static final int CLIENT_NAME_META_KEY = GridNioSessionMetaKey.nextUniqueKey();
+
+ /** Position of the first argument of a CLIENT subcommand. */
+ private static final int ARG_POS = 2;
/** {@inheritDoc} */
@Override public Collection supportedCommands() {
@@ -62,20 +53,55 @@ public GridRedisClientCommandHandler(IgniteLogger log, GridRestProtocolHandler h
}
/** {@inheritDoc} */
- @Override public GridRestRequest asRestRequest(GridRedisMessage msg) throws IgniteCheckedException {
+ @Override public IgniteInternalFuture handleAsync(GridNioSession ses, GridRedisMessage msg) {
assert msg != null;
- GridRestCacheRequest restReq = new GridRestCacheRequest();
+ String subCmd = msg.key();
- restReq.clientId(msg.clientId());
- restReq.command(GridRestCommand.CLIENT);
- restReq.cacheName(msg.cacheName());
+ if (F.isEmpty(subCmd)) {
+ msg.setResponse(GridRedisProtocolParser.toGenericError(
+ "wrong number of arguments for 'client' command"));
- return restReq;
- }
+ return new GridFinishedFuture<>(msg);
+ }
- /** {@inheritDoc} */
- @Override public ByteBuffer makeResponse(final GridRestResponse restRes, List params) {
- return GridRedisProtocolParser.oKString();
+ switch (subCmd.toUpperCase()) {
+ case "SETNAME": {
+ String name = msg.aux(ARG_POS);
+
+ if (name == null || name.indexOf(' ') >= 0 || name.indexOf('\n') >= 0)
+ msg.setResponse(GridRedisProtocolParser.toGenericError(
+ "Client names cannot contain spaces, newlines or special characters."));
+ else {
+ ses.addMeta(CLIENT_NAME_META_KEY, name);
+
+ msg.setResponse(GridRedisProtocolParser.oKString());
+ }
+
+ break;
+ }
+
+ case "GETNAME": {
+ String name = ses.meta(CLIENT_NAME_META_KEY);
+
+ msg.setResponse(name == null
+ ? GridRedisProtocolParser.nil()
+ : GridRedisProtocolParser.toBulkString(name));
+
+ break;
+ }
+
+ case "SETINFO":
+ // The library name and version announced by a driver: accepted and ignored.
+ msg.setResponse(GridRedisProtocolParser.oKString());
+
+ break;
+
+ default:
+ msg.setResponse(GridRedisProtocolParser.toGenericError(
+ "Unknown subcommand '" + subCmd + "' for 'client' command"));
+ }
+
+ return new GridFinishedFuture<>(msg);
}
-}
+}
\ No newline at end of file
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/GridRedisNioListener.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/GridRedisNioListener.java
index 1922c0f608302..4b6337955ba0c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/GridRedisNioListener.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/protocols/tcp/redis/GridRedisNioListener.java
@@ -93,7 +93,7 @@ public GridRedisNioListener(IgniteLogger log, GridRestProtocolHandler hnd, GridK
// server commands.
addCommandHandler(new GridRedisDbSizeCommandHandler(log, hnd, ctx));
addCommandHandler(new GridRedisFlushCommandHandler(log, hnd, ctx));
- addCommandHandler(new GridRedisClientCommandHandler(log, hnd, ctx));
+ addCommandHandler(new GridRedisClientCommandHandler());
}
/**
From c3a90fb871c22f0c746e5cea0e30a1dbe446a352 Mon Sep 17 00:00:00 2001
From: zstan
Date: Fri, 11 Sep 2026 20:23:46 +0300
Subject: [PATCH 9/9] new line check
---
.../handlers/redis/server/GridRedisClientCommandHandler.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/server/GridRedisClientCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/server/GridRedisClientCommandHandler.java
index 80745b7865179..e9b14dd5b6256 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/server/GridRedisClientCommandHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/redis/server/GridRedisClientCommandHandler.java
@@ -104,4 +104,4 @@ public class GridRedisClientCommandHandler implements GridRedisCommandHandler {
return new GridFinishedFuture<>(msg);
}
-}
\ No newline at end of file
+}