handle utf8 decode errors

This commit is contained in:
Naoyuki Kanezawa
2014-06-30 10:09:41 +09:00
parent 3e64ad64f9
commit b1e43ba1b2
5 changed files with 65 additions and 16 deletions

View File

@@ -2,6 +2,7 @@ package com.github.nkzawa.engineio.parser;
import com.github.nkzawa.utf8.UTF8; import com.github.nkzawa.utf8.UTF8;
import com.github.nkzawa.utf8.UTF8Exception;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@@ -73,7 +74,11 @@ public class Parser {
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
type = -1; type = -1;
} }
try {
data = UTF8.decode(data); data = UTF8.decode(data);
} catch (UTF8Exception e) {
return err;
}
if (type < 0 || type >= packetslist.size()) { if (type < 0 || type >= packetslist.size()) {
return err; return err;
@@ -164,7 +169,6 @@ public class Parser {
if (msg.length() != 0) { if (msg.length() != 0) {
Packet<String> packet = decodePacket(msg); Packet<String> packet = decodePacket(msg);
if (err.type.equals(packet.type) && err.data.equals(packet.data)) { if (err.type.equals(packet.type) && err.data.equals(packet.data)) {
callback.call(err, 0, 1); callback.call(err, 0, 1);
return; return;

View File

@@ -27,7 +27,7 @@ public class UTF8 {
return byteString.toString(); return byteString.toString();
} }
public static String decode(String byteString) { public static String decode(String byteString) throws UTF8Exception {
byteArray = uc2decode(byteString); byteArray = uc2decode(byteString);
byteCount = byteArray.length; byteCount = byteArray.length;
byteIndex = 0; byteIndex = 0;
@@ -74,7 +74,7 @@ public class UTF8 {
return Character.toChars(((codePoint >> shift) & 0x3F) | 0x80); return Character.toChars(((codePoint >> shift) & 0x3F) | 0x80);
} }
private static int decodeSymbol() { private static int decodeSymbol() throws UTF8Exception {
int byte1; int byte1;
int byte2; int byte2;
int byte3; int byte3;
@@ -82,7 +82,7 @@ public class UTF8 {
int codePoint; int codePoint;
if (byteIndex > byteCount) { if (byteIndex > byteCount) {
throw new RuntimeException("Invalid byte index"); throw new UTF8Exception("Invalid byte index");
} }
if (byteIndex == byteCount) { if (byteIndex == byteCount) {
@@ -102,7 +102,7 @@ public class UTF8 {
if (codePoint >= 0x80) { if (codePoint >= 0x80) {
return codePoint; return codePoint;
} else { } else {
throw new RuntimeException("Invalid continuation byte"); throw new UTF8Exception("Invalid continuation byte");
} }
} }
@@ -113,7 +113,7 @@ public class UTF8 {
if (codePoint >= 0x0800) { if (codePoint >= 0x0800) {
return codePoint; return codePoint;
} else { } else {
throw new RuntimeException("Invalid continuation byte"); throw new UTF8Exception("Invalid continuation byte");
} }
} }
@@ -127,12 +127,12 @@ public class UTF8 {
} }
} }
throw new RuntimeException("Invalid continuation byte"); throw new UTF8Exception("Invalid continuation byte");
} }
private static int readContinuationByte() { private static int readContinuationByte() throws UTF8Exception {
if (byteIndex >= byteCount) { if (byteIndex >= byteCount) {
throw new RuntimeException("Invalid byte index"); throw new UTF8Exception("Invalid byte index");
} }
int continuationByte = byteArray[byteIndex] & 0xFF; int continuationByte = byteArray[byteIndex] & 0xFF;
@@ -142,7 +142,7 @@ public class UTF8 {
return continuationByte & 0x3F; return continuationByte & 0x3F;
} }
throw new RuntimeException("Invalid continuation byte"); throw new UTF8Exception("Invalid continuation byte");
} }
private static String ucs2encode(int[] array) { private static String ucs2encode(int[] array) {

View File

@@ -0,0 +1,24 @@
package com.github.nkzawa.utf8;
import java.io.IOException;
public class UTF8Exception extends IOException {
public String data;
public UTF8Exception() {
super();
}
public UTF8Exception(String message) {
super(message);
}
public UTF8Exception(String message, Throwable cause) {
super(message, cause);
}
public UTF8Exception(Throwable cause) {
super(cause);
}
}

View File

@@ -169,6 +169,13 @@ public class ParserTest {
assertThat(p.data, is(ERROR_DATA)); assertThat(p.data, is(ERROR_DATA));
} }
@Test
public void decodeInvalidUTF8() {
Packet<String> p = decodePacket("4\uffff");
assertThat(p.type, is(Packet.ERROR));
assertThat(p.data, is(ERROR_DATA));
}
@Test @Test
public void encodePayloads() { public void encodePayloads() {
encodePayload(new Packet[]{new Packet(Packet.PING), new Packet(Packet.PONG)}, new EncodeCallback<byte[]>() { encodePayload(new Packet[]{new Packet(Packet.PING), new Packet(Packet.PONG)}, new EncodeCallback<byte[]>() {
@@ -313,6 +320,20 @@ public class ParserTest {
}); });
} }
@Test
public void decodePayloadInvalidUTF8() {
decodePayload("2:4\uffff", new DecodePayloadCallback<String>() {
@Override
public boolean call(Packet<String> packet, int index, int total) {
boolean isLast = index + 1 == total;
assertThat(packet.type, is(Packet.ERROR));
assertThat(packet.data, is(ERROR_DATA));
assertThat(isLast, is(true));
return true;
}
});
}
@Test @Test
public void encodeBinaryMessage() { public void encodeBinaryMessage() {
final byte[] data = new byte[5]; final byte[] data = new byte[5];

View File

@@ -55,23 +55,23 @@ public class UTF8Test {
public ExpectedException exception = ExpectedException.none(); public ExpectedException exception = ExpectedException.none();
@Test @Test
public void encodeAndDecode() { public void encodeAndDecode() throws UTF8Exception {
for (Data data : DATA) { for (Data data : DATA) {
String reason = data.description != null? data.description : "U+" + Integer.toHexString(data.codePoint).toUpperCase(); String reason = data.description != null? data.description : "U+" + Integer.toHexString(data.codePoint).toUpperCase();
assertThat("Encoding: " + reason, data.encoded, is(UTF8.encode(data.decoded))); assertThat("Encoding: " + reason, data.encoded, is(UTF8.encode(data.decoded)));
assertThat("Decoding: " + reason, data.decoded, is(UTF8.decode(data.encoded))); assertThat("Decoding: " + reason, data.decoded, is(UTF8.decode(data.encoded)));
} }
exception.expect(RuntimeException.class); exception.expect(UTF8Exception.class);
UTF8.decode("\uFFFF"); UTF8.decode("\uFFFF");
exception.expect(RuntimeException.class); exception.expect(UTF8Exception.class);
UTF8.decode("\u00E9\u0000\u0000"); UTF8.decode("\u00E9\u0000\u0000");
exception.expect(RuntimeException.class); exception.expect(UTF8Exception.class);
UTF8.decode("\u00C2\uFFFF"); UTF8.decode("\u00C2\uFFFF");
exception.expect(RuntimeException.class); exception.expect(UTF8Exception.class);
UTF8.decode("\u00F0\u009D"); UTF8.decode("\u00F0\u009D");
} }