update profile fetching

Change-Id: I788ece8371f7e24c87918a57062673be1d866e5b
diff --git a/src/ca-module.cpp b/src/ca-module.cpp
index c32a4f4..9125cc6 100644
--- a/src/ca-module.cpp
+++ b/src/ca-module.cpp
@@ -66,29 +66,16 @@
 void
 CaModule::registerPrefix()
 {
-  // register localhop discovery prefix
-  Name localhopInfoPrefix("/localhop/CA/INFO");
-  auto prefixId = m_face.setInterestFilter(InterestFilter(localhopInfoPrefix),
-                                           bind(&CaModule::onInfo, this, _2),
-                                           bind(&CaModule::onRegisterFailed, this, _2));
-  m_registeredPrefixHandles.push_back(prefixId);
-  _LOG_TRACE("Prefix " << localhopInfoPrefix << " got registered");
-
   // register prefixes
   Name prefix = m_config.m_caItem.m_caPrefix;
   prefix.append("CA");
 
-  prefixId = m_face.registerPrefix(
+  auto prefixId = m_face.registerPrefix(
       prefix,
       [&](const Name& name) {
-        // register INFO prefix
-        auto filterId = m_face.setInterestFilter(Name(name).append("INFO"),
-                                                 bind(&CaModule::onInfo, this, _2));
-        m_interestFilterHandles.push_back(filterId);
-
         // register PROBE prefix
-        filterId = m_face.setInterestFilter(Name(name).append("PROBE"),
-                                            bind(&CaModule::onProbe, this, _2));
+        auto filterId = m_face.setInterestFilter(Name(name).append("PROBE"),
+                                                 bind(&CaModule::onProbe, this, _2));
         m_interestFilterHandles.push_back(filterId);
 
         // register NEW prefix
@@ -164,21 +151,6 @@
 }
 
 void
-CaModule::onInfo(const Interest& request)
-{
-  _LOG_TRACE("Received INFO request");
-
-  if (request.getName().get(-1).type() == 32) {
-    m_face.put(*generateCaConfigMetaData());
-  }
-  else {
-    m_face.put(*generateCaConfigData());
-  }
-
-  _LOG_TRACE("Handle INFO: send out the INFO response");
-}
-
-void
 CaModule::onProbe(const Interest& request)
 {
   // PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent]
@@ -502,31 +474,6 @@
   _LOG_ERROR("Failed to register prefix in local hub's daemon, REASON: " << reason);
 }
 
-Block
-CaModule::dataContentFromJson(const JsonSection& jsonSection)
-{
-  std::stringstream ss;
-  boost::property_tree::write_json(ss, jsonSection);
-  return makeStringBlock(ndn::tlv::Content, ss.str());
-}
-
-JsonSection
-CaModule::jsonFromBlock(const Block& block)
-{
-  std::string jsonString;
-  try {
-    jsonString = encoding::readString(block);
-    std::istringstream ss(jsonString);
-    JsonSection json;
-    boost::property_tree::json_parser::read_json(ss, json);
-    return json;
-  }
-  catch (const std::exception& e) {
-    _LOG_ERROR("Cannot read JSON string from TLV Value: " << e.what());
-    return JsonSection();
-  }
-}
-
 Data
 CaModule::generateErrorDataPacket(const Name& name, ErrorCode error, const std::string& errorInfo)
 {
diff --git a/src/ca-module.hpp b/src/ca-module.hpp
index ac2a741..76713d0 100644
--- a/src/ca-module.hpp
+++ b/src/ca-module.hpp
@@ -31,16 +31,6 @@
 class CaModule : noncopyable
 {
 public:
-  /**
-   * @brief Error that can be thrown from CaModule
-   */
-  class Error : public std::runtime_error
-  {
-  public:
-    using std::runtime_error::runtime_error;
-  };
-
-public:
   CaModule(Face& face, security::v2::KeyChain& keyChain, const std::string& configPath,
            const std::string& storageType = "ca-storage-sqlite3");
 
@@ -64,12 +54,6 @@
   void
   setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback);
 
-  static JsonSection
-  jsonFromBlock(const Block& block);
-
-  static Block
-  dataContentFromJson(const JsonSection& jsonSection);
-
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   shared_ptr<Data>
   generateCaConfigMetaData();
@@ -113,7 +97,6 @@
 
   std::list<RegisteredPrefixHandle> m_registeredPrefixHandles;
   std::list<InterestFilterHandle> m_interestFilterHandles;
-
 };
 
 } // namespace ndncert
diff --git a/src/requester.cpp b/src/requester.cpp
index 6c147e9..fda2f4f 100644
--- a/src/requester.cpp
+++ b/src/requester.cpp
@@ -33,6 +33,7 @@
 #include <ndn-cxx/security/verification-helpers.hpp>
 #include <ndn-cxx/util/io.hpp>
 #include <ndn-cxx/util/random.hpp>
+#include <ndn-cxx/metadata-object.hpp>
 
 namespace ndn {
 namespace ndncert {
@@ -47,14 +48,22 @@
 }
 
 shared_ptr<Interest>
-Requester::genCaProfileInterest(const Name& caName)
+Requester::genCaProfileDiscoveryInterest(const Name& caName)
 {
-  Name interestName = caName;
+  Name contentName = caName;
   if (readString(caName.at(-1)) != "CA")
-    interestName.append("CA");
-  interestName.append("INFO");
-  auto interest = make_shared<Interest>(interestName);
-  interest->setMustBeFresh(true);
+    contentName.append("CA");
+  contentName.append("INFO");
+  return std::make_shared<Interest>(MetadataObject::makeDiscoveryInterest(contentName));
+}
+
+shared_ptr<Interest>
+Requester::genCaProfileInterestFromDiscoveryResponse(const Data& reply)
+{
+  auto metaData = MetadataObject(reply);
+  auto interestName= metaData.getVersionedName();
+  interestName.appendSegment(0);
+  auto interest = std::make_shared<Interest>(interestName);
   interest->setCanBePrefix(false);
   return interest;
 }
diff --git a/src/requester.hpp b/src/requester.hpp
index ab987dd..c6510b1 100644
--- a/src/requester.hpp
+++ b/src/requester.hpp
@@ -99,31 +99,49 @@
 {
 public:
   /**
-   * Generates a INFO interest corresponds to the CA for given prefix.
-   * @param caName the name prefix of the CA.
-   * @return A shared pointer to an interest ready to be sent.
+   * Generates a CA profile discovery Interest following RDR protocol.
+   * @param caName, the name prefix of the CA.
+   * @return A shared pointer to an Interest ready to be sent.
    */
   static shared_ptr<Interest>
-  genCaProfileInterest(const Name& caName);
+  genCaProfileDiscoveryInterest(const Name& caName);
 
   /**
-   * Decodes the replied data for the configuration of the CA.
+   * Generates a CA profile fetching Interest following RDR protocol.
+   * @param reply, the Data packet replied from discovery Interest.
+   * @return A shared pointer to an Interest ready to be sent.
+   */
+  static shared_ptr<Interest>
+  genCaProfileInterestFromDiscoveryResponse(const Data& reply);
+
+  /**
+   * Decodes the CA profile from the replied CA profile Data packet.
    * Will first verify the signature of the packet using the key provided inside the profile.
    * The application should be cautious whether to add CaProfile into the RequesterCaCache.
-   * @param reply
+   * @param reply, the Data packet replied from CA profile fetching Interest.
    * @return the CaProfile if decoding is successful
    * @throw std::runtime_error if the decoding fails or receiving an error packet.
    */
   static boost::optional<CaProfile>
   onCaProfileResponse(const Data& reply);
 
+  /**
+   * Decodes the CA profile from the replied CA profile Data packet after the redirection.
+   * Will first verify the signature of the packet using the key provided inside the profile and
+   * verify the certificate's digest matches the one obtained from the original CA.
+   * The application should be cautious whether to add CaProfile into the RequesterCaCache.
+   * @param reply, the Data packet replied from CA profile fetching Interest.
+   * @param caCertFullName, the full name obtained from original CA's probe response.
+   * @return the CaProfile if decoding is successful
+   * @throw std::runtime_error if the decoding fails or receiving an error packet.
+   */
   static boost::optional<CaProfile>
   onCaProfileResponseAfterRedirection(const Data& reply, const Name& caCertFullName);
 
   /**
    * Generates a PROBE interest to the CA (for suggested name assignments).
-   * @param ca the CA that interest is send to
-   * @param probeInfo the requester information to carry to the CA
+   * @param ca, the CA that interest is send to
+   * @param probeInfo, the requester information to carry to the CA
    * @return A shared pointer of to the encoded interest, ready to be sent.
    */
   static shared_ptr<Interest>
@@ -132,10 +150,10 @@
   /**
    * Decodes the replied data for PROBE process from the CA.
    * Will first verify the signature of the packet using the key provided inside the profile.
-   * @param reply The replied data packet
-   * @param ca the profile of the CA that replies the packet
-   * @param identityNames The vector to load the decoded identity names from the data.
-   * @param otherCas The vector to load the decoded redirection CA prefixes from the data.
+   * @param reply, The replied data packet
+   * @param ca, the profile of the CA that replies the packet
+   * @param identityNames, The vector to load the decoded identity names from the data.
+   * @param otherCas, The vector to load the decoded redirection CA prefixes from the data.
    * @throw std::runtime_error if the decoding fails or receiving an error packet.
    */
   static void
@@ -145,10 +163,10 @@
   // NEW/REVOKE/RENEW related helpers
   /**
    * Generates a NEW interest to the CA.
-   * @param state The current requester state for this request. Will be modified in the function.
-   * @param identityName The identity name to be requested.
-   * @param notBefore The expected notBefore field for the certificate (starting time)
-   * @param notAfter The expected notAfter field for the certificate (expiration time)
+   * @param state, The current requester state for this request. Will be modified in the function.
+   * @param identityName, The identity name to be requested.
+   * @param notBefore, The expected notBefore field for the certificate (starting time)
+   * @param notAfter, The expected notAfter field for the certificate (expiration time)
    * @return The shared pointer to the encoded interest.
    */
   static shared_ptr<Interest>
@@ -158,8 +176,8 @@
 
   /**
    * Generates a REVOKE interest to the CA.
-   * @param state The current requester state for this request. Will be modified in the function.
-   * @param certificate the certificate to the revoked.
+   * @param state, The current requester state for this request. Will be modified in the function.
+   * @param certificate, the certificate to the revoked.
    * @return The shared pointer to the encoded interest.
    */
   static shared_ptr<Interest>
@@ -167,8 +185,8 @@
 
   /**
    * Decodes the replied data of NEW, RENEW, or REVOKE interest from the CA.
-   * @param state the current requester state for the request. Will be updated in the function.
-   * @param reply the replied data from the network
+   * @param state, the current requester state for the request. Will be updated in the function.
+   * @param reply, the replied data from the network
    * @return the list of challenge accepted by the CA, for CHALLENGE step.
    * @throw std::runtime_error if the decoding fails or receiving an error packet.
    */
@@ -178,8 +196,8 @@
   // CHALLENGE helpers
   /**
    * Generates the required parameter for the selected challenge for the request
-   * @param state The requester state of the request.Will be updated in the function.
-   * @param challengeSelected The selected challenge for the request.
+   * @param state, The requester state of the request.Will be updated in the function.
+   * @param challengeSelected, The selected challenge for the request.
    *            Can use state.m_challengeType to continue.
    * @return The requirement list for the current stage of the challenge, in name, prompt mapping.
    */
@@ -188,8 +206,8 @@
 
   /**
    * Generates the CHALLENGE interest for the request.
-   * @param state The requester state of the request.
-   * @param parameters The requirement list, in name, value mapping.
+   * @param state, The requester state of the request.
+   * @param parameters, The requirement list, in name, value mapping.
    * @return The shared pointer to the encoded interest
    */
   static shared_ptr<Interest>
@@ -197,9 +215,9 @@
                        std::vector<std::tuple<std::string, std::string>>&& parameters);
 
   /**
-   * Decodes the responsed data from the CHALLENGE interest.
-   * @param state the corresponding requester state of the request. Will be modified.
-   * @param reply the response data.
+   * Decodes the responded data from the CHALLENGE interest.
+   * @param state, the corresponding requester state of the request. Will be modified.
+   * @param reply, the response data.
    * @throw std::runtime_error if the decoding fails or receiving an error packet.
    */
   static void
@@ -207,7 +225,7 @@
 
   /**
    * Generate the interest to fetch the issued certificate
-   * @param state the state of the request.
+   * @param state, the state of the request.
    * @return The shared pointer to the encoded interest
    */
   static shared_ptr<Interest>
@@ -215,7 +233,7 @@
 
   /**
    * Decoded and installs the response certificate from the certificate fetch.
-   * @param reply the data replied from the certificate fetch interest.
+   * @param reply, the data replied from the certificate fetch interest.
    * @return The shared pointer to the certificate being fetched.
    */
   static shared_ptr<security::v2::Certificate>
@@ -223,7 +241,7 @@
 
   /**
    * End the current request session and performs cleanup if necessary.
-   * @param state the requester state for the request.
+   * @param state, the requester state for the request.
    */
   static void
   endSession(RequesterState& state);
diff --git a/tests/unit-tests/bench.t.cpp b/tests/unit-tests/bench.t.cpp
index 28850a8..09986c6 100644
--- a/tests/unit-tests/bench.t.cpp
+++ b/tests/unit-tests/bench.t.cpp
@@ -19,9 +19,9 @@
  */
 
 #include "ca-module.hpp"
-#include "requester.hpp"
 #include "challenge-modules/challenge-pin.hpp"
 #include "protocol-detail/info.hpp"
+#include "requester.hpp"
 #include "test-common.hpp"
 
 namespace ndn {
@@ -38,12 +38,26 @@
 
   util::DummyClientFace face(io, m_keyChain, {true, true});
   CaModule ca(face, m_keyChain, "tests/unit-tests/config-files/config-ca-1", "ca-storage-memory");
+  auto metaData = ca.generateCaConfigMetaData();
+  auto profileData = ca.generateCaConfigData();
   advanceClocks(time::milliseconds(20), 60);
 
   Interest interest = MetadataObject::makeDiscoveryInterest(Name("/ndn/CA/INFO"));
   std::cout << "CA Config discovery Interest Size: " << interest.wireEncode().size() << std::endl;
   shared_ptr<Interest> infoInterest = nullptr;
 
+  face.setInterestFilter(InterestFilter("/ndn/CA/INFO"),
+                         [&](const auto&, const Interest& interest) {
+                           if (interest.matchesData(*metaData)) {
+                             face.put(*metaData);
+                           }
+                           else {
+                             BOOST_CHECK(interest.matchesData(*profileData));
+                             face.put(*profileData);
+                           }
+                         }, nullptr, nullptr);
+  advanceClocks(time::milliseconds(20), 60);
+
   int count = 0;
   face.onSendData.connect([&](const Data& response) {
     if (count == 0) {
@@ -55,7 +69,6 @@
       interest.setCanBePrefix(true);
       infoInterest = make_shared<Interest>(interest);
       std::cout << "CA Config fetch Interest Size: " << infoInterest->wireEncode().size() << std::endl;
-
     }
     else {
       count++;
diff --git a/tests/unit-tests/ca-module.t.cpp b/tests/unit-tests/ca-module.t.cpp
index 7abb727..774484d 100644
--- a/tests/unit-tests/ca-module.t.cpp
+++ b/tests/unit-tests/ca-module.t.cpp
@@ -39,11 +39,11 @@
   BOOST_CHECK_EQUAL(ca.getCaConf().m_caItem.m_caPrefix, "/ndn");
 
   advanceClocks(time::milliseconds(20), 60);
-  BOOST_CHECK_EQUAL(ca.m_registeredPrefixHandles.size(), 2);
-  BOOST_CHECK_EQUAL(ca.m_interestFilterHandles.size(), 5);  // onInfo, onProbe, onNew, onChallenge, onRevoke
+  BOOST_CHECK_EQUAL(ca.m_registeredPrefixHandles.size(), 1); // removed local discovery registration
+  BOOST_CHECK_EQUAL(ca.m_interestFilterHandles.size(), 4);  // onProbe, onNew, onChallenge, onRevoke
 }
 
-BOOST_AUTO_TEST_CASE(HandleInfo)
+BOOST_AUTO_TEST_CASE(HandleProfileFetching)
 {
   auto identity = addIdentity(Name("/ndn"));
   auto key = identity.getDefaultKey();
@@ -51,27 +51,53 @@
 
   util::DummyClientFace face(io, m_keyChain, {true, true});
   CaModule ca(face, m_keyChain, "tests/unit-tests/config-files/config-ca-1", "ca-storage-memory");
+  auto metaData = ca.generateCaConfigMetaData();
+  auto profileData = ca.generateCaConfigData();
   advanceClocks(time::milliseconds(20), 60);
 
-  Interest interest("/ndn/CA/INFO");
-  interest.setCanBePrefix(false);
+  Interest interest = MetadataObject::makeDiscoveryInterest(Name("/ndn/CA/INFO"));
+  shared_ptr<Interest> infoInterest = nullptr;
+
+  face.setInterestFilter(InterestFilter("/ndn/CA/INFO"),
+                         [&](const auto&, const Interest& interest) {
+                           if (interest.matchesData(*metaData)) {
+                             face.put(*metaData);
+                           }
+                           else {
+                             BOOST_CHECK(interest.matchesData(*profileData));
+                             face.put(*profileData);
+                           }
+                         }, nullptr, nullptr);
+  advanceClocks(time::milliseconds(20), 60);
 
   int count = 0;
   face.onSendData.connect([&](const Data& response) {
-    count++;
-    BOOST_CHECK(security::verifySignature(response, cert));
-    auto contentBlock = response.getContent();
-    contentBlock.parse();
-    auto caItem = INFO::decodeDataContent(contentBlock);
-    BOOST_CHECK_EQUAL(caItem.m_caPrefix, "/ndn");
-    BOOST_CHECK_EQUAL(caItem.m_probeParameterKeys.size(), 1);
-    BOOST_CHECK_EQUAL(caItem.m_cert->wireEncode(), cert.wireEncode());
-    BOOST_CHECK_EQUAL(caItem.m_caInfo, "ndn testbed ca");
+    if (count == 0) {
+      count++;
+      auto block = response.getContent();
+      block.parse();
+      Interest interest(Name(block.get(tlv::Name)));
+      interest.setCanBePrefix(true);
+      infoInterest = make_shared<Interest>(interest);
+    }
+    else {
+      count++;
+      BOOST_CHECK(security::verifySignature(response, cert));
+      auto contentBlock = response.getContent();
+      contentBlock.parse();
+      auto caItem = INFO::decodeDataContent(contentBlock);
+      BOOST_CHECK_EQUAL(caItem.m_caPrefix, "/ndn");
+      BOOST_CHECK_EQUAL(caItem.m_probeParameterKeys.size(), 1);
+      BOOST_CHECK_EQUAL(caItem.m_probeParameterKeys.front(), "full name");
+      BOOST_CHECK_EQUAL(caItem.m_cert->wireEncode(), cert.wireEncode());
+      BOOST_CHECK_EQUAL(caItem.m_caInfo, "ndn testbed ca");
+    }
   });
   face.receive(interest);
-
   advanceClocks(time::milliseconds(20), 60);
-  BOOST_CHECK_EQUAL(count, 1);
+  face.receive(*infoInterest);
+  advanceClocks(time::milliseconds(20), 60);
+  BOOST_CHECK_EQUAL(count, 2);
 }
 
 BOOST_AUTO_TEST_CASE(HandleProbe)
diff --git a/tools/ndncert-client.cpp b/tools/ndncert-client.cpp
index 7f0d005..cecb978 100644
--- a/tools/ndncert-client.cpp
+++ b/tools/ndncert-client.cpp
@@ -275,10 +275,19 @@
   }
   else {
     //redirects
-    auto redirectedCaName = redirects[index - names.size()];
-    std::cerr << "You selected redirects with certificate: " << redirectedCaName.getPrefix(-1).toUri() << std::endl;
-    face.expressInterest(*Requester::genCaProfileInterest(redirects[index - names.size()]),
-                         bind(&InfoCb, _2, redirectedCaName), bind(&onNackCb), bind(&timeoutCb));
+    auto redirectedCaFullName = redirects[index - names.size()];
+    std::cerr << "You selected redirects with certificate: " << redirectedCaFullName.getPrefix(-1).toUri() << std::endl;
+    face.expressInterest(
+        *Requester::genCaProfileDiscoveryInterest(redirectedCaFullName.getPrefix(-1)),
+        [&](const Interest&, const Data& data) {
+          auto fetchingInterest = Requester::genCaProfileInterestFromDiscoveryResponse(data);
+          face.expressInterest(*fetchingInterest,
+                               bind(&InfoCb, _2, redirectedCaFullName),
+                               bind(&onNackCb),
+                               bind(&timeoutCb));
+        },
+        bind(&onNackCb),
+        bind(&timeoutCb));
   }
 }
 
@@ -312,8 +321,17 @@
               << "Step " << nStep << ": ADD NEW CA\nPlease type in the CA's Name:" << std::endl;
     std::string expectedCAName;
     getline(std::cin, expectedCAName);
-    face.expressInterest(*Requester::genCaProfileInterest(Name(expectedCAName)),
-                         bind(&InfoCb, _2, Name()), bind(&onNackCb), bind(&timeoutCb));
+    face.expressInterest(
+        *Requester::genCaProfileDiscoveryInterest(Name(expectedCAName)),
+        [&](const Interest&, const Data& data) {
+          auto fetchingInterest = Requester::genCaProfileInterestFromDiscoveryResponse(data);
+          face.expressInterest(*fetchingInterest,
+                               bind(&InfoCb, _2, Name()),
+                               bind(&onNackCb),
+                               bind(&timeoutCb));
+        },
+        bind(&onNackCb),
+        bind(&timeoutCb));
   }
   else {
     size_t caIndex;