Browse Source

[trac1160] move getToken and numToToken to util

Jelte Jansen 13 years ago
parent
commit
f773f9ac21

+ 47 - 79
src/lib/dns/rdata/any_255/tsig_250.cc

@@ -19,6 +19,7 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/lexical_cast.hpp>
 
 
 #include <util/buffer.h>
 #include <util/buffer.h>
+#include <util/strutil.h>
 #include <util/encode/base64.h>
 #include <util/encode/base64.h>
 
 
 #include <dns/messagerenderer.h>
 #include <dns/messagerenderer.h>
@@ -30,6 +31,7 @@ using namespace std;
 using namespace boost;
 using namespace boost;
 using namespace isc::util;
 using namespace isc::util;
 using namespace isc::util::encode;
 using namespace isc::util::encode;
+using namespace isc::util::str;
 
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
@@ -65,45 +67,6 @@ struct TSIG::TSIGImpl {
     const vector<uint8_t> other_data_;
     const vector<uint8_t> other_data_;
 };
 };
 
 
-namespace {
-string
-getToken(istringstream& iss, const string& full_input) {
-    string token;
-    iss >> token;
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid TSIG text: parse error " <<
-                  full_input);
-    }
-    return (token);
-}
-
-// This helper function converts a string token to an *unsigned* integer.
-// NumType is a *signed* integral type (e.g. int32_t) that is sufficiently
-// wide to store resulting integers.
-// BitSize is the maximum number of bits that the resulting integer can take.
-// This function first checks whether the given token can be converted to
-// an integer of NumType type.  It then confirms the conversion result is
-// within the valid range, i.e., [0, 2^NumType - 1].  The second check is
-// necessary because lexical_cast<T> where T is an unsigned integer type
-// doesn't correctly reject negative numbers when compiled with SunStudio.
-template <typename NumType, int BitSize>
-NumType
-tokenToNum(const string& num_token) {
-    NumType num;
-    try {
-        num = lexical_cast<NumType>(num_token);
-    } catch (const boost::bad_lexical_cast& ex) {
-        isc_throw(InvalidRdataText, "Invalid TSIG numeric parameter: " <<
-                  num_token);
-    }
-    if (num < 0 || num >= (static_cast<NumType>(1) << BitSize)) {
-        isc_throw(InvalidRdataText, "Numeric TSIG parameter out of range: " <<
-                  num);
-    }
-    return (num);
-}
-}
-
 /// \brief Constructor from string.
 /// \brief Constructor from string.
 ///
 ///
 /// \c tsig_str must be formatted as follows:
 /// \c tsig_str must be formatted as follows:
