Skip to content

Commit

Permalink
changed user properties sorting to provide stable order in making/par…
Browse files Browse the repository at this point in the history
…sing
  • Loading branch information
xHasKx committed Nov 26, 2023
1 parent 3cc2dbc commit ad336c3
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 12 deletions.
40 changes: 29 additions & 11 deletions mqtt/protocol5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ local protocol5 = {}
local type = type
local error = error
local assert = assert
local ipairs = ipairs
local require = require
local tostring = tostring
local setmetatable = setmetatable
Expand Down Expand Up @@ -369,23 +370,40 @@ local function make_properties(ptype, args)
assert(type(args.user_properties) == "table", "expecting .user_properties to be a table")
assert(allowed[uprop_id], "user_property is not allowed for packet type "..ptype)
local order = {}
local dups = {}
if args.user_properties[1] then
-- at first use array items as they given as {name, value} pairs with stable order
for i, pair in ipairs(args.user_properties) do
-- validate types for name and value
if type(pair) ~= "table" then
error(fmt("user property at position %d should be {name, value} table", i))
end
if type(pair[1]) ~= "string" then
error(fmt("user property name at position %d should be a string", i))
end
if type(pair[2]) ~= "string" then
error(fmt("user property '%s' value at position %d should be a string", pair[1], i))
end
order[i] = pair
dups[pair[1]] = pair[2]
end
end
-- now add the rest of user properties given as string table keys
for name, val in sortedpairs(args.user_properties) do
local ntype = type(name)
if ntype == "string" then
if type(name) ~= "number" then -- skipping number keys as they already added above
-- validate types for name and value
if type(name) ~= "string" then
error(fmt("user property name '%s' should be a string", name))
end
if type(val) ~= "string" then
error(fmt("user property '%s' value should be a string", name))
error(fmt("user property '%s' value '%s' should be a string", name, val))
end
order[#order + 1] = {name, val, 0}
elseif ntype == "number" then
if type(val) ~= "table" or type(val[1]) ~= "string" or type(val[2]) ~= "string" then
error(fmt("user property at index %d should be a table with two strings", name))
-- check that name+value key already added
if dups[name] ~= val then
order[#order + 1] = {name, val}
end
order[#order + 1] = {val[1], val[2], name}
else
error(fmt("unknown user property name type passed: %s", ntype))
end
end
tbl_sort(order, function(a, b) if a[1] == b[1] then return a[3] < b[3] else return a[1] < b[1] end end)
for _, pair in ipairs(order) do
local name = pair[1]
local value = pair[2]
Expand Down
2 changes: 1 addition & 1 deletion tests/spec/protocol5-make.lua
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,10 @@ describe("MQTT v5.0 protocol: making packets: PUBLISH[3]", function()
09 0004 736F6D65 -- property 0x09 == "some" -- DOC: 3.3.2.3.6 Correlation Data
0B 05 -- property 0x0B == 5 -- DOC: 3.3.2.3.8 Subscription Identifier
23 1234 -- property 0x23 == 0x1234 -- DOC: 3.3.2.3.4 Topic Alias
26 000B 546F20496E66696E697479 000A 616E64204265796F6E64 -- property 0x26 (user) == ("To Infinity", "and Beyond") -- DOC: 3.3.2.3.7 User Property
26 0005 6172726179 0006 6974656D2031 -- property 0x26 (user) == ("array", "item 1") -- DOC: 3.3.2.3.7 User Property
26 0005 6172726179 0006 6974656D2033 -- property 0x26 (user) == ("array", "item 3") -- DOC: 3.3.2.3.7 User Property
26 0005 6172726179 0006 6974656D2032 -- property 0x26 (user) == ("array", "item 2") -- DOC: 3.3.2.3.7 User Property
26 000B 546F20496E66696E697479 000A 616E64204265796F6E64 -- property 0x26 (user) == ("To Infinity", "and Beyond") -- DOC: 3.3.2.3.7 User Property
26 0005 68656C6C6F 0005 776F726C64 -- property 0x26 (user) == ("hello", "world") -- DOC: 3.3.2.3.7 User Property
686579204D51545421 -- payload == "hey MQTT!"
Expand Down

0 comments on commit ad336c3

Please sign in to comment.