blob: 52ae571d32ff9f79a2b0434f2661d499dcc3b650 [file] [log] [blame]
Alexander Afanasyev197e5652014-06-13 16:56:31 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento10b24be2017-07-12 23:23:46 -04002/*
Eric Newberrya3c8bd12020-05-15 17:27:07 -07003 * Copyright (c) 2013-2020 Regents of the University of California.
Alexander Afanasyev197e5652014-06-13 16:56:31 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
Davide Pesavento7e780642018-11-24 15:51:34 -050022#include "ndn-cxx/data.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050023#include "ndn-cxx/util/sha256.hpp"
Alexander Afanasyev197e5652014-06-13 16:56:31 -070024
25namespace ndn {
26
Junxiao Shic2b8d242014-11-04 08:35:29 -070027BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Data>));
28BOOST_CONCEPT_ASSERT((WireEncodable<Data>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070029BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Data>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070030BOOST_CONCEPT_ASSERT((WireDecodable<Data>));
31static_assert(std::is_base_of<tlv::Error, Data::Error>::value,
32 "Data::Error must inherit from tlv::Error");
33
Alexander Afanasyev197e5652014-06-13 16:56:31 -070034Data::Data(const Name& name)
35 : m_name(name)
36{
37}
38
39Data::Data(const Block& wire)
40{
41 wireDecode(wire);
42}
43
Alexander Afanasyev74633892015-02-08 18:08:46 -080044template<encoding::Tag TAG>
Alexander Afanasyev197e5652014-06-13 16:56:31 -070045size_t
Junxiao Shi81206d52017-07-23 12:43:22 +000046Data::wireEncode(EncodingImpl<TAG>& encoder, bool wantUnsignedPortionOnly) const
Alexander Afanasyev197e5652014-06-13 16:56:31 -070047{
Davide Pesavento905d40f2020-06-09 21:33:25 -040048 // Data = DATA-TYPE TLV-LENGTH
49 // Name
50 // [MetaInfo]
51 // [Content]
52 // SignatureInfo
53 // SignatureValue
54 // (elements are encoded in reverse order)
Alexander Afanasyev197e5652014-06-13 16:56:31 -070055
Junxiao Shi81206d52017-07-23 12:43:22 +000056 size_t totalLength = 0;
Alexander Afanasyev197e5652014-06-13 16:56:31 -070057
Junxiao Shi81206d52017-07-23 12:43:22 +000058 // SignatureValue
59 if (!wantUnsignedPortionOnly) {
Eric Newberrya3c8bd12020-05-15 17:27:07 -070060 if (!m_signatureInfo) {
Davide Pesavento923ba442019-02-12 22:00:38 -050061 NDN_THROW(Error("Requested wire format, but Data has not been signed"));
Alexander Afanasyev197e5652014-06-13 16:56:31 -070062 }
Eric Newberrya3c8bd12020-05-15 17:27:07 -070063 totalLength += encoder.prependBlock(m_signatureValue);
Junxiao Shi81206d52017-07-23 12:43:22 +000064 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -070065
66 // SignatureInfo
Eric Newberryf165bb42020-05-22 11:28:45 -070067 totalLength += m_signatureInfo.wireEncode(encoder, SignatureInfo::Type::Data);
Alexander Afanasyev197e5652014-06-13 16:56:31 -070068
69 // Content
Davide Pesavento81bd6962020-06-17 16:03:23 -040070 if (hasContent()) {
71 totalLength += encoder.prependBlock(m_content);
72 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -070073
74 // MetaInfo
Davide Pesavento81bd6962020-06-17 16:03:23 -040075 totalLength += m_metaInfo.wireEncode(encoder);
Alexander Afanasyev197e5652014-06-13 16:56:31 -070076
77 // Name
Davide Pesavento81bd6962020-06-17 16:03:23 -040078 totalLength += m_name.wireEncode(encoder);
Alexander Afanasyev197e5652014-06-13 16:56:31 -070079
Junxiao Shi81206d52017-07-23 12:43:22 +000080 if (!wantUnsignedPortionOnly) {
81 totalLength += encoder.prependVarNumber(totalLength);
82 totalLength += encoder.prependVarNumber(tlv::Data);
83 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -070084 return totalLength;
85}
86
Alexander Afanasyev15f67312014-07-22 15:11:09 -070087template size_t
Davide Pesavento88a0d812017-08-19 21:31:42 -040088Data::wireEncode<encoding::EncoderTag>(EncodingBuffer&, bool) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -070089
90template size_t
Davide Pesavento88a0d812017-08-19 21:31:42 -040091Data::wireEncode<encoding::EstimatorTag>(EncodingEstimator&, bool) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -070092
Alexander Afanasyev197e5652014-06-13 16:56:31 -070093const Block&
94Data::wireEncode(EncodingBuffer& encoder, const Block& signatureValue) const
95{
96 size_t totalLength = encoder.size();
97 totalLength += encoder.appendBlock(signatureValue);
98
Davide Pesavento9bd4d982015-05-13 14:31:19 +020099 encoder.prependVarNumber(totalLength);
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600100 encoder.prependVarNumber(tlv::Data);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700101
102 const_cast<Data*>(this)->wireDecode(encoder.block());
103 return m_wire;
104}
105
106const Block&
107Data::wireEncode() const
108{
109 if (m_wire.hasWire())
110 return m_wire;
111
112 EncodingEstimator estimator;
113 size_t estimatedSize = wireEncode(estimator);
114
115 EncodingBuffer buffer(estimatedSize, 0);
116 wireEncode(buffer);
117
118 const_cast<Data*>(this)->wireDecode(buffer.block());
119 return m_wire;
120}
121
122void
123Data::wireDecode(const Block& wire)
124{
Davide Pesavento905d40f2020-06-09 21:33:25 -0400125 if (wire.type() != tlv::Data) {
126 NDN_THROW(Error("Data", wire.type()));
127 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700128 m_wire = wire;
129 m_wire.parse();
Junxiao Shi8b753a22018-10-24 01:51:40 +0000130
Davide Pesavento905d40f2020-06-09 21:33:25 -0400131 // Data = DATA-TYPE TLV-LENGTH
132 // Name
133 // [MetaInfo]
134 // [Content]
135 // SignatureInfo
136 // SignatureValue
137
Junxiao Shi8b753a22018-10-24 01:51:40 +0000138 auto element = m_wire.elements_begin();
139 if (element == m_wire.elements_end() || element->type() != tlv::Name) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500140 NDN_THROW(Error("Name element is missing or out of order"));
Junxiao Shi8b753a22018-10-24 01:51:40 +0000141 }
142 m_name.wireDecode(*element);
Junxiao Shi8b753a22018-10-24 01:51:40 +0000143
Davide Pesavento905d40f2020-06-09 21:33:25 -0400144 m_metaInfo = {};
Davide Pesavento81bd6962020-06-17 16:03:23 -0400145 m_content = {};
Davide Pesavento905d40f2020-06-09 21:33:25 -0400146 m_signatureInfo = {};
147 m_signatureValue = {};
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000148 m_fullName.clear();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700149
Davide Pesavento905d40f2020-06-09 21:33:25 -0400150 int lastElement = 1; // last recognized element index, in spec order
Junxiao Shi8b753a22018-10-24 01:51:40 +0000151 for (++element; element != m_wire.elements_end(); ++element) {
152 switch (element->type()) {
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000153 case tlv::MetaInfo: {
Junxiao Shi8b753a22018-10-24 01:51:40 +0000154 if (lastElement >= 2) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500155 NDN_THROW(Error("MetaInfo element is out of order"));
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000156 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000157 m_metaInfo.wireDecode(*element);
158 lastElement = 2;
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000159 break;
160 }
161 case tlv::Content: {
Junxiao Shi8b753a22018-10-24 01:51:40 +0000162 if (lastElement >= 3) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500163 NDN_THROW(Error("Content element is out of order"));
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000164 }
Junxiao Shi8b753a22018-10-24 01:51:40 +0000165 m_content = *element;
166 lastElement = 3;
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000167 break;
168 }
169 case tlv::SignatureInfo: {
Junxiao Shi8b753a22018-10-24 01:51:40 +0000170 if (lastElement >= 4) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500171 NDN_THROW(Error("SignatureInfo element is out of order"));
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000172 }
Eric Newberrya3c8bd12020-05-15 17:27:07 -0700173 m_signatureInfo.wireDecode(*element);
Junxiao Shi8b753a22018-10-24 01:51:40 +0000174 lastElement = 4;
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000175 break;
176 }
177 case tlv::SignatureValue: {
Junxiao Shi8b753a22018-10-24 01:51:40 +0000178 if (lastElement >= 5) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500179 NDN_THROW(Error("SignatureValue element is out of order"));
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000180 }
Eric Newberrya3c8bd12020-05-15 17:27:07 -0700181 m_signatureValue = *element;
Junxiao Shi8b753a22018-10-24 01:51:40 +0000182 lastElement = 5;
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000183 break;
184 }
Davide Pesavento905d40f2020-06-09 21:33:25 -0400185 default: { // unrecognized element
186 // if the TLV-TYPE is critical, abort decoding
Junxiao Shi8b753a22018-10-24 01:51:40 +0000187 if (tlv::isCriticalType(element->type())) {
Davide Pesavento905d40f2020-06-09 21:33:25 -0400188 NDN_THROW(Error("Unrecognized element of critical type " + to_string(element->type())));
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000189 }
Davide Pesavento905d40f2020-06-09 21:33:25 -0400190 // otherwise, ignore it
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000191 break;
192 }
193 }
194 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700195
Eric Newberrya3c8bd12020-05-15 17:27:07 -0700196 if (!m_signatureInfo) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500197 NDN_THROW(Error("SignatureInfo element is missing"));
Junxiao Shi81206d52017-07-23 12:43:22 +0000198 }
Davide Pesavento46cdf902020-06-08 16:38:23 -0400199 if (!m_signatureValue.isValid()) {
Eric Newberrya3c8bd12020-05-15 17:27:07 -0700200 NDN_THROW(Error("SignatureValue element is missing"));
201 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700202}
203
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700204const Name&
205Data::getFullName() const
206{
207 if (m_fullName.empty()) {
208 if (!m_wire.hasWire()) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500209 NDN_THROW(Error("Cannot compute full name because Data has no wire encoding (not signed)"));
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700210 }
211 m_fullName = m_name;
Davide Pesavento10b24be2017-07-12 23:23:46 -0400212 m_fullName.appendImplicitSha256Digest(util::Sha256::computeDigest(m_wire.wire(), m_wire.size()));
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700213 }
214
215 return m_fullName;
216}
217
Junxiao Shi81206d52017-07-23 12:43:22 +0000218void
219Data::resetWire()
220{
221 m_wire.reset();
222 m_fullName.clear();
223}
224
225Data&
226Data::setName(const Name& name)
227{
Davide Pesavento905d40f2020-06-09 21:33:25 -0400228 if (name != m_name) {
229 m_name = name;
230 resetWire();
231 }
Junxiao Shi81206d52017-07-23 12:43:22 +0000232 return *this;
233}
234
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700235Data&
236Data::setMetaInfo(const MetaInfo& metaInfo)
237{
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700238 m_metaInfo = metaInfo;
Davide Pesavento905d40f2020-06-09 21:33:25 -0400239 resetWire();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700240 return *this;
241}
242
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700243Data&
Junxiao Shi81206d52017-07-23 12:43:22 +0000244Data::setContent(const Block& block)
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700245{
Davide Pesavento81bd6962020-06-17 16:03:23 -0400246 if (!block.isValid()) {
247 NDN_THROW(std::invalid_argument("Content block must be valid"));
248 }
249
Junxiao Shi81206d52017-07-23 12:43:22 +0000250 if (block.type() == tlv::Content) {
251 m_content = block;
252 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700253 else {
Junxiao Shi81206d52017-07-23 12:43:22 +0000254 m_content = Block(tlv::Content, block);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700255 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400256 m_content.encode();
Davide Pesavento905d40f2020-06-09 21:33:25 -0400257 resetWire();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700258 return *this;
259}
260
261Data&
Davide Pesavento81bd6962020-06-17 16:03:23 -0400262Data::setContent(const uint8_t* value, size_t length)
Junxiao Shi81206d52017-07-23 12:43:22 +0000263{
Davide Pesavento81bd6962020-06-17 16:03:23 -0400264 if (value == nullptr && length != 0) {
265 NDN_THROW(std::invalid_argument("Content buffer cannot be nullptr"));
266 }
267
268 m_content = makeBinaryBlock(tlv::Content, value, length);
Davide Pesavento905d40f2020-06-09 21:33:25 -0400269 resetWire();
Junxiao Shi81206d52017-07-23 12:43:22 +0000270 return *this;
271}
272
273Data&
Davide Pesavento3b101d02018-07-21 22:44:09 -0400274Data::setContent(ConstBufferPtr value)
Junxiao Shi81206d52017-07-23 12:43:22 +0000275{
Davide Pesavento14c56cd2020-05-21 01:44:03 -0400276 if (value == nullptr) {
277 NDN_THROW(std::invalid_argument("Content buffer cannot be nullptr"));
278 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400279
Davide Pesavento3b101d02018-07-21 22:44:09 -0400280 m_content = Block(tlv::Content, std::move(value));
Davide Pesavento905d40f2020-06-09 21:33:25 -0400281 resetWire();
Junxiao Shi81206d52017-07-23 12:43:22 +0000282 return *this;
283}
284
Davide Pesavento81bd6962020-06-17 16:03:23 -0400285Data&
286Data::unsetContent()
287{
288 m_content = {};
289 resetWire();
290 return *this;
291}
292
Eric Newberrya3c8bd12020-05-15 17:27:07 -0700293Data&
294Data::setSignatureInfo(const SignatureInfo& info)
295{
Eric Newberrya3c8bd12020-05-15 17:27:07 -0700296 m_signatureInfo = info;
Davide Pesavento905d40f2020-06-09 21:33:25 -0400297 resetWire();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700298 return *this;
299}
300
301Data&
Davide Pesavento14c56cd2020-05-21 01:44:03 -0400302Data::setSignatureValue(ConstBufferPtr value)
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700303{
Davide Pesavento14c56cd2020-05-21 01:44:03 -0400304 if (value == nullptr) {
305 NDN_THROW(std::invalid_argument("SignatureValue buffer cannot be nullptr"));
Eric Newberrya3c8bd12020-05-15 17:27:07 -0700306 }
Davide Pesavento81bd6962020-06-17 16:03:23 -0400307
Davide Pesavento14c56cd2020-05-21 01:44:03 -0400308 m_signatureValue = Block(tlv::SignatureValue, std::move(value));
Davide Pesavento905d40f2020-06-09 21:33:25 -0400309 resetWire();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700310 return *this;
311}
312
Eric Newberrye36aae12020-08-31 22:23:13 -0700313InputBuffers
314Data::extractSignedRanges() const
315{
316 InputBuffers bufs;
317 bufs.reserve(1); // One range containing data value up to, but not including, SignatureValue
318
319 wireEncode();
320 auto lastSignedIt = std::prev(m_wire.find(tlv::SignatureValue));
321 bufs.emplace_back(m_wire.value(),
322 std::distance(m_wire.value_begin(), lastSignedIt->end()));
323 return bufs;
324}
325
Junxiao Shi81206d52017-07-23 12:43:22 +0000326Data&
327Data::setContentType(uint32_t type)
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700328{
Davide Pesavento905d40f2020-06-09 21:33:25 -0400329 if (type != m_metaInfo.getType()) {
330 m_metaInfo.setType(type);
331 resetWire();
332 }
Junxiao Shi81206d52017-07-23 12:43:22 +0000333 return *this;
334}
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700335
Junxiao Shi81206d52017-07-23 12:43:22 +0000336Data&
Junxiao Shiebfe4a22018-04-01 23:53:40 +0000337Data::setFreshnessPeriod(time::milliseconds freshnessPeriod)
Junxiao Shi81206d52017-07-23 12:43:22 +0000338{
Davide Pesavento905d40f2020-06-09 21:33:25 -0400339 if (freshnessPeriod != m_metaInfo.getFreshnessPeriod()) {
340 m_metaInfo.setFreshnessPeriod(freshnessPeriod);
341 resetWire();
342 }
Junxiao Shi81206d52017-07-23 12:43:22 +0000343 return *this;
344}
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700345
Junxiao Shi81206d52017-07-23 12:43:22 +0000346Data&
Junxiao Shiebfe4a22018-04-01 23:53:40 +0000347Data::setFinalBlock(optional<name::Component> finalBlockId)
348{
Davide Pesavento905d40f2020-06-09 21:33:25 -0400349 if (finalBlockId != m_metaInfo.getFinalBlock()) {
350 m_metaInfo.setFinalBlock(std::move(finalBlockId));
351 resetWire();
352 }
Junxiao Shiebfe4a22018-04-01 23:53:40 +0000353 return *this;
354}
355
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700356bool
Junxiao Shi81206d52017-07-23 12:43:22 +0000357operator==(const Data& lhs, const Data& rhs)
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700358{
Junxiao Shi81206d52017-07-23 12:43:22 +0000359 return lhs.getName() == rhs.getName() &&
Davide Pesaventoef654dd2019-07-18 20:02:44 -0400360 lhs.getMetaInfo().wireEncode() == rhs.getMetaInfo().wireEncode() &&
Junxiao Shi81206d52017-07-23 12:43:22 +0000361 lhs.getContent() == rhs.getContent() &&
Eric Newberrya3c8bd12020-05-15 17:27:07 -0700362 lhs.getSignatureInfo() == rhs.getSignatureInfo() &&
363 lhs.getSignatureValue() == rhs.getSignatureValue();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700364}
365
366std::ostream&
367operator<<(std::ostream& os, const Data& data)
368{
Davide Pesavento81bd6962020-06-17 16:03:23 -0400369 os << "Name: " << data.getName() << "\n"
370 << "MetaInfo: [" << data.getMetaInfo() << "]\n";
371
372 if (data.hasContent()) {
373 os << "Content: [" << data.getContent().value_size() << " bytes]\n";
374 }
375
376 os << "Signature: [type: " << static_cast<tlv::SignatureTypeValue>(data.getSignatureType())
377 << ", length: "<< data.getSignatureValue().value_size() << "]\n";
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700378
379 return os;
380}
381
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700382} // namespace ndn