]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1652] Almost done
authorFrancis Dupont <fdupont@isc.org>
Fri, 2 Apr 2021 18:40:27 +0000 (20:40 +0200)
committerFrancis Dupont <fdupont@isc.org>
Fri, 23 Apr 2021 15:15:33 +0000 (17:15 +0200)
src/lib/cc/json_feed.cc
src/lib/cc/json_feed.h
src/lib/cc/tests/json_feed_unittests.cc

index 433164e40982964e39dbae48afad4fee6fb7c545..f101896fa84884d9706378e9b784604bf44c972e 100644 (file)
@@ -27,6 +27,11 @@ const int JSONFeed::JSON_START_ST;
 const int JSONFeed::INNER_JSON_ST;
 const int JSONFeed::STRING_JSON_ST;
 const int JSONFeed::ESCAPE_JSON_ST;
+const int JSONFeed::OLD_COMMENT_ST;
+const int JSONFeed::NEW_COMMENT_ST;
+const int JSONFeed::CPP_COMMENT_ST;
+const int JSONFeed::C_COMMENT_ST;
+const int JSONFeed::END_C_COMMENT_ST;
 const int JSONFeed::JSON_END_ST;
 const int JSONFeed::FEED_OK_ST;
 const int JSONFeed::FEED_FAILED_ST;
@@ -159,6 +164,16 @@ JSONFeed::defineStates() {
                 std::bind(&JSONFeed::stringJSONHandler, this));
     defineState(ESCAPE_JSON_ST, "ESCAPE_JSON_ST",
                 std::bind(&JSONFeed::escapeJSONHandler, this));
+    defineState(OLD_COMMENT_ST, "OLD_COMMENT_ST",
+                std::bind(&JSONFeed::oldCommentHandler, this));
+    defineState(NEW_COMMENT_ST, "NEW_COMMENT_ST",
+                std::bind(&JSONFeed::newCommentHandler, this));
+    defineState(CPP_COMMENT_ST, "CPP_COMMENT_ST",
+                std::bind(&JSONFeed::cppCommentHandler, this));
+    defineState(C_COMMENT_ST, "C_COMMENT_ST",
+                std::bind(&JSONFeed::cCommentHandler, this));
+    defineState(END_C_COMMENT_ST, "END_C_COMMENT_ST",
+                std::bind(&JSONFeed::endCCommentHandler, this));
     defineState(JSON_END_ST, "JSON_END_ST",
                 std::bind(&JSONFeed::endJSONHandler, this));
 }
