Browse Source

[master] Merge branch 'trac2498'

Conflicts:
	src/lib/dns/gen-rdatacode.py.in
Jelte Jansen 12 years ago
parent
commit
13674dda1c

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

@@ -126,7 +126,6 @@ libb10_dns___la_SOURCES += tsig.h tsig.cc
 libb10_dns___la_SOURCES += tsigerror.h tsigerror.cc
 libb10_dns___la_SOURCES += tsigerror.h tsigerror.cc
 libb10_dns___la_SOURCES += tsigkey.h tsigkey.cc
 libb10_dns___la_SOURCES += tsigkey.h tsigkey.cc
 libb10_dns___la_SOURCES += tsigrecord.h tsigrecord.cc
 libb10_dns___la_SOURCES += tsigrecord.h tsigrecord.cc
-libb10_dns___la_SOURCES += character_string.h character_string.cc
 libb10_dns___la_SOURCES += master_loader_callbacks.h master_loader_callbacks.cc
 libb10_dns___la_SOURCES += master_loader_callbacks.h master_loader_callbacks.cc
 libb10_dns___la_SOURCES += master_loader.h
 libb10_dns___la_SOURCES += master_loader.h
 libb10_dns___la_SOURCES += rrset_collection_base.h
 libb10_dns___la_SOURCES += rrset_collection_base.h

+ 0 - 145
src/lib/dns/character_string.cc

@@ -1,145 +0,0 @@
-// 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 "character_string.h"
-#include "rdata.h"
-
-using namespace std;
-using namespace isc::dns::rdata;
-
-namespace isc {
-namespace dns {
-
-namespace {
-bool isDigit(char c) {
-    return (('0' <= c) && (c <= '9'));
-}
-}
-
-std::string
-characterstr::getNextCharacterString(const std::string& input_str,
-                              std::string::const_iterator& input_iterator,
-                              bool* quoted)
-{
-    string result;
-
-    // If the input string only contains white-spaces, it is an invalid
-    // <character-string>
-    if (input_iterator >= input_str.end()) {
-        isc_throw(InvalidRdataText, "Invalid text format, \
-                  <character-string> field is missing.");
-    }
-
-    // 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 \
-                          prematurely.");
-            } else {
-                if (isDigit(*(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 \
-                                  prematurely.");
-                    } else {
-                        int n = 0;
-                        ++input_iterator;
-                        for (int i = 0; i < 3; ++i) {
-                            if (isDigit(*input_iterator)) {
-                                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 == '"') {
-                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,
-            // it is seperated with <space> char
-            break;
-        }
-
-        result.push_back(*input_iterator);
-
-        ++input_iterator;
-    }
-
-    if (result.size() > MAX_CHARSTRING_LEN) {
-        isc_throw(CharStringTooLong, "<character-string> is too long");
-    }
-
-    if (quotes_separated && !quotes_paired) {
-        isc_throw(InvalidRdataText, "The quotes are not paired");
-    }
-
-    if (quoted != NULL) {
-        *quoted = quotes_separated;
-    }
-
-    return (result);
-}
-
-std::string
-characterstr::getNextCharacterString(util::InputBuffer& buffer, size_t len) {
-    uint8_t str_len = buffer.readUint8();
-
-    size_t pos = buffer.getPosition();
-    if (len - pos < str_len) {
-        isc_throw(InvalidRdataLength, "Invalid string length");
-    }
-
-    uint8_t buf[MAX_CHARSTRING_LEN];
-    buffer.readData(buf, str_len);
-    return (string(buf, buf + str_len));
-}
-
-} // end of namespace dns
-} // end of namespace isc

+ 0 - 60
src/lib/dns/character_string.h

@@ -1,60 +0,0 @@
-// 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.
-
-#ifndef CHARACTER_STRING_H
-#define CHARACTER_STRING_H
-
-#include <string>
-#include <exceptions/exceptions.h>
-#include <util/buffer.h>
-
-namespace isc {
-namespace dns {
-
-// \brief Some utility functions to extract <character-string> from string
-// or InputBuffer
-//
-// <character-string> is expressed in one or two ways: as a contiguous set
-// of characters without interior spaces, or as a string beginning with a "
-// and ending with a ".  Inside a " delimited string any character can
-// occur, except for a " itself, which must be quoted using \ (back slash).
-// Ref. RFC1035
-
-
-namespace characterstr {
-    /// Get a <character-string> from a string
-    ///
-    /// \param input_str The input string
-    /// \param input_iterator The iterator from which to start extracting,
-    ///        the iterator will be updated to new position after the function
-    ///        is returned
-    /// \param quoted If not \c NULL, returns \c true at this address if
-    ///        the string is quoted, \cfalse otherwise
-    /// \return A std::string that contains the extracted <character-string>
-    std::string getNextCharacterString(const std::string& input_str,
-                                       std::string::const_iterator& input_iterator,
-                                       bool* quoted = NULL);
-
-    /// Get a <character-string> from a input buffer
-    ///
-    /// \param buffer The input buffer
-    /// \param len The input buffer total length
-    /// \return A std::string that contains the extracted <character-string>
-    std::string getNextCharacterString(util::InputBuffer& buffer, size_t len);
-
-} // namespace characterstr
-} // namespace dns
-} // namespace isc
-
-#endif // CHARACTER_STRING_H

+ 7 - 2
src/lib/dns/gen-rdatacode.py.in

@@ -32,8 +32,13 @@ import sys
 #
 #
 # Example:
 # Example:
 #     new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
 #     new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
-new_rdata_factory_users = [('soa', 'generic'), ('txt', 'generic'),
-                           ('aaaa', 'in'), ('spf', 'generic')]
+new_rdata_factory_users = [('aaaa', 'in'),
+                           ('hinfo', 'generic'),
+                           ('naptr', 'generic'),
+                           ('soa', 'generic'),
+                           ('spf', 'generic'),
+                           ('txt', 'generic')
+                          ]
 
 
 re_typecode = re.compile('([\da-z]+)_(\d+)')
 re_typecode = re.compile('([\da-z]+)_(\d+)')
 classcode2txt = {}
 classcode2txt = {}

+ 56 - 0
src/lib/dns/rdata/generic/detail/char_string.cc

@@ -14,9 +14,11 @@
 
 
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 
 
+#include <dns/exceptions.h>
 #include <dns/rdata.h>
 #include <dns/rdata.h>
 #include <dns/master_lexer.h>
 #include <dns/master_lexer.h>
 #include <dns/rdata/generic/detail/char_string.h>
 #include <dns/rdata/generic/detail/char_string.h>
+#include <util/buffer.h>
 
 
 #include <boost/lexical_cast.hpp>
 #include <boost/lexical_cast.hpp>
 
 
@@ -114,6 +116,60 @@ charStringToString(const CharString& char_string) {
     return (s);
     return (s);
 }
 }
 
 
+int compareCharStrings(const detail::CharString& self,
+                       const detail::CharString& other) {
+    if (self.size() == 0 && other.size() == 0) {
+        return (0);
+    }
+    if (self.size() == 0) {
+        return (-1);
+    }
+    if (other.size() == 0) {
+        return (1);
+    }
+    const size_t self_len = self[0];
+    const size_t other_len = other[0];
+    const size_t cmp_len = std::min(self_len, other_len);
+    const int cmp = memcmp(&self[1], &other[1], cmp_len);
+    if (cmp < 0) {
+        return (-1);
+    } else if (cmp > 0) {
+        return (1);
+    } else if (self_len < other_len) {
+        return (-1);
+    } else if (self_len > other_len) {
+        return (1);
+    } else {
+        return (0);
+    }
+}
+
+size_t
+bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len,
+                   CharString& target) {
+    if (rdata_len < 1 || buffer.getLength() - buffer.getPosition() < 1) {
+        isc_throw(isc::dns::DNSMessageFORMERR,
+                  "insufficient data to read character-string length");
+    }
+    const uint8_t len = buffer.readUint8();
+    if (rdata_len < len + 1) {
+        isc_throw(isc::dns::DNSMessageFORMERR,
+                  "character string length is too large: " <<
+                  static_cast<int>(len));
+    }
+    if (buffer.getLength() - buffer.getPosition() < len) {
+        isc_throw(isc::dns::DNSMessageFORMERR,
+                  "not enough data in buffer to read character-string of len"
+                  << static_cast<int>(len));
+    }
+
+    target.resize(len + 1);
+    target[0] = len;
+    buffer.readData(&target[0] + 1, len);
+
+    return (len + 1);
+}
+
 } // end of detail
 } // end of detail
 } // end of generic
 } // end of generic
 } // end of rdata
 } // end of rdata

