BIND 10 master, updated. a6865a7686a02c7026150be1304ee682e8ddbb51 [master] Merge branch 'trac2382' with fixing Conflicts for src/lib/dns/gen-rdatacode.py.in src/lib/dns/rdata.cc src/lib/dns/rrparamregistry-placeholder.cc src/lib/dns/tests/rdata_hinfo_unittest.cc src/lib/dns/tests/rdata_txt_like_unittest.cc
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Dec 5 19:35:12 UTC 2012
The branch, master has been updated
via a6865a7686a02c7026150be1304ee682e8ddbb51 (commit)
via 816eacf47e4168d336c2f64b1b621f13f8ca6cb4 (commit)
via 09d70952ca89ef967f8652046ed6fe869625b42e (commit)
via 6944e7758d326b69482bcfd7d3f501df5113b394 (commit)
via 970ee33b88d3268780fc4a7d8950ba2a4a8202fd (commit)
via 5d239b6aed71f987330add0bbcfc7baed670e804 (commit)
via 9440d65d7e71ec30e0d268f5f9f5b1980d288b98 (commit)
via dfd0dd105b4fc8054e3b9cfd1bc5547302f54578 (commit)
via e441d6b05a022f3c0a7140ae43fe42d5fd12cce3 (commit)
via 0ad163bb379066067551f1f3623afe43cf5bd327 (commit)
via f7f3060b97886bea4fbc4408a5c432e81096e3a9 (commit)
via b9f1eefe7e7040db4841e75a38b6a9cd1511eb59 (commit)
via 03dc2386b14131c0eb35408952e3ddc8ca017831 (commit)
via 3ae13a89a2f238602d5dd7e3dc12da963de21ec8 (commit)
via f73f27474fe73abacded88f4dad74867331cb402 (commit)
via ca8fc9f4147a8f332280fde6cfad99b963ebc40a (commit)
via b48ecd894a0ee52c132e041f686938bdb230d743 (commit)
via 638a2d7fbb2a0548e002d57f662f51621175a3a4 (commit)
via cb52403a8ad934f8dc32c6404b5c97b65057d63d (commit)
via a9a6007e022bdc61bcec8d01b51562f9f33f8fd3 (commit)
via 3e964a48bd208e8a7dc04ef1ff8de5cf1da5a514 (commit)
via 8e32eb96aad5d079931b5c7afac55a02f332f3cf (commit)
via 6226330df851a092d9df353081fe1d9c10743d36 (commit)
from e66472386a716a31089a2306b9e5d51f7618feeb (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit a6865a7686a02c7026150be1304ee682e8ddbb51
Merge: e664723 816eacf
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Wed Dec 5 11:34:59 2012 -0800
[master] Merge branch 'trac2382'
with fixing Conflicts for
src/lib/dns/gen-rdatacode.py.in
src/lib/dns/rdata.cc
src/lib/dns/rrparamregistry-placeholder.cc
src/lib/dns/tests/rdata_hinfo_unittest.cc
src/lib/dns/tests/rdata_txt_like_unittest.cc
-----------------------------------------------------------------------
Summary of changes:
src/lib/dns/gen-rdatacode.py.in | 29 ++++-
src/lib/dns/master_lexer.cc | 17 ++-
src/lib/dns/master_lexer.h | 7 ++
src/lib/dns/rdata.cc | 108 +++++++++++++++---
src/lib/dns/rdata.h | 41 ++++++-
src/lib/dns/rdata/in_1/aaaa_28.cc | 27 +++--
src/lib/dns/rdata/template.cc | 5 +
src/lib/dns/rrparamregistry-placeholder.cc | 1 +
src/lib/dns/rrparamregistry.h | 35 +++++-
src/lib/dns/tests/master_lexer_state_unittest.cc | 10 ++
src/lib/dns/tests/rdata_unittest.cc | 133 ++++++++++++++++++++++
src/lib/dns/tests/rdata_unittest.h | 2 +
12 files changed, 373 insertions(+), 42 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in
index 5f0f2ef..72b7674 100755
--- a/src/lib/dns/gen-rdatacode.py.in
+++ b/src/lib/dns/gen-rdatacode.py.in
@@ -32,7 +32,7 @@ import sys
#
# Example:
# new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
-new_rdata_factory_users = []
+new_rdata_factory_users = [('aaaa', 'in')]
re_typecode = re.compile('([\da-z]+)_(\d+)')
classcode2txt = {}
@@ -126,6 +126,9 @@ class AbstractMessageRenderer;\n\n'''
explicit ''' + type_utxt + '''(const std::string& type_str);
''' + type_utxt + '''(isc::util::InputBuffer& buffer, size_t rdata_len);
''' + type_utxt + '''(const ''' + type_utxt + '''& other);
+ ''' + type_utxt + '''(
+ MasterLexer& lexer, const Name* name,
+ MasterLoader::Options options, MasterLoaderCallbacks& callbacks);
virtual std::string toText() const;
virtual void toWire(isc::util::OutputBuffer& buffer) const;
virtual void toWire(AbstractMessageRenderer& renderer) const;
@@ -213,17 +216,33 @@ def generate_rdatadef(file, basemtime):
rdata_deffile.write(class_definitions)
rdata_deffile.close()
-def generate_rdatahdr(file, declarations, basemtime):
+def generate_rdatahdr(file, heading, declarations, basemtime):
if not need_generate(file, basemtime):
print('skip generating ' + file);
return
+ heading += '''
+#ifndef DNS_RDATACLASS_H
+#define DNS_RDATACLASS_H 1
+
+#include <dns/master_loader.h>
+
+namespace isc {
+namespace dns {
+class Name;
+class MasterLexer;
+class MasterLoaderCallbacks;
+}
+}
+'''
declarations += '''
+#endif // DNS_RDATACLASS_H
+
// Local Variables:
// mode: c++
// End:
'''
rdata_header = open(file, 'w')
- rdata_header.write(heading_txt)
+ rdata_header.write(heading)
rdata_header.write(declarations)
rdata_header.close()
@@ -320,8 +339,8 @@ if __name__ == "__main__":
try:
import_definitions(classcode2txt, typecode2txt, typeandclass)
generate_rdatadef('@builddir@/rdataclass.cc', rdatadef_mtime)
- generate_rdatahdr('@builddir@/rdataclass.h', rdata_declarations,
- rdatahdr_mtime)
+ generate_rdatahdr('@builddir@/rdataclass.h', heading_txt,
+ rdata_declarations, rdatahdr_mtime)
generate_typeclasscode('rrtype', rdatahdr_mtime, typecode2txt, 'Type')
generate_typeclasscode('rrclass', classdir_mtime,
classcode2txt, 'Class')
diff --git a/src/lib/dns/master_lexer.cc b/src/lib/dns/master_lexer.cc
index f1f5749..b3b78c0 100644
--- a/src/lib/dns/master_lexer.cc
+++ b/src/lib/dns/master_lexer.cc
@@ -458,8 +458,11 @@ String::handle(MasterLexer& lexer) const {
if (getLexerImpl(lexer)->isTokenEnd(c, escaped)) {
getLexerImpl(lexer)->source_->ungetChar();
+ // make sure it nul-terminated as a c-str (excluded from token
+ // data).
+ data.push_back('\0');
getLexerImpl(lexer)->token_ =
- MasterToken(&data.at(0), data.size());
+ MasterToken(&data.at(0), data.size() - 1);
return;
}
escaped = (c == '\\' && !escaped);
@@ -486,7 +489,10 @@ QString::handle(MasterLexer& lexer) const {
escaped = false;
data.back() = '"';
} else {
- token = MasterToken(&data.at(0), data.size(), true);
+ // make sure it nul-terminated as a c-str (excluded from token
+ // data). This also simplifies the case of an empty string.
+ data.push_back('\0');
+ token = MasterToken(&data.at(0), data.size() - 1, true);
return;
}
} else if (c == '\n' && !escaped) {
@@ -516,9 +522,10 @@ Number::handle(MasterLexer& lexer) const {
getLexerImpl(lexer)->source_->getChar(), escaped);
if (getLexerImpl(lexer)->isTokenEnd(c, escaped)) {
getLexerImpl(lexer)->source_->ungetChar();
+ // We need to close the string whether it's digits-only (for
+ // lexical_cast) or not (see String::handle()).
+ data.push_back('\0');
if (digits_only) {
- // Close the string for lexical_cast
- data.push_back('\0');
try {
const uint32_t number32 =
boost::lexical_cast<uint32_t, const char*>(&data[0]);
@@ -529,7 +536,7 @@ Number::handle(MasterLexer& lexer) const {
token = MasterToken(MasterToken::NUMBER_OUT_OF_RANGE);
}
} else {
- token = MasterToken(&data.at(0), data.size());
+ token = MasterToken(&data.at(0), data.size() - 1);
}
return;
}
diff --git a/src/lib/dns/master_lexer.h b/src/lib/dns/master_lexer.h
index fdc69fc..35586fe 100644
--- a/src/lib/dns/master_lexer.h
+++ b/src/lib/dns/master_lexer.h
@@ -90,6 +90,13 @@ public:
/// the region. On the other hand, it is not ensured that the string
/// is nul-terminated. So the usual string manipulation API may not work
/// as expected.
+ ///
+ /// The `MasterLexer` implementation ensures that there are at least
+ /// len + 1 bytes of valid memory region starting from beg, and that
+ /// beg[len] is \0. This means the application can use the bytes as a
+ /// validly nul-terminated C string if there is no intermediate nul
+ /// character. Note also that due to this property beg is always non
+ /// NULL; for an empty string len will be set to 0 and beg[0] is \0.
struct StringRegion {
const char* beg; ///< The start address of the string
size_t len; ///< The length of the string in bytes
diff --git a/src/lib/dns/rdata.cc b/src/lib/dns/rdata.cc
index 46224c6..081f855 100644
--- a/src/lib/dns/rdata.cc
+++ b/src/lib/dns/rdata.cc
@@ -12,6 +12,20 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+
+#include <dns/name.h>
+#include <dns/messagerenderer.h>
+#include <dns/master_lexer.h>
+#include <dns/rdata.h>
+#include <dns/rrparamregistry.h>
+#include <dns/rrtype.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/shared_ptr.hpp>
+
#include <algorithm>
#include <cctype>
#include <string>
@@ -24,16 +38,6 @@
#include <stdint.h>
#include <string.h>
-#include <boost/lexical_cast.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <util/buffer.h>
-#include <dns/name.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rrparamregistry.h>
-#include <dns/rrtype.h>
-
using namespace std;
using boost::lexical_cast;
using namespace isc::util;
@@ -81,23 +85,92 @@ createRdata(const RRType& rrtype, const RRClass& rrclass, const Rdata& source)
source));
}
+namespace {
+void
+fromtextError(bool& error_issued, const MasterLexer& lexer,
+ MasterLoaderCallbacks& callbacks,
+ const MasterToken* token, const char* reason)
+{
+ // Don't be too noisy if there are many issues for single RDATA
+ if (error_issued) {
+ return;
+ }
+ error_issued = true;
+
+ if (token == NULL) {
+ callbacks.error(lexer.getSourceName(), lexer.getSourceLine(),
+ "createRdata from text failed: " + string(reason));
+ return;
+ }
+
+ switch (token->getType()) {
+ case MasterToken::STRING:
+ case MasterToken::QSTRING:
+ callbacks.error(lexer.getSourceName(), lexer.getSourceLine(),
+ "createRdata from text failed near '" +
+ token->getString() + "': " + string(reason));
+ break;
+ case MasterToken::ERROR:
+ callbacks.error(lexer.getSourceName(), lexer.getSourceLine(),
+ "createRdata from text failed: " +
+ token->getErrorText());
+ break;
+ default:
+ // This case shouldn't happen based on how we use MasterLexer in
+ // createRdata(), so we could assert() that here. But since it
+ // depends on detailed behavior of other classes, we treat the case
+ // in a bit less harsh way.
+ isc_throw(Unexpected, "bug: createRdata() saw unexpected token type");
+ }
+}
+}
+
RdataPtr
createRdata(const RRType& rrtype, const RRClass& rrclass,
MasterLexer& lexer, const Name* origin,
MasterLoader::Options options,
MasterLoaderCallbacks& callbacks)
{
- RdataPtr ret;
+ RdataPtr rdata;
+ bool error_issued = false;
try {
- ret = RRParamRegistry::getRegistry().createRdata(rrtype, rrclass,
- lexer, origin,
- options, callbacks);
- } catch (...) {
- // ret is NULL here.
+ rdata = RRParamRegistry::getRegistry().createRdata(
+ rrtype, rrclass, lexer, origin, options, callbacks);
+ } catch (const MasterLexer::LexerError& error) {
+ fromtextError(error_issued, lexer, callbacks, &error.token_, "");
+ } catch (const Exception& ex) {
+ // Catching all isc::Exception is too broad, but right now we don't
+ // have better granularity. When we complete #2518 we can make this
+ // finer.
+ fromtextError(error_issued, lexer, callbacks, NULL, ex.what());
}
+ // Other exceptions mean a serious implementation bug or fatal system
+ // error; it doesn't make sense to catch and try to recover from them
+ // here. Just propagate.
+
+ // Consume to end of line / file.
+ // Call callback via fromtextError once if there was an error.
+ do {
+ const MasterToken& token = lexer.getNextToken();
+ switch (token.getType()) {
+ case MasterToken::END_OF_LINE:
+ return (rdata);
+ case MasterToken::END_OF_FILE:
+ callbacks.warning(lexer.getSourceName(), lexer.getSourceLine(),
+ "file does not end with newline");
+ return (rdata);
+ default:
+ rdata.reset(); // we'll return NULL
+ fromtextError(error_issued, lexer, callbacks, &token,
+ "extra input text");
+ // Continue until we see EOL or EOF
+ }
+ } while (true);
- return (ret);
+ // We shouldn't reach here
+ assert(false);
+ return (RdataPtr()); // add explicit return to silence some compilers
}
int
@@ -214,6 +287,7 @@ Generic::Generic(MasterLexer& lexer, const Name*,
const MasterToken& token = lexer.getNextToken();
if ((token.getType() == MasterToken::END_OF_FILE) ||
(token.getType() == MasterToken::END_OF_LINE)) {
+ lexer.ungetToken(); // let the upper layer handle the end-of token
break;
}
diff --git a/src/lib/dns/rdata.h b/src/lib/dns/rdata.h
index e7811c9..4cd63cc 100644
--- a/src/lib/dns/rdata.h
+++ b/src/lib/dns/rdata.h
@@ -485,8 +485,47 @@ RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
const Rdata& source);
-/// \brief Create RDATA of a given pair of RR type and class from the
+/// \brief Create RDATA of a given pair of RR type and class using the
/// master lexer.
+///
+/// This is a more generic form of factory from textual RDATA, and is mainly
+/// intended to be used internally by the master file parser (\c MasterLoader)
+/// of this library.
+///
+/// The \c lexer is expected to be at the beginning of textual RDATA of the
+/// specified type and class. This function (and its underlying Rdata
+/// implementations) extracts necessary tokens from the lexer and constructs
+/// the RDATA from them.
+///
+/// Due to the intended usage of this version, this function handles error
+/// cases quite differently from other versions. It internally catches
+/// most of syntax and semantics errors of the input (reported as exceptions),
+/// calls the corresponding callback specified by the \c callbacks parameters,
+/// and returns a NULL smart pointer. If the caller rather wants to get
+/// an exception in these cases, it can pass a callback that internally
+/// throws on error. Some critical exceptions such as \c std::bad_alloc are
+/// still propagated to the upper layer as it doesn't make sense to try
+/// recovery from such a situation within this function.
+///
+/// Whether or not the creation succeeds, this function updates the lexer
+/// until it reaches either the end of line or file, starting from the end of
+/// the RDATA text (or the point of failure if the parsing fails in the
+/// middle of it). The caller can therefore assume it's ready for reading
+/// the next data (which is normally a subsequent RR in the zone file) on
+/// return, whether or not this function succeeds.
+///
+/// \param rrtype An \c RRType object specifying the type/class pair.
+/// \param rrclass An \c RRClass object specifying the type/class pair.
+/// \param lexer A \c MasterLexer object parsing a master file for the
+/// RDATA to be created
+/// \param origin If non NULL, specifies the origin of any domain name fields
+/// of the RDATA that are non absolute.
+/// \param options Master loader options controlling how to deal with errors
+/// or non critical issues in the parsed RDATA.
+/// \param callbacks Callback to be called when an error or non critical issue
+/// is found.
+/// \return An \c RdataPtr object pointing to the created
+/// \c Rdata object. Will be NULL if parsing fails.
RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
MasterLexer& lexer, const Name* origin,
MasterLoader::Options options,
diff --git a/src/lib/dns/rdata/in_1/aaaa_28.cc b/src/lib/dns/rdata/in_1/aaaa_28.cc
index ce49a04..0466f1a 100644
--- a/src/lib/dns/rdata/in_1/aaaa_28.cc
+++ b/src/lib/dns/rdata/in_1/aaaa_28.cc
@@ -12,6 +12,15 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <exceptions/exceptions.h>
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/master_lexer.h>
+#include <dns/master_loader.h>
+
#include <stdint.h>
#include <string.h>
@@ -20,14 +29,6 @@
#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards
#include <sys/socket.h> // for AF_INET/AF_INET6
-#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-#include <dns/exceptions.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-
using namespace std;
using namespace isc::util;
@@ -42,6 +43,16 @@ AAAA::AAAA(const std::string& addrstr) {
}
}
+AAAA::AAAA(MasterLexer& lexer, const Name*,
+ MasterLoader::Options, MasterLoaderCallbacks&)
+{
+ const MasterToken& token = lexer.getNextToken(MasterToken::STRING);
+ if (inet_pton(AF_INET6, token.getStringRegion().beg, &addr_) != 1) {
+ isc_throw(InvalidRdataText, "Failed to convert '"
+ << token.getString() << "' to IN/AAAA RDATA");
+ }
+}
+
AAAA::AAAA(InputBuffer& buffer, size_t rdata_len) {
if (rdata_len != sizeof(addr_)) {
isc_throw(DNSMessageFORMERR,
diff --git a/src/lib/dns/rdata/template.cc b/src/lib/dns/rdata/template.cc
index ee1097e..6486e6a 100644
--- a/src/lib/dns/rdata/template.cc
+++ b/src/lib/dns/rdata/template.cc
@@ -34,6 +34,11 @@ using namespace isc::util;
// If you added member functions specific to this derived class, you'll need
// to implement them here, of course.
+MyType::MyType(MasterLexer& lexer, const Name* origin,
+ MasterLoader::Options options, MasterLoaderCallbacks& callbacks)
+{
+}
+
MyType::MyType(const string& type_str) {
}
diff --git a/src/lib/dns/rrparamregistry-placeholder.cc b/src/lib/dns/rrparamregistry-placeholder.cc
index 8160851..16ec23c 100644
--- a/src/lib/dns/rrparamregistry-placeholder.cc
+++ b/src/lib/dns/rrparamregistry-placeholder.cc
@@ -54,6 +54,7 @@ AbstractRdataFactory::create(MasterLexer& lexer, const Name*,
const MasterToken& token = lexer.getNextToken();
if ((token.getType() == MasterToken::END_OF_FILE) ||
(token.getType() == MasterToken::END_OF_LINE)) {
+ lexer.ungetToken(); // let the upper layer handle the end-of token
break;
}
diff --git a/src/lib/dns/rrparamregistry.h b/src/lib/dns/rrparamregistry.h
index e156dc9..56ae981 100644
--- a/src/lib/dns/rrparamregistry.h
+++ b/src/lib/dns/rrparamregistry.h
@@ -119,10 +119,22 @@ public:
/// \return An \c RdataPtr object pointing to the created \c Rdata object.
virtual RdataPtr create(const rdata::Rdata& source) const = 0;
- /// \brief Create RDATA from MasterLexer
- virtual RdataPtr create(MasterLexer& lexer, const Name*,
- MasterLoader::Options,
- MasterLoaderCallbacks&) const;
+ /// \brief Create RDATA using MasterLexer.
+ ///
+ /// This version of the method defines the entry point of factory
+ /// of a specific RR type and class for \c RRParamRegistry::createRdata()
+ /// that uses \c MasterLexer. See its description for the expected
+ /// behavior and meaning of the parameters.
+ ///
+ /// \note Right now this is not defined as a pure virtual method and
+ /// provides the default implementation. This is an intermediate
+ /// workaround until we implement the underlying constructor for all
+ /// supported \c Rdata classes; once it's completed the workaround
+ /// default implementation should be removed and this method should become
+ /// pure virtual.
+ virtual RdataPtr create(MasterLexer& lexer, const Name* origin,
+ MasterLoader::Options options,
+ MasterLoaderCallbacks& callbacks) const;
//@}
};
@@ -504,9 +516,20 @@ public:
rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
const rdata::Rdata& source);
- /// \brief Create RDATA from MasterLexer
+ /// \brief Create RDATA using MasterLexer
+ ///
+ /// This method is expected to be used as the underlying implementation
+ /// of the same signature of \c rdata::createRdata(). One main
+ /// difference is that this method is only responsible for constructing
+ /// the Rdata; it doesn't update the lexer to reach the end of line or
+ /// file or doesn't care about whether there's an extra (garbage) token
+ /// after the textual RDATA representation. Another difference is that
+ /// this method can throw on error and never returns a NULL pointer.
+ ///
+ /// For other details and parameters, see the description of
+ /// \c rdata::createRdata().
rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
- MasterLexer& lexer, const Name* name,
+ MasterLexer& lexer, const Name* origin,
MasterLoader::Options options,
MasterLoaderCallbacks& callbacks);
//@}
diff --git a/src/lib/dns/tests/master_lexer_state_unittest.cc b/src/lib/dns/tests/master_lexer_state_unittest.cc
index 7645ede..846c4c2 100644
--- a/src/lib/dns/tests/master_lexer_state_unittest.cc
+++ b/src/lib/dns/tests/master_lexer_state_unittest.cc
@@ -269,6 +269,10 @@ stringTokenCheck(const std::string& expected, const MasterToken& token,
token.getStringRegion().beg +
token.getStringRegion().len);
EXPECT_EQ(expected, actual);
+
+ // There should be "hidden" nul-terminator after the string data.
+ ASSERT_NE(static_cast<const char*>(NULL), token.getStringRegion().beg);
+ EXPECT_EQ(0, *(token.getStringRegion().beg + token.getStringRegion().len));
}
TEST_F(MasterLexerStateTest, string) {
@@ -365,6 +369,7 @@ TEST_F(MasterLexerStateTest, stringEscape) {
TEST_F(MasterLexerStateTest, quotedString) {
ss << "\"ignore-quotes\"\n";
ss << "\"quoted string\" "; // space is part of the qstring
+ ss << "\"\" "; // empty quoted string
// also check other separator characters. note that \r doesn't cause
// UNBALANCED_QUOTES. Not sure if it's intentional, but that's how the
// BIND 9 version works, so we follow it (it should be too minor to matter
@@ -391,6 +396,11 @@ TEST_F(MasterLexerStateTest, quotedString) {
s_qstring.handle(lexer);
stringTokenCheck("quoted string", s_string.getToken(lexer), true);
+ // Empty string is okay as qstring
+ EXPECT_EQ(&s_qstring, State::start(lexer, options));
+ s_qstring.handle(lexer);
+ stringTokenCheck("", s_string.getToken(lexer), true);
+
// Also checks other separator characters within a qstring
EXPECT_EQ(&s_qstring, State::start(lexer, options));
s_qstring.handle(lexer);
diff --git a/src/lib/dns/tests/rdata_unittest.cc b/src/lib/dns/tests/rdata_unittest.cc
index bc91f7a..7f0dd65 100644
--- a/src/lib/dns/tests/rdata_unittest.cc
+++ b/src/lib/dns/tests/rdata_unittest.cc
@@ -29,6 +29,7 @@
#include <dns/tests/rdata_unittest.h>
#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
using isc::UnitTestUtil;
using namespace std;
@@ -82,6 +83,138 @@ createRdataUsingLexer(const RRType& rrtype, const RRClass& rrclass,
} // end of namespace isc::dns::rdata::test
+// A mock class to check parameters passed via loader callbacks. Its callback
+// records the passed parameters, allowing the test to check them later via
+// the check() method.
+class CreateRdataCallback {
+public:
+ enum CallbackType { NONE, ERROR, WARN };
+ CreateRdataCallback() : type_(NONE), line_(0) {}
+ void callback(CallbackType type, const string& source, size_t line,
+ const string& reason_txt) {
+ type_ = type;
+ source_ = source;
+ line_ = line;
+ reason_txt_ = reason_txt;
+ }
+
+ void clear() {
+ type_ = NONE;
+ source_.clear();
+ line_ = 0;
+ reason_txt_.clear();
+ }
+
+ // Return if callback is called since the previous call to clear().
+ bool isCalled() const { return (type_ != NONE); }
+
+ void check(const string& expected_srcname, size_t expected_line,
+ CallbackType expected_type, const string& expected_reason)
+ const
+ {
+ EXPECT_EQ(expected_srcname, source_);
+ EXPECT_EQ(expected_line, line_);
+ EXPECT_EQ(expected_type, type_);
+ EXPECT_EQ(expected_reason, reason_txt_);
+ }
+
+private:
+ CallbackType type_;
+ string source_;
+ size_t line_;
+ string reason_txt_;
+};
+
+// Test class/type-independent behavior of createRdata().
+TEST_F(RdataTest, createRdataWithLexer) {
+ const in::AAAA aaaa_rdata("2001:db8::1");
+
+ stringstream ss;
+ const string src_name = "stream-" + boost::lexical_cast<string>(&ss);
+ ss << aaaa_rdata.toText() << "\n"; // valid case
+ ss << aaaa_rdata.toText() << "; comment, should be ignored\n";
+ ss << aaaa_rdata.toText() << " extra-token\n"; // extra token
+ ss << aaaa_rdata.toText() << " extra token\n"; // 2 extra tokens
+ ss << ")\n"; // causing lexer error in parsing the RDATA text
+ ss << "192.0.2.1\n"; // semantics error: IPv4 address is given for AAAA
+ ss << aaaa_rdata.toText(); // valid, but end with EOF, not EOL
+ lexer.pushSource(ss);
+
+ CreateRdataCallback callback;
+ MasterLoaderCallbacks callbacks(
+ boost::bind(&CreateRdataCallback::callback, &callback,
+ CreateRdataCallback::ERROR, _1, _2, _3),
+ boost::bind(&CreateRdataCallback::callback, &callback,
+ CreateRdataCallback::WARN, _1, _2, _3));
+
+ size_t line = 0;
+
+ // Valid case.
+ ++line;
+ ConstRdataPtr rdata = createRdata(RRType::AAAA(), RRClass::IN(), lexer,
+ NULL, MasterLoader::MANY_ERRORS,
+ callbacks);
+ EXPECT_EQ(0, aaaa_rdata.compare(*rdata));
+ EXPECT_FALSE(callback.isCalled());
+
+ // Similar to the previous case, but RDATA is followed by a comment.
+ // It should cause any confusion.
+ ++line;
+ callback.clear();
+ rdata = createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks);
+ EXPECT_EQ(0, aaaa_rdata.compare(*rdata));
+ EXPECT_FALSE(callback.isCalled());
+
+ // Broken RDATA text: extra token. createRdata() returns NULL, error
+ // callback is called.
+ ++line;
+ callback.clear();
+ EXPECT_FALSE(createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks));
+ callback.check(src_name, line, CreateRdataCallback::ERROR,
+ "createRdata from text failed near 'extra-token': "
+ "extra input text");
+
+ // Similar to the previous case, but only the first extra token triggers
+ // callback.
+ ++line;
+ callback.clear();
+ EXPECT_FALSE(createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks));
+ callback.check(src_name, line, CreateRdataCallback::ERROR,
+ "createRdata from text failed near 'extra': "
+ "extra input text");
+
+ // Lexer error will happen, corresponding error callback will be triggered.
+ ++line;
+ callback.clear();
+ EXPECT_FALSE(createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks));
+ callback.check(src_name, line, CreateRdataCallback::ERROR,
+ "createRdata from text failed: unbalanced parentheses");
+
+ // Semantics level error will happen, corresponding error callback will be
+ // triggered.
+ ++line;
+ callback.clear();
+ EXPECT_FALSE(createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks));
+ callback.check(src_name, line, CreateRdataCallback::ERROR,
+ "createRdata from text failed: Failed to convert "
+ "'192.0.2.1' to IN/AAAA RDATA");
+
+ // Input is valid and parse will succeed, but with a warning that the
+ // file is not ended with a newline.
+ ++line;
+ callback.clear();
+ rdata = createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
+ MasterLoader::MANY_ERRORS, callbacks);
+ EXPECT_EQ(0, aaaa_rdata.compare(*rdata));
+ callback.check(src_name, line, CreateRdataCallback::WARN,
+ "file does not end with newline");
+}
+
}
}
}
diff --git a/src/lib/dns/tests/rdata_unittest.h b/src/lib/dns/tests/rdata_unittest.h
index 3efb5d8..af19311 100644
--- a/src/lib/dns/tests/rdata_unittest.h
+++ b/src/lib/dns/tests/rdata_unittest.h
@@ -20,6 +20,7 @@
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include <dns/rdata.h>
+#include <dns/master_lexer.h>
#include <gtest/gtest.h>
@@ -40,6 +41,7 @@ protected:
/// This is an RDATA object of some "unknown" RR type so that it can be
/// used to test the compare() method against a well-known RR type.
RdataPtr rdata_nomatch;
+ MasterLexer lexer;
};
namespace test {
More information about the bind10-changes
mailing list