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 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | Q_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 | */ |
70 | QCoapOption::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 | */ |
84 | QCoapOption::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 | */ |
98 | QCoapOption::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 | */ |
112 | QCoapOption::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 | */ |
121 | QCoapOption::QCoapOption(QCoapOption &&other) : |
122 | d_ptr(other.d_ptr) |
123 | { |
124 | other.d_ptr = nullptr; |
125 | } |
126 | |
127 | /*! |
128 | Destroys the QCoapOption object. |
129 | */ |
130 | QCoapOption::~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 | */ |
139 | QCoapOption &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 | */ |
149 | QCoapOption &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 | */ |
158 | void 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 | */ |
166 | QByteArray 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 | */ |
175 | quint32 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 | */ |
189 | QString 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 | */ |
198 | int 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 | */ |
207 | QCoapOption::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 | */ |
216 | bool 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 | */ |
225 | bool 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 | */ |
235 | bool 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 | */ |
245 | void 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 | */ |
311 | void 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 | */ |
322 | void 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 | */ |
336 | QCoapOptionPrivate *QCoapOption::d_func() |
337 | { |
338 | return d_ptr; |
339 | } |
340 | |
341 | QT_END_NAMESPACE |
342 | |