Browse Source

Merge pull request #206 from alim-akbashev/issue-205

fix unescaped \n, " etc in json inside packet + minor optimization
master
Nikita Koksharov 11 years ago
parent
commit
2b0001e8e0
  1. 5
      src/main/java/com/corundumstudio/socketio/JsonSupportWrapper.java
  2. 2
      src/main/java/com/corundumstudio/socketio/handler/EncoderHandler.java
  3. 40
      src/main/java/com/corundumstudio/socketio/protocol/JacksonJsonSupport.java
  4. 2
      src/main/java/com/corundumstudio/socketio/protocol/JsonSupport.java
  5. 40
      src/main/java/com/corundumstudio/socketio/protocol/PacketEncoder.java

5
src/main/java/com/corundumstudio/socketio/JsonSupportWrapper.java

@ -73,11 +73,6 @@ class JsonSupportWrapper implements JsonSupport {
delegate.removeEventMapping(namespaceName, eventName); delegate.removeEventMapping(namespaceName, eventName);
} }
@Override
public void writeJsonpValue(ByteBufOutputStream out, Object value) throws IOException {
delegate.writeJsonpValue(out, value);
}
@Override @Override
public List<byte[]> getArrays() { public List<byte[]> getArrays() {
return delegate.getArrays(); return delegate.getArrays();

2
src/main/java/com/corundumstudio/socketio/handler/EncoderHandler.java

@ -212,7 +212,7 @@ public class EncoderHandler extends ChannelOutboundHandlerAdapter {
} }
final ByteBuf out = encoder.allocateBuffer(ctx.alloc()); final ByteBuf out = encoder.allocateBuffer(ctx.alloc());
encoder.encodePacket(packet, out, ctx.alloc(), true, false);
encoder.encodePacket(packet, out, ctx.alloc(), true);
WebSocketFrame res = new TextWebSocketFrame(out); WebSocketFrame res = new TextWebSocketFrame(out);
if (log.isTraceEnabled()) { if (log.isTraceEnabled()) {

40
src/main/java/com/corundumstudio/socketio/protocol/JacksonJsonSupport.java

@ -69,36 +69,6 @@ import com.fasterxml.jackson.databind.type.ArrayType;
public class JacksonJsonSupport implements JsonSupport { public class JacksonJsonSupport implements JsonSupport {
public static class HTMLCharacterEscapes extends CharacterEscapes
{
private static final long serialVersionUID = 6159367941232231133L;
private final int[] asciiEscapes;
public HTMLCharacterEscapes()
{
// start with set of characters known to require escaping (double-quote, backslash etc)
int[] esc = CharacterEscapes.standardAsciiEscapesForJSON();
// and force escaping of a few others:
esc['"'] = CharacterEscapes.ESCAPE_CUSTOM;
asciiEscapes = esc;
}
// this method gets called for character codes 0 - 127
@Override
public int[] getEscapeCodesForAscii() {
return asciiEscapes;
}
@Override
public SerializableString getEscapeSequence(int ch) {
if (ch == '"') {
return new SerializedString("\\\\" + (char)ch);
}
return null;
}
}
private class AckArgsDeserializer extends StdDeserializer<AckArgs> { private class AckArgsDeserializer extends StdDeserializer<AckArgs> {
private static final long serialVersionUID = 7810461017389946707L; private static final long serialVersionUID = 7810461017389946707L;
@ -325,7 +295,6 @@ public class JacksonJsonSupport implements JsonSupport {
private final ThreadLocal<String> namespaceClass = new ThreadLocal<String>(); private final ThreadLocal<String> namespaceClass = new ThreadLocal<String>();
private final ThreadLocal<AckCallback<?>> currentAckClass = new ThreadLocal<AckCallback<?>>(); private final ThreadLocal<AckCallback<?>> currentAckClass = new ThreadLocal<AckCallback<?>>();
private final ObjectMapper objectMapper = new ObjectMapper(); private final ObjectMapper objectMapper = new ObjectMapper();
private final ObjectMapper jsonpObjectMapper = new ObjectMapper();
private final EventDeserializer eventDeserializer = new EventDeserializer(); private final EventDeserializer eventDeserializer = new EventDeserializer();
private final AckArgsDeserializer ackArgsDeserializer = new AckArgsDeserializer(); private final AckArgsDeserializer ackArgsDeserializer = new AckArgsDeserializer();
@ -334,11 +303,8 @@ public class JacksonJsonSupport implements JsonSupport {
public JacksonJsonSupport(Module... modules) { public JacksonJsonSupport(Module... modules) {
if (modules != null && modules.length > 0) { if (modules != null && modules.length > 0) {
objectMapper.registerModules(modules); objectMapper.registerModules(modules);
jsonpObjectMapper.registerModules(modules);
} }
init(objectMapper); init(objectMapper);
init(jsonpObjectMapper);
jsonpObjectMapper.getFactory().setCharacterEscapes(new HTMLCharacterEscapes());
} }
protected void init(ObjectMapper objectMapper) { protected void init(ObjectMapper objectMapper) {
@ -382,12 +348,6 @@ public class JacksonJsonSupport implements JsonSupport {
objectMapper.writeValue(out, value); objectMapper.writeValue(out, value);
} }
@Override
public void writeJsonpValue(ByteBufOutputStream out, Object value) throws IOException {
modifier.getSerializer().clear();
jsonpObjectMapper.writeValue(out, value);
}
@Override @Override
public List<byte[]> getArrays() { public List<byte[]> getArrays() {
return modifier.getSerializer().getArrays(); return modifier.getSerializer().getArrays();

2
src/main/java/com/corundumstudio/socketio/protocol/JsonSupport.java

@ -31,8 +31,6 @@ import com.corundumstudio.socketio.AckCallback;
*/ */
public interface JsonSupport { public interface JsonSupport {
void writeJsonpValue(ByteBufOutputStream out, Object value) throws IOException;
AckArgs readAckArgs(ByteBufInputStream src, AckCallback<?> callback) throws IOException; AckArgs readAckArgs(ByteBufInputStream src, AckCallback<?> callback) throws IOException;
<T> T readValue(String namespaceName, ByteBufInputStream src, Class<T> valueType) throws IOException; <T> T readValue(String namespaceName, ByteBufInputStream src, Class<T> valueType) throws IOException;

40
src/main/java/com/corundumstudio/socketio/protocol/PacketEncoder.java

@ -33,12 +33,11 @@ import com.corundumstudio.socketio.Configuration;
public class PacketEncoder { public class PacketEncoder {
private static final Pattern QUOTES_PATTERN = Pattern.compile("\"", Pattern.LITERAL);
private static final byte[] BINARY_HEADER = "b4".getBytes(CharsetUtil.UTF_8); private static final byte[] BINARY_HEADER = "b4".getBytes(CharsetUtil.UTF_8);
private static final byte[] B64_DELIMITER = new byte[] {':'}; private static final byte[] B64_DELIMITER = new byte[] {':'};
private static final byte[] JSONP_HEAD = "___eio[".getBytes(CharsetUtil.UTF_8); private static final byte[] JSONP_HEAD = "___eio[".getBytes(CharsetUtil.UTF_8);
private static final byte[] JSONP_START = "](\"".getBytes(CharsetUtil.UTF_8);
private static final byte[] JSONP_END = "\");".getBytes(CharsetUtil.UTF_8);
private static final byte[] JSONP_START = "]('".getBytes(CharsetUtil.UTF_8);
private static final byte[] JSONP_END = "');".getBytes(CharsetUtil.UTF_8);
private final JsonSupport jsonSupport; private final JsonSupport jsonSupport;
private final Configuration configuration; private final Configuration configuration;
@ -72,14 +71,9 @@ public class PacketEncoder {
} }
ByteBuf packetBuf = allocateBuffer(allocator); ByteBuf packetBuf = allocateBuffer(allocator);
encodePacket(packet, packetBuf, allocator, true, jsonpMode);
encodePacket(packet, packetBuf, allocator, true);
int packetSize = packetBuf.writerIndex(); int packetSize = packetBuf.writerIndex();
if (jsonpMode) {
// scan for \\\"
int count = count(packetBuf, Unpooled.copiedBuffer("\\\"", CharsetUtil.UTF_8));
packetSize -= count;
}
buf.writeBytes(toChars(packetSize)); buf.writeBytes(toChars(packetSize));
buf.writeBytes(B64_DELIMITER); buf.writeBytes(B64_DELIMITER);
@ -106,7 +100,7 @@ public class PacketEncoder {
String packet = buf.toString(CharsetUtil.UTF_8); String packet = buf.toString(CharsetUtil.UTF_8);
buf.release(); buf.release();
// TODO optimize // TODO optimize
packet = QUOTES_PATTERN.matcher(packet).replaceAll("\\\\\"");
packet = packet.replace("\\", "\\\\").replace("'", "\\'");
packet = new String(packet.getBytes(CharsetUtil.UTF_8), CharsetUtil.ISO_8859_1); packet = new String(packet.getBytes(CharsetUtil.UTF_8), CharsetUtil.ISO_8859_1);
out.writeBytes(packet.getBytes(CharsetUtil.UTF_8)); out.writeBytes(packet.getBytes(CharsetUtil.UTF_8));
@ -121,7 +115,7 @@ public class PacketEncoder {
if (packet == null || i == limit) { if (packet == null || i == limit) {
break; break;
} }
encodePacket(packet, buffer, allocator, false, false);
encodePacket(packet, buffer, allocator, false);
i++; i++;
@ -221,7 +215,7 @@ public class PacketEncoder {
return res; return res;
} }
public void encodePacket(Packet packet, ByteBuf buffer, ByteBufAllocator allocator, boolean binary, boolean jsonp) throws IOException {
public void encodePacket(Packet packet, ByteBuf buffer, ByteBufAllocator allocator, boolean binary) throws IOException {
ByteBuf buf = buffer; ByteBuf buf = buffer;
if (!binary) { if (!binary) {
buf = allocateBuffer(allocator); buf = allocateBuffer(allocator);
@ -239,11 +233,7 @@ public class PacketEncoder {
case OPEN: { case OPEN: {
ByteBufOutputStream out = new ByteBufOutputStream(buf); ByteBufOutputStream out = new ByteBufOutputStream(buf);
if (jsonp) {
jsonSupport.writeJsonpValue(out, packet.getData());
} else {
jsonSupport.writeValue(out, packet.getData());
}
jsonSupport.writeValue(out, packet.getData());
break; break;
} }
@ -267,11 +257,7 @@ public class PacketEncoder {
List<Object> args = packet.getData(); List<Object> args = packet.getData();
values.addAll(args); values.addAll(args);
ByteBufOutputStream out = new ByteBufOutputStream(encBuf); ByteBufOutputStream out = new ByteBufOutputStream(encBuf);
if (jsonp) {
jsonSupport.writeJsonpValue(out, values);
} else {
jsonSupport.writeValue(out, values);
}
jsonSupport.writeValue(out, values);
if (!jsonSupport.getArrays().isEmpty()) { if (!jsonSupport.getArrays().isEmpty()) {
packet.initAttachments(jsonSupport.getArrays().size()); packet.initAttachments(jsonSupport.getArrays().size());
@ -329,16 +315,6 @@ public class PacketEncoder {
} }
} }
private int count(ByteBuf buffer, ByteBuf searchValue) {
int count = 0;
for (int i = 0; i < buffer.readableBytes(); i++) {
if (isValueFound(buffer, i, searchValue)) {
count++;
}
}
return count;
}
public static int find(ByteBuf buffer, ByteBuf searchValue) { public static int find(ByteBuf buffer, ByteBuf searchValue) {
for (int i = buffer.readerIndex(); i < buffer.readerIndex() + buffer.readableBytes(); i++) { for (int i = buffer.readerIndex(); i < buffer.readerIndex() + buffer.readableBytes(); i++) {
if (isValueFound(buffer, i, searchValue)) { if (isValueFound(buffer, i, searchValue)) {

Loading…
Cancel
Save