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
This commit is contained in:
Trustin Lee 2014-02-06 14:59:31 -08:00
parent 7a1a30f0ad
commit 4a86446053
5 changed files with 206 additions and 49 deletions

View File

@ -15,6 +15,8 @@
*/ */
package io.netty.handler.codec.socks; package io.netty.handler.codec.socks;
import io.netty.util.internal.StringUtil;
final class SocksCommonUtils { final class SocksCommonUtils {
public static final SocksRequest UNKNOWN_SOCKS_REQUEST = new UnknownSocksRequest(); public static final SocksRequest UNKNOWN_SOCKS_REQUEST = new UnknownSocksRequest();
public static final SocksResponse UNKNOWN_SOCKS_RESPONSE = new UnknownSocksResponse(); public static final SocksResponse UNKNOWN_SOCKS_RESPONSE = new UnknownSocksResponse();
@ -28,7 +30,7 @@ final class SocksCommonUtils {
* A constructor to stop this class being constructed. * A constructor to stop this class being constructed.
*/ */
private SocksCommonUtils() { private SocksCommonUtils() {
//NOOP // NOOP
} }
public static String intToIp(int i) { public static String intToIp(int i) {
@ -41,7 +43,7 @@ final class SocksCommonUtils {
private static final char[] ipv6conseqZeroFiller = {':', ':'}; private static final char[] ipv6conseqZeroFiller = {':', ':'};
private static final char ipv6hextetSeparator = ':'; private static final char ipv6hextetSeparator = ':';
/* /**
* Convert numeric IPv6 to compressed format, where * Convert numeric IPv6 to compressed format, where
* the longest sequence of 0's (with 2 or more 0's) is replaced with "::" * the longest sequence of 0's (with 2 or more 0's) is replaced with "::"
*/ */
@ -77,11 +79,8 @@ final class SocksCommonUtils {
return sb.toString(); return sb.toString();
} }
/* /**
* Convert numeric IPv6 to standard (non-compressed) format. * Converts numeric IPv6 to standard (non-compressed) format.
*
* Borrowed from Inet6Address.java #numericToTextFormat(byte[])
* Changed StringBuffer -> StringBuilder and ":" -> ':' for performance.
*/ */
public static String ipv6toStr(byte[] src) { public static String ipv6toStr(byte[] src) {
assert src.length == 16; assert src.length == 16;
@ -90,14 +89,18 @@ final class SocksCommonUtils {
return sb.toString(); return sb.toString();
} }
private static void ipv6toStr(StringBuilder sb, byte[] src, private static void ipv6toStr(StringBuilder sb, byte[] src, int fromHextet, int toHextet) {
int fromHextet, int toHextet) { int i;
for (int i = fromHextet; i < toHextet; i++) { toHextet --;
sb.append(Integer.toHexString(src[i << 1] << 8 & 0xff00 for (i = fromHextet; i < toHextet; i++) {
| src[(i << 1) + 1] & 0xff)); appendHextet(sb, src, i);
if (i < toHextet - 1) {
sb.append(ipv6hextetSeparator); sb.append(ipv6hextetSeparator);
} }
appendHextet(sb, src, i);
} }
private static void appendHextet(StringBuilder sb, byte[] src, int i) {
StringUtil.toHexString(sb, src, i << 1, 2);
} }
} }

View File

@ -77,7 +77,8 @@ public class SocksCmdResponseDecoderTest {
"testDomain.com", 80); "testDomain.com", 80);
testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, SocksAddressType.IPv6, testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, SocksAddressType.IPv6,
"2001:db8:85a3:42:1000:8a2e:370:7334", 80); "2001:db8:85a3:42:1000:8a2e:370:7334", 80);
testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, SocksAddressType.IPv6,
"1111:111:11:1:0:0:0:1", 80);
} }
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.util.internal; package io.netty.util.internal;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Formatter; import java.util.Formatter;
import java.util.List; import java.util.List;
@ -24,13 +25,14 @@ import java.util.List;
*/ */
public final class StringUtil { public final class StringUtil {
private StringUtil() {
// Unused.
}
public static final String NEWLINE; 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 { static {
// Determine the newline character of the current platform.
String newLine; String newLine;
try { try {
@ -41,9 +43,32 @@ public final class StringUtil {
} }
NEWLINE = newLine; 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 * 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()]); 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 extends Appendable> 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 extends Appendable> 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 extends Appendable> 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 extends Appendable> 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 extends Appendable> 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 extends Appendable> 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())}. * The shortcut to {@link #simpleClassName(Class) simpleClassName(o.getClass())}.
*/ */
@ -113,4 +256,8 @@ public final class StringUtil {
return clazz.getName(); return clazz.getName();
} }
} }
private StringUtil() {
// Unused.
}
} }

View File

@ -17,37 +17,57 @@ package io.netty.util.internal;
import org.junit.Test; import org.junit.Test;
import static io.netty.util.internal.StringUtil.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class StringUtilTest { public class StringUtilTest {
@Test @Test
public void ensureNewlineExists() { 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 @Test
public void splitSimple() { public void splitSimple() {
assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo:bar", ':')); assertArrayEquals(new String[] { "foo", "bar" }, split("foo:bar", ':'));
} }
@Test @Test
public void splitWithTrailingDelimiter() { public void splitWithTrailingDelimiter() {
assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo,bar,", ',')); assertArrayEquals(new String[] { "foo", "bar" }, split("foo,bar,", ','));
} }
@Test @Test
public void splitWithTrailingDelimiters() { public void splitWithTrailingDelimiters() {
assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo!bar!!", '!')); assertArrayEquals(new String[] { "foo", "bar" }, split("foo!bar!!", '!'));
} }
@Test @Test
public void splitWithConsecutiveDelimiters() { public void splitWithConsecutiveDelimiters() {
assertArrayEquals(new String[] { "foo", "", "bar" }, StringUtil.split("foo$$bar", '$')); assertArrayEquals(new String[] { "foo", "", "bar" }, split("foo$$bar", '$'));
} }
@Test @Test
public void splitWithDelimiterAtBeginning() { public void splitWithDelimiterAtBeginning() {
assertArrayEquals(new String[] { "", "foo", "bar" }, StringUtil.split("#foo#bar", '#')); assertArrayEquals(new String[] { "", "foo", "bar" }, split("#foo#bar", '#'));
} }
} }

View File

@ -22,6 +22,7 @@ import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.logging.InternalLogLevel; import io.netty.util.internal.logging.InternalLogLevel;
import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
@ -50,23 +51,8 @@ public class LoggingHandler extends ChannelHandlerAdapter {
int i; int i;
// Generate the lookup table for byte-to-hex-dump conversion // Generate the lookup table for byte-to-hex-dump conversion
for (i = 0; i < 10; i ++) { for (i = 0; i < BYTE2HEX.length; i ++) {
StringBuilder buf = new StringBuilder(3); BYTE2HEX[i] = ' ' + StringUtil.byteToHexStringPadded(i);
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();
} }
// Generate the lookup table for hex dump paddings // Generate the lookup table for hex dump paddings