Skip to content

Commit 335389e

Browse files
committed
INTERNAL: Use KeyValidator class for validating keys
1 parent 16ef432 commit 335389e

8 files changed

Lines changed: 252 additions & 179 deletions

File tree

src/main/java/net/spy/memcached/ArcusClient.java

Lines changed: 58 additions & 101 deletions
Large diffs are not rendered by default.
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/*
2+
* arcus-java-client : Arcus Java client
3+
* Copyright 2010-2014 NAVER Corp.
4+
* Copyright 2014-present JaM2in Co., Ltd.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package net.spy.memcached;
19+
20+
import java.util.Collection;
21+
22+
/**
23+
* Validator for memcached keys.
24+
*/
25+
public final class KeyValidator {
26+
27+
public static final int MAX_KEY_LENGTH = 4000;
28+
public static final int MAX_MKEY_LENGTH = 250;
29+
private static final int MAX_BKEY_BYTE_ARRAY_LENGTH = 31;
30+
31+
private final byte delimiter;
32+
33+
public KeyValidator(byte delimiter) {
34+
this.delimiter = delimiter;
35+
}
36+
37+
/**
38+
* Validate cache key.
39+
*
40+
* @param key the cache key to validate
41+
* @throws IllegalArgumentException if the key is invalid
42+
*/
43+
public void validateKey(String key) {
44+
boolean hasPrefix = false;
45+
46+
byte[] keyBytes = KeyUtil.getKeyBytes(key);
47+
if (keyBytes.length > MAX_KEY_LENGTH) {
48+
throw new IllegalArgumentException("Key is too long (maxlen = "
49+
+ MAX_KEY_LENGTH + ")");
50+
} else if (keyBytes.length == 0) {
51+
throw new IllegalArgumentException(
52+
"Key must contain at least one character.");
53+
}
54+
// Validate the key
55+
for (byte b : keyBytes) {
56+
if (b == ' ' || b == '\n' || b == '\r' || b == 0) {
57+
throw new IllegalArgumentException(
58+
"Key contains invalid characters: ``" + key + "''");
59+
}
60+
if (b == delimiter) {
61+
hasPrefix = true;
62+
}
63+
}
64+
65+
// Validate the prefix
66+
if (hasPrefix) {
67+
if (keyBytes[0] == '-') {
68+
throw new IllegalArgumentException(
69+
"Key contains invalid prefix: ``" + key + "''");
70+
}
71+
for (byte b : keyBytes) {
72+
if (b == delimiter) {
73+
break;
74+
}
75+
if (!(('a' <= b && b <= 'z') || ('A' <= b && b <= 'Z') ||
76+
('0' <= b && b <= '9') ||
77+
(b == '_') || (b == '-') || (b == '+') || (b == '.'))) {
78+
throw new IllegalArgumentException(
79+
"Key contains invalid prefix: ``" + key + "''");
80+
}
81+
}
82+
}
83+
}
84+
85+
/**
86+
* Validate cache keys.
87+
*
88+
* @param keyList the cache keys to validate
89+
* @throws IllegalArgumentException if the key list is null, empty, or contains invalid keys
90+
*/
91+
public void validateKey(Collection<String> keyList) {
92+
if (keyList == null) {
93+
throw new IllegalArgumentException("Key list is null.");
94+
} else if (keyList.isEmpty()) {
95+
throw new IllegalArgumentException("Key list is empty.");
96+
}
97+
98+
for (String key : keyList) {
99+
validateKey(key);
100+
}
101+
}
102+
103+
/**
104+
* Validate map key.
105+
*
106+
* @param mkey the mkey to validate
107+
* @throws IllegalArgumentException if the mkey is invalid
108+
*/
109+
public static void validateMKey(String mkey) {
110+
if (mkey == null) {
111+
throw new IllegalArgumentException("mkey is null");
112+
}
113+
114+
byte[] keyBytes = KeyUtil.getKeyBytes(mkey);
115+
if (keyBytes.length > MAX_MKEY_LENGTH) {
116+
throw new IllegalArgumentException("MKey is too long (maxlen = "
117+
+ MAX_MKEY_LENGTH + ")");
118+
}
119+
if (keyBytes.length == 0) {
120+
throw new IllegalArgumentException("MKey must contain at least one character.");
121+
}
122+
// Validate the mkey
123+
for (byte b : keyBytes) {
124+
if (b == ' ' || b == '\n' || b == '\r' || b == 0) {
125+
throw new IllegalArgumentException("MKey contains invalid characters: ``"
126+
+ mkey + "''");
127+
}
128+
}
129+
}
130+
131+
/**
132+
* Validate map keys.
133+
*
134+
* @param mkeyList the mkeys to validate
135+
* @throws IllegalArgumentException if the mkey list is null, empty, or contains invalid mkeys
136+
*/
137+
public static void validateMKey(Collection<String> mkeyList) {
138+
if (mkeyList == null) {
139+
throw new IllegalArgumentException("mkeyList is null.");
140+
} else if (mkeyList.isEmpty()) {
141+
throw new IllegalArgumentException("mkeyList is empty.");
142+
}
143+
144+
for (String mkey : mkeyList) {
145+
validateMKey(mkey);
146+
}
147+
}
148+
149+
/**
150+
* Validate byte type bkeys.
151+
*
152+
* @param bkeys the bkeys to validate
153+
* @throws IllegalArgumentException if the bkey is invalid
154+
*/
155+
public static void validateBKey(byte[]... bkeys) {
156+
for (byte[] bkey : bkeys) {
157+
if (bkey == null) {
158+
throw new IllegalArgumentException("bkey is null");
159+
}
160+
if (bkey.length > MAX_BKEY_BYTE_ARRAY_LENGTH) {
161+
throw new IllegalArgumentException("bkey size exceeded 31");
162+
}
163+
}
164+
}
165+
166+
/**
167+
* Validate long type bkeys.
168+
*
169+
* @param bkeys the bkeys to validate
170+
* @throws IllegalArgumentException if the bkey is invalid
171+
*/
172+
public static void validateBKey(long... bkeys) {
173+
for (long bkey : bkeys) {
174+
if (bkey < 0) {
175+
throw new IllegalArgumentException(
176+
String.format("not supported unsigned long bkey : %s, use byte array bkey", bkey));
177+
}
178+
}
179+
}
180+
}

