Details
-
Type:
Bug
-
Status:
Open
-
Priority:
Default
-
Resolution: Unresolved
-
Affects Version/s: 1.4.0
-
Fix Version/s: None
-
Component/s: Engine
-
Labels:None
Description
When BeginString=FIXT.1.1 messages can be skipped if the buffer ends before the last '=' of "8=FIXT.1.1\0019=". That will happen if the buffer contains a correct message before that.
Example:
in messages:
8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\0018=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\001
the second message will fail to be decoded if the buffer contents presented to the FixMessageDecoder in two subsequent decode() invocations are:
"8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\0018=FIXT.1.1\0019"
and
"=12\00135=X\001108=30\00110=036\001"
I have created tests to replicate this issue (and also issue QFJ-505) and included fixes (for this and the fix proposed in QFJ-505).
Here is the diff:
Index: core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java
===================================================================
--- core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java (revision 46)
+++ core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java (revision 49)
@@ -348,7 +348,22 @@
@Test
public void testMinaDemux() throws Exception {
- DemuxingProtocolCodecFactory codecFactory = new DemuxingProtocolCodecFactory();
+ String message = "8=FIX.4.2\0019=12\00135=X\001108=30\00110=036\001";
+
+ doTestMinaDemux(message);
+
+ }
+
+ @Test
+ public void testMinaDemuxFixt() throws Exception {
+ String message = "8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\001";
+
+ doTestMinaDemux(message);
+
+ }
+
+ private void doTestMinaDemux(String message) throws Exception, UnsupportedEncodingException {
+ DemuxingProtocolCodecFactory codecFactory = new DemuxingProtocolCodecFactory();
codecFactory.register(FIXMessageDecoder.class);
ProtocolDecoder decoder = codecFactory.getDecoder();
@@ -359,7 +374,7 @@
int count = 5;
String data = "";
for (int i = 0; i < count; i++) {
- data += "8=FIX.4.2\0019=12\00135=X\001108=30\00110=036\001";
+ data += message;
}
for (int i = 1; i < data.length(); i++) {
@@ -379,9 +394,8 @@
output.reset();
buffer.clear();
}
-
- }
-
+ }
+
private void assertMessageFound(String data) throws ProtocolCodecException {
assertMessageFound(data, 1);
}
Index: core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java
===================================================================
--- core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java (revision 46)
+++ core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java (revision 49)
@@ -123,7 +123,7 @@
}
if (messageCount > 0) {
// Mina will compact the buffer because we can't detect a header
- if (in.remaining() < minMaskLength(HEADER_PATTERN)) {
+ if (state == SEEKING_HEADER) {
position = 0;
}
return MessageDecoderResult.OK;
@@ -297,7 +297,8 @@
}
private static BufPos indexOf(ByteBuffer buffer, int position, byte[] data) {
- for (int offset = position, limit = buffer.limit() - minMaskLength(data) + 1; offset < limit; offset++) {
+ int limit = buffer.limit() - minMaskLength(data) + 1;
+ for (int offset = position ; offset < limit; offset++) {
int length;
if (buffer.get(offset) == data[0] && (length = startsWith(buffer, offset, data)) > 0) {
return new BufPos(offset, length);
@@ -337,6 +338,10 @@
return -1;
}
}
+ if(dataOffset != data.length){
+ // when minMaskLength(data) != data.length we might run out of buffer before we run out of data
+ return -1;
+ }
return bufferOffset - initOffset;
}
Example:
in messages:
8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\0018=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\001
the second message will fail to be decoded if the buffer contents presented to the FixMessageDecoder in two subsequent decode() invocations are:
"8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\0018=FIXT.1.1\0019"
and
"=12\00135=X\001108=30\00110=036\001"
I have created tests to replicate this issue (and also issue QFJ-505) and included fixes (for this and the fix proposed in QFJ-505).
Here is the diff:
Index: core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java
===================================================================
--- core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java (revision 46)
+++ core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java (revision 49)
@@ -348,7 +348,22 @@
@Test
public void testMinaDemux() throws Exception {
- DemuxingProtocolCodecFactory codecFactory = new DemuxingProtocolCodecFactory();
+ String message = "8=FIX.4.2\0019=12\00135=X\001108=30\00110=036\001";
+
+ doTestMinaDemux(message);
+
+ }
+
+ @Test
+ public void testMinaDemuxFixt() throws Exception {
+ String message = "8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\001";
+
+ doTestMinaDemux(message);
+
+ }
+
+ private void doTestMinaDemux(String message) throws Exception, UnsupportedEncodingException {
+ DemuxingProtocolCodecFactory codecFactory = new DemuxingProtocolCodecFactory();
codecFactory.register(FIXMessageDecoder.class);
ProtocolDecoder decoder = codecFactory.getDecoder();
@@ -359,7 +374,7 @@
int count = 5;
String data = "";
for (int i = 0; i < count; i++) {
- data += "8=FIX.4.2\0019=12\00135=X\001108=30\00110=036\001";
+ data += message;
}
for (int i = 1; i < data.length(); i++) {
@@ -379,9 +394,8 @@
output.reset();
buffer.clear();
}
-
- }
-
+ }
+
private void assertMessageFound(String data) throws ProtocolCodecException {
assertMessageFound(data, 1);
}
Index: core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java
===================================================================
--- core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java (revision 46)
+++ core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java (revision 49)
@@ -123,7 +123,7 @@
}
if (messageCount > 0) {
// Mina will compact the buffer because we can't detect a header
- if (in.remaining() < minMaskLength(HEADER_PATTERN)) {
+ if (state == SEEKING_HEADER) {
position = 0;
}
return MessageDecoderResult.OK;
@@ -297,7 +297,8 @@
}
private static BufPos indexOf(ByteBuffer buffer, int position, byte[] data) {
- for (int offset = position, limit = buffer.limit() - minMaskLength(data) + 1; offset < limit; offset++) {
+ int limit = buffer.limit() - minMaskLength(data) + 1;
+ for (int offset = position ; offset < limit; offset++) {
int length;
if (buffer.get(offset) == data[0] && (length = startsWith(buffer, offset, data)) > 0) {
return new BufPos(offset, length);
@@ -337,6 +338,10 @@
return -1;
}
}
+ if(dataOffset != data.length){
+ // when minMaskLength(data) != data.length we might run out of buffer before we run out of data
+ return -1;
+ }
return bufferOffset - initOffset;
}
the svn references are unrelated to the QuickFixJ svn repository.