+ 33 - 0
src/lib/dns/rdata/generic/detail/char_string.h

@@ -19,6 +19,7 @@
 
 
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
+#include <algorithm>
 #include <stdint.h>
 #include <stdint.h>
 
 
 namespace isc {
 namespace isc {
@@ -66,6 +67,38 @@ void stringToCharString(const MasterToken::StringRegion& str_region,
 /// \return A string representation of \c char_string.
 /// \return A string representation of \c char_string.
 std::string charStringToString(const CharString& char_string);
 std::string charStringToString(const CharString& char_string);
 
 
+/// \brief Compare two CharString objects
+///
+/// \param self The CharString field to compare
+/// \param other The CharString field to compare to
+///
+/// \return -1 if \c self would be sorted before \c other
+///          1 if \c self would be sorted after \c other
+///          0 if \c self and \c other are equal
+int compareCharStrings(const CharString& self, const CharString& other);
+
+/// \brief Convert a buffer containing a character-string to CharString
+///
+/// This method reads one character-string from the given buffer (in wire
+/// format) and places the result in the given \c CharString object.
+/// Since this is expected to be used in message parsing, the exception it
+/// raises is of that type.
+///
+/// On success, the buffer position is advanced to the end of the char-string,
+/// and the number of bytes read is returned.
+///
+/// \param buffer The buffer to read from.
+/// \param rdata_len The total size of the rr's rdata currently being read
+/// (used for integrity checks in the wire data)
+/// \param target The \c CharString where the result will be stored. Any
+/// existing data in the target will be overwritten.
+/// \throw DNSMessageFORMERR If the available data is not enough to read
+/// the character-string, or if the character-string length is out of bounds
+/// \return The number of bytes read
+size_t bufferToCharString(isc::util::InputBuffer& buffer, size_t rdata_len,
+                          CharString& target);
+
+
 } // namespace detail
 } // namespace detail
 } // namespace generic
 } // namespace generic
 } // namespace rdata
 } // namespace rdata

+ 84 - 66
src/lib/dns/rdata/generic/hinfo_13.cc

@@ -14,66 +14,105 @@
 
 
 #include <config.h>
 #include <config.h>
 
 
-#include <string>
-
-#include <boost/lexical_cast.hpp>
-
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
-
-#include <dns/name.h>
-#include <dns/messagerenderer.h>
+#include <dns/exceptions.h>
 #include <dns/rdata.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 #include <dns/rdataclass.h>
-#include <dns/character_string.h>
-#include <util/strutil.h>
+#include <dns/rdata/generic/detail/char_string.h>
+#include <util/buffer.h>
 
 
 using namespace std;
 using namespace std;
-using boost::lexical_cast;
 using namespace isc::util;
 using namespace isc::util;
 using namespace isc::dns;
 using namespace isc::dns;
-using namespace isc::dns::characterstr;
 
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
 
+class HINFOImpl {
+public:
+    HINFOImpl(const std::string& hinfo_str) {
+        std::istringstream ss(hinfo_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        try {
+            parseHINFOData(lexer);
+            // Should be at end of data now
+            if (lexer.getNextToken(MasterToken::QSTRING, true).getType() !=
+                MasterToken::END_OF_FILE) {
+                isc_throw(InvalidRdataText,
+                          "Invalid HINFO text format: too many fields.");
+            }
+        } catch (const MasterLexer::LexerError& ex) {
+            isc_throw(InvalidRdataText, "Failed to construct HINFO RDATA from "
+                                        << hinfo_str << "': " << ex.what());
+        }
+    }
 
 
-HINFO::HINFO(const std::string& hinfo_str) {
-    string::const_iterator input_iterator = hinfo_str.begin();
+    HINFOImpl(InputBuffer& buffer, size_t rdata_len) {
+        rdata_len -= detail::bufferToCharString(buffer, rdata_len, cpu);
+        rdata_len -= detail::bufferToCharString(buffer, rdata_len, os);
+        if (rdata_len != 0) {
+            isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " <<
+                      "HINFO RDATA: bytes left at end: " <<
+                      static_cast<int>(rdata_len));
+        }
+    }
 
 
-    bool quoted;
-    cpu_ = getNextCharacterString(hinfo_str, input_iterator, &quoted);
+    HINFOImpl(MasterLexer& lexer)
+    {
+        parseHINFOData(lexer);
+    }
 
 
-    skipLeftSpaces(hinfo_str, input_iterator, quoted);
+private:
+    void
+    parseHINFOData(MasterLexer& lexer) {
+        MasterToken token = lexer.getNextToken(MasterToken::QSTRING);
+        stringToCharString(token.getStringRegion(), cpu);
+        token = lexer.getNextToken(MasterToken::QSTRING);
+        stringToCharString(token.getStringRegion(), os);
+    }
 
 
-    os_ = getNextCharacterString(hinfo_str, input_iterator);
+public:
+    detail::CharString cpu;
+    detail::CharString os;
+};
 
 
-    // Skip whitespace at the end.
-    while (input_iterator < hinfo_str.end() && isspace(*input_iterator)) {
-        ++input_iterator;
-    }
-    if (input_iterator < hinfo_str.end()) {
-        isc_throw(InvalidRdataText,
-                  "Invalid HINFO text format: too many fields.");
-    }
-}
+HINFO::HINFO(const std::string& hinfo_str) : impl_(new HINFOImpl(hinfo_str))
+{}
 
 
-HINFO::HINFO(InputBuffer& buffer, size_t rdata_len) {
-    cpu_ = getNextCharacterString(buffer, rdata_len);
-    os_ = getNextCharacterString(buffer, rdata_len);
-}
+
+HINFO::HINFO(InputBuffer& buffer, size_t rdata_len) :
+    impl_(new HINFOImpl(buffer, rdata_len))
+{}
 
 
 HINFO::HINFO(const HINFO& source):
 HINFO::HINFO(const HINFO& source):