@@ -148,47 +111,52 @@ tokenToNum(const string& num_token) {
 TSIG::TSIG(const std::string& tsig_str) : impl_(NULL) {
 TSIG::TSIG(const std::string& tsig_str) : impl_(NULL) {
     istringstream iss(tsig_str);
     istringstream iss(tsig_str);
 
 
-    const Name algorithm(getToken(iss, tsig_str));
-    const int64_t time_signed = tokenToNum<int64_t, 48>(getToken(iss,
-                                                                 tsig_str));
-    const int32_t fudge = tokenToNum<int32_t, 16>(getToken(iss, tsig_str));
-    const int32_t macsize = tokenToNum<int32_t, 16>(getToken(iss, tsig_str));
-
-    const string mac_txt = (macsize > 0) ? getToken(iss, tsig_str) : "";
-    vector<uint8_t> mac;
-    decodeBase64(mac_txt, mac);
-    if (mac.size() != macsize) {
-        isc_throw(InvalidRdataText, "TSIG MAC size and data are inconsistent");
-    }
-
-    const int32_t orig_id = tokenToNum<int32_t, 16>(getToken(iss, tsig_str));
-
-    const string error_txt = getToken(iss, tsig_str);
-    int32_t error = 0;
-    // XXX: In the initial implementation we hardcode the mnemonics.
-    // We'll soon generalize this.
-    if (error_txt == "BADSIG") {
-        error = 16;
-    } else if (error_txt == "BADKEY") {
-        error = 17;
-    } else if (error_txt == "BADTIME") {
-        error = 18;
-    } else {
-        error = tokenToNum<int32_t, 16>(error_txt);
-    }
-
-    const int32_t otherlen = tokenToNum<int32_t, 16>(getToken(iss, tsig_str));
-    const string otherdata_txt = (otherlen > 0) ? getToken(iss, tsig_str) : "";
-    vector<uint8_t> other_data;
-    decodeBase64(otherdata_txt, other_data);
-
-    if (!iss.eof()) {
-        isc_throw(InvalidRdataText, "Unexpected input for TSIG RDATA: " <<
-                  tsig_str);
+    try {
+        const Name algorithm(getToken(iss));
+        const int64_t time_signed = tokenToNum<int64_t, 48>(getToken(iss));
+        const int32_t fudge = tokenToNum<int32_t, 16>(getToken(iss));
+        const int32_t macsize = tokenToNum<int32_t, 16>(getToken(iss));
+
+        const string mac_txt = (macsize > 0) ? getToken(iss) : "";
+        vector<uint8_t> mac;
+        decodeBase64(mac_txt, mac);
+        if (mac.size() != macsize) {
+            isc_throw(InvalidRdataText, "TSIG MAC size and data are inconsistent");
+        }
+
+        const int32_t orig_id = tokenToNum<int32_t, 16>(getToken(iss));
+
+        const string error_txt = getToken(iss);
+        int32_t error = 0;
+        // XXX: In the initial implementation we hardcode the mnemonics.
+        // We'll soon generalize this.
+        if (error_txt == "BADSIG") {
+            error = 16;
+        } else if (error_txt == "BADKEY") {
+            error = 17;
+        } else if (error_txt == "BADTIME") {
+            error = 18;
+        } else {
+            error = tokenToNum<int32_t, 16>(error_txt);
+        }
+
+        const int32_t otherlen = tokenToNum<int32_t, 16>(getToken(iss));
+        const string otherdata_txt = (otherlen > 0) ? getToken(iss) : "";
+        vector<uint8_t> other_data;
+        decodeBase64(otherdata_txt, other_data);
+
+        if (!iss.eof()) {
+            isc_throw(InvalidRdataText, "Unexpected input for TSIG RDATA: " <<
+                    tsig_str);
+        }
+
+        impl_ = new TSIGImpl(algorithm, time_signed, fudge, mac, orig_id,
+                            error, other_data);
+
+    } catch (StringTokenError ste) {
+        isc_throw(InvalidRdataText, "Invalid TSIG text: " << ste.what() <<
+                  ": " << tsig_str);
     }
     }
-
-    impl_ = new TSIGImpl(algorithm, time_signed, fudge, mac, orig_id,
-                         error, other_data);
 }
 }
 
 
 /// \brief Constructor from wire-format data.
 /// \brief Constructor from wire-format data.

+ 16 - 43
src/lib/dns/rdata/in_1/srv_33.cc

@@ -18,6 +18,7 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/lexical_cast.hpp>
 
 
 #include <util/buffer.h>
 #include <util/buffer.h>
+#include <util/strutil.h>
 
 
 #include <dns/messagerenderer.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/name.h>
@@ -44,39 +45,6 @@ struct SRVImpl {
     Name target_;
     Name target_;
 };
 };
 
 
-namespace {
-string
-getToken(istringstream& iss, const string& full_input) {
-    string token;
-    iss >> token;
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid SRV text: parse error " <<
-                  full_input);
-    }
-    return (token);
-}
-
-// This helper function converts a string token to an *unsigned* integer.
-// NumType is a *signed* integral type (e.g. int32_t) that is sufficiently
-// wide to store resulting integers.
-template <typename NumType, int BitSize>
-NumType
-tokenToNum(const string& num_token) {
-    NumType num;
-    try {
-        num = lexical_cast<NumType>(num_token);
-    } catch (const boost::bad_lexical_cast& ex) {
-        isc_throw(InvalidRdataText, "Invalid SRV numeric parameter: " <<
-                  num_token);
-    }
-    if (num < 0 || num >= (static_cast<NumType>(1) << BitSize)) {
-        isc_throw(InvalidRdataText, "Numeric SRV parameter out of range: " <<
-                  num);
-    }
-    return (num);
-}
-}
-
 /// \brief Constructor from string.
 /// \brief Constructor from string.
 ///
 ///
 /// \c srv_str must be formatted as follows:
 /// \c srv_str must be formatted as follows:
