Source code

Revision control

Copy as Markdown

// Copyright (C) 2017 Witekio.
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qcoapoption_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
Q_STATIC_LOGGING_CATEGORY(lcCoapOption, "qt.coap.option")
/*!
\class QCoapOption
\inmodule QtCoap
\brief The QCoapOption class holds data about CoAP options.
\reentrant
CoAP defines a number of options that can be included in a message.
Both requests and responses may include a list of one or more
options. For example, the URI in a request is transported in several
options, and metadata that would be carried in an HTTP header in HTTP
is supplied as options as well.
An option contains a name, related to an option ID, and a value.
The name is one of the values from the OptionName enumeration.
*/
/*!
\enum QCoapOption::OptionName
Indicates the name of an option.
The value of each ID is as specified by the CoAP standard, with the
exception of Invalid. You can refer to
\l{https://tools.ietf.org/html/rfc7959#section-2.1}{RFC 7959} for more details.
\value Invalid An invalid option.
\value IfMatch If-Match option.
\value UriHost Uri-Host option.
\value Etag Etag option.
\value IfNoneMatch If-None-Match option.
\value Observe Observe option.
\value UriPort Uri-Port option.
\value LocationPath Location-path option.
\value UriPath Uri-Path option.
\value ContentFormat Content-Format option.
\value MaxAge Max-Age option.
\value UriQuery Uri-Query option.
\value Accept Accept option.
\value LocationQuery Location-Query option.
\value Block2 Block2 option.
\value Block1 Block1 option.
\value Size2 Size2 option.
\value ProxyUri Proxy-Uri option.
\value ProxyScheme Proxy-Scheme option.
\value Size1 Size1 option.
*/
/*!
Constructs a new CoAP option with the given \a name
and QByteArray \a opaqueValue.
If no parameters are passed, constructs an Invalid object.
\sa isValid()
*/
QCoapOption::QCoapOption(OptionName name, const QByteArray &opaqueValue) :
d_ptr(new QCoapOptionPrivate)
{
Q_D(QCoapOption);
d->name = name;
d->setValue(opaqueValue);
}
/*!
Constructs a new CoAP option with the given \a name
and the QString \a stringValue.
\sa isValid()
*/
QCoapOption::QCoapOption(OptionName name, const QString &stringValue) :
d_ptr(new QCoapOptionPrivate)
{
Q_D(QCoapOption);
d->name = name;
d->setValue(stringValue);
}
/*!
Constructs a new CoAP option with the given \a name
and the unsigned integer \a intValue.
\sa isValid()
*/
QCoapOption::QCoapOption(OptionName name, quint32 intValue) :
d_ptr(new QCoapOptionPrivate)
{
Q_D(QCoapOption);
d->name = name;
d->setValue(intValue);
}
/*!
Constructs a new CoAP option as a copy of \a other, making the two
options identical.
\sa isValid()
*/
QCoapOption::QCoapOption(const QCoapOption &other) :
d_ptr(new QCoapOptionPrivate(*other.d_ptr))
{
}
/*!
Move-constructs a QCoapOption, making it point to the same object
as \a other was pointing to.
*/
QCoapOption::QCoapOption(QCoapOption &&other) :
d_ptr(other.d_ptr)
{
other.d_ptr = nullptr;
}
/*!
Destroys the QCoapOption object.
*/
QCoapOption::~QCoapOption()
{
delete d_ptr;
}
/*!
Copies \a other into this option, making the two options identical.
Returns a reference to this QCoapOption.
*/
QCoapOption &QCoapOption::operator=(const QCoapOption &other)
{
QCoapOption copy(other);
swap(copy);
return *this;
}
/*!
Moves \a other into this option and returns a reference to this QCoapOption.
*/
QCoapOption &QCoapOption::operator=(QCoapOption &&other) noexcept
{
swap(other);
return *this;
}
/*!
Swaps this option with \a other. This operation is very fast and never fails.
*/
void QCoapOption::swap(QCoapOption &other) noexcept
{
qt_ptr_swap(d_ptr, other.d_ptr);
}
/*!
Returns the value of the option.
*/
QByteArray QCoapOption::opaqueValue() const
{
Q_D(const QCoapOption);
return d->value;
}
/*!
Returns the integer value of the option.
\note A uint option holds at most 4 bytes. If the option value is longer,
only its low 4 bytes are used to compute the result; use \l length() to
detect an over-long value.
*/
quint32 QCoapOption::uintValue() const
{
Q_D(const QCoapOption);
quint32 intValue = 0;
// A uint option holds at most 4 bytes (32 bits). Stop at 4 so the shift can
// never reach 32 bits (undefined behaviour), and cast to the result type
// before shifting to avoid signed overflow on the top byte.
for (int i = 0; i < d->value.size() && i < 4; ++i)
intValue |= static_cast<quint32>(static_cast<quint8>(d->value.at(i))) << (8 * i);
return intValue;
}
/*!
Returns the QString value of the option.
*/
QString QCoapOption::stringValue() const
{
Q_D(const QCoapOption);
return QString::fromUtf8(d->value);
}
/*!
Returns the length of the value of the option.
*/
int QCoapOption::length() const
{
Q_D(const QCoapOption);
return d->value.size();
}
/*!
Returns the name of the option.
*/
QCoapOption::OptionName QCoapOption::name() const
{
Q_D(const QCoapOption);
return d->name;
}
/*!
Returns \c true if the option is valid.
*/
bool QCoapOption::isValid() const
{
Q_D(const QCoapOption);
return d->name != QCoapOption::Invalid;
}
/*!
Returns \c true if this QCoapOption and \a other are equals.
*/
bool QCoapOption::operator==(const QCoapOption &other) const
{
Q_D(const QCoapOption);
return (d->name == other.d_ptr->name
&& d->value == other.d_ptr->value);
}
/*!
Returns \c true if this QCoapOption and \a other are different.
*/
bool QCoapOption::operator!=(const QCoapOption &other) const
{
return !(*this == other);
}
/*!
\internal
Sets the \a value for the option.
*/
void QCoapOptionPrivate::setValue(const QByteArray &opaqueValue)
{
bool oversized = false;
// Check for value maximum size, according to section 5.10 of RFC 7252
switch (name) {
case QCoapOption::IfNoneMatch:
if (opaqueValue.size() > 0)
oversized = true;
break;
case QCoapOption::UriPort:
case QCoapOption::ContentFormat:
case QCoapOption::Accept:
if (opaqueValue.size() > 2)
oversized = true;
break;
case QCoapOption::MaxAge:
case QCoapOption::Size1:
if (opaqueValue.size() > 4)
oversized = true;
break;
case QCoapOption::IfMatch:
case QCoapOption::Etag:
if (opaqueValue.size() > 8)
oversized = true;
break;
case QCoapOption::UriHost:
case QCoapOption::LocationPath:
case QCoapOption::UriPath:
case QCoapOption::UriQuery:
case QCoapOption::LocationQuery:
case QCoapOption::ProxyScheme:
if (opaqueValue.size() > 255)
oversized = true;
break;
case QCoapOption::ProxyUri:
if (opaqueValue.size() > 1034)
oversized = true;
break;
case QCoapOption::Observe:
case QCoapOption::Block2:
case QCoapOption::Block1:
case QCoapOption::Size2:
default:
break;
}
if (oversized)
qCWarning(lcCoapOption) << "Value" << opaqueValue << "is probably too big for option" << name;
value = opaqueValue;
}
/*!
\internal
\overload
Sets the \a value for the option.
*/
void QCoapOptionPrivate::setValue(const QString &value)
{
setValue(value.toUtf8());
}
/*!
\internal
\overload
Sets the \a value for the option.
*/
void QCoapOptionPrivate::setValue(quint32 value)
{
QByteArray data;
for (; value; value >>= 8)
data.append(static_cast<qint8>(value & 0xFF));
setValue(data);
}
/*!
\internal
For QSharedDataPointer.
*/
QCoapOptionPrivate *QCoapOption::d_func()
{
return d_ptr;
}
QT_END_NAMESPACE