1// Copyright (C) 2017 Witekio.
2// Copyright (C) 2018 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5#include "qcoapoption_p.h"
6
7#include <QtCore/qdebug.h>
8#include <QtCore/qloggingcategory.h>
9
10QT_BEGIN_NAMESPACE
11
12Q_LOGGING_CATEGORY(lcCoapOption, "qt.coap.option")
13
14/*!
15 \class QCoapOption
16 \inmodule QtCoap
17
18 \brief The QCoapOption class holds data about CoAP options.
19
20 \reentrant
21
22 CoAP defines a number of options that can be included in a message.
23 Both requests and responses may include a list of one or more
24 options. For example, the URI in a request is transported in several
25 options, and metadata that would be carried in an HTTP header in HTTP
26 is supplied as options as well.
27
28 An option contains a name, related to an option ID, and a value.
29 The name is one of the values from the OptionName enumeration.
30*/
31
32/*!
33 \enum QCoapOption::OptionName
34
35 Indicates the name of an option.
36 The value of each ID is as specified by the CoAP standard, with the
37 exception of Invalid. You can refer to
38 \l{https://tools.ietf.org/html/rfc7252#section-5.10}{RFC 7252} and
39 \l{https://tools.ietf.org/html/rfc7959#section-2.1}{RFC 7959} for more details.
40
41 \value Invalid An invalid option.
42 \value IfMatch If-Match option.
43 \value UriHost Uri-Host option.
44 \value Etag Etag option.
45 \value IfNoneMatch If-None-Match option.
46 \value Observe Observe option.
47 \value UriPort Uri-Port option.
48 \value LocationPath Location-path option.
49 \value UriPath Uri-Path option.
50 \value ContentFormat Content-Format option.
51 \value MaxAge Max-Age option.
52 \value UriQuery Uri-Query option.
53 \value Accept Accept option.
54 \value LocationQuery Location-Query option.
55 \value Block2 Block2 option.
56 \value Block1 Block1 option.
57 \value Size2 Size2 option.
58 \value ProxyUri Proxy-Uri option.
59 \value ProxyScheme Proxy-Scheme option.
60 \value Size1 Size1 option.
61*/
62
63/*!
64 Constructs a new CoAP option with the given \a name
65 and QByteArray \a opaqueValue.
66 If no parameters are passed, constructs an Invalid object.
67
68 \sa isValid()
69 */
70QCoapOption::QCoapOption(OptionName name, const QByteArray &opaqueValue) :
71 d_ptr(new QCoapOptionPrivate)
72{
73 Q_D(QCoapOption);
74 d->name = name;
75 d->setValue(opaqueValue);
76}
77
78/*!
79 Constructs a new CoAP option with the given \a name
80 and the QString \a stringValue.
81
82 \sa isValid()
83 */
84QCoapOption::QCoapOption(OptionName name, const QString &stringValue) :
85 d_ptr(new QCoapOptionPrivate)
86{
87 Q_D(QCoapOption);
88 d->name = name;
89 d->setValue(stringValue);
90}
91
92/*!
93 Constructs a new CoAP option with the given \a name
94 and the unsigned integer \a intValue.
95
96 \sa isValid()
97 */
98QCoapOption::QCoapOption(OptionName name, quint32 intValue) :
99 d_ptr(new QCoapOptionPrivate)
100{
101 Q_D(QCoapOption);
102 d->name = name;
103 d->setValue(intValue);
104}
105
106/*!
107 Constructs a new CoAP option as a copy of \a other, making the two
108 options identical.
109
110 \sa isValid()
111 */
112QCoapOption::QCoapOption(const QCoapOption &other) :
113 d_ptr(new QCoapOptionPrivate(*other.d_ptr))
114{
115}
116
117/*!
118 Move-constructs a QCoapOption, making it point to the same object
119 as \a other was pointing to.
120 */
121QCoapOption::QCoapOption(QCoapOption &&other) :
122 d_ptr(other.d_ptr)
123{
124 other.d_ptr = nullptr;
125}
126
127/*!
128 Destroys the QCoapOption object.
129 */
130QCoapOption::~QCoapOption()
131{
132 delete d_ptr;
133}
134
135/*!
136 Copies \a other into this option, making the two options identical.
137 Returns a reference to this QCoapOption.
138 */
139QCoapOption &QCoapOption::operator=(const QCoapOption &other)
140{
141 QCoapOption copy(other);
142 swap(other&: copy);
143 return *this;
144}
145
146/*!
147 Move-assignment operator.
148 */
149QCoapOption &QCoapOption::operator=(QCoapOption &&other) noexcept
150{
151 swap(other);
152 return *this;
153}
154
155/*!
156 Swaps this option with \a other. This operation is very fast and never fails.
157 */
158void QCoapOption::swap(QCoapOption &other) noexcept
159{
160 qSwap(value1&: d_ptr, value2&: other.d_ptr);
161}
162
163/*!
164 Returns the value of the option.
165 */
166QByteArray QCoapOption::opaqueValue() const
167{
168 Q_D(const QCoapOption);
169 return d->value;
170}
171
172/*!
173 Returns the integer value of the option.
174 */
175quint32 QCoapOption::uintValue() const
176{
177 Q_D(const QCoapOption);
178
179 quint32 intValue = 0;
180 for (int i = 0; i < d->value.size(); i++)
181 intValue |= static_cast<quint8>(d->value.at(i)) << (8 * i);
182
183 return intValue;
184}
185
186/*!
187 Returns the QString value of the option.
188*/
189QString QCoapOption::stringValue() const
190{
191 Q_D(const QCoapOption);
192 return QString::fromUtf8(ba: d->value);
193}
194
195/*!
196 Returns the length of the value of the option.
197 */
198int QCoapOption::length() const
199{
200 Q_D(const QCoapOption);
201 return d->value.size();
202}
203
204/*!
205 Returns the name of the option.
206 */
207QCoapOption::OptionName QCoapOption::name() const
208{
209 Q_D(const QCoapOption);
210 return d->name;
211}
212
213/*!
214 Returns \c true if the option is valid.
215 */
216bool QCoapOption::isValid() const
217{
218 Q_D(const QCoapOption);
219 return d->name != QCoapOption::Invalid;
220}
221
222/*!
223 Returns \c true if this QCoapOption and \a other are equals.
224 */
225bool QCoapOption::operator==(const QCoapOption &other) const
226{
227 Q_D(const QCoapOption);
228 return (d->name == other.d_ptr->name
229 && d->value == other.d_ptr->value);
230}
231
232/*!
233 Returns \c true if this QCoapOption and \a other are different.
234 */
235bool QCoapOption::operator!=(const QCoapOption &other) const
236{
237 return !(*this == other);
238}
239
240/*!
241 \internal
242
243 Sets the \a value for the option.
244 */
245void QCoapOptionPrivate::setValue(const QByteArray &opaqueValue)
246{
247 bool oversized = false;
248
249 // Check for value maximum size, according to section 5.10 of RFC 7252
250 // https://tools.ietf.org/html/rfc7252#section-5.10
251 switch (name) {
252 case QCoapOption::IfNoneMatch:
253 if (opaqueValue.size() > 0)
254 oversized = true;
255 break;
256
257 case QCoapOption::UriPort:
258 case QCoapOption::ContentFormat:
259 case QCoapOption::Accept:
260 if (opaqueValue.size() > 2)
261 oversized = true;
262 break;
263
264 case QCoapOption::MaxAge:
265 case QCoapOption::Size1:
266 if (opaqueValue.size() > 4)
267 oversized = true;
268 break;
269
270 case QCoapOption::IfMatch:
271 case QCoapOption::Etag:
272 if (opaqueValue.size() > 8)
273 oversized = true;
274 break;
275
276 case QCoapOption::UriHost:
277 case QCoapOption::LocationPath:
278 case QCoapOption::UriPath:
279 case QCoapOption::UriQuery:
280 case QCoapOption::LocationQuery:
281 case QCoapOption::ProxyScheme:
282 if (opaqueValue.size() > 255)
283 oversized = true;
284 break;
285
286 case QCoapOption::ProxyUri:
287 if (opaqueValue.size() > 1034)
288 oversized = true;
289 break;
290
291 case QCoapOption::Observe:
292 case QCoapOption::Block2:
293 case QCoapOption::Block1:
294 case QCoapOption::Size2:
295 default:
296 break;
297 }
298
299 if (oversized)
300 qCWarning(lcCoapOption) << "Value" << opaqueValue << "is probably too big for option" << name;
301
302 value = opaqueValue;
303}
304
305/*!
306 \internal
307 \overload
308
309 Sets the \a value for the option.
310 */
311void QCoapOptionPrivate::setValue(const QString &value)
312{
313 setValue(value.toUtf8());
314}
315
316/*!
317 \internal
318 \overload
319
320 Sets the \a value for the option.
321 */
322void QCoapOptionPrivate::setValue(quint32 value)
323{
324 QByteArray data;
325 for (; value; value >>= 8)
326 data.append(c: static_cast<qint8>(value & 0xFF));
327
328 setValue(data);
329}
330
331/*!
332 \internal
333
334 For QSharedDataPointer.
335*/
336QCoapOptionPrivate *QCoapOption::d_func()
337{
338 return d_ptr;
339}
340
341QT_END_NAMESPACE
342

source code of qtcoap/src/coap/qcoapoption.cpp