@@ -103,17 +71,22 @@ SRV::SRV(const string& srv_str) :
 {
 {
     istringstream iss(srv_str);
     istringstream iss(srv_str);
 
 
-    const int32_t priority = tokenToNum<int32_t, 16>(getToken(iss, srv_str));
-    const int32_t weight = tokenToNum<int32_t, 16>(getToken(iss, srv_str));
-    const int32_t port = tokenToNum<int32_t, 16>(getToken(iss, srv_str));
-    const Name targetname(getToken(iss, srv_str));
-
-    if (!iss.eof()) {
-        isc_throw(InvalidRdataText, "Unexpected input for SRV RDATA: " <<
-                  srv_str);
+    try {
+        const int32_t priority = str::tokenToNum<int32_t, 16>(str::getToken(iss));
+        const int32_t weight = str::tokenToNum<int32_t, 16>(str::getToken(iss));
+        const int32_t port = str::tokenToNum<int32_t, 16>(str::getToken(iss));
+        const Name targetname(str::getToken(iss));
+
+        if (!iss.eof()) {
+            isc_throw(InvalidRdataText, "Unexpected input for SRV RDATA: " <<
+                    srv_str);
+        }
+
+        impl_ = new SRVImpl(priority, weight, port, targetname);
+    } catch (str::StringTokenError ste) {
+        isc_throw(InvalidRdataText, "Invalid SRV text: " <<
+                  ste.what() << ": " << srv_str);
     }
     }
-
-    impl_ = new SRVImpl(priority, weight, port, targetname);
 }
 }
 
 
 /// \brief Constructor from wire-format data.
 /// \brief Constructor from wire-format data.

+ 11 - 0
src/lib/util/strutil.cc

@@ -132,6 +132,17 @@ format(const std::string& format, const std::vector<std::string>& args) {
     return (result);
     return (result);
 }
 }
 
 
+std::string
+getToken(std::istringstream& iss) {
+    string token;
+    iss >> token;
+    if (iss.bad() || iss.fail()) {
+        isc_throw(StringTokenError, "could not read token from string");
+    }
+    return (token);
+}
+
+
 } // namespace str
 } // namespace str
 } // namespace util
 } // namespace util
 } // namespace isc
 } // namespace isc

+ 62 - 0
src/lib/util/strutil.h

@@ -18,7 +18,10 @@
 #include <algorithm>
 #include <algorithm>
 #include <cctype>
 #include <cctype>
 #include <string>
 #include <string>
+#include <sstream>
 #include <vector>
 #include <vector>
+#include <exceptions/exceptions.h>
+#include <boost/lexical_cast.hpp>
 
 
 namespace isc {
 namespace isc {
 namespace util {
 namespace util {
@@ -26,6 +29,16 @@ namespace str {
 
 
 /// \brief A Set of C++ Utilities for Manipulating Strings
 /// \brief A Set of C++ Utilities for Manipulating Strings
 
 
+///
+/// \brief A standard string util exception that is thrown if getToken or
+/// numToToken are called with bad input data
+///
+class StringTokenError : public Exception {
+public:
+    StringTokenError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
 /// \brief Normalize Backslash
 /// \brief Normalize Backslash
 ///
 ///
 /// Only relevant to Windows, this replaces all "\" in a string with "/" and
 /// Only relevant to Windows, this replaces all "\" in a string with "/" and
@@ -140,6 +153,55 @@ std::string format(const std::string& format,
     const std::vector<std::string>& args);
     const std::vector<std::string>& args);
 
 
 
 
+/// \brief Returns one token from the given stringstream
+///
+/// Using the >> operator, with basic error checking
+///
+/// \exception StringTokenError if the token cannot be read from the stream
+///
+/// \param iss stringstream to read one token from
+///
+/// \return the first token read from the stringstream
+std::string getToken(std::istringstream& iss);
+
+/// \brief Converts a string token to an *unsigned* integer.
+///
+/// The value is converted using a lexical cast, with error and bounds
+/// checking.
+///
+/// NumType is a *signed* integral type (e.g. int32_t) that is sufficiently
+/// wide to store resulting integers.
+///
+/// BitSize is the maximum number of bits that the resulting integer can take.
+/// This function first checks whether the given token can be converted to
+/// an integer of NumType type.  It then confirms the conversion result is
+/// within the valid range, i.e., [0, 2^NumType - 1].  The second check is
+/// necessary because lexical_cast<T> where T is an unsigned integer type
+/// doesn't correctly reject negative numbers when compiled with SunStudio.
+///
+/// \exception StringTokenError if the value is out of range, or if it
+///            could not be converted
+///
+/// \param num_token the string token to convert
+///
+/// \return the converted value, of type NumType
+template <typename NumType, int BitSize>
+NumType
+tokenToNum(const std::string& num_token) {
+    NumType num;
+    try {
+        num = boost::lexical_cast<NumType>(num_token);
+    } catch (const boost::bad_lexical_cast& ex) {
+        isc_throw(StringTokenError, "Invalid SRV numeric parameter: " <<
+                  num_token);
+    }
+    if (num < 0 || num >= (static_cast<NumType>(1) << BitSize)) {
+        isc_throw(StringTokenError, "Numeric SRV parameter out of range: " <<
+                  num);
+    }
+    return (num);
+}
+
 } // namespace str
 } // namespace str
 } // namespace util
 } // namespace util
 } // namespace isc
 } // namespace isc

