diff --git a/src/main/java/tools/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/tools/jackson/core/json/ReaderBasedJsonParser.java index cfb5c681ac..fb3d2b4053 100644 --- a/src/main/java/tools/jackson/core/json/ReaderBasedJsonParser.java +++ b/src/main/java/tools/jackson/core/json/ReaderBasedJsonParser.java @@ -1393,6 +1393,9 @@ protected final JsonToken _parseUnsignedNumber(int ch) throws JacksonException // As per #105, need separating space between root values; check here if (_streamReadContext.inRoot()) { _verifyRootSpace(ch); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(ch); } int len = ptr-startPtr; _textBuffer.resetWithShared(_inputBuffer, startPtr, len); @@ -1458,6 +1461,9 @@ private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg, // As per #105, need separating space between root values; check here if (_streamReadContext.inRoot()) { _verifyRootSpace(ch); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(ch); } int len = ptr-startPtr; _textBuffer.resetWithShared(_inputBuffer, startPtr, len); @@ -1515,6 +1521,9 @@ private final JsonToken _parseSignedNumber(final boolean negative) throws Jackso _inputPtr = ptr; if (_streamReadContext.inRoot()) { _verifyRootSpace(ch); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(ch); } int len = ptr-startPtr; _textBuffer.resetWithShared(_inputBuffer, startPtr, len); @@ -1668,6 +1677,9 @@ private final JsonToken _parseNumber2(boolean neg, int startPtr) throws JacksonE --_inputPtr; if (_streamReadContext.inRoot()) { _verifyRootSpace(c); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(c); } } _textBuffer.setCurrentLength(outPtr); @@ -1807,6 +1819,40 @@ private final void _verifyRootSpace(int ch) throws JacksonException _reportMissingRootWS(ch); } + // [core#105]: Verify non-root values followed by valid separator + private final void _verifyNonRootSeparator(int ch) throws JacksonException + { + // caller had pushed it back, before calling; reset + ++_inputPtr; + switch (ch) { + // Whitespace is always valid + case ' ': + case '\t': + return; + case '\r': + --_inputPtr; + return; + case '\n': + ++_currInputRow; + _currInputRowStart = _inputPtr; + return; + // Valid structural characters + case ',': // next value + case ']': // end of array + case '}': // end of object + --_inputPtr; // push back for proper processing + return; + } + // Could be a comment - need to check + if (ch == '/' || ch == '#') { + // Let it fall through to be handled by nextToken() which will + // properly validate based on enabled features + --_inputPtr; + return; + } + _reportUnexpectedChar(ch, "Expected space, comma, or structural character after number"); + } + /* /********************************************************************** /* Internal methods, secondary parsing diff --git a/src/main/java/tools/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/tools/jackson/core/json/UTF8DataInputJsonParser.java index 364dc4225b..6bdf5102d3 100644 --- a/src/main/java/tools/jackson/core/json/UTF8DataInputJsonParser.java +++ b/src/main/java/tools/jackson/core/json/UTF8DataInputJsonParser.java @@ -1061,6 +1061,9 @@ protected JsonToken _parseUnsignedNumber(int c) throws IOException _nextByte = c; if (_streamReadContext.inRoot()) { _verifyRootSpace(); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(); } // And there we have it! return resetInt(false, intLen); @@ -1122,6 +1125,9 @@ private final JsonToken _parseSignedNumber(boolean negative) throws IOException _nextByte = c; if (_streamReadContext.inRoot()) { _verifyRootSpace(); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(); } // And there we have it! return resetInt(negative, intLen); @@ -1227,6 +1233,9 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c, _nextByte = c; if (_streamReadContext.inRoot()) { _verifyRootSpace(); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(); } _textBuffer.setCurrentLength(outPtr); @@ -1255,6 +1264,26 @@ private final void _verifyRootSpace() throws JacksonException _reportMissingRootWS(ch); } + // [core#105]: Verify non-root values followed by valid separator + private final void _verifyNonRootSeparator() throws JacksonException + { + int ch = _nextByte; + if (ch <= INT_SPACE) { + _nextByte = -1; + if (ch == INT_CR || ch == INT_LF) { + ++_currInputRow; + } + return; + } + // Valid structural characters and comment starts + if (ch == INT_COMMA || ch == INT_RBRACKET || ch == INT_RCURLY + || ch == INT_SLASH || ch == INT_HASH) { + // Keep _nextByte set for proper processing + return; + } + _reportUnexpectedChar(ch, "Expected space, comma, or structural character after number"); + } + /* /********************************************************************** /* Internal methods, secondary parsing diff --git a/src/main/java/tools/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/tools/jackson/core/json/UTF8StreamJsonParser.java index 39e0090100..64542a5b74 100644 --- a/src/main/java/tools/jackson/core/json/UTF8StreamJsonParser.java +++ b/src/main/java/tools/jackson/core/json/UTF8StreamJsonParser.java @@ -1825,6 +1825,9 @@ protected JsonToken _parseUnsignedNumber(int c) throws JacksonException // As per #105, need separating space between root values; check here if (_streamReadContext.inRoot()) { _verifyRootSpace(c); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(c); } // And there we have it! return resetInt(false, intLen); @@ -1885,6 +1888,9 @@ private final JsonToken _parseSignedNumber(boolean negative) throws JacksonExcep // As per #105, need separating space between root values; check here if (_streamReadContext.inRoot()) { _verifyRootSpace(c); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(c); } // And there we have it! @@ -1921,6 +1927,9 @@ private final JsonToken _parseNumber2(char[] outBuf, int outPtr, boolean negativ // As per #105, need separating space between root values; check here if (_streamReadContext.inRoot()) { _verifyRootSpace(_inputBuffer[_inputPtr] & 0xFF); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(_inputBuffer[_inputPtr] & 0xFF); } // And there we have it! @@ -2053,6 +2062,9 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c, // As per [core#105], need separating space between root values; check here if (_streamReadContext.inRoot()) { _verifyRootSpace(c); + } else { + // [core#105]: Also verify non-root values have valid separator + _verifyNonRootSeparator(c); } } _textBuffer.setCurrentLength(outPtr); @@ -2096,6 +2108,35 @@ private final void _verifyRootSpace(int ch) throws JacksonException _reportMissingRootWS(ch); } + // [core#105]: Verify non-root values followed by valid separator + private final void _verifyNonRootSeparator(int ch) throws JacksonException + { + // caller had pushed it back, before calling; reset + ++_inputPtr; + switch (ch) { + // Whitespace is always valid + case ' ': + case '\t': + return; + case '\r': + --_inputPtr; + return; + case '\n': + ++_currInputRow; + _currInputRowStart = _inputPtr; + return; + // Valid structural characters + case ',': // next value + case ']': // end of array + case '}': // end of object + case '/': // start of comment (C-style) + case '#': // start of comment (YAML-style) + --_inputPtr; // push back for proper processing + return; + } + _reportUnexpectedChar(ch, "Expected space, comma, or structural character after number"); + } + /* /********************************************************************** /* Internal methods, secondary parsing diff --git a/src/test/java/module-info.java b/src/test/java/module-info.java index 788d61d9d6..54a6eab6e8 100644 --- a/src/test/java/module-info.java +++ b/src/test/java/module-info.java @@ -34,7 +34,6 @@ opens tools.jackson.core.unittest.jsonptr; opens tools.jackson.core.unittest.read; opens tools.jackson.core.unittest.read.loc; - opens tools.jackson.core.unittest.tofix; opens tools.jackson.core.unittest.tofix.async; opens tools.jackson.core.unittest.sym; opens tools.jackson.core.unittest.type; diff --git a/src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandling679Test.java b/src/test/java/tools/jackson/core/unittest/read/ParserErrorHandling679Test.java similarity index 92% rename from src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandling679Test.java rename to src/test/java/tools/jackson/core/unittest/read/ParserErrorHandling679Test.java index e840284b09..d26bca83e5 100644 --- a/src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandling679Test.java +++ b/src/test/java/tools/jackson/core/unittest/read/ParserErrorHandling679Test.java @@ -1,4 +1,4 @@ -package tools.jackson.core.unittest.tofix; +package tools.jackson.core.unittest.read; import org.junit.jupiter.api.Test; @@ -10,32 +10,27 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; +// Tests for [core#679] - partially fixed by #105 fix, but "/" case still fails class ParserErrorHandling679Test extends tools.jackson.core.unittest.JacksonCoreTestBase { - // [core#679] - @JacksonTestFailureExpected @Test void nonRootMangledFloats679Bytes() throws Exception { _testNonRootMangledFloats679(MODE_INPUT_STREAM); _testNonRootMangledFloats679(MODE_INPUT_STREAM_THROTTLED); } - // [core#679] - @JacksonTestFailureExpected @Test void nonRootMangledFloats679DataInput() throws Exception { _testNonRootMangledFloats679(MODE_DATA_INPUT); } - // [core#679] @Test - @JacksonTestFailureExpected void nonRootMangledFloats679Chars() throws Exception { _testNonRootMangledFloats679(MODE_READER); } - // [core#679] + // "/" tests still fail - need more work to distinguish "/" from "//" and "/*" @JacksonTestFailureExpected @Test void nonRootMangledInts679Bytes() throws Exception { @@ -43,14 +38,12 @@ void nonRootMangledInts679Bytes() throws Exception { _testNonRootMangledInts(MODE_INPUT_STREAM_THROTTLED); } - // [core#679] @JacksonTestFailureExpected @Test void nonRootMangledInts679DataInput() throws Exception { _testNonRootMangledInts(MODE_DATA_INPUT); } - // [core#679] @JacksonTestFailureExpected @Test void nonRootMangledInts679Chars() throws Exception { diff --git a/src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandlingBytes105Test.java b/src/test/java/tools/jackson/core/unittest/read/ParserErrorHandlingBytes105Test.java similarity index 84% rename from src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandlingBytes105Test.java rename to src/test/java/tools/jackson/core/unittest/read/ParserErrorHandlingBytes105Test.java index e5ba0d6de3..bec910c70d 100644 --- a/src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandlingBytes105Test.java +++ b/src/test/java/tools/jackson/core/unittest/read/ParserErrorHandlingBytes105Test.java @@ -1,27 +1,23 @@ -package tools.jackson.core.unittest.tofix; +package tools.jackson.core.unittest.read; import org.junit.jupiter.api.Test; import tools.jackson.core.JsonParser; import tools.jackson.core.JsonToken; import tools.jackson.core.exc.StreamReadException; -import tools.jackson.core.unittest.testutil.failure.JacksonTestFailureExpected; import static org.junit.jupiter.api.Assertions.fail; -// Failing tests for non-root-token problem +// Tests for [core#105] ("eager number parsing misses errors") class ParserErrorHandlingBytes105Test extends tools.jackson.core.unittest.JacksonCoreTestBase { - // Tests for [core#105] ("eager number parsing misses errors") - @JacksonTestFailureExpected @Test void mangledIntsBytes() throws Exception { _testMangledNonRootInts(MODE_INPUT_STREAM); _testMangledNonRootInts(MODE_INPUT_STREAM_THROTTLED); } - @JacksonTestFailureExpected @Test void mangledFloatsBytes() throws Exception { _testMangledNonRootFloats(MODE_INPUT_STREAM); diff --git a/src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandlingChars105Test.java b/src/test/java/tools/jackson/core/unittest/read/ParserErrorHandlingChars105Test.java similarity index 83% rename from src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandlingChars105Test.java rename to src/test/java/tools/jackson/core/unittest/read/ParserErrorHandlingChars105Test.java index c324f1918a..409098f7df 100644 --- a/src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandlingChars105Test.java +++ b/src/test/java/tools/jackson/core/unittest/read/ParserErrorHandlingChars105Test.java @@ -1,26 +1,22 @@ -package tools.jackson.core.unittest.tofix; +package tools.jackson.core.unittest.read; import org.junit.jupiter.api.Test; import tools.jackson.core.JsonParser; import tools.jackson.core.JsonToken; import tools.jackson.core.exc.StreamReadException; -import tools.jackson.core.unittest.testutil.failure.JacksonTestFailureExpected; import static org.junit.jupiter.api.Assertions.fail; -// Failing tests for non-root-token problem +// Tests for [core#105] ("eager number parsing misses errors") class ParserErrorHandlingChars105Test extends tools.jackson.core.unittest.JacksonCoreTestBase { - // Tests for [core#105] ("eager number parsing misses errors") - @JacksonTestFailureExpected @Test void mangledIntsChars() throws Exception { _testMangledNonRootInts(MODE_READER); } - @JacksonTestFailureExpected @Test void mangledFloatsChars() throws Exception { _testMangledNonRootFloats(MODE_READER); diff --git a/src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandlingDataInput105Test.java b/src/test/java/tools/jackson/core/unittest/read/ParserErrorHandlingDataInput105Test.java similarity index 78% rename from src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandlingDataInput105Test.java rename to src/test/java/tools/jackson/core/unittest/read/ParserErrorHandlingDataInput105Test.java index a4799e28dc..26446c1f22 100644 --- a/src/test/java/tools/jackson/core/unittest/tofix/ParserErrorHandlingDataInput105Test.java +++ b/src/test/java/tools/jackson/core/unittest/read/ParserErrorHandlingDataInput105Test.java @@ -1,28 +1,22 @@ -package tools.jackson.core.unittest.tofix; +package tools.jackson.core.unittest.read; import org.junit.jupiter.api.Test; import tools.jackson.core.JsonParser; import tools.jackson.core.JsonToken; import tools.jackson.core.exc.StreamReadException; -import tools.jackson.core.unittest.testutil.failure.JacksonTestFailureExpected; import static org.junit.jupiter.api.Assertions.fail; -// Failing tests for non-root-token problem +// Tests for [core#105] ("eager number parsing misses errors") class ParserErrorHandlingDataInput105Test extends tools.jackson.core.unittest.JacksonCoreTestBase { - // Tests for [core#105] ("eager number parsing misses errors") - @JacksonTestFailureExpected @Test void mangledIntsDataInput() throws Exception { - // 02-Jun-2017, tatu: Fails to fail; should check whether this is expected - // (since DataInput can't do look-ahead) _testMangledNonRootInts(MODE_DATA_INPUT); } - @JacksonTestFailureExpected @Test void mangledFloatsDataInput() throws Exception { _testMangledNonRootFloats(MODE_DATA_INPUT);