| 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 | Moves \a other into this option and returns a reference to this QCoapOption. |
| 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 | |