@@ -394,17 +409,17 @@ void
 JSONFeed::innerJSONHandler() {
     char c = getNextFromBuffer();
     if (getNextEvent() != NEED_MORE_DATA_EVT) {
-        output_.push_back(c);
-
         switch(c) {
         case '{':
         case '[':
+            output_.push_back(c);
             transition(getCurrState(), DATA_READ_OK_EVT);
             ++open_scopes_;
             break;
 
         case '}':
         case ']':
+            output_.push_back(c);
             if (--open_scopes_ == 0) {
                 transition(JSON_END_ST, FEED_OK_EVT);
 
@@ -414,10 +429,20 @@ JSONFeed::innerJSONHandler() {
             break;
 
         case '"':
+            output_.push_back(c);
             transition(STRING_JSON_ST, DATA_READ_OK_EVT);
             break;
 
+        case '#':
+            transition(OLD_COMMENT_ST, DATA_READ_OK_EVT);
+            break;
+
+        case '/':
+            transition(NEW_COMMENT_ST, DATA_READ_OK_EVT);
+            break;
+
         default:
+            output_.push_back(c);
             postNextEvent(DATA_READ_OK_EVT);
         }
     }
@@ -454,6 +479,100 @@ JSONFeed::escapeJSONHandler() {
     }
 }
 
+void
+JSONFeed::oldCommentHandler() {
+    char c = getNextFromBuffer();
+    if (getNextEvent() != NEED_MORE_DATA_EVT) {
+        switch (c) {
+        case '\n':
+            output_.push_back(c);
+            transition(INNER_JSON_ST, DATA_READ_OK_EVT);
+            break;
+
+        default:
+            postNextEvent(DATA_READ_OK_EVT);
+            break;
+        }
+    }
+}
+
+void
+JSONFeed::newCommentHandler() {
+    char c = getNextFromBuffer();
+    if (getNextEvent() != NEED_MORE_DATA_EVT) {
+        switch (c) {
+        case '/':
+            transition(CPP_COMMENT_ST, DATA_READ_OK_EVT);
+            break;
+
+        case '*':
+            transition(C_COMMENT_ST, DATA_READ_OK_EVT);
+            break;
+
+        default:
+            feedFailure("invalid characters /" + std::string(1, c));
+        }
+    }
+}
+
+void
+JSONFeed::cppCommentHandler() {
+    char c = getNextFromBuffer();
+    if (getNextEvent() != NEED_MORE_DATA_EVT) {
+        switch (c) {
+        case '\n':
+            transition(INNER_JSON_ST, DATA_READ_OK_EVT);
+            break;
+
+        default:
+            postNextEvent(DATA_READ_OK_EVT);
+            break;
+        }
+    }
+}
+
+void
+JSONFeed::cCommentHandler() {
+    char c = getNextFromBuffer();
+    if (getNextEvent() != NEED_MORE_DATA_EVT) {
+        switch (c) {
+        case '*':
+            transition(END_C_COMMENT_ST, DATA_READ_OK_EVT);
+            break;
+
+        case '\n':
+            output_.push_back(c);
+            postNextEvent(DATA_READ_OK_EVT);
+            break;
+
+        default:
+            postNextEvent(DATA_READ_OK_EVT);
+            break;
+        }
+    }
+}
+
+void
+JSONFeed::endCCommentHandler() {
+    char c = getNextFromBuffer();
+    if (getNextEvent() != NEED_MORE_DATA_EVT) {
+        switch (c) {
+        case '/':
+            transition(INNER_JSON_ST, DATA_READ_OK_EVT);
+            break;
+
+        case '\n':
+            output_.push_back(c);
+            transition(C_COMMENT_ST, DATA_READ_OK_EVT);
+            break;
+
+        default:
+            transition(C_COMMENT_ST, DATA_READ_OK_EVT);
+            break;
+        }
+    }
+}
+
 void
 JSONFeed::endJSONHandler() {
     switch (getNextEvent()) {
index 5649cb2ebe9d6663638a809f9855f40c2e1776b6..26503aaad0c03883f72ed344b54df222d82021f7 100644 (file)
@@ -108,8 +108,23 @@ public:
     /// @brief JSON escape next character.
     static const int ESCAPE_JSON_ST = SM_DERIVED_STATE_MIN + 11;
 
+    /// @brief Skipping an old style comment.
+    static const int OLD_COMMENT_ST = SM_DERIVED_STATE_MIN + 12;
+
+    /// @brief Skipping a new style comment.
+    static const int NEW_COMMENT_ST = SM_DERIVED_STATE_MIN + 13;
+
+    /// @brief Skipping a C++ style comment.
+    static const int CPP_COMMENT_ST = SM_DERIVED_STATE_MIN + 14;
+
+    /// @brief Skipping a C style comment.
+    static const int C_COMMENT_ST = SM_DERIVED_STATE_MIN + 15;
+
+    /// @brief Ending a C style comment.
+    static const int END_C_COMMENT_ST = SM_DERIVED_STATE_MIN + 16;
+
     /// @brief Found last closing brace or square bracket.
-    static const int JSON_END_ST = SM_DERIVED_STATE_MIN + 12;
+    static const int JSON_END_ST = SM_DERIVED_STATE_MIN + 17;
 
     /// @brief Found opening and closing brace or square bracket.
     ///
@@ -305,6 +320,21 @@ private:
     /// @brief Handler for the ESCAPE_JSON_ST;
     void escapeJSONHandler();
 
+    /// @brief Handler for OLD_COMMENT_ST.
+    void oldCommentHandler();
+
+    /// @brief Handler for NEW_COMMENT_ST.
+    void newCommentHandler();
+
+    /// @brief Handler for CPP_COMMENT_ST.
+    void cppCommentHandler();
+
+    /// @brief Handler for C_COMMENT_ST.
+    void cCommentHandler();
+
+    /// @brief Handler for END_C_COMMENT_ST.
+    void endCCommentHandler();
+
     /// @brief Handler for the JSON_END_ST.
     void endJSONHandler();
 
index 8a772440dbca30310b35f291b974178ed673e2fc..004400ee11b118722cef9cac0c506a855ce9f480 100644 (file)
@@ -280,8 +280,8 @@ TEST_F(JSONFeedTest, whiteSpaceBefore) {
     testRead(json, expected);
 }
 
-// This test verifies that shell style comments before JSON are ignored.
-TEST_F(JSONFeedTest, shellCommentBefore) {
+// This test verifies that bash style comments before JSON are ignored.
+TEST_F(JSONFeedTest, bashCommentBefore) {
     std::string json = "# ahah\n  # foo\"bar\n{ }\n";
     std::string expected = "{ }";
     testRead(json, expected);
@@ -302,13 +302,42 @@ TEST_F(JSONFeedTest, multiLineCommentBefore) {
 }
 
 // This test verifies that an error is signalled a slash does not begin
-// a C++ or C style comment.
+// a C++ or C style comment before JSON.
 TEST_F(JSONFeedTest, badCommentBefore) {
     std::string json = "/# foo\n [ ]\n";
     std::string err_msg = "invalid characters /#";
     testInvalidRead(json, err_msg);
 }
 
+// This test verifies that bash style comments are ignored.
+TEST_F(JSONFeedTest, bashComments) {
+    std::string json = "{ # ahah\n \"foo\": # value?\n \"bar\" }";
+    std::string expected = "{ \n \"foo\": \n \"bar\" }";
+    testRead(json, expected);
+}
+
+// This test verifies that C++ style comments are ignored.
+TEST_F(JSONFeedTest, cppComments) {
+    std::string json = "[ # ahah\n \"foo\", # value?\n \"bar\" ]";
+    std::string expected = "[ \n \"foo\", \n \"bar\" ]";
+    testRead(json, expected);
+}
+
+// This test verifies that multi-line comments are ignored.
+TEST_F(JSONFeedTest, multiLineComments) {
+    std::string json = "{ /* ahah\n \"// foobar*/\n \"foo\": \"bar\" }\n";
+    std::string expected = "{ \n\n \"foo\": \"bar\" }";
+    testRead(json, expected);
+}
+
+// This test verifies that an error is signalled a slash does not begin
+// a C++ or C style comment.
+TEST_F(JSONFeedTest, badComment) {
+    std::string json = "[ /# foo\n ]\n";
+    std::string err_msg = "invalid characters /#";
+    testInvalidRead(json, err_msg);
+}
+
 // This test verifies that trailing garbage is ignored.
 TEST_F(JSONFeedTest, trailing) {
     JSONFeed feed;
@@ -322,4 +351,98 @@ TEST_F(JSONFeedTest, trailing) {
     EXPECT_EQ(expected, feed.getProcessedText());
 }
 
+// Example from DHCPv4 unit tests.
+TEST_F(JSONFeedTest, bashComment4) {
+    JSONFeed feed;
+    ASSERT_NO_THROW(feed.initModel());
+    std::string json = "{ \"Dhcp4\": { \"interfaces-config\": {"
+        "  \"interfaces\": [ \"*\" ]"
+        "},\n"
+        "# this is a comment\n"
+        "\"rebind-timer\": 2000, \n"
+        "# lots of comments here\n"
+        "# and here\n"
+        "\"renew-timer\": 1000, \n"
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
+        "    \"subnet\": \"192.0.2.0/24\", "
+        "    \"interface\": \"eth0\""
+        " } ],"
+        "\"valid-lifetime\": 4000 } }";
+    feed.postBuffer(&json[0], json.size());
+    feed.poll();
+    EXPECT_FALSE(feed.needData());
+    EXPECT_TRUE(feed.feedOk());
+    EXPECT_NO_THROW(feed.toElement());
+}
+
+// Example from DHCPv4 unit tests.
+TEST_F(JSONFeedTest, bashCommentsInline4) {
+    JSONFeed feed;
+    ASSERT_NO_THROW(feed.initModel());
+    std::string json = "{ \"Dhcp4\": { \"interfaces-config\": {"
+        "  \"interfaces\": [ \"*\" ]"
+        "},\n"
+        "\"rebind-timer\": 2000, # everything after # is ignored\n"
+        "\"renew-timer\": 1000, # this will be ignored, too\n"
+        "\"subnet4\": [ { "
+        "    \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
+        "    \"subnet\": \"192.0.2.0/24\", "
+        "    \"interface\": \"eth0\""
+        " } ],"
+        "\"valid-lifetime\": 4000 } }";
+    feed.postBuffer(&json[0], json.size());
+    feed.poll();
+    EXPECT_FALSE(feed.needData());
+    EXPECT_TRUE(feed.feedOk());
+    EXPECT_NO_THROW(feed.toElement());
+}
+
+// Example from DHCPv6 unit tests.
+TEST_F(JSONFeedTest, cppComments6) {
+    JSONFeed feed;
+    ASSERT_NO_THROW(feed.initModel());
+    std::string json = "{ \"Dhcp6\": { \"interfaces-config\": {"
+        "  \"interfaces\": [ \"*\" ]"
+        "},\n"
+        "\"preferred-lifetime\": 3000, // this is a comment \n"
+        "\"rebind-timer\": 2000, // everything after // is ignored\n"
+        "\"renew-timer\": 1000, // this will be ignored, too\n"
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+        "    \"subnet\": \"2001:db8:1::/48\", "
+        "    \"interface\": \"eth0\""
+        " } ],"
+        "\"valid-lifetime\": 4000 } }";
+    feed.postBuffer(&json[0], json.size());
+    feed.poll();
+    EXPECT_FALSE(feed.needData());
+    EXPECT_TRUE(feed.feedOk());
+    EXPECT_NO_THROW(feed.toElement());
+}
+
+// Example from DHCPv6 unit tests.
+TEST_F(JSONFeedTest, multilineComments6) {
+    JSONFeed feed;
+    ASSERT_NO_THROW(feed.initModel());
+    std::string json = "{ \"Dhcp6\": { \"interfaces-config\": {"
+        "  \"interfaces\": [ \"*\" ]"
+        "},\n"
+        "\"preferred-lifetime\": 3000, /* this is a C style comment\n"
+        "that\n can \n span \n multiple \n lines */ \n"
+        "\"rebind-timer\": 2000,\n"
+        "\"renew-timer\": 1000, \n"
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+        "    \"subnet\": \"2001:db8:1::/48\", "
+        "    \"interface\": \"eth0\""
+        " } ],"
+        "\"valid-lifetime\": 4000 } }";
+    feed.postBuffer(&json[0], json.size());
+    feed.poll();
+    EXPECT_FALSE(feed.needData());
+    EXPECT_TRUE(feed.feedOk());
+    EXPECT_NO_THROW(feed.toElement());
+}
+
 } // end of anonymous namespace.