From c4c71e6d289b034e6415e3b04ea8e56c0fd11b99 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Thu, 6 Feb 2014 14:59:31 -0800 Subject: [PATCH] Fix the potential copyright issue in SocksCommonUtils - Add StringUtil.toHexString() methods which are based on LoggingHandler's lookup table implementation, and use it wherever possible --- .../handler/codec/socks/SocksCommonUtils.java | 41 ++--- .../socks/SocksCmdResponseDecoderTest.java | 3 +- .../io/netty/util/internal/StringUtil.java | 159 +++++++++++++++++- .../netty/util/internal/StringUtilTest.java | 32 +++- .../netty/handler/logging/LoggingHandler.java | 20 +-- 5 files changed, 206 insertions(+), 49 deletions(-) diff --git a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCommonUtils.java b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCommonUtils.java index b16a741e8e..c762d70185 100644 --- a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCommonUtils.java +++ b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksCommonUtils.java @@ -15,6 +15,8 @@ */ package io.netty.handler.codec.socks; +import io.netty.util.internal.StringUtil; + final class SocksCommonUtils { public static final SocksRequest UNKNOWN_SOCKS_REQUEST = new UnknownSocksRequest(); public static final SocksResponse UNKNOWN_SOCKS_RESPONSE = new UnknownSocksResponse(); @@ -28,7 +30,7 @@ final class SocksCommonUtils { * A constructor to stop this class being constructed. */ private SocksCommonUtils() { - //NOOP + // NOOP } public static String intToIp(int i) { @@ -41,10 +43,10 @@ final class SocksCommonUtils { private static final char[] ipv6conseqZeroFiller = {':', ':'}; private static final char ipv6hextetSeparator = ':'; - /* - * Convert numeric IPv6 to compressed format, where - * the longest sequence of 0's (with 2 or more 0's) is replaced with "::" - */ + /** + * Convert numeric IPv6 to compressed format, where + * the longest sequence of 0's (with 2 or more 0's) is replaced with "::" + */ public static String ipv6toCompressedForm(byte[] src) { assert src.length == 16; //Find the longest sequence of 0's @@ -77,12 +79,9 @@ final class SocksCommonUtils { return sb.toString(); } - /* - * Convert numeric IPv6 to standard (non-compressed) format. - * - * Borrowed from Inet6Address.java #numericToTextFormat(byte[]) - * Changed StringBuffer -> StringBuilder and ":" -> ':' for performance. - */ + /** + * Converts numeric IPv6 to standard (non-compressed) format. + */ public static String ipv6toStr(byte[] src) { assert src.length == 16; StringBuilder sb = new StringBuilder(39); @@ -90,14 +89,18 @@ final class SocksCommonUtils { return sb.toString(); } - private static void ipv6toStr(StringBuilder sb, byte[] src, - int fromHextet, int toHextet) { - for (int i = fromHextet; i < toHextet; i++) { - sb.append(Integer.toHexString(src[i << 1] << 8 & 0xff00 - | src[(i << 1) + 1] & 0xff)); - if (i < toHextet - 1) { - sb.append(ipv6hextetSeparator); - } + private static void ipv6toStr(StringBuilder sb, byte[] src, int fromHextet, int toHextet) { + int i; + toHextet --; + for (i = fromHextet; i < toHextet; i++) { + appendHextet(sb, src, i); + sb.append(ipv6hextetSeparator); } + + appendHextet(sb, src, i); + } + + private static void appendHextet(StringBuilder sb, byte[] src, int i) { + StringUtil.toHexString(sb, src, i << 1, 2); } } diff --git a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdResponseDecoderTest.java b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdResponseDecoderTest.java index 1a98a8f765..058a06f44c 100644 --- a/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdResponseDecoderTest.java +++ b/codec-socks/src/test/java/io/netty/handler/codec/socks/SocksCmdResponseDecoderTest.java @@ -77,7 +77,8 @@ public class SocksCmdResponseDecoderTest { "testDomain.com", 80); testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, SocksAddressType.IPv6, "2001:db8:85a3:42:1000:8a2e:370:7334", 80); + testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, SocksAddressType.IPv6, + "1111:111:11:1:0:0:0:1", 80); } } - } diff --git a/common/src/main/java/io/netty/util/internal/StringUtil.java b/common/src/main/java/io/netty/util/internal/StringUtil.java index 7aabe7fdfd..69d3bfa7db 100644 --- a/common/src/main/java/io/netty/util/internal/StringUtil.java +++ b/common/src/main/java/io/netty/util/internal/StringUtil.java @@ -15,6 +15,7 @@ */ package io.netty.util.internal; +import java.io.IOException; import java.util.ArrayList; import java.util.Formatter; import java.util.List; @@ -24,13 +25,14 @@ import java.util.List; */ public final class StringUtil { - private StringUtil() { - // Unused. - } - public static final String NEWLINE; + private static final String[] BYTE2HEX_PAD = new String[256]; + private static final String[] BYTE2HEX_NOPAD = new String[256]; + private static final String EMPTY_STRING = ""; + static { + // Determine the newline character of the current platform. String newLine; try { @@ -41,9 +43,32 @@ public final class StringUtil { } NEWLINE = newLine; - } - private static final String EMPTY_STRING = ""; + // Generate the lookup table that converts a byte into a 2-digit hexadecimal integer. + int i; + for (i = 0; i < 10; i ++) { + StringBuilder buf = new StringBuilder(2); + buf.append('0'); + buf.append(i); + BYTE2HEX_PAD[i] = buf.toString(); + BYTE2HEX_NOPAD[i] = String.valueOf(i); + } + for (; i < 16; i ++) { + StringBuilder buf = new StringBuilder(2); + char c = (char) ('a' + i - 10); + buf.append('0'); + buf.append(c); + BYTE2HEX_PAD[i] = buf.toString(); + BYTE2HEX_NOPAD[i] = String.valueOf(c); + } + for (; i < BYTE2HEX_PAD.length; i ++) { + StringBuilder buf = new StringBuilder(2); + buf.append(Integer.toHexString(i)); + String str = buf.toString(); + BYTE2HEX_PAD[i] = str; + BYTE2HEX_NOPAD[i] = str; + } + } /** * Splits the specified {@link String} with the specified delimiter. This operation is a simplified and optimized @@ -86,6 +111,124 @@ public final class StringUtil { return res.toArray(new String[res.size()]); } + /** + * Converts the specified byte value into a 2-digit hexadecimal integer. + */ + public static String byteToHexStringPadded(int value) { + return BYTE2HEX_PAD[value & 0xff]; + } + + /** + * Converts the specified byte value into a 2-digit hexadecimal integer and appends it to the specified buffer. + */ + public static T byteToHexStringPadded(T buf, int value) { + try { + buf.append(byteToHexStringPadded(value)); + } catch (IOException e) { + PlatformDependent.throwException(e); + } + return buf; + } + + /** + * Converts the specified byte array into a hexadecimal value. + */ + public static String toHexStringPadded(byte[] src) { + return toHexStringPadded(src, 0, src.length); + } + + /** + * Converts the specified byte array into a hexadecimal value. + */ + public static String toHexStringPadded(byte[] src, int offset, int length) { + return toHexStringPadded(new StringBuilder(length << 1), src, offset, length).toString(); + } + + /** + * Converts the specified byte array into a hexadecimal value and appends it to the specified buffer. + */ + public static T toHexStringPadded(T dst, byte[] src) { + return toHexStringPadded(dst, src, 0, src.length); + } + + /** + * Converts the specified byte array into a hexadecimal value and appends it to the specified buffer. + */ + public static T toHexStringPadded(T dst, byte[] src, int offset, int length) { + final int end = offset + length; + for (int i = offset; i < end; i ++) { + byteToHexStringPadded(dst, src[i]); + } + return dst; + } + + /** + * Converts the specified byte value into a hexadecimal integer. + */ + public static String byteToHexString(int value) { + return BYTE2HEX_NOPAD[value & 0xff]; + } + + /** + * Converts the specified byte value into a hexadecimal integer and appends it to the specified buffer. + */ + public static T byteToHexString(T buf, int value) { + try { + buf.append(byteToHexString(value)); + } catch (IOException e) { + PlatformDependent.throwException(e); + } + return buf; + } + + /** + * Converts the specified byte array into a hexadecimal value. + */ + public static String toHexString(byte[] src) { + return toHexString(src, 0, src.length); + } + + /** + * Converts the specified byte array into a hexadecimal value. + */ + public static String toHexString(byte[] src, int offset, int length) { + return toHexString(new StringBuilder(length << 1), src, offset, length).toString(); + } + + /** + * Converts the specified byte array into a hexadecimal value and appends it to the specified buffer. + */ + public static T toHexString(T dst, byte[] src) { + return toHexString(dst, src, 0, src.length); + } + + /** + * Converts the specified byte array into a hexadecimal value and appends it to the specified buffer. + */ + public static T toHexString(T dst, byte[] src, int offset, int length) { + assert length >= 0; + if (length == 0) { + return dst; + } + + final int end = offset + length; + final int endMinusOne = end - 1; + int i; + + // Skip preceding zeroes. + for (i = offset; i < endMinusOne; i ++) { + if (src[i] != 0) { + break; + } + } + + byteToHexString(dst, src[i ++]); + int remaining = end - i; + toHexStringPadded(dst, src, i, remaining); + + return dst; + } + /** * The shortcut to {@link #simpleClassName(Class) simpleClassName(o.getClass())}. */ @@ -113,4 +256,8 @@ public final class StringUtil { return clazz.getName(); } } + + private StringUtil() { + // Unused. + } } diff --git a/common/src/test/java/io/netty/util/internal/StringUtilTest.java b/common/src/test/java/io/netty/util/internal/StringUtilTest.java index 24ba3814c0..5f59849a9e 100644 --- a/common/src/test/java/io/netty/util/internal/StringUtilTest.java +++ b/common/src/test/java/io/netty/util/internal/StringUtilTest.java @@ -17,37 +17,57 @@ package io.netty.util.internal; import org.junit.Test; +import static io.netty.util.internal.StringUtil.*; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; public class StringUtilTest { @Test public void ensureNewlineExists() { - assertNotNull(StringUtil.NEWLINE); + assertNotNull(NEWLINE); + } + + @Test + public void testToHexString() { + assertThat(toHexString(new byte[] { 0 }), is("0")); + assertThat(toHexString(new byte[] { 1 }), is("1")); + assertThat(toHexString(new byte[] { 0, 0 }), is("0")); + assertThat(toHexString(new byte[] { 1, 0 }), is("100")); + assertThat(toHexString(EmptyArrays.EMPTY_BYTES), is("")); + } + + @Test + public void testToHexStringPadded() { + assertThat(toHexStringPadded(new byte[]{0}), is("00")); + assertThat(toHexStringPadded(new byte[]{1}), is("01")); + assertThat(toHexStringPadded(new byte[]{0, 0}), is("0000")); + assertThat(toHexStringPadded(new byte[]{1, 0}), is("0100")); + assertThat(toHexStringPadded(EmptyArrays.EMPTY_BYTES), is("")); } @Test public void splitSimple() { - assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo:bar", ':')); + assertArrayEquals(new String[] { "foo", "bar" }, split("foo:bar", ':')); } @Test public void splitWithTrailingDelimiter() { - assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo,bar,", ',')); + assertArrayEquals(new String[] { "foo", "bar" }, split("foo,bar,", ',')); } @Test public void splitWithTrailingDelimiters() { - assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo!bar!!", '!')); + assertArrayEquals(new String[] { "foo", "bar" }, split("foo!bar!!", '!')); } @Test public void splitWithConsecutiveDelimiters() { - assertArrayEquals(new String[] { "foo", "", "bar" }, StringUtil.split("foo$$bar", '$')); + assertArrayEquals(new String[] { "foo", "", "bar" }, split("foo$$bar", '$')); } @Test public void splitWithDelimiterAtBeginning() { - assertArrayEquals(new String[] { "", "foo", "bar" }, StringUtil.split("#foo#bar", '#')); + assertArrayEquals(new String[] { "", "foo", "bar" }, split("#foo#bar", '#')); } } diff --git a/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java b/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java index 154f1074b1..c35aa8ae33 100644 --- a/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java +++ b/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java @@ -22,6 +22,7 @@ import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; +import io.netty.util.internal.StringUtil; import io.netty.util.internal.logging.InternalLogLevel; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -48,23 +49,8 @@ public class LoggingHandler extends ChannelDuplexHandler { int i; // Generate the lookup table for byte-to-hex-dump conversion - for (i = 0; i < 10; i ++) { - StringBuilder buf = new StringBuilder(3); - buf.append(" 0"); - buf.append(i); - BYTE2HEX[i] = buf.toString(); - } - for (; i < 16; i ++) { - StringBuilder buf = new StringBuilder(3); - buf.append(" 0"); - buf.append((char) ('a' + i - 10)); - BYTE2HEX[i] = buf.toString(); - } - for (; i < BYTE2HEX.length; i ++) { - StringBuilder buf = new StringBuilder(3); - buf.append(' '); - buf.append(Integer.toHexString(i)); - BYTE2HEX[i] = buf.toString(); + for (i = 0; i < BYTE2HEX.length; i ++) { + BYTE2HEX[i] = ' ' + StringUtil.byteToHexStringPadded(i); } // Generate the lookup table for hex dump paddings