name: select canonical vs alternate URI representation
refs #4777
Change-Id: Ic644593228bd155de9dcd7005e1b9dc5303a6e66
diff --git a/ndn-cxx/name-component.cpp b/ndn-cxx/name-component.cpp
index f41fda0..4338cc4 100644
--- a/ndn-cxx/name-component.cpp
+++ b/ndn-cxx/name-component.cpp
@@ -86,6 +86,17 @@
return (to_underlying(g_conventionDecoding) & to_underlying(Convention::TYPED)) != 0;
}
+static bool
+chooseAltUri(UriFormat format)
+{
+ if (format == UriFormat::DEFAULT) {
+ static const char* env = std::getenv("NDN_NAME_ALT_URI");
+ static bool defaultSetting = env == nullptr || env[0] != '0';
+ return defaultSetting;
+ }
+ return format == UriFormat::ALTERNATE;
+}
+
void
Component::ensureValid() const
{
@@ -169,16 +180,21 @@
}
void
-Component::toUri(std::ostream& os) const
+Component::toUri(std::ostream& os, UriFormat format) const
{
- detail::getComponentTypeTable().get(type()).writeUri(os, *this);
+ if (chooseAltUri(format)) {
+ detail::getComponentTypeTable().get(type()).writeUri(os, *this);
+ }
+ else {
+ detail::ComponentType().writeUri(os, *this);
+ }
}
std::string
-Component::toUri() const
+Component::toUri(UriFormat format) const
{
std::ostringstream os;
- toUri(os);
+ toUri(os, format);
return os.str();
}
diff --git a/ndn-cxx/name-component.hpp b/ndn-cxx/name-component.hpp
index 2039e21..5f89110 100644
--- a/ndn-cxx/name-component.hpp
+++ b/ndn-cxx/name-component.hpp
@@ -30,6 +30,14 @@
namespace ndn {
namespace name {
+/** @brief Identify a format of URI representation.
+ */
+enum class UriFormat {
+ DEFAULT, ///< ALTERNATE, unless `NDN_NAME_ALT_URI` environment variable is set to '0'
+ CANONICAL, ///< always use <type-number>=<percent-encoded-value> format
+ ALTERNATE, ///< prefer alternate format when available
+};
+
/** @brief Identify a style of NDN Naming Conventions.
* @sa https://named-data.net/publications/techreports/ndn-tr-22-2-ndn-memo-naming-conventions/
*/
@@ -251,19 +259,17 @@
/**
* @brief Write *this to the output stream, escaping characters according to the NDN URI format.
- * @param os The output stream where to write the URI escaped version of *this
- * @sa http://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
+ * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
*/
void
- toUri(std::ostream& os) const;
+ toUri(std::ostream& os, UriFormat format = UriFormat::DEFAULT) const;
/**
* @brief Convert *this by escaping characters according to the NDN URI format.
- * @return The escaped string
- * @sa http://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
+ * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
*/
std::string
- toUri() const;
+ toUri(UriFormat format = UriFormat::DEFAULT) const;
public: // naming conventions
/**
diff --git a/ndn-cxx/name.cpp b/ndn-cxx/name.cpp
index 01513b7..9763f25 100644
--- a/ndn-cxx/name.cpp
+++ b/ndn-cxx/name.cpp
@@ -112,14 +112,6 @@
}
}
-std::string
-Name::toUri() const
-{
- std::ostringstream os;
- os << *this;
- return os.str();
-}
-
template<encoding::Tag TAG>
size_t
Name::wireEncode(EncodingImpl<TAG>& encoder) const
@@ -350,21 +342,28 @@
return count1 - count2;
}
-// ---- stream operators ----
+// ---- URI representation ----
-std::ostream&
-operator<<(std::ostream& os, const Name& name)
+void
+Name::toUri(std::ostream& os, name::UriFormat format) const
{
- if (name.empty()) {
+ if (empty()) {
os << "/";
+ return;
}
- else {
- for (const auto& component : name) {
- os << "/";
- component.toUri(os);
- }
+
+ for (const auto& component : *this) {
+ os << "/";
+ component.toUri(os, format);
}
- return os;
+}
+
+std::string
+Name::toUri(name::UriFormat format) const
+{
+ std::ostringstream os;
+ toUri(os, format);
+ return os.str();
}
std::istream&
diff --git a/ndn-cxx/name.hpp b/ndn-cxx/name.hpp
index 18b1fc3..d1c9c8d 100644
--- a/ndn-cxx/name.hpp
+++ b/ndn-cxx/name.hpp
@@ -92,13 +92,19 @@
*/
Name(std::string uri);
+ /** @brief Write URI representation of the name to the output stream
+ * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
+ */
+ void
+ toUri(std::ostream& os, name::UriFormat format = name::UriFormat::DEFAULT) const;
+
/** @brief Get URI representation of the name
* @return URI representation; "ndn:" scheme identifier is not included
* @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
* @note To print URI representation into a stream, it is more efficient to use ``os << name``.
*/
std::string
- toUri() const;
+ toUri(name::UriFormat format = name::UriFormat::DEFAULT) const;
/** @brief Check if this Name instance already has wire encoding
*/
@@ -636,6 +642,16 @@
return lhs.compare(rhs) >= 0;
}
+ /** @brief Print URI representation of a name
+ * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
+ */
+ friend std::ostream&
+ operator<<(std::ostream& os, const Name& name)
+ {
+ name.toUri(os);
+ return os;
+ }
+
public:
/** @brief Indicates "until the end" in getSubName() and compare().
*/
@@ -647,12 +663,6 @@
NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(Name);
-/** @brief Print URI representation of a name
- * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
- */
-std::ostream&
-operator<<(std::ostream& os, const Name& name);
-
/** @brief Parse URI from stream as Name
* @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
*/
diff --git a/tests/unit/name-component.t.cpp b/tests/unit/name-component.t.cpp
index c009175..fe62ee0 100644
--- a/tests/unit/name-component.t.cpp
+++ b/tests/unit/name-component.t.cpp
@@ -48,6 +48,8 @@
BOOST_CHECK_EQUAL(comp.type(), tlv::GenericNameComponent);
BOOST_CHECK_EQUAL(comp.isGeneric(), true);
BOOST_CHECK_EQUAL(comp.toUri(), "ndn-cxx");
+ BOOST_CHECK_EQUAL(comp.toUri(UriFormat::CANONICAL), "8=ndn-cxx");
+ BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ALTERNATE), "ndn-cxx");
BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(comp), "ndn-cxx");
BOOST_CHECK_EQUAL(Component::fromEscapedString("ndn-cxx"), comp);
BOOST_CHECK_EQUAL(Component::fromEscapedString("8=ndn-cxx"), comp);
@@ -98,15 +100,19 @@
for (size_t i = 0; i < hexUpper.size(); i += 2) {
hexPct += "%" + hexUpper.substr(i, 2);
}
+ const std::string hexPctCanonical = "%28%BA%D4%B5%27%5B%D3%92%DB%B6p%C7%5C%F0%B6o%13%F7%94%2B%21%E8%0FU%C0%E8k7GS%A5H";
Component comp(Block(type, fromHex(hexLower)));
BOOST_CHECK_EQUAL(comp.type(), type);
BOOST_CHECK_EQUAL(comp.toUri(), uriPrefix + hexLower);
+ BOOST_CHECK_EQUAL(comp.toUri(UriFormat::CANONICAL), to_string(type) + "=" + hexPctCanonical);
+ BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ALTERNATE), uriPrefix + hexLower);
BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(comp), uriPrefix + hexLower);
BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(uriPrefix + hexLower));
BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(uriPrefix + hexUpper));
BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(to_string(type) + "=" + hexPct));
+ BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(to_string(type) + "=" + hexPctCanonical));
CHECK_COMP_ERR(comp.wireDecode(Block(type, fromHex("A791806951F25C4D"))), "TLV-LENGTH must be 32");
CHECK_COMP_ERR(Component::fromEscapedString(uriPrefix), "TLV-LENGTH must be 32");
@@ -133,6 +139,8 @@
BOOST_CHECK_EQUAL(comp.isNumber(), true);
const auto compUri = uriPrefix + "42";
BOOST_CHECK_EQUAL(comp.toUri(), compUri);
+ BOOST_CHECK_EQUAL(comp.toUri(UriFormat::CANONICAL), to_string(type) + "=%2A");
+ BOOST_CHECK_EQUAL(comp.toUri(UriFormat::ALTERNATE), compUri);
BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(comp), compUri);
BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(compUri));
BOOST_CHECK_EQUAL(comp, Component::fromEscapedString(to_string(type) + "=%2A"));
diff --git a/tests/unit/name.t.cpp b/tests/unit/name.t.cpp
index 44c261e..21ecc00 100644
--- a/tests/unit/name.t.cpp
+++ b/tests/unit/name.t.cpp
@@ -29,6 +29,7 @@
namespace tests {
using Component = name::Component;
+using UriFormat = name::UriFormat;
BOOST_AUTO_TEST_SUITE(TestName)
@@ -47,6 +48,10 @@
BOOST_CHECK_EQUAL(name[4], Component("\x1C\x9F"));
BOOST_CHECK(name[5].isImplicitSha256Digest());
+ BOOST_CHECK_EQUAL(name.toUri(UriFormat::CANONICAL),
+ "/8=Emid/25042=P3/8=.../8=..../8=%1C%9F/"
+ "1=%04%15%E3bJ%15%18P%AChl%84%F1U%F2%98%08%C0%DDs%81%9A%A4%A4%C2%0B%E7%3AM%8A%87L");
+
Block wire = name.wireEncode();
BOOST_CHECK_EQUAL(wire,
"0737 0804456D6964 FD61D2025033 0800 08012E 08021C9F "
@@ -58,6 +63,9 @@
BOOST_AUTO_TEST_CASE(ParseUri)
{
+ // canonical URI
+ BOOST_CHECK_EQUAL(Name("/8=hello/8=world").toUri(), "/hello/world");
+
// URI with correct scheme
BOOST_CHECK_EQUAL(Name("ndn:/hello/world").toUri(), "/hello/world");