-// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013 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
#include <boost/lexical_cast.hpp>
+#include <dns/rdata/generic/detail/lexer_util.h>
+
using namespace std;
+using boost::lexical_cast;
using namespace isc::util;
-using namespace isc::util::str;
+using isc::dns::rdata::generic::detail::createNameFromLexer;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
AFSDB::AFSDB(const std::string& afsdb_str) :
subtype_(0), server_(Name::ROOT_NAME())
{
- istringstream iss(afsdb_str);
-
try {
- const uint32_t subtype = tokenToNum<int32_t, 16>(getToken(iss));
- const Name servername(getToken(iss));
+ std::istringstream ss(afsdb_str);
+ MasterLexer lexer;
+ lexer.pushSource(ss);
- if (!iss.eof()) {
- isc_throw(InvalidRdataText, "Unexpected input for AFSDB"
- "RDATA: " << afsdb_str);
+ createFromLexer(lexer, NULL);
+
+ if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
+ isc_throw(InvalidRdataText, "extra input text for AFSDB: "
+ << afsdb_str);
}
+ } catch (const MasterLexer::LexerError& ex) {
+ isc_throw(InvalidRdataText, "Failed to construct AFSDB from '" <<
+ afsdb_str << "': " << ex.what());
+ }
+}
- subtype_ = subtype;
- server_ = servername;
+/// \brief Constructor with a context of MasterLexer.
+///
+/// The \c lexer should point to the beginning of valid textual representation
+/// of an AFSDB RDATA. The EXCHANGE field can be non-absolute if \c origin
+/// is non-NULL, in which case \c origin is used to make it absolute.
+/// It must not be represented as a quoted string.
+///
+/// The SUBTYPE field must be a valid decimal representation of an
+/// unsigned 16-bit integer.
+///
+/// \throw MasterLexer::LexerError General parsing error such as missing field.
+/// \throw Other Exceptions from the Name and RRTTL constructors if
+/// construction of textual fields as these objects fail.
+///
+/// \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 EXCHANGE when it
+/// is non-absolute.
+AFSDB::AFSDB(MasterLexer& lexer, const Name* origin,
+ MasterLoader::Options, MasterLoaderCallbacks&) :
+ subtype_(0), server_(".")
+{
+ createFromLexer(lexer, origin);
+}
- } catch (const StringTokenError& ste) {
- isc_throw(InvalidRdataText, "Invalid AFSDB text: " <<
- ste.what() << ": " << afsdb_str);
+void
+AFSDB::createFromLexer(MasterLexer& lexer, const Name* origin)
+{
+ const uint32_t num = lexer.getNextToken(MasterToken::NUMBER).getNumber();
+ if (num > 65535) {
+ isc_throw(InvalidRdataText, "Invalid AFSDB subtype: " << num);
}
+ subtype_ = static_cast<uint16_t>(num);
+
+ server_ = createNameFromLexer(lexer, origin);
}
/// \brief Constructor from wire-format data.
/// \return A \c string object that represents the \c AFSDB object.
string
AFSDB::toText() const {
- return (boost::lexical_cast<string>(subtype_) + " " + server_.toText());
+ return (lexical_cast<string>(subtype_) + " " + server_.toText());
}
/// \brief Render the \c AFSDB in the wire format without name compression.
-// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013 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
uint16_t getSubtype() const;
private:
+ void createFromLexer(MasterLexer& lexer, const Name* origin);
+
uint16_t subtype_;
Name server_;
};
-// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2013 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
const char* const afsdb_text = "1 afsdb.example.com.";
const char* const afsdb_text2 = "0 root.example.com.";
const char* const too_long_label("012345678901234567890123456789"
- "0123456789012345678901234567890123");
+ "0123456789012345678901234567890123.");
namespace {
class Rdata_AFSDB_Test : public RdataTest {
// number of fields (must be 2) is incorrect
EXPECT_THROW(const generic::AFSDB rdata_afsdb("10 afsdb. example.com."),
InvalidRdataText);
+ // No origin and relative
+ EXPECT_THROW(const generic::AFSDB rdata_afsdb("1 afsdb.example.com"),
+ MissingNameOrigin);
// bad name
EXPECT_THROW(const generic::AFSDB rdata_afsdb("1 afsdb.example.com." +
- string(too_long_label)), TooLongLabel);
+ string(too_long_label)), TooLongLabel);
+}
+
+TEST_F(Rdata_AFSDB_Test, copy) {
+ const generic::AFSDB rdata_afsdb2(rdata_afsdb);
+ EXPECT_EQ(0, rdata_afsdb.compare(rdata_afsdb2));
}
TEST_F(Rdata_AFSDB_Test, assignment) {
*test::createRdataUsingLexer(RRType::AFSDB(), RRClass::IN(),
afsdb_text)));
+ // test::createRdataUsingLexer() constructs relative to
+ // "example.org." origin.
+ generic::AFSDB tmp = generic::AFSDB("1 afsdb2.example.org.");
+ EXPECT_EQ(0, tmp.compare(
+ *test::createRdataUsingLexer(RRType::AFSDB(), RRClass::IN(),
+ "1 afsdb2")));
+
// Exceptions cause NULL to be returned.
EXPECT_FALSE(test::createRdataUsingLexer(RRType::AFSDB(), RRClass::IN(),
"1root.example.com."));
+
+ // 65536 is larger than maximum possible subtype
+ EXPECT_FALSE(test::createRdataUsingLexer(RRType::AFSDB(), RRClass::IN(),
+ "65536 afsdb.example.com."));
+
+ // Extra text at end of line
+ EXPECT_FALSE(test::createRdataUsingLexer(RRType::AFSDB(), RRClass::IN(),
+ "1 afsdb.example.com. extra."));
}
TEST_F(Rdata_AFSDB_Test, toWireBuffer) {
EXPECT_EQ(0, rdata_afsdb.compare(generic::AFSDB("1 "
"AFSDB.example.com.")));
- const generic::AFSDB small1("10 afsdb.example.com");
- const generic::AFSDB large1("65535 afsdb.example.com");
- const generic::AFSDB large2("256 afsdb.example.com");
+ const generic::AFSDB small1("10 afsdb.example.com.");
+ const generic::AFSDB large1("65535 afsdb.example.com.");
+ const generic::AFSDB large2("256 afsdb.example.com.");
// confirm these are compared as unsigned values
EXPECT_GT(0, rdata_afsdb.compare(large1));
EXPECT_LT(0, large2.compare(small1));
// another AFSDB whose server name is larger than that of rdata_afsdb.
- const generic::AFSDB large3("256 zzzzz.example.com");
+ const generic::AFSDB large3("256 zzzzz.example.com.");
EXPECT_GT(0, large2.compare(large3));
EXPECT_LT(0, large3.compare(large2));