mirror of
https://github.com/nlohmann/json.git
synced 2026-10-27 16:28:57 +00:00
Skip CBOR tags in front of map keys, validate indefinite text chunks, fix CBOR docs (#5927)
* Skip CBOR tags in front of map keys and validate indefinite text chunks A tag in front of a text string map key was rejected with parse_error.113 even with cbor_tag_handler_t::ignore or store, although tags in front of values are handled. The tags are now skipped iteratively before the key is read; the handler error still rejects them. The chunks of an indefinite-length text string were concatenated before the single UTF-8 check, so a code point split over two chunks, or an invalid chunk, was accepted. RFC 8949, Section 3.2.3 requires every chunk to be valid on its own. With error_handler_t::strict, replace and ignore each chunk is now checked; keep is unchanged. The chunks are appended with append(ptr, len), so StringType needs nothing new. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: correct and extend the CBOR documentation Fix the negative-integer rows (they used MessagePack boundaries), the number_integer range of the 0x1B row, and the half-precision entry in the list of unused types; correct the NaN history (0xF9 since 3.8.0) and the tagged-item wording (only the tag directly in front of a byte string is stored, and only in the 0xD8..0xDB form). Document that to_cbor is not RFC 8949 deterministic, that duplicate keys are accepted (last wins), tags in front of keys, per-chunk UTF-8 validation, the exceptions parse_error.113, out_of_range.406/408 of from_cbor, the pointer and C array input traps, the partially written output on exceptions, and the store/ignore results in the binary values example. Drop the claim that the CBOR reader needs StringType::append(const StringType&) and BinaryType::insert(pos, first, last). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Regenerate single_include and apply astyle Result of make amalgamate (including make pretty) for the preceding changes. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Address review of the CBOR changes Cite RFC 8949 Section 5.3.1 for duplicate keys, describe the out_of_range.408 condition precisely, rewrap a long line, and update the stale get_string comment (per-chunk UTF-8 check). single_include regenerated. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: drop discarded-value remarks Remove the mention that a discarded value cannot be serialized to CBOR (type_error.321) from the exception-safety and mapping sections. The integer table and all added prose already follow the table-format and Oxford-comma rules. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 parent
81d66291c5
commit
d5da84249f
9 files changed
+372
-49
No files matched your search
Generated
+75
-11
@@ -18685,6 +18685,10 @@ class binary_reader
|
||||
// level as required by RFC 8949, Section 3.2.3
|
||||
bool indefinite = false;
|
||||
|
||||
// the chunk currently being validated; only used for the chunks of an
|
||||
// indefinite-length string when the UTF-8 check can do something
|
||||
string_t chunk;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("string")))
|
||||
@@ -18704,26 +18708,82 @@ class binary_reader
|
||||
}
|
||||
|
||||
// a break marker closes the indefinite-length string; outside
|
||||
// of one it falls through to the error below
|
||||
// of one it falls through to the error below. Every chunk has
|
||||
// been checked on its own, so there is nothing left to check.
|
||||
if (indefinite && current == 0xFF)
|
||||
{
|
||||
return check_string_utf8(result, context);
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(result, indefinite)))
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!indefinite)
|
||||
{
|
||||
return check_string_utf8(result, context);
|
||||
return get_cbor_string_chunk(result, false) && check_string_utf8(result, context);
|
||||
}
|
||||
|
||||
if (error_handler == error_handler_t::keep)
|
||||
{
|
||||
// nothing to check: read the chunk directly into the result
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(result, true)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// RFC 8949, Section 3.2.3: each chunk is a text string of its
|
||||
// own and must be valid UTF-8 by itself, i.e., a code point
|
||||
// cannot be spread over two chunks
|
||||
chunk.clear();
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string_chunk(chunk, true) || !check_string_utf8(chunk, context)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
result.append(chunk.data(), chunk.size());
|
||||
}
|
||||
|
||||
get();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief skips the tags in front of a CBOR object key
|
||||
|
||||
A tag may wrap any data item, so it may also wrap a key. Like in front of a
|
||||
value, the tags are skipped for the handlers ignore and store; with the
|
||||
handler error they are left to @ref get_cbor_object_key, which rejects the
|
||||
key. The tag loop is iterative, so the number of tags is not limited by the
|
||||
recursion depth.
|
||||
|
||||
@param[in] tag_handler how CBOR tags should be treated
|
||||
|
||||
@return whether the tags could be skipped (false on EOF in a tag argument)
|
||||
|
||||
@pre @a current is the first byte of the key
|
||||
*/
|
||||
bool skip_cbor_key_tags(const cbor_tag_handler_t tag_handler)
|
||||
{
|
||||
if (tag_handler == cbor_tag_handler_t::error)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0xC0..0xDB: tag with the tag number in the head (0xC0..0xD7) or in
|
||||
// the 1, 2, 4, or 8 bytes that follow (0xD8..0xDB)
|
||||
while (current >= 0xC0 && current <= 0xDB)
|
||||
{
|
||||
if (current >= 0xD8)
|
||||
{
|
||||
std::uint64_t tag_to_ignore{};
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_cbor_argument(tag_to_ignore)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
get();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief reads a CBOR object key
|
||||
|
||||
@@ -19090,6 +19150,10 @@ class binary_reader
|
||||
|
||||
if (top.is_object)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!skip_cbor_key_tags(tag_handler)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(!read_object_key<&binary_reader::get_cbor_object_key>(key)))
|
||||
{
|
||||
return false;
|
||||
@@ -21597,9 +21661,9 @@ class binary_reader
|
||||
// sequence), UBJSON, BJData, or BSON requires a decoder to reject
|
||||
// ill-formed UTF-8. Checking (and, with @ref error_handler_t::strict,
|
||||
// rejecting, or with `replace`/`ignore`, sanitizing) is opt-in via
|
||||
// @ref error_handler, applied once the whole string (all chunks of
|
||||
// an indefinite-length CBOR string included) has been assembled, by
|
||||
// @ref check_string_utf8 at the call site.
|
||||
// @ref error_handler, applied by @ref check_string_utf8 at the call
|
||||
// site to the whole string or, for an indefinite-length CBOR string,
|
||||
// to each chunk on its own (RFC 8949, Section 3.2.3).
|
||||
return get_bytes(len, "string", result);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user