From db4781282f364b3a57b829db4362d77f449b612c Mon Sep 17 00:00:00 2001 From: Violeta Georgieva Date: Fri, 4 Aug 2017 14:33:00 +0300 Subject: [PATCH] Handle partially decoded elements while streaming Json array Motivation: 'insideString' and 'openBraces' need a proper handling when streaming Json array over multiple writes and an element decoding was started but not completed. Related to #6969 Modifications: If the idx is reset: - 'insideString' has to be reset to 'false' in order to indicate that array element will be decoded from the beginning - 'openBraces' has to be reset to '1' to indicate that Json array decoding is in progress. Result: Json array is properly decoded when in streaming mode --- .../handler/codec/json/JsonObjectDecoder.java | 4 + .../codec/json/JsonObjectDecoderTest.java | 90 +++++++++++++------ 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/codec/src/main/java/io/netty/handler/codec/json/JsonObjectDecoder.java b/codec/src/main/java/io/netty/handler/codec/json/JsonObjectDecoder.java index 037c60c0af..123618b143 100644 --- a/codec/src/main/java/io/netty/handler/codec/json/JsonObjectDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/json/JsonObjectDecoder.java @@ -92,6 +92,10 @@ public class JsonObjectDecoder extends ByteToMessageDecoder { if (this.idx > in.readerIndex() && lastReaderIndex != in.readerIndex()) { this.idx = in.readerIndex(); + if (state == ST_DECODING_ARRAY_STREAM) { + insideString = false; + openBraces = 1; + } } // index of next byte to process. diff --git a/codec/src/test/java/io/netty/handler/codec/json/JsonObjectDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/json/JsonObjectDecoderTest.java index 29175db3c7..12eb13ac19 100644 --- a/codec/src/test/java/io/netty/handler/codec/json/JsonObjectDecoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/json/JsonObjectDecoderTest.java @@ -72,35 +72,73 @@ public class JsonObjectDecoderTest { } @Test - public void testStreamJsonArrayOverMultipleWrites() { + public void testStreamJsonArrayOverMultipleWrites1() { + String[] array = new String[] { + " [{\"test", + "case\" : \"\\\"}]Escaped dou\\\"ble quotes \\\" in JSON str\\\"ing\"", + " }\n\n , ", + "{\"testcase\" : \"Streaming string me", + "ssage\"} ] " + }; + String[] result = new String[] { + "{\"testcase\" : \"\\\"}]Escaped dou\\\"ble quotes \\\" in JSON str\\\"ing\" }", + "{\"testcase\" : \"Streaming string message\"}" + }; + doTestStreamJsonArrayOverMultipleWrites(2, array, result); + } + + @Test + public void testStreamJsonArrayOverMultipleWrites2() { + String[] array = new String[] { + " [{\"test", + "case\" : \"\\\"}]Escaped dou\\\"ble quotes \\\" in JSON str\\\"ing\"", + " }\n\n , {\"test", + "case\" : \"Streaming string me", + "ssage\"} ] " + }; + String[] result = new String[] { + "{\"testcase\" : \"\\\"}]Escaped dou\\\"ble quotes \\\" in JSON str\\\"ing\" }", + "{\"testcase\" : \"Streaming string message\"}" + }; + doTestStreamJsonArrayOverMultipleWrites(2, array, result); + } + + @Test + public void testStreamJsonArrayOverMultipleWrites3() { + String[] array = new String[] { + " [{\"test", + "case\" : \"\\\"}]Escaped dou\\\"ble quotes \\\" in JSON str\\\"ing\"", + " }\n\n , [{\"test", + "case\" : \"Streaming string me", + "ssage\"}] ] " + }; + String[] result = new String[] { + "{\"testcase\" : \"\\\"}]Escaped dou\\\"ble quotes \\\" in JSON str\\\"ing\" }", + "[{\"testcase\" : \"Streaming string message\"}]" + }; + doTestStreamJsonArrayOverMultipleWrites(2, array, result); + } + + private static void doTestStreamJsonArrayOverMultipleWrites(int indexDataAvailable, + String[] array, String[] result) { EmbeddedChannel ch = new EmbeddedChannel(new JsonObjectDecoder(true)); - String arrayPart1 = "[{\"test"; - String arrayPart2 = "case\" : \"\\\"}]Escaped dou\\\"ble quotes \\\" in JSON str\\\"ing\""; - String arrayPart3 = " }\n\n , "; - String arrayPart4 = "{\"testcase\" : \"Streaming string me"; - String arrayPart5 = "ssage\"} ]"; + boolean dataAvailable = false; + for (String part : array) { + dataAvailable = ch.writeInbound(Unpooled.copiedBuffer(part, CharsetUtil.UTF_8)); + if (indexDataAvailable > 0) { + assertFalse(dataAvailable); + } else { + assertTrue(dataAvailable); + } + indexDataAvailable--; + } - // Test array - boolean dataAvailable = ch.writeInbound(Unpooled.copiedBuffer(" " + arrayPart1, CharsetUtil.UTF_8)); - assertFalse(dataAvailable); - dataAvailable = ch.writeInbound(Unpooled.copiedBuffer(arrayPart2, CharsetUtil.UTF_8)); - assertFalse(dataAvailable); - dataAvailable = ch.writeInbound(Unpooled.copiedBuffer(arrayPart3, CharsetUtil.UTF_8)); - assertTrue(dataAvailable); - dataAvailable = ch.writeInbound(Unpooled.copiedBuffer(arrayPart4, CharsetUtil.UTF_8)); - assertTrue(dataAvailable); - dataAvailable = ch.writeInbound(Unpooled.copiedBuffer(arrayPart5 + " ", CharsetUtil.UTF_8)); - assertTrue(dataAvailable); - - ByteBuf res = ch.readInbound(); - assertEquals("{\"testcase\" : \"\\\"}]Escaped dou\\\"ble quotes \\\" in JSON str\\\"ing\" }", - res.toString(CharsetUtil.UTF_8)); - res.release(); - - res = ch.readInbound(); - assertEquals("{\"testcase\" : \"Streaming string message\"}", res.toString(CharsetUtil.UTF_8)); - res.release(); + for (String part : result) { + ByteBuf res = ch.readInbound(); + assertEquals(part, res.toString(CharsetUtil.UTF_8)); + res.release(); + } assertFalse(ch.finish()); }