-    Rdata(), cpu_(source.cpu_), os_(source.os_)
+    Rdata(), impl_(new HINFOImpl(*source.impl_))
+{
+}
+
+HINFO::HINFO(MasterLexer& lexer, const Name*,
+             MasterLoader::Options, MasterLoaderCallbacks&) :
+    impl_(new HINFOImpl(lexer))
+{}
+
+HINFO&
+HINFO::operator=(const HINFO& source)
 {
 {
+    impl_.reset(new HINFOImpl(*source.impl_));
+    return (*this);
+}
+
+HINFO::~HINFO() {
 }
 }
 
 
 std::string
 std::string
 HINFO::toText() const {
 HINFO::toText() const {
     string result;
     string result;
     result += "\"";
     result += "\"";
-    result += cpu_;
+    result += detail::charStringToString(impl_->cpu);
     result += "\" \"";
     result += "\" \"";
-    result += os_;
+    result += detail::charStringToString(impl_->os);
     result += "\"";
     result += "\"";
     return (result);
     return (result);
 }
 }
@@ -92,49 +131,28 @@ int
 HINFO::compare(const Rdata& other) const {
 HINFO::compare(const Rdata& other) const {
     const HINFO& other_hinfo = dynamic_cast<const HINFO&>(other);
     const HINFO& other_hinfo = dynamic_cast<const HINFO&>(other);
 
 
-    if (cpu_ < other_hinfo.cpu_) {
-        return (-1);
-    } else if (cpu_ > other_hinfo.cpu_) {
-        return (1);
-    }
-
-    if (os_ < other_hinfo.os_) {
-        return (-1);
-    } else if (os_ > other_hinfo.os_) {
-        return (1);
+    const int cmp = compareCharStrings(impl_->cpu, other_hinfo.impl_->cpu);
+    if (cmp != 0) {
+        return (cmp);
     }
     }
-
-    return (0);
+    return (compareCharStrings(impl_->os, other_hinfo.impl_->os));
 }
 }
 
 
-const std::string&
+const std::string
 HINFO::getCPU() const {
 HINFO::getCPU() const {
-    return (cpu_);
+    return (detail::charStringToString(impl_->cpu));
 }
 }
 
 
-const std::string&
+const std::string
 HINFO::getOS() const {
 HINFO::getOS() const {
-    return (os_);
+    return (detail::charStringToString(impl_->os));
 }
 }
 
 
+template <typename T>
 void
 void
-HINFO::skipLeftSpaces(const std::string& input_str,
-                      std::string::const_iterator& input_iterator,
-                      bool optional)
-{
-    if (input_iterator >= input_str.end()) {
-        isc_throw(InvalidRdataText,
-                  "Invalid HINFO text format: field is missing.");
-    }
-
-    if (!isspace(*input_iterator) && !optional) {
-        isc_throw(InvalidRdataText,
-            "Invalid HINFO text format: fields are not separated by space.");
-    }
-    // Skip white spaces
-    while (input_iterator < input_str.end() && isspace(*input_iterator)) {
-        ++input_iterator;
-    }
+HINFO::toWireHelper(T& outputer) const {
+    outputer.writeData(&impl_->cpu[0], impl_->cpu.size());
+    outputer.writeData(&impl_->os[0], impl_->os.size());
 }
 }
 
 
 // END_RDATA_NAMESPACE
 // END_RDATA_NAMESPACE

+ 13 - 25
src/lib/dns/rdata/generic/hinfo_13.h

@@ -17,6 +17,9 @@
 
 
 #include <string>
 #include <string>
 
 
+#include <boost/scoped_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
 #include <dns/name.h>
 #include <dns/name.h>
 #include <dns/rdata.h>
 #include <dns/rdata.h>
 #include <util/buffer.h>
 #include <util/buffer.h>
@@ -28,6 +31,8 @@
 
 
 // BEGIN_RDATA_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
 
+class HINFOImpl;
+
 /// \brief \c HINFO class represents the HINFO rdata defined in
 /// \brief \c HINFO class represents the HINFO rdata defined in
 /// RFC1034, RFC1035
 /// RFC1034, RFC1035
 ///
 ///
@@ -40,38 +45,21 @@ public:
     // END_COMMON_MEMBERS
     // END_COMMON_MEMBERS
 
 
     // HINFO specific methods
     // HINFO specific methods
-    const std::string& getCPU() const;
-    const std::string& getOS() const;
+    ~HINFO();
 
 
-private:
-    /// Skip the left whitespaces of the input string
-    ///
-    /// If \c optional argument is \c true and no spaces occur at the
-    /// current location, then nothing happens. If \c optional is
-    /// \c false and no spaces occur at the current location, then
-    /// the \c InvalidRdataText exception is thrown.
-    ///
-    /// \param input_str The input string
-    /// \param input_iterator From which the skipping started
-    /// \param optional If true, the spaces are optionally skipped.
-    void skipLeftSpaces(const std::string& input_str,
-                        std::string::const_iterator& input_iterator,
-                        bool optional);
+    HINFO& operator=(const HINFO&);
+
+    const std::string getCPU() const;
+    const std::string getOS() const;
 
 
+private:
     /// Helper template function for toWire()
     /// Helper template function for toWire()
     ///
     ///
     /// \param outputer Where to write data in
     /// \param outputer Where to write data in
     template <typename T>
     template <typename T>
-    void toWireHelper(T& outputer) const {
-        outputer.writeUint8(cpu_.size());
-        outputer.writeData(cpu_.c_str(), cpu_.size());
-
-        outputer.writeUint8(os_.size());
-        outputer.writeData(os_.c_str(), os_.size());
-    }
+    void toWireHelper(T& outputer) const;
 
 
-    std::string cpu_;
-    std::string os_;
+    boost::scoped_ptr<HINFOImpl> impl_;
 };
 };
 
 
 
 

+ 156 - 117
src/lib/dns/rdata/generic/naptr_35.cc

@@ -14,119 +14,147 @@
 
 
 #include <config.h>
 #include <config.h>
 
 
-#include <string>
-
-#include <boost/lexical_cast.hpp>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/character_string.h>
 #include <dns/name.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
 #include <dns/rdataclass.h>
