diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b8198cf..632a3b97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ HEAD * Renamed `JsonObject::getOrCreate()` to `getOrAddMember()` * Fixed `JsonVariant::isNull()` not returning `true` after `set((char*)0)` * Fixed segfault after `variant.set(serialized((char*)0))` +* Detect `IncompleteInput` in `false`, `true`, and `null` v6.8.0-beta (2019-01-30) ----------- diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index f4f749ad..2e41cb77 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -253,18 +253,29 @@ class JsonDeserializer { if (isInteger(buffer)) { result.setInteger(parseInteger(buffer)); - } else if (isFloat(buffer)) { - result.setFloat(parseFloat(buffer)); - } else if (!strcmp(buffer, "true")) { - result.setBoolean(true); - } else if (!strcmp(buffer, "false")) { - result.setBoolean(false); - } else if (!strcmp(buffer, "null")) { - // already null - } else { - return DeserializationError::InvalidInput; + return DeserializationError::Ok; } - return DeserializationError::Ok; + if (isFloat(buffer)) { + result.setFloat(parseFloat(buffer)); + return DeserializationError::Ok; + } + c = buffer[0]; + if (c == 't') { // true + result.setBoolean(true); + return n == 4 ? DeserializationError::Ok + : DeserializationError::IncompleteInput; + } + if (c == 'f') { // false + result.setBoolean(false); + return n == 5 ? DeserializationError::Ok + : DeserializationError::IncompleteInput; + } + if (c == 'n') { // null + // the variant is already null + return n == 4 ? DeserializationError::Ok + : DeserializationError::IncompleteInput; + } + return DeserializationError::InvalidInput; } DeserializationError parseCodepoint(uint16_t &codepoint) { diff --git a/test/JsonDeserializer/CMakeLists.txt b/test/JsonDeserializer/CMakeLists.txt index 7bf5ac56..43da0adc 100644 --- a/test/JsonDeserializer/CMakeLists.txt +++ b/test/JsonDeserializer/CMakeLists.txt @@ -11,6 +11,8 @@ add_executable(JsonDeserializerTests deserializeJsonValue.cpp deserializeJsonString.cpp input_types.cpp + incomplete_input.cpp + invalid_input.cpp nestingLimit.cpp ) diff --git a/test/JsonDeserializer/deserializeJsonString.cpp b/test/JsonDeserializer/deserializeJsonString.cpp index cdfcf4c6..26bb4394 100644 --- a/test/JsonDeserializer/deserializeJsonString.cpp +++ b/test/JsonDeserializer/deserializeJsonString.cpp @@ -6,8 +6,6 @@ #include #include -using namespace Catch::Matchers; - TEST_CASE("Valid JSON strings value") { struct TestCase { const char* input; diff --git a/test/JsonDeserializer/incomplete_input.cpp b/test/JsonDeserializer/incomplete_input.cpp new file mode 100644 index 00000000..50bb2823 --- /dev/null +++ b/test/JsonDeserializer/incomplete_input.cpp @@ -0,0 +1,27 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#define ARDUINOJSON_DECODE_UNICODE 1 +#include +#include + +TEST_CASE("Truncated JSON input") { + const char* testCases[] = {"\"hello", "\'hello", "'\\u", "'\\u00", "'\\u000", + // false + "f", "fa", "fal", "fals", + // true + "t", "tr", "tru", + // null + "n", "nu", "nul"}; + const size_t testCount = sizeof(testCases) / sizeof(testCases[0]); + + DynamicJsonDocument doc(4096); + + for (size_t i = 0; i < testCount; i++) { + const char* input = testCases[i]; + CAPTURE(input); + REQUIRE(deserializeJson(doc, input) == + DeserializationError::IncompleteInput); + } +} diff --git a/test/JsonDeserializer/invalid_input.cpp b/test/JsonDeserializer/invalid_input.cpp new file mode 100644 index 00000000..487fc6f8 --- /dev/null +++ b/test/JsonDeserializer/invalid_input.cpp @@ -0,0 +1,34 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#define ARDUINOJSON_DECODE_UNICODE 1 +#include +#include + +TEST_CASE("Invalid JSON input") { + const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'", + "'\\u000G'", "'\\u000/'", "\\x1234"}; + const size_t testCount = sizeof(testCases) / sizeof(testCases[0]); + + DynamicJsonDocument doc(4096); + + for (size_t i = 0; i < testCount; i++) { + const char* input = testCases[i]; + CAPTURE(input); + REQUIRE(deserializeJson(doc, input) == DeserializationError::InvalidInput); + } +} + +TEST_CASE("Invalid JSON input that should pass") { + const char* testCases[] = {"nulL", "tru3", "fals3"}; + const size_t testCount = sizeof(testCases) / sizeof(testCases[0]); + + DynamicJsonDocument doc(4096); + + for (size_t i = 0; i < testCount; i++) { + const char* input = testCases[i]; + CAPTURE(input); + REQUIRE(deserializeJson(doc, input) == DeserializationError::Ok); + } +}