Parcourir la source

[trac1112] Add escaped characters support and unit tests to to characterstr class

Ocean Wang il y a 13 ans
Parent
commit
9f441d72a2

+ 53 - 10
src/lib/dns/character_string.cc

@@ -21,6 +21,8 @@ using namespace isc::dns::rdata;
 namespace isc {
 namespace dns {
 
+#define IS_DIGIT(c) (('0' <= (c)) && ((c) <= '9'))
+
 std::string
 characterstr::getNextCharacterString(const std::string& input_str,
                               std::string::const_iterator& input_iterator)
@@ -36,27 +38,64 @@ characterstr::getNextCharacterString(const std::string& input_str,
 
     // Whether the <character-string> is separated with double quotes (")
     bool quotes_separated = (*input_iterator == '"');
+    // Whether the quotes are pared if the string is quotes separated
+    bool quotes_paired = false;
 
     if (quotes_separated) {
         ++input_iterator;
     }
 
     while(input_iterator < input_str.end()){
+        // Escaped characters processing
+        if (*input_iterator == '\\') {
+            if (input_iterator + 1 == input_str.end()) {
+                isc_throw(InvalidRdataText, "<character-string> ended \
+                          exceptionally.");
+            } else {
+                if (IS_DIGIT(*(input_iterator + 1))) {
+                    // \DDD where each D is a digit. It its the octet
+                    // corresponding to the decimal number described by DDD
+                    if (input_iterator + 3 >= input_str.end()) {
+                        isc_throw(InvalidRdataText, "<character-string> ended \
+                                  exceptionally.");
+                    } else {
+                        int n = 0;
+                        ++input_iterator;
+                        for (int i = 0; i < 3; ++i) {
+                            if (('0' <= *input_iterator) &&
+                                (*input_iterator <= '9')) {
+                                n = n*10 + (*input_iterator - '0');
+                                ++input_iterator;
+                            } else {
+                                isc_throw(InvalidRdataText, "Illegal decimal \
+                                          escaping series");
+                            }
+                        }
+                        if (n > 255) {
+                            isc_throw(InvalidRdataText, "Illegal octet \
+                                      number");
+                        }
+                        result.push_back(n);
+                        continue;
+                    }
+                } else {
+                    ++input_iterator;
+                    result.push_back(*input_iterator);
+                    ++input_iterator;
+                    continue;
+                }
+            }
+        }
+
         if (quotes_separated) {
             // If the <character-string> is seperated with quotes symbol and
             // another quotes symbol is encountered, it is the end of the
             // <character-string>
             if (*input_iterator == '"') {
-                // Inside a " delimited string any character can occur, except
-                // for a " itself, which must be quoted using \ (back slash).
-                if (*(input_iterator - 1) == '\\') {
-                    // pop the '\' character
-                    result.resize(result.size() - 1);
-                } else {
-                    ++input_iterator;
-                    // Reach the end of character string
-                    break;
-                }
+                quotes_paired = true;
+                ++input_iterator;
+                // Reach the end of character string
+                break;
             }
         } else if (*input_iterator == ' ') {
             // If the <character-string> is not seperated with quotes symbol,
@@ -73,6 +112,10 @@ characterstr::getNextCharacterString(const std::string& input_str,
         isc_throw(CharStringTooLong, "<character-string> is too long");
     }
 
+    if (quotes_separated && !quotes_paired) {
+        isc_throw(InvalidRdataText, "The quotes are not paired");
+    }
+
     return (result);
 }
 

+ 1 - 0
src/lib/dns/tests/Makefile.am

@@ -56,6 +56,7 @@ run_unittests_SOURCES += tsig_unittest.cc
 run_unittests_SOURCES += tsigerror_unittest.cc
 run_unittests_SOURCES += tsigkey_unittest.cc
 run_unittests_SOURCES += tsigrecord_unittest.cc
+run_unittests_SOURCES += character_string_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 # We shouldn't need to include BOTAN_LDFLAGS here, but there

+ 94 - 0
src/lib/dns/tests/character_string_unittest.cc

@@ -0,0 +1,94 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+
+#include <gtest/gtest.h>
+
+#include <dns/rdata.h>
+#include <dns/tests/unittest_util.h>
+#include <dns/character_string.h>
+
+using isc::UnitTestUtil;
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::dns::characterstr;
+using namespace isc::dns::rdata;
+
+namespace {
+class CharacterStringTest : public ::testing::Test {
+};
+
+class CharacterString {
+public:
+    CharacterString(const string& str){
+        string::const_iterator it = str.begin();
+        characterStr_ = getNextCharacterString(str, it);
+    }
+    const string& str() const { return characterStr_; }
+private:
+    string characterStr_;
+};
+
+TEST_F(CharacterStringTest, testNormalCase) {
+    CharacterString cstr1("foo");
+    EXPECT_EQ(string("foo"), cstr1.str());
+
+    // Test <character-string> that separated by space
+    CharacterString cstr2("foo bar");
+    EXPECT_EQ(string("foo"), cstr2.str());
+
+    // Test <character-string> that separated by quotes
+    CharacterString cstr3("\"foo bar\"");
+    EXPECT_EQ(string("foo bar"), cstr3.str());
+
+    // Test <character-string> that not separate by quotes but ended with quotes
+    CharacterString cstr4("foo\"");
+    EXPECT_EQ(string("foo\""), cstr4.str());
+}
+
+TEST_F(CharacterStringTest, testBadCase) {
+    // The <character-string> that started with quotes should also be ended
+    // with quotes
+    EXPECT_THROW(CharacterString cstr("\"foo"), InvalidRdataText);
+
+    // The string length cannot exceed 255 characters
+    string str;
+    for (int i = 0; i < 257; ++i) {
+        str += 'A';
+    }
+    EXPECT_THROW(CharacterString cstr(str), CharStringTooLong);
+}
+
+TEST_F(CharacterStringTest, testEscapeCharacter) {
+    CharacterString cstr1("foo\\bar");
+    EXPECT_EQ(string("foobar"), cstr1.str());
+
+    CharacterString cstr2("foo\\\\bar");
+    EXPECT_EQ(string("foo\\bar"), cstr2.str());
+
+    CharacterString cstr3("fo\\111bar");
+    EXPECT_EQ(string("foobar"), cstr3.str());
+
+    CharacterString cstr4("fo\\1112bar");
+    EXPECT_EQ(string("foo2bar"), cstr4.str());
+
+    // There must be at least 3 digits followed by '\'
+    EXPECT_THROW(CharacterString cstr("foo\\98ar"), InvalidRdataText);
+    EXPECT_THROW(CharacterString cstr("foo\\9ar"), InvalidRdataText);
+    EXPECT_THROW(CharacterString cstr("foo\\98"), InvalidRdataText);
+}
+
+} // namespace