Skip to content

Commit 40b098e

Browse files
Client setinfo ignore all exception (#3449) (#3458)
This PR contains the following changes: 1. Check the character legality of clientName in advance through `validateClientInfo`, so that character exceptions are ignored in `initializeFromClientConfig`. 2. Move the `select` command out of the fire-and-forget message (we care about its return value). 3. For the test of RedisCredentials, we gave it "invalidPass" for the first time to make it fail the verification instead of skipping the verification. --------- Co-authored-by: bodong.ybd <[email protected]>
1 parent 0fa8151 commit 40b098e

File tree

3 files changed

+61
-33
lines changed

3 files changed

+61
-33
lines changed

src/main/java/redis/clients/jedis/Connection.java

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -352,70 +352,69 @@ public List<Object> getMany(final int count) {
352352
return responses;
353353
}
354354

355+
/**
356+
* Check if the client name libname, libver, characters are legal
357+
* @param info the name
358+
* @return Returns true if legal, false throws exception
359+
* @throws JedisException if characters illegal
360+
*/
361+
private static boolean validateClientInfo(String info) {
362+
for (int i = 0; i < info.length(); i++) {
363+
char c = info.charAt(i);
364+
if (c < '!' || c > '~') {
365+
throw new JedisException("client info cannot contain spaces, "
366+
+ "newlines or special characters.");
367+
}
368+
}
369+
return true;
370+
}
371+
355372
private void initializeFromClientConfig(JedisClientConfig config) {
356373
try {
357374
connect();
358375

359376
Supplier<RedisCredentials> credentialsProvider = config.getCredentialsProvider();
360377
if (credentialsProvider instanceof RedisCredentialsProvider) {
361-
((RedisCredentialsProvider) credentialsProvider).prepare();
362-
auth(credentialsProvider);
363-
((RedisCredentialsProvider) credentialsProvider).cleanUp();
378+
try {
379+
((RedisCredentialsProvider) credentialsProvider).prepare();
380+
auth(credentialsProvider);
381+
} finally {
382+
((RedisCredentialsProvider) credentialsProvider).cleanUp();
383+
}
364384
} else {
365385
auth(credentialsProvider);
366386
}
367387

368-
List<CommandArguments> fireAndForgetMsg = new ArrayList<>();
369-
370388
int dbIndex = config.getDatabase();
371389
if (dbIndex > 0) {
372-
fireAndForgetMsg.add(new CommandArguments(Command.SELECT).add(Protocol.toByteArray(dbIndex)));
390+
select(dbIndex);
373391
}
374392

393+
List<CommandArguments> fireAndForgetMsg = new ArrayList<>();
394+
375395
String clientName = config.getClientName();
376-
if (clientName != null) {
396+
if (clientName != null && validateClientInfo(clientName)) {
377397
fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETNAME).add(clientName));
378398
}
379399

380400
String libName = JedisMetaInfo.getArtifactId();
381-
if (libName != null) {
401+
if (libName != null && validateClientInfo(libName)) {
382402
fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETINFO)
383403
.add(ClientAttributeOption.LIB_NAME.getRaw()).add(libName));
384404
}
385405

386406
String libVersion = JedisMetaInfo.getVersion();
387-
if (libVersion != null) {
407+
if (libVersion != null && validateClientInfo(libVersion)) {
388408
fireAndForgetMsg.add(new CommandArguments(Command.CLIENT).add(Keyword.SETINFO)
389409
.add(ClientAttributeOption.LIB_VER.getRaw()).add(libVersion));
390410
}
391411

392412
for (CommandArguments arg : fireAndForgetMsg) {
393413
sendCommand(arg);
394414
}
395-
396-
List<Object> objects = getMany(fireAndForgetMsg.size());
397-
for (Object obj : objects) {
398-
if (obj instanceof JedisDataException) {
399-
JedisDataException e = (JedisDataException)obj;
400-
String errorMsg = e.getMessage().toUpperCase();
401-
/**
402-
* 1. Redis 4.0 and before, we need to ignore `Syntax error`.
403-
* 2. Redis 5.0 and later, we need to ignore `Unknown subcommand error`.
404-
* 3. Because Jedis allows Jedis jedis = new Jedis() in advance, and jedis.auth(password) later,
405-
* we need to ignore `NOAUTH errors`.
406-
*/
407-
if (errorMsg.contains("SYNTAX") ||
408-
errorMsg.contains("UNKNOWN") ||
409-
errorMsg.contains("NOAUTH")) { // TODO: not filter out NOAUTH
410-
// ignore
411-
} else {
412-
throw e;
413-
}
414-
}
415-
}
415+
getMany(fireAndForgetMsg.size());
416416
} catch (JedisException je) {
417417
try {
418-
setBroken();
419418
disconnect();
420419
} catch (Exception e) {
421420
// the first exception 'je' will be thrown
@@ -447,7 +446,6 @@ private void auth(final Supplier<RedisCredentials> credentialsProvider) {
447446
getStatusCodeReply(); // OK
448447
}
449448

450-
@Deprecated
451449
public String select(final int index) {
452450
sendCommand(Protocol.Command.SELECT, Protocol.toByteArray(index));
453451
return getStatusCodeReply();

src/test/java/redis/clients/jedis/JedisPoolTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.apache.commons.pool2.PooledObjectFactory;
1414
import org.apache.commons.pool2.impl.DefaultPooledObject;
1515
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
16+
import org.junit.Assert;
1617
import org.junit.Test;
1718

1819
import redis.clients.jedis.exceptions.InvalidURIException;
@@ -219,6 +220,17 @@ public void customClientName() {
219220
}
220221
}
221222

223+
@Test
224+
public void invalidClientName() {
225+
try (JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000,
226+
"foobared", 0, "invalid client name"); Jedis jedis = pool.getResource()) {
227+
} catch (Exception e) {
228+
if (!e.getMessage().startsWith("client info cannot contain space")) {
229+
Assert.fail("invalid client name test fail");
230+
}
231+
}
232+
}
233+
222234
@Test
223235
public void returnResourceDestroysResourceOnException() {
224236

src/test/java/redis/clients/jedis/JedisPooledTest.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.net.URISyntaxException;
1010
import java.util.concurrent.atomic.AtomicInteger;
1111
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
12+
import org.junit.Assert;
1213
import org.junit.Test;
1314

1415
import redis.clients.jedis.exceptions.JedisConnectionException;
@@ -98,6 +99,18 @@ public void customClientName() {
9899
}
99100
}
100101

102+
@Test
103+
public void invalidClientName() {
104+
try (JedisPooled pool = new JedisPooled(hnp, DefaultJedisClientConfig.builder()
105+
.clientName("invalid client name").build());
106+
Connection jedis = pool.getPool().getResource()) {
107+
} catch (Exception e) {
108+
if (!e.getMessage().startsWith("client info cannot contain space")) {
109+
Assert.fail("invalid client name test fail");
110+
}
111+
}
112+
}
113+
101114
@Test
102115
public void getNumActiveWhenPoolIsClosed() {
103116
JedisPooled pool = new JedisPooled(hnp);
@@ -209,7 +222,12 @@ public void prepare() {
209222
public RedisCredentials get() {
210223
if (firstCall) {
211224
firstCall = false;
212-
return new RedisCredentials() { };
225+
return new RedisCredentials() {
226+
@Override
227+
public char[] getPassword() {
228+
return "invalidPass".toCharArray();
229+
}
230+
};
213231
}
214232

215233
return new RedisCredentials() {

0 commit comments

Comments
 (0)