name-component: recognize typed name components
refs #4526
Change-Id: I9d32a5dc216c6b0921d181573a4e043fccc2814e
diff --git a/src/encoding/tlv.hpp b/src/encoding/tlv.hpp
index 57ee509..fac222b 100644
--- a/src/encoding/tlv.hpp
+++ b/src/encoding/tlv.hpp
@@ -65,7 +65,7 @@
Data = 6,
Name = 7,
ImplicitSha256DigestComponent = 1,
- NameComponent = 8,
+ GenericNameComponent = 8,
Selectors = 9,
Nonce = 10,
InterestLifetime = 12,
@@ -90,10 +90,15 @@
LinkPreference = 30,
LinkDelegation = 31,
+ NameComponentMin = 1,
+ NameComponentMax = 65535,
+
AppPrivateBlock1 = 128,
AppPrivateBlock2 = 32767
};
+constexpr int NameComponent NDN_CXX_DEPRECATED = GenericNameComponent;
+
enum SignatureTypeValue : uint16_t {
DigestSha256 = 0,
SignatureSha256WithRsa = 1,
diff --git a/src/exclude.cpp b/src/exclude.cpp
index f352948..bf6bfef 100644
--- a/src/exclude.cpp
+++ b/src/exclude.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -194,6 +194,9 @@
catch (const name::Component::Error&) {
BOOST_THROW_EXCEPTION(Error("Incorrect format of Exclude filter"));
}
+ if (!component.isGeneric() && !component.isImplicitSha256Digest()) {
+ BOOST_THROW_EXCEPTION(Error("Excluded component must be generic or ImplicitSha256Digest"));
+ }
++i;
if (i != m_wire.elements_end() && i->type() == tlv::Any) {
diff --git a/src/exclude.hpp b/src/exclude.hpp
index 0bd6155..a5a2db6 100644
--- a/src/exclude.hpp
+++ b/src/exclude.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -33,6 +33,11 @@
/**
* @brief Represents Exclude selector in NDN Interest
+ *
+ * NDN Packet Format v0.3 defines name component types other than GenericNameComponent and
+ * ImplicitSha256DigestComponent, and removes Exclude selector. This implementation follows v0.2
+ * semantics and can only store GenericNameComponent and ImplicitSha256DigestComponent.
+ * The behavior of \c isExcluded on a name component of other types is unspecified.
*/
class Exclude
{
diff --git a/src/name-component.cpp b/src/name-component.cpp
index fb89f65..bd551b2 100644
--- a/src/name-component.cpp
+++ b/src/name-component.cpp
@@ -51,102 +51,114 @@
return prefix;
}
-Component::Component()
- : Block(tlv::NameComponent)
+void
+Component::ensureValid() const
{
+ if (type() < tlv::NameComponentMin || type() > tlv::NameComponentMax) {
+ BOOST_THROW_EXCEPTION(Error("TLV-TYPE " + to_string(type()) + " is not a valid NameComponent"));
+ }
+ if (type() == tlv::ImplicitSha256DigestComponent && value_size() != util::Sha256::DIGEST_SIZE) {
+ BOOST_THROW_EXCEPTION(Error("ImplicitSha256DigestComponent TLV-LENGTH must be " +
+ to_string(util::Sha256::DIGEST_SIZE)));
+ }
+}
+
+Component::Component(uint32_t type)
+ : Block(type)
+{
+ ensureValid();
}
Component::Component(const Block& wire)
: Block(wire)
{
- if (!isGeneric() && !isImplicitSha256Digest())
- BOOST_THROW_EXCEPTION(Error("Cannot construct name::Component from not a NameComponent "
- "or ImplicitSha256DigestComponent TLV wire block"));
+ ensureValid();
}
-Component::Component(const ConstBufferPtr& buffer)
- : Block(tlv::NameComponent, buffer)
+Component::Component(uint32_t type, ConstBufferPtr buffer)
+ : Block(type, std::move(buffer))
{
}
-Component::Component(const Buffer& value)
- : Block(makeBinaryBlock(tlv::NameComponent, value.data(), value.size()))
-{
-}
-
-Component::Component(const uint8_t* value, size_t valueLen)
- : Block(makeBinaryBlock(tlv::NameComponent, value, valueLen))
+Component::Component(uint32_t type, const uint8_t* value, size_t valueLen)
+ : Block(makeBinaryBlock(type, value, valueLen))
{
}
Component::Component(const char* str)
- : Block(makeBinaryBlock(tlv::NameComponent, str, std::char_traits<char>::length(str)))
+ : Block(makeBinaryBlock(tlv::GenericNameComponent, str, std::char_traits<char>::length(str)))
{
}
Component::Component(const std::string& str)
- : Block(makeStringBlock(tlv::NameComponent, str))
+ : Block(makeStringBlock(tlv::GenericNameComponent, str))
{
}
+static Component
+parseSha256DigestUri(std::string input)
+{
+ input.erase(0, getSha256DigestUriPrefix().size());
+
+ try {
+ return Component::fromImplicitSha256Digest(fromHex(input));
+ }
+ catch (const StringHelperError&) {
+ BOOST_THROW_EXCEPTION(Component::Error("Cannot convert to a ImplicitSha256DigestComponent "
+ "(invalid hex encoding)"));
+ }
+}
+
Component
-Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset)
+Component::fromEscapedString(std::string input)
{
- std::string trimmedString(escapedString + beginOffset, escapedString + endOffset);
- boost::algorithm::trim(trimmedString);
-
- if (trimmedString.compare(0, getSha256DigestUriPrefix().size(),
- getSha256DigestUriPrefix()) == 0) {
- if (trimmedString.size() != getSha256DigestUriPrefix().size() + util::Sha256::DIGEST_SIZE * 2)
- BOOST_THROW_EXCEPTION(Error("Cannot convert to ImplicitSha256DigestComponent"
- "(expected sha256 in hex encoding)"));
-
- try {
- trimmedString.erase(0, getSha256DigestUriPrefix().size());
- return fromImplicitSha256Digest(fromHex(trimmedString));
+ boost::algorithm::trim(input);
+ uint32_t type = tlv::GenericNameComponent;
+ size_t equalPos = input.find('=');
+ if (equalPos != std::string::npos) {
+ if (equalPos + 1 == getSha256DigestUriPrefix().size() &&
+ input.compare(0, getSha256DigestUriPrefix().size(), getSha256DigestUriPrefix()) == 0) {
+ return parseSha256DigestUri(std::move(input));
}
- catch (const StringHelperError&) {
- BOOST_THROW_EXCEPTION(Error("Cannot convert to a ImplicitSha256DigestComponent (invalid hex "
- "encoding)"));
+
+ long parsedType = std::strtol(input.data(), nullptr, 10);
+ if (parsedType < tlv::NameComponentMin || parsedType > tlv::NameComponentMax ||
+ parsedType == tlv::ImplicitSha256DigestComponent || parsedType == tlv::GenericNameComponent ||
+ to_string(parsedType).size() != equalPos) {
+ BOOST_THROW_EXCEPTION(Error("Incorrect TLV-TYPE in NameComponent URI"));
}
+ type = static_cast<uint32_t>(parsedType);
+ input.erase(0, equalPos + 1);
}
- else {
- std::string value = unescape(trimmedString);
- if (value.find_first_not_of(".") == std::string::npos) {
- // Special case for component of only periods.
- if (value.size() <= 2)
- // Zero, one or two periods is illegal. Ignore this component.
- BOOST_THROW_EXCEPTION(Error("Illegal URI (name component cannot be . or ..)"));
- else
- // Remove 3 periods.
- return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
+ std::string value = unescape(input);
+ if (value.find_first_not_of('.') == std::string::npos) { // all periods
+ if (value.size() < 3) {
+ BOOST_THROW_EXCEPTION(Error("Illegal URI (name component cannot be . or ..)"));
}
- else
- return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
+ return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size() - 3);
}
+ return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size());
}
void
-Component::toUri(std::ostream& result) const
+Component::toUri(std::ostream& os) const
{
if (type() == tlv::ImplicitSha256DigestComponent) {
- result << getSha256DigestUriPrefix();
- printHex(result, value(), value_size(), false);
+ os << getSha256DigestUriPrefix();
+ printHex(os, value(), value_size(), false);
+ return;
}
- else {
- bool hasNonDot = std::any_of(value_begin(), value_end(),
- [] (uint8_t x) { return x != '.'; });
- if (!hasNonDot) {
- // Special case for component of zero or more periods. Add 3 periods.
- result << "...";
- for (size_t i = 0; i < value_size(); ++i)
- result << '.';
- }
- else {
- escape(result, reinterpret_cast<const char*>(value()), value_size());
- }
+
+ if (type() != tlv::GenericNameComponent) {
+ os << type() << '=';
}
+
+ if (std::all_of(value_begin(), value_end(), [] (uint8_t x) { return x == '.'; })) { // all periods
+ os << "...";
+ }
+
+ escape(os, reinterpret_cast<const char*>(value()), value_size());
}
std::string
@@ -262,7 +274,7 @@
Component
Component::fromNumber(uint64_t number)
{
- return makeNonNegativeIntegerBlock(tlv::NameComponent, number);
+ return makeNonNegativeIntegerBlock(tlv::GenericNameComponent, number);
}
Component
@@ -274,13 +286,13 @@
valueLength += estimator.prependByteArray(&marker, 1);
size_t totalLength = valueLength;
totalLength += estimator.prependVarNumber(valueLength);
- totalLength += estimator.prependVarNumber(tlv::NameComponent);
+ totalLength += estimator.prependVarNumber(tlv::GenericNameComponent);
EncodingBuffer encoder(totalLength, 0);
encoder.prependNonNegativeInteger(number);
encoder.prependByteArray(&marker, 1);
encoder.prependVarNumber(valueLength);
- encoder.prependVarNumber(tlv::NameComponent);
+ encoder.prependVarNumber(tlv::GenericNameComponent);
return encoder.block();
}
@@ -322,14 +334,14 @@
bool
Component::isGeneric() const
{
- return (type() == tlv::NameComponent);
+ return type() == tlv::GenericNameComponent;
}
bool
Component::isImplicitSha256Digest() const
{
- return (type() == tlv::ImplicitSha256DigestComponent &&
- value_size() == util::Sha256::DIGEST_SIZE);
+ return type() == tlv::ImplicitSha256DigestComponent &&
+ value_size() == util::Sha256::DIGEST_SIZE;
}
Component
diff --git a/src/name-component.hpp b/src/name-component.hpp
index c537eb1..4e3563c 100644
--- a/src/name-component.hpp
+++ b/src/name-component.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -41,15 +41,15 @@
/// @brief Sequence number marker for NDN naming conventions
static const uint8_t SEQUENCE_NUMBER_MARKER = 0xFE;
-/**
- * @brief Component holds a read-only name component value.
+/** @brief Represents a name component.
+ *
+ * The @c Component class provides a read-only view of a @c Block interpreted as a name component.
+ * Although it inherits mutation methods from @c Block base class, they must not be used, because
+ * the enclosing @c Name would not be updated correctly.
*/
class Component : public Block
{
public:
- /**
- * @brief Error that can be thrown from name::Component
- */
class Error : public Block::Error
{
public:
@@ -60,91 +60,114 @@
}
};
+public: // constructors
/**
- * Create a new name::Component with an empty value
+ * @brief Construct a NameComponent of @p type, using empty TLV-VALUE.
+ * @throw Error the NameComponent is invalid (see @c ensureValid).
*/
- Component();
+ explicit
+ Component(uint32_t type = tlv::GenericNameComponent);
/**
- * @brief Create name::Component from a wire block
+ * @brief Construct a NameComponent from @p block.
+ * @throw Error the NameComponent is invalid (see @c ensureValid).
*
- * @param wire tlv::NameComponent Block from which to create name::Component
- * @throws Error if wire.type() is not tlv::NameComponent
- *
- * Any block can be implicitly converted to name::Component
+ * This contructor enables implicit conversion from @c Block.
*/
Component(const Block& wire);
/**
- * @brief Create a new name::Component from the buffer pointer (buffer pointer will be copied)
+ * @brief Construct a NameComponent of @p type, using TLV-VALUE from @p buffer.
+ * @throw Error the NameComponent is invalid (see @c ensureValid).
*
- * @param buffer A pointer to an immutable buffer
+ * This constructor does not copy the underlying buffer, but retains a pointer to it.
+ * Therefore, the caller must not change the underlying buffer.
+ */
+ Component(uint32_t type, ConstBufferPtr buffer);
+
+ /**
+ * @brief Construct a GenericNameComponent, using TLV-VALUE from @p buffer.
+ * @throw Error the NameComponent is invalid (see @c ensureValid).
*
- * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
- * Note that this method **will not** allocate new memory for and copy the payload until
- * toWire() method is called.
+ * This constructor does not copy the underlying buffer, but retains a pointer to it.
+ * Therefore, the caller must not change the underlying buffer.
*/
explicit
- Component(const ConstBufferPtr& buffer);
+ Component(ConstBufferPtr buffer)
+ : Component(tlv::GenericNameComponent, std::move(buffer))
+ {
+ }
/**
- * @brief Create a new name::Component from the buffer (data from buffer will be copied)
- * @param buffer A reference to the buffer
- *
- * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
- * Note that this method **will** allocate new memory for and copy the payload.
+ * @brief Construct a NameComponent of @p type, copying TLV-VALUE from @p buffer.
+ */
+ Component(uint32_t type, const Buffer& buffer)
+ : Component(type, buffer.data(), buffer.size())
+ {
+ }
+
+ /**
+ * @brief Construct a GenericNameComponent, copying TLV-VALUE from @p buffer.
*/
explicit
- Component(const Buffer& buffer);
+ Component(const Buffer& buffer)
+ : Component(tlv::GenericNameComponent, buffer)
+ {
+ }
/**
- * @brief Create a new name::Component from the buffer (data from buffer will be copied)
- * @param buffer A pointer to the first byte of the buffer
- * @param bufferSize Size of the buffer
- *
- * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
- * Note that this method **will** allocate new memory for and copy the payload.
+ * @brief Construct a NameComponent of @p type, copying @p count bytes at @p value as TLV-VALUE.
*/
- Component(const uint8_t* buffer, size_t bufferSize);
+ Component(uint32_t type, const uint8_t* value, size_t count);
/**
- * @brief Create a new name::Component frome the range [@p first, @p last) of bytes
- * @param first Iterator pointing to the beginning of the buffer
- * @param last Iterator pointing to the ending of the buffer
- * @tparam Iterator iterator type satisfying at least InputIterator concept. Implementation
- * is more optimal when the iterator type satisfies RandomAccessIterator concept.
- * It is required that sizeof(std::iterator_traits<Iterator>::value_type) == 1.
- *
- * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
- * Note that this method **will** allocate new memory for and copy the payload.
+ * @brief Construct a GenericNameComponent, copying @p count bytes at @p value as TLV-VALUE.
+ */
+ Component(const uint8_t* value, size_t count)
+ : Component(tlv::GenericNameComponent, value, count)
+ {
+ }
+
+ /**
+ * @brief Construct a NameComponent of @p type, copying TLV-VALUE from a range.
+ * @tparam Iterator an @c InputIterator dereferencing to a one-octet value type. More efficient
+ * implementation is available when it is a @c RandomAccessIterator.
+ * @param type the TLV-TYPE.
+ * @param first beginning of the range.
+ * @param last past-end of the range.
*/
template<class Iterator>
- Component(Iterator first, Iterator last);
+ Component(uint32_t type, Iterator first, Iterator last)
+ : Block(makeBinaryBlock(type, first, last))
+ {
+ }
/**
- * @brief Create a new name::Component from the C string (data from string will be copied)
+ * @brief Construct a GenericNameComponent, copying TLV-VALUE from a range.
+ */
+ template<class Iterator>
+ Component(Iterator first, Iterator last)
+ : Component(tlv::GenericNameComponent, first, last)
+ {
+ }
+
+ /**
+ * @brief Construct a GenericNameComponent, copying TLV-VALUE from a null-terminated string.
*
- * @param str Zero-ended string. Note that this string will be interpreted as is (i.e.,
- * it will not be interpreted as URI)
- *
- * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
- * Note that this method **will** allocate new memory for and copy the payload.
+ * Bytes from the string are copied as is, and not interpreted as URI component.
*/
explicit
Component(const char* str);
/**
- * @brief Create a new name::Component from the STL string (data from string will be copied)
+ * @brief Construct a GenericNameComponent, copying TLV-VALUE from a string.
*
- * @param str Const reference to STL string. Note that this string will be interpreted
- * as is (i.e., it will not be interpreted as URI)
- *
- * This constructor will create a new tlv::NameComponent Block with `buffer` as a payload.
- * Note that this method **will** allocate new memory for and copy the payload.
+ * Bytes from the string are copied as is, and not interpreted as URI component.
*/
explicit
Component(const std::string& str);
+public: // encoding and URI
/**
* @brief Fast encoding or block size estimation
*/
@@ -165,45 +188,36 @@
wireDecode(const Block& wire);
/**
- * @brief Create name::Component by decoding the escapedString between beginOffset and
- * endOffset according to the NDN URI Scheme.
+ * @brief Decode NameComponent from a URI component.
*
- * If the escaped string is "", "." or ".." then return an empty name::Component. Note
- * that an empty name::Component should not be added to Name and if attempted, an
- * exception will be thrown.
+ * The URI component is read from `[input+beginOffset, input+endOffset)` range.
*
- * @param escapedString String containing NDN URI-encoded name
- * component. [escapedString+beginOffset, beginOffset+endOffset)
- * must be a valid memory buffer.
- * @param beginOffset The offset in escapedString of the beginning of the portion to decode.
- * @param endOffset The offset in escapedString of the end of the portion to decode.
+ * @throw Error URI component does not represent a valid NameComponent.
*/
static Component
- fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset);
-
- /**
- * @brief Create name::Component by decoding the escapedString according to the NDN URI Scheme
- *
- * This overload is a convenience wrapper for fromEscapedString(char*,size_t,size)
- */
- static Component
- fromEscapedString(const char* escapedString)
+ fromEscapedString(const char* input, size_t beginOffset, size_t endOffset)
{
- return fromEscapedString(escapedString, 0, std::char_traits<char>::length(escapedString));
+ return fromEscapedString(std::string(input + beginOffset, input + endOffset));
}
/**
- * @brief Create name::Component by decoding the escapedString according to the NDN URI Scheme
- *
- * This overload is a convenience wrapper for fromEscapedString(char*,size_t,size)
+ * @brief Decode NameComponent from a URI component.
+ * @throw Error URI component does not represent a valid NameComponent.
*/
static Component
- fromEscapedString(const std::string& escapedString)
+ fromEscapedString(const char* input)
{
- return fromEscapedString(escapedString.c_str(), 0, escapedString.size());
+ return fromEscapedString(std::string(input));
}
/**
+ * @brief Decode NameComponent from a URI component.
+ * @throw Error URI component does not represent a valid NameComponent.
+ */
+ static Component
+ fromEscapedString(std::string input);
+
+ /**
* @brief Write *this to the output stream, escaping characters according to the NDN URI Scheme
*
* This also adds "..." to a value with zero or more "."
@@ -223,8 +237,7 @@
std::string
toUri() const;
- ////////////////////////////////////////////////////////////////////////////////
-
+public: // naming conventions
/**
* @brief Check if the component is nonNegativeInteger
* @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
@@ -274,8 +287,6 @@
bool
isSequenceNumber() const;
- ////////////////////////////////////////////////////////////////////////////////
-
/**
* @brief Interpret this name component as nonNegativeInteger
*
@@ -354,8 +365,6 @@
uint64_t
toSequenceNumber() const;
- ////////////////////////////////////////////////////////////////////////////////
-
/**
* @brief Create a component encoded as nonNegativeInteger
*
@@ -431,8 +440,7 @@
static Component
fromSequenceNumber(uint64_t seqNo);
- ////////////////////////////////////////////////////////////////////////////////
-
+public: // commonly used TLV-TYPEs
/**
* @brief Check if the component is GenericComponent
*/
@@ -457,8 +465,7 @@
static Component
fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize);
- ////////////////////////////////////////////////////////////////////////////////
-
+public: // operators
bool
empty() const
{
@@ -561,6 +568,16 @@
Component
getSuccessor() const;
+private:
+ /**
+ * @brief Throw @c Error if this NameComponent is invalid.
+ *
+ * A NameComponent is invalid if its TLV-TYPE is outside the 1-65535 range.
+ * Additionally, if this is an ImplicitSha256DigestComponent, the TLV-LENGTH must be 32.
+ */
+ void
+ ensureValid() const;
+
// !!! NOTE TO IMPLEMENTOR !!!
//
// This class MUST NOT contain any data fields.
@@ -576,13 +593,6 @@
return os;
}
-template<class Iterator>
-inline
-Component::Component(Iterator first, Iterator last)
- : Block(makeBinaryBlock(tlv::NameComponent, first, last))
-{
-}
-
} // namespace name
} // namespace ndn