+ 62 - 0
src/lib/util/tests/strutil_unittest.cc

@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
+#include <stdint.h>
+
 #include <string>
 #include <string>
 
 
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
@@ -213,3 +215,63 @@ TEST_F(StringUtilTest, Formatting) {
     string format9 = "%s %s";
     string format9 = "%s %s";
     EXPECT_EQ(format9, isc::util::str::format(format9, args));
     EXPECT_EQ(format9, isc::util::str::format(format9, args));
 }
 }
+
+TEST_F(StringUtilTest, getToken) {
+    string s("a b c");
+    istringstream ss(s);
+    EXPECT_EQ("a", isc::util::str::getToken(ss));
+    EXPECT_EQ("b", isc::util::str::getToken(ss));
+    EXPECT_EQ("c", isc::util::str::getToken(ss));
+    EXPECT_THROW(isc::util::str::getToken(ss), isc::util::str::StringTokenError);
+}
+
+int32_t tokenToNumCall_32_16(const string& token) {
+    return isc::util::str::tokenToNum<int32_t, 16>(token);
+}
+
+int16_t tokenToNumCall_16_8(const string& token) {
+    return isc::util::str::tokenToNum<int16_t, 8>(token);
+}
+
+TEST_F(StringUtilTest, tokenToNum) {
+    uint32_t num32 = tokenToNumCall_32_16("0");
+    EXPECT_EQ(0, num32);
+    num32 = tokenToNumCall_32_16("123");
+    EXPECT_EQ(123, num32);
+    num32 = tokenToNumCall_32_16("65535");
+    EXPECT_EQ(65535, num32);
+
+    EXPECT_THROW(tokenToNumCall_32_16(""),
+                 isc::util::str::StringTokenError);
+    EXPECT_THROW(tokenToNumCall_32_16("a"),
+                 isc::util::str::StringTokenError);
+    EXPECT_THROW(tokenToNumCall_32_16("-1"),
+                 isc::util::str::StringTokenError);
+    EXPECT_THROW(tokenToNumCall_32_16("65536"),
+                 isc::util::str::StringTokenError);
+    EXPECT_THROW(tokenToNumCall_32_16("1234567890"),
+                 isc::util::str::StringTokenError);
+    EXPECT_THROW(tokenToNumCall_32_16("-1234567890"),
+                 isc::util::str::StringTokenError);
+
+    uint16_t num16 = tokenToNumCall_16_8("123");
+    EXPECT_EQ(123, num16);
+    num16 = tokenToNumCall_16_8("0");
+    EXPECT_EQ(0, num16);
+    num16 = tokenToNumCall_16_8("255");
+    EXPECT_EQ(255, num16);
+
+    EXPECT_THROW(tokenToNumCall_16_8(""),
+                 isc::util::str::StringTokenError);
+    EXPECT_THROW(tokenToNumCall_16_8("a"),
+                 isc::util::str::StringTokenError);
+    EXPECT_THROW(tokenToNumCall_16_8("-1"),
+                 isc::util::str::StringTokenError);
+    EXPECT_THROW(tokenToNumCall_16_8("256"),
+                 isc::util::str::StringTokenError);
+    EXPECT_THROW(tokenToNumCall_16_8("1234567890"),
+                 isc::util::str::StringTokenError);
+    EXPECT_THROW(tokenToNumCall_16_8("-1234567890"),
+                 isc::util::str::StringTokenError);
+
+}