src/main/java/net/spy/memcached/MemcachedClient.java

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public class MemcachedClient extends SpyThread
130130

131131
protected final Transcoder<Object> transcoder;
132132

133-
private final byte delimiter;
133+
protected final KeyValidator keyValidator;
134134

135135
private static final String DEFAULT_MEMCACHED_CLIENT_NAME = "MemcachedClient";
136136

@@ -213,7 +213,7 @@ public MemcachedClient(ConnectionFactory cf, String name, List<InetSocketAddress
213213
conn = cf.createConnection(name, addrs);
214214
assert conn != null : "Connection factory failed to make a connection";
215215
operationTimeout = cf.getOperationTimeout();
216-
delimiter = cf.getDelimiter();
216+
keyValidator = new KeyValidator(cf.getDelimiter());
217217
setName("Memcached IO over " + conn);
218218
setDaemon(cf.isDaemon());
219219
start();
@@ -283,49 +283,6 @@ public OperationFactory getOpFact() {
283283
return opFact;
284284
}
285285

286-
protected void validateKey(String key) {
287-
boolean hasPrefix = false;
288-
289-
byte[] keyBytes = KeyUtil.getKeyBytes(key);
290-
if (keyBytes.length > MAX_KEY_LENGTH) {
291-
throw new IllegalArgumentException("Key is too long (maxlen = "
292-
+ MAX_KEY_LENGTH + ")");
293-
}
294-
if (keyBytes.length == 0) {
295-
throw new IllegalArgumentException(
296-
"Key must contain at least one character.");
297-
}
298-
// Validate the key
299-
for (byte b : keyBytes) {
300-
if (b == ' ' || b == '\n' || b == '\r' || b == 0) {
301-
throw new IllegalArgumentException(
302-
"Key contains invalid characters: ``" + key + "''");
303-
}
304-
if (b == delimiter) {
305-
hasPrefix = true;
306-
}
307-
}
308-
309-
// Validate the prefix
310-
if (hasPrefix) {
311-
if (keyBytes[0] == '-') {
312-
throw new IllegalArgumentException(
313-
"Key contains invalid prefix: ``" + key + "''");
314-
}
315-
for (byte b : keyBytes) {
316-
if (b == delimiter) {
317-
break;
318-
}
319-
if (!(('a' <= b && b <= 'z') || ('A' <= b && b <= 'Z') ||
320-
('0' <= b && b <= '9') ||
321-
(b == '_') || (b == '-') || (b == '+') || (b == '.'))) {
322-
throw new IllegalArgumentException(
323-
"Key contains invalid prefix: ``" + key + "''");
324-
}
325-
}
326-
}
327-
}
328-
329286
protected void checkState() {
330287
if (shuttingDown) {
331288
throw new IllegalStateException("Shutting down");
@@ -342,7 +299,7 @@ protected void checkState() {
342299
* @return the Operation
343300
*/
344301
public Operation addOp(final String key, final Operation op) {
345-
validateKey(key);
302+
keyValidator.validateKey(key);
346303
checkState();
347304
conn.addOperation(key, op);
348305
return op;
@@ -1067,7 +1024,7 @@ public <T> BulkFuture<Map<String, T>> asyncGetBulk(Collection<String> keys,
10671024
for (String key : keys) {
10681025
if (tcIter.hasNext()) {
10691026
tcMap.put(key, tcIter.next());
1070-
validateKey(key);
1027+
keyValidator.validateKey(key);
10711028
}
10721029
}
10731030

@@ -1200,7 +1157,7 @@ public <T> BulkFuture<Map<String, CASValue<T>>> asyncGetsBulk(Collection<String>
12001157
for (String key : keys) {
12011158
if (tcIter.hasNext()) {
12021159
tcMap.put(key, tcIter.next());
1203-
validateKey(key);
1160+
keyValidator.validateKey(key);
12041161
}
12051162
}
12061163

src/main/java/net/spy/memcached/MemcachedClientIF.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@
1515
* This interface is provided as a helper for testing clients of the MemcachedClient.
1616
*/
1717
public interface MemcachedClientIF {
18-
/**
19-
* Maximum supported key length.
20-
*/
21-
int MAX_KEY_LENGTH = 4000;
2218

2319
Collection<SocketAddress> getAvailableServers();
2420

src/main/java/net/spy/memcached/collection/BKeyObject.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.util.Objects;
2121

22+
import net.spy.memcached.KeyValidator;
2223
import net.spy.memcached.util.BTreeUtil;
2324

2425
public class BKeyObject implements Comparable<BKeyObject> {
@@ -32,14 +33,14 @@ public enum BKeyType {
3233
private final ByteArrayBKey byteArrayBKey;
3334

3435
public BKeyObject(long longBKey) {
35-
BTreeUtil.validateBkey(longBKey);
36+
KeyValidator.validateBKey(longBKey);
3637
this.type = BKeyType.LONG;
3738
this.longBKey = longBKey;
3839
this.byteArrayBKey = null;
3940
}
4041

4142
public BKeyObject(byte[] byteArrayBKey) {
42-
BTreeUtil.validateBkey(byteArrayBKey);
43+
KeyValidator.validateBKey(byteArrayBKey);
4344
this.type = BKeyType.BYTEARRAY;
4445
this.longBKey = null;
4546
this.byteArrayBKey = new ByteArrayBKey(byteArrayBKey);

src/main/java/net/spy/memcached/collection/ByteArrayBKey.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.util.Arrays;
2121

22+
import net.spy.memcached.KeyValidator;
2223
import net.spy.memcached.util.BTreeUtil;
2324

2425
public class ByteArrayBKey implements Comparable<ByteArrayBKey> {
@@ -37,7 +38,7 @@ public class ByteArrayBKey implements Comparable<ByteArrayBKey> {
3738
private final byte[] bkey;
3839

3940
public ByteArrayBKey(byte[] bkey) {
40-
BTreeUtil.validateBkey(bkey);
41+
KeyValidator.validateBKey(bkey);
4142
this.bkey = bkey;
4243
}
4344

src/main/java/net/spy/memcached/util/BTreeUtil.java

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
public final class BTreeUtil {
2626

2727
private static final String HEXES = "0123456789ABCDEF";
28-
private static final int MAX_BKEY_BYTE_ARRAY_SIZE = 31;
2928

3029
private BTreeUtil() {
3130
}
@@ -86,26 +85,6 @@ public static int compareByteArraysInLexOrder(byte[] array1, byte[] array2) {
8685
return array1.length - array2.length;
8786
}
8887

89-
public static void validateBkey(byte[] ...bkeys) {
90-
for (byte[] bkey : bkeys) {
91-
if (bkey == null) {
92-
throw new IllegalArgumentException("bkey is null");
93-
}
94-
if (bkey.length > MAX_BKEY_BYTE_ARRAY_SIZE) {
95-
throw new IllegalArgumentException("bkey size exceeded 31");
96-
}
97-
}
98-
}
99-
100-
public static void validateBkey(long ...bkeys) {
101-
for (long bkey : bkeys) {
102-
if (bkey < 0) {
103-
throw new IllegalArgumentException(
104-
String.format("not supported unsigned long bkey : %s, use byte array bkey", bkey));
105-
}
106-
}
107-
}
108-
10988
public static <T> Element<T> makeBTreeElement(BKeyObject bkey,
11089
CachedData cachedData,
11190
Transcoder<T> tc) {

src/test/java/net/spy/memcached/util/BTreeUtilTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.util.Arrays;
2020

21+
import net.spy.memcached.KeyValidator;
22+
2123
import org.junit.jupiter.api.Test;
2224

2325
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -90,15 +92,15 @@ void testCompareDifferentLengthByteArrays() throws Exception {
9092
@Test
9193
void testInValidSizeBkey() {
9294
assertThrows(IllegalArgumentException.class, () -> {
93-
BTreeUtil.validateBkey(new byte[32]);
95+
KeyValidator.validateBKey(new byte[32]);
9496
});
9597
}
9698

9799
@Test
98100
void testMinusLongBkey() {
99101
final long bkey = -1;
100102
assertThrows(IllegalArgumentException.class, () -> {
101-
BTreeUtil.validateBkey(bkey);
103+
KeyValidator.validateBKey(bkey);
102104
});
103105
}
104106
}

0 commit comments

Comments
 (0)