]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5582] Fixed handling of unicode escapes 45-fromjson-unicode-escapes
authorFrancis Dupont <fdupont@isc.org>
Mon, 18 Jun 2018 15:11:05 +0000 (17:11 +0200)
committerFrancis Dupont <fdupont@isc.org>
Tue, 11 Dec 2018 15:24:18 +0000 (10:24 -0500)
src/lib/cc/data.cc
src/lib/cc/tests/data_unittests.cc

index fda46871ee491857c704674815faf08a7559e39c..79b25034e35bed25367dca9cf53e27aaf8e90cce 100644 (file)
@@ -357,6 +357,7 @@ strFromStringstream(std::istream& in, const std::string& file,
     while (c != EOF && c != '"') {
         if (c == '\\') {
             // see the spec for allowed escape characters
+            int d;
             switch (in.peek()) {
             case '"':
                 c = '"';
@@ -382,6 +383,48 @@ strFromStringstream(std::istream& in, const std::string& file,
             case 't':
                 c = '\t';
                 break;
+            case 'u':
+                // skip first 0
+                in.ignore();
+                ++pos;
+                c = in.peek();
+                if (c != '0') {
+                    throwJSONError("Unsupported unicode escape", file, line, pos);
+                }
+                // skip second 0
+                in.ignore();
+                ++pos;
+                c = in.peek();
+                if (c != '0') {
+                    throwJSONError("Unsupported unicode escape", file, line, pos - 2);
+                }
+                // get first digit
+                in.ignore();
+                ++pos;
+                d = in.peek();
+                if ((d >= '0') && (d <= '9')) {
+                    c = (d - '0') << 4;
+                } else if ((d >= 'A') && (d <= 'F')) {
+                    c = (d - 'A' + 10) << 4;
+                } else if ((d >= 'a') && (d <= 'f')) {
+                    c = (d - 'a' + 10) << 4;
+                } else {
+                    throwJSONError("Not hexadecimal in unicode escape", file, line, pos - 3);
+                }
+                // get second digit
+                in.ignore();
+                ++pos;
+                d = in.peek();
+                if ((d >= '0') && (d <= '9')) {
+                    c |= d - '0';
+                } else if ((d >= 'A') && (d <= 'F')) {
+                    c |= d - 'A' + 10;
+                } else if ((d >= 'a') && (d <= 'f')) {
+                    c |= d - 'a' + 10;
+                } else {
+                    throwJSONError("Not hexadecimal in unicode escape", file, line, pos - 4);
+                }
+                break;
             default:
                 throwJSONError("Bad escape", file, line, pos);
             }
@@ -797,7 +840,7 @@ StringElement::toJSON(std::ostream& ss) const {
             ss << '\\' << 't';
             break;
         default:
-            if ((c >= 0) && (c < 0x20)) {
+            if (((c >= 0) && (c < 0x20)) || (c < 0) || (c >= 0x7f)) {
                 std::ostringstream esc;
                 esc << "\\u"
                     << hex
index a45633875b8328299708a3e05d1b6430da207c60..5c60e61d2b1c69fb8997fc6af1ba66a06afee6c0 100644 (file)
@@ -100,7 +100,7 @@ TEST(Element, from_and_to_json) {
     // We should confirm that our string handling is 8-bit clean.
     // At one point we were using char-length data and comparing to EOF,
     // which means that character '\xFF' would not parse properly.
-    sv.push_back("\"\xFF\"");
+    sv.push_back("\"\\u00ff\"");
 
     BOOST_FOREACH(const std::string& s, sv) {
         // Test two types of fromJSON(): with string and istream.
@@ -150,7 +150,12 @@ TEST(Element, from_and_to_json) {
     // String not delimited correctly
     sv.push_back("\"hello");
     sv.push_back("hello\"");
-
+    // Bad unicode
+    sv.push_back("\"\\u123\"");
+    sv.push_back("\"\\u1234\"");
+    sv.push_back("\"\\u0123\"");
+    sv.push_back("\"\\u00ag\"");
+    sv.push_back("\"\\u00BH\"");
 
     BOOST_FOREACH(std::string s, sv) {
         EXPECT_THROW(el = Element::fromJSON(s), isc::data::JSONError);
@@ -550,11 +555,21 @@ TEST(Element, escape) {
     escapeHelper("foo\nbar", "\"foo\\nbar\"");
     escapeHelper("foo\rbar", "\"foo\\rbar\"");
     escapeHelper("foo\tbar", "\"foo\\tbar\"");
+    escapeHelper("foo\u001fbar", "\"foo\\u001fbar\"");
     // Bad escapes
     EXPECT_THROW(Element::fromJSON("\\a"), JSONError);
     EXPECT_THROW(Element::fromJSON("\\"), JSONError);
     // Can't have escaped quotes outside strings
     EXPECT_THROW(Element::fromJSON("\\\"\\\""), JSONError);
+    // Unicode use lower u and 4 hexa, only 00 prefix is supported
+    EXPECT_THROW(Element::fromJSON("\\U0020"), JSONError);
+    EXPECT_THROW(Element::fromJSON("\\u002"), JSONError);
+    EXPECT_THROW(Element::fromJSON("\\u0123"), JSONError);
+    EXPECT_THROW(Element::fromJSON("\\u1023"), JSONError);
+    EXPECT_THROW(Element::fromJSON("\\u00ag"), JSONError);
+    EXPECT_THROW(Element::fromJSON("\\u00ga"), JSONError);
+    EXPECT_THROW(Element::fromJSON("\\u00BH"), JSONError);
+    EXPECT_THROW(Element::fromJSON("\\u00HB"), JSONError);
     // Inside strings is OK
     EXPECT_NO_THROW(Element::fromJSON("\"\\\"\\\"\""));
     // A whitespace test
@@ -565,6 +580,19 @@ TEST(Element, escape) {
     // Control characters
     StringElement bell("foo\abar");
     EXPECT_EQ("\"foo\\u0007bar\"", bell.str());
+    // 8 bit escape
+    StringElement ab("foo\253bar");
+    EXPECT_EQ("\"foo\\u00abbar\"", ab.str());
+    ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00abbar\""));
+    EXPECT_TRUE(ab.equals(*Element::fromJSON("\"foo\\u00abbar\"")));
+    ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00ABbar\""));
+    EXPECT_TRUE(ab.equals(*Element::fromJSON("\"foo\\u00ABbar\"")));
+    StringElement f1("foo\361bar");
+    EXPECT_EQ("\"foo\\u00f1bar\"", f1.str());
+    ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00f1bar\""));
+    EXPECT_TRUE(f1.equals(*Element::fromJSON("\"foo\\u00f1bar\"")));
+    ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00F1bar\""));
+    EXPECT_TRUE(f1.equals(*Element::fromJSON("\"foo\\u00F1bar\"")));
 }
 
 // This test verifies that strings are copied.