+#include <dns/rdata/generic/detail/char_string.h>
+#include <exceptions/exceptions.h>
+
+#include <string>
+#include <boost/lexical_cast.hpp>
 
 
 using namespace std;
 using namespace std;
 using boost::lexical_cast;
 using boost::lexical_cast;
 using namespace isc::util;
 using namespace isc::util;
 using namespace isc::dns;
 using namespace isc::dns;
-using namespace isc::dns::characterstr;
 
 
 // BEGIN_ISC_NAMESPACE
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
 
-namespace {
-/// Skip the left whitespaces of the input string
-///
-/// \param input_str The input string
-/// \param input_iterator From which the skipping started
-void
-skipLeftSpaces(const std::string& input_str,
-               std::string::const_iterator& input_iterator)
-{
-    if (input_iterator >= input_str.end()) {
-        isc_throw(InvalidRdataText,
-                  "Invalid NAPTR text format, field is missing.");
+class NAPTRImpl {
+public:
+    NAPTRImpl() : replacement(".") {}
+
+    NAPTRImpl(InputBuffer& buffer, size_t rdata_len) : replacement(".") {
+        if (rdata_len < 4 || buffer.getLength() - buffer.getPosition() < 4) {
+            isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing "
+                      "NAPTR RDATA wire format: insufficient length ");
+        }
+        order = buffer.readUint16();
+        preference = buffer.readUint16();
+        rdata_len -= 4;
+
+        rdata_len -= detail::bufferToCharString(buffer, rdata_len, flags);
+        rdata_len -= detail::bufferToCharString(buffer, rdata_len, services);
+        rdata_len -= detail::bufferToCharString(buffer, rdata_len, regexp);
+        replacement = Name(buffer);
+        if (rdata_len < 1) {
+            isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing "
+                      "NAPTR RDATA wire format: missing replacement name");
+        }
+        rdata_len -= replacement.getLength();
+
+        if (rdata_len != 0) {
+            isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " <<
+                      "NAPTR RDATA: bytes left at end: " <<
+                      static_cast<int>(rdata_len));
+        }
     }
     }
 
 
-    if (!isspace(*input_iterator)) {
-        isc_throw(InvalidRdataText,
-            "Invalid NAPTR text format, fields are not separated by space.");
+    NAPTRImpl(const std::string& naptr_str) : replacement(".") {
+        std::istringstream ss(naptr_str);
+        MasterLexer lexer;
+        lexer.pushSource(ss);
+
+        try {
+            parseNAPTRData(lexer);
+            // Should be at end of data now
+            if (lexer.getNextToken(MasterToken::QSTRING, true).getType() !=
+                MasterToken::END_OF_FILE) {
+                isc_throw(InvalidRdataText,
+                          "Invalid NAPTR text format: too many fields.");
+            }
+        } catch (const MasterLexer::LexerError& ex) {
+            isc_throw(InvalidRdataText, "Failed to construct NAPTR RDATA from "
+                                        << naptr_str << "': " << ex.what());
+        }
     }
     }
-    // Skip white spaces
-    while (input_iterator < input_str.end() && isspace(*input_iterator)) {
-        ++input_iterator;
-    }
-}
 
 
-} // Anonymous namespace
+    NAPTRImpl(MasterLexer& lexer) : replacement(".")
+    {
+        parseNAPTRData(lexer);
+    }
 
 
-NAPTR::NAPTR(InputBuffer& buffer, size_t len):
-    replacement_(".")
-{
-    order_ = buffer.readUint16();
-    preference_ = buffer.readUint16();
+private:
+    void
+    parseNAPTRData(MasterLexer& lexer) {
+        MasterToken token = lexer.getNextToken(MasterToken::NUMBER);
+        if (token.getNumber() > 65535) {
+            isc_throw(InvalidRdataText,
+                      "Invalid NAPTR text format: order out of range: "
+                      << token.getNumber());
+        }
+        order = token.getNumber();
+        token = lexer.getNextToken(MasterToken::NUMBER);
+        if (token.getNumber() > 65535) {
+            isc_throw(InvalidRdataText,
+                      "Invalid NAPTR text format: preference out of range: "
+                      << token.getNumber());
+        }
+        preference = token.getNumber();
+
+        token = lexer.getNextToken(MasterToken::QSTRING);
+        stringToCharString(token.getStringRegion(), flags);
+        token = lexer.getNextToken(MasterToken::QSTRING);
+        stringToCharString(token.getStringRegion(), services);
+        token = lexer.getNextToken(MasterToken::QSTRING);
+        stringToCharString(token.getStringRegion(), regexp);
+
+        token = lexer.getNextToken(MasterToken::STRING);
+        replacement = Name(token.getString());
+    }
 
 
-    flags_ = getNextCharacterString(buffer, len);
-    services_ = getNextCharacterString(buffer, len);
-    regexp_ = getNextCharacterString(buffer, len);
-    replacement_ = Name(buffer);
-}
 
 
-NAPTR::NAPTR(const std::string& naptr_str):
-    replacement_(".")
-{
-    istringstream iss(naptr_str);
+public:
     uint16_t order;
     uint16_t order;
     uint16_t preference;
     uint16_t preference;
-
-    iss >> order >> preference;
-
-    if (iss.bad() || iss.fail()) {
-        isc_throw(InvalidRdataText, "Invalid NAPTR text format");
-    }
-
-    order_ = order;
-    preference_ = preference;
-
-    string::const_iterator input_iterator = naptr_str.begin() + iss.tellg();
-
-    skipLeftSpaces(naptr_str, input_iterator);
-
-    flags_ = getNextCharacterString(naptr_str, input_iterator);
-
-    skipLeftSpaces(naptr_str, input_iterator);
-
-    services_ = getNextCharacterString(naptr_str, input_iterator);
-
-    skipLeftSpaces(naptr_str, input_iterator);
-
-    regexp_ = getNextCharacterString(naptr_str, input_iterator);
-
-    skipLeftSpaces(naptr_str, input_iterator);
-
-    if (input_iterator < naptr_str.end()) {
-        string replacementStr(input_iterator, naptr_str.end());
-
-        replacement_ = Name(replacementStr);
-    } else {
-        isc_throw(InvalidRdataText,
-                  "Invalid NAPTR text format, replacement field is missing");
-    }
+    detail::CharString flags;
+    detail::CharString services;
+    detail::CharString regexp;
+    Name replacement;
+};
+
+NAPTR::NAPTR(InputBuffer& buffer, size_t rdata_len) :
+    impl_(new NAPTRImpl(buffer, rdata_len))
+{}
+
+NAPTR::NAPTR(const std::string& naptr_str) : impl_(new NAPTRImpl(naptr_str))
+{}
+
+NAPTR::NAPTR(MasterLexer& lexer, const Name*,
+             MasterLoader::Options, MasterLoaderCallbacks&) :
+    impl_(new NAPTRImpl(lexer))
+{}
+
+NAPTR::NAPTR(const NAPTR& naptr) :  Rdata(),
+                                    impl_(new NAPTRImpl(*naptr.impl_))
+{}
+
+NAPTR&
+NAPTR::operator=(const NAPTR& source)
+{
+    impl_.reset(new NAPTRImpl(*source.impl_));
+    return (*this);
 }
 }
 
 
