mirror of
https://github.com/boostorg/mqtt5.git
synced 2025-10-04 12:50:54 +02:00
Properties & string validation
Summary: related to T13318 Reviewers: ivica Reviewed By: ivica Subscribers: miljen, iljazovic Differential Revision: https://repo.mireo.local/D26975
This commit is contained in:
@@ -7,9 +7,10 @@
|
||||
|
||||
#include <async_mqtt5/types.hpp>
|
||||
|
||||
#include <async_mqtt5/detail/cancellable_handler.hpp>
|
||||
#include <async_mqtt5/detail/control_packet.hpp>
|
||||
#include <async_mqtt5/detail/internal_types.hpp>
|
||||
#include <async_mqtt5/detail/cancellable_handler.hpp>
|
||||
#include <async_mqtt5/detail/utf8_mqtt.hpp>
|
||||
|
||||
#include <async_mqtt5/impl/codecs/message_encoders.hpp>
|
||||
|
||||
@@ -60,6 +61,10 @@ public:
|
||||
}
|
||||
|
||||
void perform() {
|
||||
error_code ec = validate_disconnect(_context.props);
|
||||
if (ec)
|
||||
return complete_post(ec);
|
||||
|
||||
auto disconnect = control_packet<allocator_type>::of(
|
||||
no_pid, get_allocator(),
|
||||
encoders::encode_disconnect,
|
||||
@@ -108,9 +113,28 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static error_code validate_disconnect(const disconnect_props& props) {
|
||||
auto reason_string = props[prop::reason_string];
|
||||
if (
|
||||
reason_string &&
|
||||
validate_mqtt_utf8(*reason_string) != validation_result::valid
|
||||
)
|
||||
return client::error::malformed_packet;
|
||||
|
||||
auto user_properties = props[prop::user_property];
|
||||
for (const auto& user_prop: user_properties)
|
||||
if (validate_mqtt_utf8(user_prop) != validation_result::valid)
|
||||
return client::error::malformed_packet;
|
||||
return error_code {};
|
||||
}
|
||||
|
||||
void complete(error_code ec) {
|
||||
_handler.complete(ec);
|
||||
}
|
||||
|
||||
void complete_post(error_code ec) {
|
||||
_handler.complete_post(ec);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ClientService, typename CompletionToken>
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <async_mqtt5/detail/control_packet.hpp>
|
||||
#include <async_mqtt5/detail/internal_types.hpp>
|
||||
#include <async_mqtt5/detail/topic_validation.hpp>
|
||||
#include <async_mqtt5/detail/utf8_mqtt.hpp>
|
||||
|
||||
#include <async_mqtt5/impl/disconnect_op.hpp>
|
||||
#include <async_mqtt5/impl/codecs/message_decoders.hpp>
|
||||
@@ -99,7 +100,7 @@ public:
|
||||
std::string topic, std::string payload,
|
||||
retain_e retain, const publish_props& props
|
||||
) {
|
||||
auto ec = validate_publish(topic, retain, props);
|
||||
auto ec = validate_publish(topic, payload, retain, props);
|
||||
if (ec)
|
||||
return complete_post(ec);
|
||||
|
||||
@@ -340,35 +341,78 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
error_code validate_props(
|
||||
const publish_props& props,
|
||||
prop::value_type_t<prop::topic_alias_maximum> topic_alias_max_opt
|
||||
) {
|
||||
auto topic_alias = props[prop::topic_alias];
|
||||
if (topic_alias) {
|
||||
auto topic_alias_max = topic_alias_max_opt.value_or(0);
|
||||
|
||||
if (topic_alias_max == 0 || *topic_alias > topic_alias_max)
|
||||
return client::error::topic_alias_maximum_reached;
|
||||
if (*topic_alias == 0 )
|
||||
return client::error::malformed_packet;
|
||||
}
|
||||
|
||||
auto response_topic = props[prop::response_topic];
|
||||
if (
|
||||
response_topic &&
|
||||
validate_topic_name(*response_topic) != validation_result::valid
|
||||
)
|
||||
return client::error::malformed_packet;
|
||||
|
||||
auto user_properties = props[prop::user_property];
|
||||
for (const auto& user_prop: user_properties)
|
||||
if (validate_mqtt_utf8(user_prop) != validation_result::valid)
|
||||
return client::error::malformed_packet;
|
||||
|
||||
auto subscription_identifier = props[prop::subscription_identifier];
|
||||
if (
|
||||
subscription_identifier &&
|
||||
(*subscription_identifier < 1 || *subscription_identifier > 268'435'455)
|
||||
)
|
||||
return client::error::malformed_packet;
|
||||
|
||||
auto content_type = props[prop::content_type];
|
||||
if (
|
||||
content_type &&
|
||||
validate_mqtt_utf8(*content_type) != validation_result::valid
|
||||
)
|
||||
return client::error::malformed_packet;
|
||||
|
||||
return error_code {};
|
||||
}
|
||||
|
||||
error_code validate_publish(
|
||||
const std::string& topic, retain_e retain, const publish_props& props
|
||||
const std::string& topic, const std::string& payload,
|
||||
retain_e retain, const publish_props& props
|
||||
) {
|
||||
if (validate_topic_name(topic) != validation_result::valid)
|
||||
return client::error::invalid_topic;
|
||||
|
||||
const auto& [max_qos, retain_avail, topic_alias_max] =
|
||||
const auto& [max_qos_opt, retain_available_opt, topic_alias_max_opt] =
|
||||
_svc_ptr->connack_props(
|
||||
prop::maximum_qos, prop::retain_available,
|
||||
prop::topic_alias_maximum
|
||||
);
|
||||
auto max_qos = max_qos_opt.value_or(2);
|
||||
auto retain_available = retain_available_opt.value_or(1);
|
||||
|
||||
if (max_qos && uint8_t(qos_type) > *max_qos)
|
||||
if (uint8_t(qos_type) > max_qos)
|
||||
return client::error::qos_not_supported;
|
||||
|
||||
if (retain_avail && *retain_avail == 0 && retain == retain_e::yes)
|
||||
if (retain_available == 0 && retain == retain_e::yes)
|
||||
return client::error::retain_not_available;
|
||||
|
||||
auto topic_alias = props[prop::topic_alias];
|
||||
auto payload_format = props[prop::payload_format_indicator].value_or(0);
|
||||
if (
|
||||
(!topic_alias_max || topic_alias_max && *topic_alias_max == 0) &&
|
||||
topic_alias
|
||||
payload_format == 1 &&
|
||||
validate_mqtt_utf8(payload) != validation_result::valid
|
||||
)
|
||||
return client::error::topic_alias_maximum_reached;
|
||||
return client::error::malformed_packet;
|
||||
|
||||
if (topic_alias_max && topic_alias && *topic_alias > *topic_alias_max)
|
||||
return client::error::topic_alias_maximum_reached;
|
||||
|
||||
return error_code {};
|
||||
return validate_props(props, topic_alias_max_opt);
|
||||
}
|
||||
|
||||
void on_malformed_packet(const std::string& reason) {
|
||||
|
@@ -156,6 +156,11 @@ private:
|
||||
static error_code validate_props(
|
||||
const subscribe_props& props, bool sub_id_available
|
||||
) {
|
||||
auto user_properties = props[prop::user_property];
|
||||
for (const auto& user_prop: user_properties)
|
||||
if (validate_mqtt_utf8(user_prop) != validation_result::valid)
|
||||
return client::error::malformed_packet;
|
||||
|
||||
auto sub_id = props[prop::subscription_identifier];
|
||||
if (!sub_id.has_value())
|
||||
return error_code {};
|
||||
|
@@ -59,7 +59,7 @@ public:
|
||||
const std::vector<std::string>& topics,
|
||||
const unsubscribe_props& props
|
||||
) {
|
||||
auto ec = validate_topics(topics);
|
||||
auto ec = validate_unsubscribe(topics, props);
|
||||
if (ec)
|
||||
return complete_post(ec, topics.size());
|
||||
|
||||
@@ -147,10 +147,18 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
static error_code validate_topics(const std::vector<std::string>& topics) {
|
||||
static error_code validate_unsubscribe(
|
||||
const std::vector<std::string>& topics,
|
||||
const unsubscribe_props& props
|
||||
) {
|
||||
for (const auto& topic : topics)
|
||||
if (validate_topic_filter(topic) != validation_result::valid)
|
||||
return client::error::invalid_topic;
|
||||
|
||||
auto user_properties = props[prop::user_property];
|
||||
for (const auto& user_prop: user_properties)
|
||||
if (validate_mqtt_utf8(user_prop) != validation_result::valid)
|
||||
return client::error::malformed_packet;
|
||||
return error_code {};
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user