blob: 0f9892010f6fd56d432653ddff67afd38e7b036b [file] [log] [blame]
Junxiao Shid2e60632018-08-10 10:48:44 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2013-2018 Regents of the University of California.
4 *
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
22#ifndef NDN_DETAIL_NAME_COMPONENT_TYPES_HPP
23#define NDN_DETAIL_NAME_COMPONENT_TYPES_HPP
24
25#include "../name-component.hpp"
26
27#include "../util/sha256.hpp"
28#include "../util/string-helper.hpp"
29
30#include <array>
31#include <unordered_map>
32
33namespace ndn {
34namespace name {
35namespace detail {
36
37/** \brief Declare rules regarding a NameComponent type.
38 */
39class ComponentType : noncopyable
40{
41public:
42 using Error = Component::Error;
43
44 virtual
45 ~ComponentType() = default;
46
47 /** \brief Throw Component::Error if \p comp is invalid.
48 */
49 virtual void
50 check(const Component& comp) const
51 {
52 }
53
54 /** \brief Calculate the successor of \p comp.
55 *
56 * If \p comp is the maximum possible value of this component type, return true to indicate
57 * that the successor should have a greater TLV-TYPE.
58 */
59 virtual std::pair<bool, Component>
60 getSuccessor(const Component& comp) const
61 {
62 return {false, getSuccessorImpl(comp).second};
63 }
64
65 /** \brief Return the minimum allowable TLV-VALUE of this component type.
66 */
67 virtual const std::vector<uint8_t>&
68 getMinValue() const
69 {
70 static std::vector<uint8_t> value;
71 return value;
72 }
73
74 /** \brief Return the prefix of the alternate URI representation.
75 *
76 * NDN URI specification allows a name component type to declare an alternate URI representation
77 * in the form of `<prefix>=<value>`, in addition to the plain `<type-number>=<escaped-value>`
78 * syntax.
79 *
80 * \return the `<prefix>` portion of the alternate URI representation.
81 * \retval nullptr this component does not have an alternate URI representation.
82 */
83 virtual const char*
84 getAltUriPrefix() const
85 {
86 return nullptr;
87 }
88
89 /** \brief Parse component from alternate URI representation.
90 * \param input the `<value>` portion of the alternate URI representation.
91 * \throw Component::Error
92 * \pre getAltUriPrefix() != nullptr
93 */
94 virtual Component
95 parseAltUriValue(const std::string& input) const
96 {
97 BOOST_ASSERT(false);
98 return Component();
99 }
100
101 /** \brief Write URI representation of \p comp to \p os.
102 *
103 * This base class implementation encodes the component in the plain
104 * `<type-number>=<escaped-value>` syntax.
105 */
106 virtual void
107 writeUri(std::ostream& os, const Component& comp) const
108 {
109 os << comp.type() << '=';
110 writeUriEscapedValue(os, comp);
111 }
112
113protected:
114 /** \brief Calculate the successor of \p comp, extending TLV-LENGTH if value overflows.
115 * \return whether TLV-LENGTH was extended, and the successor
116 */
117 std::pair<bool, Block>
118 getSuccessorImpl(const Component& comp) const
119 {
120 EncodingBuffer encoder(comp.size() + 9, 9);
121 // leave room for additional byte when TLV-VALUE overflows, and for TLV-LENGTH size increase
122
123 bool isOverflow = true;
124 size_t i = comp.value_size();
125 for (; isOverflow && i > 0; i--) {
126 uint8_t newValue = static_cast<uint8_t>((comp.value()[i - 1] + 1) & 0xFF);
127 encoder.prependByte(newValue);
128 isOverflow = (newValue == 0);
129 }
130 encoder.prependByteArray(comp.value(), i);
131
132 if (isOverflow) {
133 // new name component has to be extended
134 encoder.appendByte(0);
135 }
136
137 encoder.prependVarNumber(encoder.size());
138 encoder.prependVarNumber(comp.type());
139 return {isOverflow, encoder.block()};
140 }
141
142 /** \brief Write TLV-VALUE as `<escaped-value>` of NDN URI syntax.
143 */
144 void
145 writeUriEscapedValue(std::ostream& os, const Component& comp) const
146 {
147 bool isAllPeriods = std::all_of(comp.value_begin(), comp.value_end(),
148 [] (uint8_t x) { return x == '.'; });
149 if (isAllPeriods) {
150 os << "...";
151 }
152 escape(os, reinterpret_cast<const char*>(comp.value()), comp.value_size());
153 }
154};
155
156/** \brief Rules regarding GenericNameComponent.
157 *
158 * GenericNameComponent has an alternate URI representation that omits the `<type-number>` prefix.
159 * This must be special-cased in the caller, and is not handled by this class.
160 */
161class GenericNameComponentType final : public ComponentType
162{
163public:
164 void
165 writeUri(std::ostream& os, const Component& comp) const final
166 {
167 writeUriEscapedValue(os, comp);
168 }
169};
170
171/** \brief Rules regarding a component type holding a SHA256 digest value.
172 */
173class Sha256ComponentType final : public ComponentType
174{
175public:
176 Sha256ComponentType(uint32_t type, const std::string& typeName, const std::string& uriPrefix)
177 : m_type(type)
178 , m_typeName(typeName)
179 , m_uriPrefix(uriPrefix)
180 {
181 }
182
Junxiao Shi4053bd52018-08-16 13:39:25 -0600183 bool
184 match(const Component& comp) const
185 {
186 return comp.type() == m_type && comp.value_size() == util::Sha256::DIGEST_SIZE;
187 }
188
Junxiao Shid2e60632018-08-10 10:48:44 -0600189 void
190 check(const Component& comp) const final
191 {
Junxiao Shi4053bd52018-08-16 13:39:25 -0600192 if (!match(comp)) {
Junxiao Shid2e60632018-08-10 10:48:44 -0600193 BOOST_THROW_EXCEPTION(Error(m_typeName + " TLV-LENGTH must be " +
194 to_string(util::Sha256::DIGEST_SIZE)));
195 }
196 }
197
Junxiao Shi4053bd52018-08-16 13:39:25 -0600198 Component
199 create(ConstBufferPtr value) const
200 {
201 return Component(Block(m_type, std::move(value)));
202 }
203
204 Component
205 create(const uint8_t* value, size_t valueSize) const
206 {
207 return Component(makeBinaryBlock(m_type, value, valueSize));
208 }
209
Junxiao Shid2e60632018-08-10 10:48:44 -0600210 std::pair<bool, Component>
211 getSuccessor(const Component& comp) const final
212 {
213 bool isExtended = false;
214 Block successor;
215 std::tie(isExtended, successor) = getSuccessorImpl(comp);
216 if (isExtended) {
217 return {true, comp};
218 }
219 return {false, Component(successor)};
220 }
221
222 const std::vector<uint8_t>&
223 getMinValue() const final
224 {
Junxiao Shi4053bd52018-08-16 13:39:25 -0600225 static std::vector<uint8_t> value(util::Sha256::DIGEST_SIZE);
Junxiao Shid2e60632018-08-10 10:48:44 -0600226 return value;
227 }
228
229 const char*
230 getAltUriPrefix() const final
231 {
232 return m_uriPrefix.data();
233 }
234
235 Component
236 parseAltUriValue(const std::string& input) const final
237 {
238 shared_ptr<Buffer> value;
239 try {
240 value = fromHex(input);
241 }
242 catch (const StringHelperError&) {
243 BOOST_THROW_EXCEPTION(Error("Cannot convert to " + m_typeName + " (invalid hex encoding)"));
244 }
245 return Component(m_type, std::move(value));
246 }
247
248 void
249 writeUri(std::ostream& os, const Component& comp) const final
250 {
251 os << m_uriPrefix << '=';
252 printHex(os, comp.value(), comp.value_size(), false);
253 }
254
255private:
256 uint32_t m_type;
257 std::string m_typeName;
258 std::string m_uriPrefix;
259};
260
Junxiao Shi4053bd52018-08-16 13:39:25 -0600261inline const Sha256ComponentType&
262getComponentType1()
263{
264 static Sha256ComponentType ct1(tlv::ImplicitSha256DigestComponent,
265 "ImplicitSha256DigestComponent", "sha256digest");
266 return ct1;
267}
268
269inline const Sha256ComponentType&
270getComponentType2()
271{
272 static Sha256ComponentType ct2(tlv::ParametersSha256DigestComponent,
273 "ParametersSha256DigestComponent", "params-sha256");
274 return ct2;
275}
276
Junxiao Shid2e60632018-08-10 10:48:44 -0600277/** \brief Rules regarding NameComponent types.
278 */
279class ComponentTypeTable : noncopyable
280{
281public:
282 ComponentTypeTable();
283
284 /** \brief Retrieve ComponentType by TLV-TYPE.
285 */
286 const ComponentType&
287 get(uint32_t type) const
288 {
289 if (type >= m_table.size() || m_table[type] == nullptr) {
290 return m_baseType;
291 }
292 return *m_table[type];
293 }
294
295 /** \brief Retrieve ComponentType by alternate URI prefix.
296 */
297 const ComponentType*
298 findByUriPrefix(const std::string& prefix) const
299 {
300 auto it = m_uriPrefixes.find(prefix);
301 if (it == m_uriPrefixes.end()) {
302 return nullptr;
303 }
304 return it->second;
305 }
306
307private:
308 void
309 set(uint32_t type, const ComponentType& ct)
310 {
311 m_table.at(type) = &ct;
312 if (ct.getAltUriPrefix() != nullptr) {
313 m_uriPrefixes[ct.getAltUriPrefix()] = &ct;
314 }
315 }
316
317private:
318 ComponentType m_baseType;
319 std::array<const ComponentType*, 32> m_table;
320 std::unordered_map<std::string, const ComponentType*> m_uriPrefixes;
321};
322
Junxiao Shi4053bd52018-08-16 13:39:25 -0600323inline
Junxiao Shid2e60632018-08-10 10:48:44 -0600324ComponentTypeTable::ComponentTypeTable()
325{
326 m_table.fill(nullptr);
327
328 static GenericNameComponentType ct8;
329 set(tlv::GenericNameComponent, ct8);
330
Junxiao Shi4053bd52018-08-16 13:39:25 -0600331 set(tlv::ImplicitSha256DigestComponent, getComponentType1());
332 set(tlv::ParametersSha256DigestComponent, getComponentType2());
Junxiao Shid2e60632018-08-10 10:48:44 -0600333}
334
335/** \brief Get the global ComponentTypeTable.
336 */
Junxiao Shi4053bd52018-08-16 13:39:25 -0600337inline const ComponentTypeTable&
Junxiao Shid2e60632018-08-10 10:48:44 -0600338getComponentTypeTable()
339{
340 static ComponentTypeTable ctt;
341 return ctt;
342}
343
344} // namespace detail
345} // namespace name
346} // namespace ndn
347
348#endif // NDN_DETAIL_NAME_COMPONENT_TYPES_HPP