-NAPTR::NAPTR(const NAPTR& naptr):
-    Rdata(), order_(naptr.order_), preference_(naptr.preference_),
-    flags_(naptr.flags_), services_(naptr.services_), regexp_(naptr.regexp_),
-    replacement_(naptr.replacement_)
-{
+NAPTR::~NAPTR() {
 }
 }
 
 
 void
 void
 NAPTR::toWire(OutputBuffer& buffer) const {
 NAPTR::toWire(OutputBuffer& buffer) const {
     toWireHelper(buffer);
     toWireHelper(buffer);
-    replacement_.toWire(buffer);
-
+    impl_->replacement.toWire(buffer);
 }
 }
 
 
 void
 void
@@ -134,23 +162,23 @@ NAPTR::toWire(AbstractMessageRenderer& renderer) const {
     toWireHelper(renderer);
     toWireHelper(renderer);
     // Type NAPTR is not "well-known", and name compression must be disabled
     // Type NAPTR is not "well-known", and name compression must be disabled
     // per RFC3597.
     // per RFC3597.
-    renderer.writeName(replacement_, false);
+    renderer.writeName(impl_->replacement, false);
 }
 }
 
 
 string
 string
 NAPTR::toText() const {
 NAPTR::toText() const {
     string result;
     string result;
-    result += lexical_cast<string>(order_);
+    result += lexical_cast<string>(impl_->order);
     result += " ";
     result += " ";
-    result += lexical_cast<string>(preference_);
+    result += lexical_cast<string>(impl_->preference);
     result += " \"";
     result += " \"";
-    result += flags_;
+    result += detail::charStringToString(impl_->flags);
     result += "\" \"";
     result += "\" \"";
-    result += services_;
+    result += detail::charStringToString(impl_->services);
     result += "\" \"";
     result += "\" \"";
-    result += regexp_;
+    result += detail::charStringToString(impl_->regexp);
     result += "\" ";
     result += "\" ";
-    result += replacement_.toText();
+    result += impl_->replacement.toText();
     return (result);
     return (result);
 }
 }
 
 
@@ -158,67 +186,78 @@ int
 NAPTR::compare(const Rdata& other) const {
 NAPTR::compare(const Rdata& other) const {
     const NAPTR other_naptr = dynamic_cast<const NAPTR&>(other);
     const NAPTR other_naptr = dynamic_cast<const NAPTR&>(other);
 
 
-    if (order_ < other_naptr.order_) {
+    if (impl_->order < other_naptr.impl_->order) {
         return (-1);
         return (-1);
-    } else if (order_ > other_naptr.order_) {
+    } else if (impl_->order > other_naptr.impl_->order) {
         return (1);
         return (1);
     }
     }
 
 
-    if (preference_ < other_naptr.preference_) {
+    if (impl_->preference < other_naptr.impl_->preference) {
         return (-1);
         return (-1);
-    } else if (preference_ > other_naptr.preference_) {
+    } else if (impl_->preference > other_naptr.impl_->preference) {
         return (1);
         return (1);
     }
     }
 
 
-    if (flags_ < other_naptr.flags_) {
-        return (-1);
-    } else if (flags_ > other_naptr.flags_) {
-        return (1);
+    const int fcmp = detail::compareCharStrings(impl_->flags,
+                                                other_naptr.impl_->flags);
+    if (fcmp != 0) {
+        return (fcmp);
     }
     }
 
 
-    if (services_ < other_naptr.services_) {
-        return (-1);
-    } else if (services_ > other_naptr.services_) {
-        return (1);
+    const int scmp = detail::compareCharStrings(impl_->services,
+                                                other_naptr.impl_->services);
+    if (scmp != 0) {
+        return (scmp);
     }
     }
 
 
-    if (regexp_ < other_naptr.regexp_) {
-        return (-1);
-    } else if (regexp_ > other_naptr.regexp_) {
-        return (1);
+    const int rcmp = detail::compareCharStrings(impl_->regexp,
+                                                other_naptr.impl_->regexp);
+    if (rcmp != 0) {
+        return (rcmp);
     }
     }
 
 
-    return (compareNames(replacement_, other_naptr.replacement_));
+    return (compareNames(impl_->replacement, other_naptr.impl_->replacement));
 }
 }
 
 
 uint16_t
 uint16_t
 NAPTR::getOrder() const {
 NAPTR::getOrder() const {
-    return (order_);
+    return (impl_->order);
 }
 }
 
 
 uint16_t
 uint16_t
 NAPTR::getPreference() const {
 NAPTR::getPreference() const {
-    return (preference_);
+    return (impl_->preference);
 }
 }
 
 
-const std::string&
+const std::string
 NAPTR::getFlags() const {
 NAPTR::getFlags() const {
-    return (flags_);
+    return (detail::charStringToString(impl_->flags));
 }
 }
 
 
-const std::string&
+const std::string
 NAPTR::getServices() const {
 NAPTR::getServices() const {
-    return (services_);
+    return (detail::charStringToString(impl_->services));
 }
 }
 
 
-const std::string&
+const std::string
 NAPTR::getRegexp() const {
 NAPTR::getRegexp() const {
-    return (regexp_);
+    return (detail::charStringToString(impl_->regexp));
 }
 }
 
 
 const Name&
 const Name&
 NAPTR::getReplacement() const {
 NAPTR::getReplacement() const {
-    return (replacement_);
+    return (impl_->replacement);
+}
+
+template <typename T>
+void
+NAPTR::toWireHelper(T& outputer) const {
+    outputer.writeUint16(impl_->order);
+    outputer.writeUint16(impl_->preference);
+
+    outputer.writeData(&impl_->flags[0], impl_->flags.size());
+    outputer.writeData(&impl_->services[0], impl_->services.size());
+    outputer.writeData(&impl_->regexp[0], impl_->regexp.size());
 }
 }
 
 
 // END_RDATA_NAMESPACE
 // END_RDATA_NAMESPACE

+ 13 - 22
src/lib/dns/rdata/generic/naptr_35.h

@@ -16,6 +16,8 @@
 
 
 #include <string>
 #include <string>
 
 
+#include <boost/scoped_ptr.hpp>
+
 #include <dns/name.h>
 #include <dns/name.h>
 #include <dns/rdata.h>
 #include <dns/rdata.h>
 #include <util/buffer.h>
 #include <util/buffer.h>
@@ -27,6 +29,8 @@
 
 
 // BEGIN_RDATA_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
 
