From 9c0ad8147de1d84319eb08dd5030f03ff7a9eaf2 Mon Sep 17 00:00:00 2001 From: Jonathan Ellis Date: Thu, 1 Jul 2010 01:24:35 +0000 Subject: [PATCH] validate UTF8 keys in legacy OPP and COPP. patch by Nick Bailey; reviewed by Stu Hood and jbellis git-svn-id: https://svn.apache.org/repos/asf/cassandra/trunk@959483 13f79535-47bb-0310-9956-ffa450edef68 --- .../dht/CollatingOrderPreservingPartitioner.java | 12 +++++++++++- .../cassandra/dht/OrderPreservingPartitioner.java | 12 +++++++++++- src/java/org/apache/cassandra/utils/FBUtilities.java | 9 +++++++++ .../org/apache/cassandra/utils/FBUtilitiesTest.java | 9 +++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/java/org/apache/cassandra/dht/CollatingOrderPreservingPartitioner.java b/src/java/org/apache/cassandra/dht/CollatingOrderPreservingPartitioner.java index 7fb9dd0f8e..76b878b4a0 100644 --- a/src/java/org/apache/cassandra/dht/CollatingOrderPreservingPartitioner.java +++ b/src/java/org/apache/cassandra/dht/CollatingOrderPreservingPartitioner.java @@ -19,6 +19,7 @@ package org.apache.cassandra.dht; import java.math.BigInteger; +import java.nio.charset.CharacterCodingException; import java.text.Collator; import java.util.Arrays; import java.util.Comparator; @@ -39,7 +40,16 @@ public class CollatingOrderPreservingPartitioner extends AbstractByteOrderedPart { if (key.length == 0) return MINIMUM; - String skey = new String(key, FBUtilities.UTF8); + + String skey; + try + { + skey = FBUtilities.decodeToUTF8(key); + } + catch (CharacterCodingException e) + { + throw new RuntimeException("The provided key was not UTF8 encoded.", e); + } return new BytesToken(collator.getCollationKey(skey).toByteArray()); } } diff --git a/src/java/org/apache/cassandra/dht/OrderPreservingPartitioner.java b/src/java/org/apache/cassandra/dht/OrderPreservingPartitioner.java index 9e1522e0d2..27aa614a9c 100644 --- a/src/java/org/apache/cassandra/dht/OrderPreservingPartitioner.java +++ b/src/java/org/apache/cassandra/dht/OrderPreservingPartitioner.java @@ -20,6 +20,7 @@ package org.apache.cassandra.dht; import java.io.UnsupportedEncodingException; import java.math.BigInteger; +import java.nio.charset.CharacterCodingException; import java.util.Arrays; import java.util.Comparator; import java.util.Random; @@ -163,6 +164,15 @@ public class OrderPreservingPartitioner implements IPartitioner public StringToken getToken(byte[] key) { - return new StringToken(new String(key, FBUtilities.UTF8)); + String skey; + try + { + skey = FBUtilities.decodeToUTF8(key); + } + catch (CharacterCodingException e) + { + throw new RuntimeException("The provided key was not UTF8 encoded.", e); + } + return new StringToken(skey); } } diff --git a/src/java/org/apache/cassandra/utils/FBUtilities.java b/src/java/org/apache/cassandra/utils/FBUtilities.java index e6fce1f017..e2ffb2fcde 100644 --- a/src/java/org/apache/cassandra/utils/FBUtilities.java +++ b/src/java/org/apache/cassandra/utils/FBUtilities.java @@ -27,7 +27,9 @@ import java.net.InetAddress; import java.net.URL; import java.net.UnknownHostException; import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; import java.security.MessageDigest; import java.util.Arrays; import java.util.Collections; @@ -37,6 +39,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import com.google.common.base.Charsets; import org.apache.commons.collections.iterators.CollatingIterator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,6 +66,7 @@ public class FBUtilities private static volatile InetAddress localInetAddress_; public static final int MAX_UNSIGNED_SHORT = 0xFFFF; + public static final CharsetDecoder utf8Decoder = Charsets.UTF_8.newDecoder(); public static Charset UTF8; static @@ -480,6 +484,11 @@ public class FBUtilities return utflen; } + public static String decodeToUTF8(byte[] bytes) throws CharacterCodingException + { + return utf8Decoder.decode(ByteBuffer.wrap(bytes)).toString(); + } + /** * Test if a particular bit is set using a bit mask. * diff --git a/test/unit/org/apache/cassandra/utils/FBUtilitiesTest.java b/test/unit/org/apache/cassandra/utils/FBUtilitiesTest.java index 216f41d244..7ad79b7012 100644 --- a/test/unit/org/apache/cassandra/utils/FBUtilitiesTest.java +++ b/test/unit/org/apache/cassandra/utils/FBUtilitiesTest.java @@ -21,6 +21,8 @@ package org.apache.cassandra.utils; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import java.io.IOException; +import java.nio.charset.CharacterCodingException; import java.util.concurrent.atomic.AtomicReference; import org.apache.cassandra.db.IClock; @@ -80,4 +82,11 @@ public class FBUtilitiesTest FBUtilities.atomicSetMax(atomicClock, new TimestampClock(3L)); assert ((TimestampClock)atomicClock.get()).timestamp() == 9L; } + + @Test(expected=CharacterCodingException.class) + public void testDecode() throws IOException + { + byte[] bytes = new byte[]{(byte)0xff, (byte)0xfe}; + FBUtilities.decodeToUTF8(bytes); + } }