+class NAPTRImpl;
+
 /// \brief \c NAPTR class represents the NAPTR rdata defined in
 /// \brief \c NAPTR class represents the NAPTR rdata defined in
 /// RFC2915, RFC2168 and RFC3403
 /// RFC2915, RFC2168 and RFC3403
 ///
 ///
@@ -39,37 +43,24 @@ public:
     // END_COMMON_MEMBERS
     // END_COMMON_MEMBERS
 
 
     // NAPTR specific methods
     // NAPTR specific methods
+    ~NAPTR();
+
+    NAPTR& operator=(const NAPTR& source);
+
     uint16_t getOrder() const;
     uint16_t getOrder() const;
     uint16_t getPreference() const;
     uint16_t getPreference() const;
-    const std::string& getFlags() const;
-    const std::string& getServices() const;
-    const std::string& getRegexp() const;
+    const std::string getFlags() const;
+    const std::string getServices() const;
+    const std::string getRegexp() const;
     const Name& getReplacement() const;
     const Name& getReplacement() const;
 private:
 private:
     /// Helper template function for toWire()
     /// Helper template function for toWire()
     ///
     ///
     /// \param outputer Where to write data in
     /// \param outputer Where to write data in
     template <typename T>
     template <typename T>
-    void toWireHelper(T& outputer) const {
-        outputer.writeUint16(order_);
-        outputer.writeUint16(preference_);
-
-        outputer.writeUint8(flags_.size());
-        outputer.writeData(flags_.c_str(), flags_.size());
-
-        outputer.writeUint8(services_.size());
-        outputer.writeData(services_.c_str(), services_.size());
-
-        outputer.writeUint8(regexp_.size());
-        outputer.writeData(regexp_.c_str(), regexp_.size());
-    }
+    void toWireHelper(T& outputer) const;
 
 
-    uint16_t order_;
-    uint16_t preference_;
-    std::string flags_;
-    std::string services_;
-    std::string regexp_;
-    Name replacement_;
+    boost::scoped_ptr<NAPTRImpl> impl_;
 };
 };
 
 
 // END_RDATA_NAMESPACE
 // END_RDATA_NAMESPACE

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

@@ -73,7 +73,6 @@ run_unittests_SOURCES += tsig_unittest.cc
 run_unittests_SOURCES += tsigerror_unittest.cc
 run_unittests_SOURCES += tsigerror_unittest.cc
 run_unittests_SOURCES += tsigkey_unittest.cc
 run_unittests_SOURCES += tsigkey_unittest.cc
 run_unittests_SOURCES += tsigrecord_unittest.cc
 run_unittests_SOURCES += tsigrecord_unittest.cc
-run_unittests_SOURCES += character_string_unittest.cc
 run_unittests_SOURCES += master_loader_callbacks_test.cc
 run_unittests_SOURCES += master_loader_callbacks_test.cc
 run_unittests_SOURCES += rrset_collection_unittest.cc
 run_unittests_SOURCES += rrset_collection_unittest.cc
 run_unittests_SOURCES += zone_checker_unittest.cc
 run_unittests_SOURCES += zone_checker_unittest.cc

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

@@ -1,97 +0,0 @@
-// 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 CharacterString {
-public:
-    CharacterString(const string& str){
-        string::const_iterator it = str.begin();
-        characterStr_ = getNextCharacterString(str, it, &is_quoted_);
-    }
-    const string& str() const { return characterStr_; }
-    bool quoted() const { return (is_quoted_); }
-private:
-    string characterStr_;
-    bool is_quoted_;
-};
-
-TEST(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());
-    EXPECT_FALSE(cstr2.quoted());
-
-    // Test <character-string> that separated by quotes
-    CharacterString cstr3("\"foo bar\"");
-    EXPECT_EQ(string("foo bar"), cstr3.str());
-    EXPECT_TRUE(cstr3.quoted());
-
-    // Test <character-string> that not separate by quotes but ended with quotes
-    CharacterString cstr4("foo\"");
-    EXPECT_EQ(string("foo\""), cstr4.str());
-    EXPECT_FALSE(cstr4.quoted());
-}
-
-TEST(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(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

+ 78 - 0
src/lib/dns/tests/rdata_char_string_unittest.cc

@@ -14,8 +14,10 @@
 
 
 #include <util/unittests/wiredata.h>
 #include <util/unittests/wiredata.h>
 
 
+#include <dns/exceptions.h>
 #include <dns/rdata.h>
 #include <dns/rdata.h>
 #include <dns/rdata/generic/detail/char_string.h>
 #include <dns/rdata/generic/detail/char_string.h>
+#include <util/buffer.h>
 
 
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
@@ -25,8 +27,10 @@
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::dns::rdata;
 using isc::dns::rdata::generic::detail::CharString;
 using isc::dns::rdata::generic::detail::CharString;
+using isc::dns::rdata::generic::detail::bufferToCharString;
 using isc::dns::rdata::generic::detail::stringToCharString;
 using isc::dns::rdata::generic::detail::stringToCharString;
 using isc::dns::rdata::generic::detail::charStringToString;
 using isc::dns::rdata::generic::detail::charStringToString;
+using isc::dns::rdata::generic::detail::compareCharStrings;
 using isc::util::unittests::matchWireData;
 using isc::util::unittests::matchWireData;
 
 
 namespace {
 namespace {
@@ -171,4 +175,78 @@ TEST_F(CharStringTest, charStringToString) {
     }
     }
 }
 }
 
 
+TEST_F(CharStringTest, bufferToCharString) {
+    const size_t chstr_size = sizeof(test_charstr);
+    isc::util::InputBuffer buf(test_charstr, chstr_size);
+    size_t read = bufferToCharString(buf, chstr_size, chstr);
+
+    EXPECT_EQ(chstr_size, read);
+    EXPECT_EQ("Test String", charStringToString(chstr));
+}
+
+TEST_F(CharStringTest, bufferToCharString_bad) {
+    const size_t chstr_size = sizeof(test_charstr);
+    isc::util::InputBuffer buf(test_charstr, chstr_size);
+    // Set valid data in both so we can make sure the charstr is not
+    // modified
+    bufferToCharString(buf, chstr_size, chstr);
+    ASSERT_EQ("Test String", charStringToString(chstr));
+
+    // Should be at end of buffer now, so it should fail
+    EXPECT_THROW(bufferToCharString(buf, chstr_size - 1, chstr),
+                 DNSMessageFORMERR);
+    EXPECT_EQ("Test String", charStringToString(chstr));
+
+    // reset and try to read with too low rdata_len
+    buf.setPosition(0);
+    EXPECT_THROW(bufferToCharString(buf, chstr_size - 1, chstr),
+                 DNSMessageFORMERR);
+    EXPECT_EQ("Test String", charStringToString(chstr));
+
+    // set internal charstring len too high
+    const uint8_t test_charstr_err[] = {
+        sizeof("Test String") + 1,
+        'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
+    };
+    buf = isc::util::InputBuffer(test_charstr_err, sizeof(test_charstr_err));
+    EXPECT_THROW(bufferToCharString(buf, chstr_size, chstr),
+                 DNSMessageFORMERR);
+    EXPECT_EQ("Test String", charStringToString(chstr));
+
+}
+
+
+
+TEST_F(CharStringTest, compareCharString) {
+    CharString charstr;
+    CharString charstr2;
+    CharString charstr_small1;
+    CharString charstr_small2;
+    CharString charstr_large1;
+    CharString charstr_large2;
+    CharString charstr_empty;
+
+    stringToCharString(createStringRegion("test string"), charstr);
+    stringToCharString(createStringRegion("test string"), charstr2);
+    stringToCharString(createStringRegion("test strin"), charstr_small1);
+    stringToCharString(createStringRegion("test strina"), charstr_small2);
+    stringToCharString(createStringRegion("test stringa"), charstr_large1);
+    stringToCharString(createStringRegion("test strinz"), charstr_large2);
+
+    EXPECT_EQ(0, compareCharStrings(charstr, charstr2));
+    EXPECT_EQ(0, compareCharStrings(charstr2, charstr));
+    EXPECT_EQ(1, compareCharStrings(charstr, charstr_small1));
+    EXPECT_EQ(1, compareCharStrings(charstr, charstr_small2));
+    EXPECT_EQ(-1, compareCharStrings(charstr, charstr_large1));
+    EXPECT_EQ(-1, compareCharStrings(charstr, charstr_large2));
+    EXPECT_EQ(-1, compareCharStrings(charstr_small1, charstr));
+    EXPECT_EQ(-1, compareCharStrings(charstr_small2, charstr));
+    EXPECT_EQ(1, compareCharStrings(charstr_large1, charstr));
+    EXPECT_EQ(1, compareCharStrings(charstr_large2, charstr));
+
+    EXPECT_EQ(-1, compareCharStrings(charstr_empty, charstr));
+    EXPECT_EQ(1, compareCharStrings(charstr, charstr_empty));
+    EXPECT_EQ(0, compareCharStrings(charstr_empty, charstr_empty));
+}
+
 } // unnamed namespace
 } // unnamed namespace

+ 23 - 2
src/lib/dns/tests/rdata_hinfo_unittest.cc

@@ -51,10 +51,9 @@ TEST_F(Rdata_HINFO_Test, createFromText) {
     HINFO hinfo(hinfo_str);
     HINFO hinfo(hinfo_str);
     EXPECT_EQ(string("Pentium"), hinfo.getCPU());
     EXPECT_EQ(string("Pentium"), hinfo.getCPU());
     EXPECT_EQ(string("Linux"), hinfo.getOS());
     EXPECT_EQ(string("Linux"), hinfo.getOS());
-
     // Test the text with double quotes in the middle of string
     // Test the text with double quotes in the middle of string
     HINFO hinfo1(hinfo_str1);
     HINFO hinfo1(hinfo_str1);
-    EXPECT_EQ(string("Pen\"tium"), hinfo1.getCPU());
+    EXPECT_EQ(string("Pen\\\"tium"), hinfo1.getCPU());
 }
 }
 
 
 TEST_F(Rdata_HINFO_Test, badText) {
 TEST_F(Rdata_HINFO_Test, badText) {
@@ -96,11 +95,20 @@ TEST_F(Rdata_HINFO_Test, createFromLexer) {
     EXPECT_FALSE(test::createRdataUsingLexer(RRType::HINFO(), RRClass::IN(),
     EXPECT_FALSE(test::createRdataUsingLexer(RRType::HINFO(), RRClass::IN(),
                                              "\"Pentium\" \"Linux\" "
                                              "\"Pentium\" \"Linux\" "
                                              "\"Computer\""));
                                              "\"Computer\""));
+    EXPECT_FALSE(test::createRdataUsingLexer(RRType::HINFO(), RRClass::IN(),
+                                             "\"Pentium\""));
 }
 }
 
 
 TEST_F(Rdata_HINFO_Test, toText) {
 TEST_F(Rdata_HINFO_Test, toText) {
     HINFO hinfo(hinfo_str);
     HINFO hinfo(hinfo_str);
     EXPECT_EQ(hinfo_str, hinfo.toText());
     EXPECT_EQ(hinfo_str, hinfo.toText());
+
+    // will add quotes even if they were not in the original input
+    EXPECT_EQ("\"a\" \"b\"", HINFO("a b").toText());
+    // will not add additional quotes
+    EXPECT_EQ("\"a\" \"b\"", HINFO("\"a\" \"b\"").toText());
+    // And make sure escaped quotes and spaces are left intact
+    EXPECT_EQ("\"a\\\"\" \"b c\"", HINFO("\"a\\\"\" \"b c\"").toText());
 }
 }
 
 
 TEST_F(Rdata_HINFO_Test, toWire) {
 TEST_F(Rdata_HINFO_Test, toWire) {
@@ -135,4 +143,17 @@ TEST_F(Rdata_HINFO_Test, compare) {
     EXPECT_EQ(-1, hinfo.compare(HINFO(hinfo_str_large2)));
     EXPECT_EQ(-1, hinfo.compare(HINFO(hinfo_str_large2)));
 }
 }
 
 
+// Copy/assign test
+TEST_F(Rdata_HINFO_Test, copy) {
+    HINFO hinfo(hinfo_str);
+    HINFO hinfo2(hinfo);
+    HINFO hinfo3 = hinfo;
+
+    EXPECT_EQ(0, hinfo.compare(hinfo2));
+    EXPECT_EQ(0, hinfo.compare(hinfo3));
+
+    hinfo3 = hinfo;
+    EXPECT_EQ(0, hinfo.compare(hinfo3));
+}
+
 }
 }

+ 64 - 12
src/lib/dns/tests/rdata_naptr_unittest.cc

@@ -99,10 +99,12 @@ TEST_F(Rdata_NAPTR_Test, badText) {
     // Order or preference cannot be missed
     // Order or preference cannot be missed
     EXPECT_THROW(const NAPTR naptr("10 \"S\" SIP \"\" _sip._udp.example.com."),
     EXPECT_THROW(const NAPTR naptr("10 \"S\" SIP \"\" _sip._udp.example.com."),
                  InvalidRdataText);
                  InvalidRdataText);
-    // Fields must be seperated by spaces
+    // Unquoted fields must be seperated by spaces
     EXPECT_THROW(const NAPTR naptr("100 10S SIP \"\" _sip._udp.example.com."),
     EXPECT_THROW(const NAPTR naptr("100 10S SIP \"\" _sip._udp.example.com."),
                  InvalidRdataText);
                  InvalidRdataText);
-    EXPECT_THROW(const NAPTR naptr("100 10 \"S\"\"SIP\" \"\" _sip._udp.example.com."),
+    EXPECT_THROW(const NAPTR naptr("10010 \"S\" \"SIP\" \"\" _sip._udp.example.com."),
+                 InvalidRdataText);
+    EXPECT_THROW(const NAPTR naptr("100 10 SSIP \"\" _sip._udp.example.com."),
                  InvalidRdataText);
                  InvalidRdataText);
     // Field cannot be missing
     // Field cannot be missing
     EXPECT_THROW(const NAPTR naptr("100 10 \"S\""), InvalidRdataText);
     EXPECT_THROW(const NAPTR naptr("100 10 \"S\""), InvalidRdataText);
@@ -128,6 +130,26 @@ TEST_F(Rdata_NAPTR_Test, createFromWire) {
     EXPECT_EQ(Name("_sip._udp.example.com."), naptr.getReplacement());
     EXPECT_EQ(Name("_sip._udp.example.com."), naptr.getReplacement());
 }
 }
 
 
+TEST_F(Rdata_NAPTR_Test, createFromWireTooLongDataLen) {
+    static uint8_t naptr_rdata_long[] = {
+    0x00,0x0a,0x00,0x64,0x01,0x53,0x07,0x53,0x49,0x50,0x2b,0x44,0x32,0x55,
+    0x00,0x04,0x5f,0x73,0x69,0x70,0x04,0x5f,0x75,0x64,0x70,0x07,0x65,0x78,
+    0x61,0x6d,0x70,0x6c,0x65,0x03,0x63,0x6f,0x6d,0x00,0xff,0xff,0xff,0xff};
+    InputBuffer input_buffer(naptr_rdata_long, sizeof(naptr_rdata_long));
+    EXPECT_THROW(NAPTR naptr(input_buffer, sizeof(naptr_rdata_long)),
+                 isc::dns::DNSMessageFORMERR);
+}
+
+TEST_F(Rdata_NAPTR_Test, createFromWireTooShortDataLen) {
+    // missing data (just set rdata_len too low)
+    for (size_t i = 0; i < sizeof(naptr_rdata); ++i) {
+        // Just use existing correct buffer but set rdata_len too low
+        InputBuffer input_buffer(naptr_rdata, sizeof(naptr_rdata));
+        EXPECT_THROW(NAPTR naptr(input_buffer, i),
+                     isc::dns::DNSMessageFORMERR);
+    }
+}
+
 TEST_F(Rdata_NAPTR_Test, createFromLexer) {
 TEST_F(Rdata_NAPTR_Test, createFromLexer) {
     const NAPTR rdata_naptr(naptr_str);
     const NAPTR rdata_naptr(naptr_str);
 
 
@@ -161,6 +183,14 @@ TEST_F(Rdata_NAPTR_Test, toWireRenderer) {
 TEST_F(Rdata_NAPTR_Test, toText) {
 TEST_F(Rdata_NAPTR_Test, toText) {
     NAPTR naptr(naptr_str);
     NAPTR naptr(naptr_str);
     EXPECT_EQ(naptr_str, naptr.toText());
     EXPECT_EQ(naptr_str, naptr.toText());
+
+    // will add quotes even if they were not in the original input
+    EXPECT_EQ("10 100 \"S\" \"SIP+D2U\" \".*\" _sip._udp.example.com.",
+              NAPTR("10 100 S SIP+D2U .* _sip._udp.example.com.").toText());
+    // will not add additional quotes
+    EXPECT_EQ("10 100 \"S\" \"SIP+D2U\" \".*\" _sip._udp.example.com.",
+              NAPTR("10 100 \"S\" \"SIP+D2U\" \".*\" _sip._udp.example.com.")
+                .toText());
 }
 }
 
 
 TEST_F(Rdata_NAPTR_Test, compare) {
 TEST_F(Rdata_NAPTR_Test, compare) {
@@ -177,16 +207,38 @@ TEST_F(Rdata_NAPTR_Test, compare) {
     NAPTR naptr_large5(naptr_str_large5);
     NAPTR naptr_large5(naptr_str_large5);
 
 
     EXPECT_EQ(0, naptr.compare(NAPTR(naptr_str)));
     EXPECT_EQ(0, naptr.compare(NAPTR(naptr_str)));
-    EXPECT_EQ(1, naptr.compare(NAPTR(naptr_str_small1)));
-    EXPECT_EQ(1, naptr.compare(NAPTR(naptr_str_small2)));
-    EXPECT_EQ(1, naptr.compare(NAPTR(naptr_str_small3)));
-    EXPECT_EQ(1, naptr.compare(NAPTR(naptr_str_small4)));
-    EXPECT_EQ(1, naptr.compare(NAPTR(naptr_str_small5)));
-    EXPECT_EQ(-1, naptr.compare(NAPTR(naptr_str_large1)));
-    EXPECT_EQ(-1, naptr.compare(NAPTR(naptr_str_large2)));
-    EXPECT_EQ(-1, naptr.compare(NAPTR(naptr_str_large3)));
-    EXPECT_EQ(-1, naptr.compare(NAPTR(naptr_str_large4)));
-    EXPECT_EQ(-1, naptr.compare(NAPTR(naptr_str_large5)));
+    EXPECT_EQ(1, naptr.compare(naptr_small1));
+    EXPECT_EQ(1, naptr.compare(naptr_small2));
+    EXPECT_EQ(1, naptr.compare(naptr_small3));
+    EXPECT_EQ(1, naptr.compare(naptr_small4));
+    EXPECT_EQ(1, naptr.compare(naptr_small5));
+    EXPECT_EQ(-1, naptr.compare(naptr_large1));
+    EXPECT_EQ(-1, naptr.compare(naptr_large2));
+    EXPECT_EQ(-1, naptr.compare(naptr_large3));
+    EXPECT_EQ(-1, naptr.compare(naptr_large4));
+    EXPECT_EQ(-1, naptr.compare(naptr_large5));
+    EXPECT_EQ(-1, naptr_small1.compare(naptr));
+    EXPECT_EQ(-1, naptr_small2.compare(naptr));
+    EXPECT_EQ(-1, naptr_small3.compare(naptr));
+    EXPECT_EQ(-1, naptr_small4.compare(naptr));
+    EXPECT_EQ(-1, naptr_small5.compare(naptr));
+    EXPECT_EQ(1, naptr_large1.compare(naptr));
+    EXPECT_EQ(1, naptr_large2.compare(naptr));
+    EXPECT_EQ(1, naptr_large3.compare(naptr));
+    EXPECT_EQ(1, naptr_large4.compare(naptr));
+    EXPECT_EQ(1, naptr_large5.compare(naptr));
+}
+
+TEST_F(Rdata_NAPTR_Test, copy) {
+    NAPTR naptr(naptr_str);
+    NAPTR naptr2(naptr);
+    NAPTR naptr3 = naptr;
+
+    EXPECT_EQ(0, naptr.compare(naptr2));
+    EXPECT_EQ(0, naptr.compare(naptr3));
+
+    naptr3 = naptr;
+    EXPECT_EQ(0, naptr.compare(naptr3));
 }
 }
 
 
 }
 }