Handler specifies structure and string limits

This commit is contained in:
Krystian Stasiowski 2020-09-07 13:44:58 -04:00 committed by Vinnie Falco
parent da65b25f4d
commit f3d0710e37
22 changed files with 478 additions and 372 deletions

View File

@ -387,6 +387,11 @@ class boost_null_impl : public any_impl
{
struct handler
{
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
bool on_document_begin(error_code&) { return true; }
bool on_document_end(error_code&) { return true; }
bool on_object_begin(error_code&) { return true; }

View File

@ -26,60 +26,64 @@ using namespace boost::json;
//[example_validate
// The null parser discards all the data
class null_parser
{
struct handler
{
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
bool on_string( string_view, std::size_t, error_code& ) { return true; }
bool on_number_part( string_view, error_code& ) { return true; }
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
bool on_double( double, string_view, error_code& ) { return true; }
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part(string_view, error_code&) { return true; }
bool on_comment(string_view, error_code&) { return true; }
};
basic_parser<handler> p_;
public:
null_parser()
: p_(parse_options())
{
}
~null_parser()
{
}
std::size_t
write(
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write( false, data, size, ec );
if(! ec && n < size)
ec = error::extra_data;
return n;
}
};
bool
validate( string_view s )
{
// The null parser discards all the data
class null_parser
{
struct handler
{
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
bool on_string( string_view, std::size_t, error_code& ) { return true; }
bool on_number_part( string_view, error_code& ) { return true; }
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
bool on_double( double, string_view, error_code& ) { return true; }
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part(string_view, error_code&) { return true; }
bool on_comment(string_view, error_code&) { return true; }
};
basic_parser<handler> p_;
public:
null_parser()
: p_(parse_options())
{
}
~null_parser()
{
}
std::size_t
write(
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write( false, data, size, ec );
if(! ec && n < size)
ec = error::extra_data;
return n;
}
};
// Parse with the null parser and return false on error
null_parser p;
error_code ec;

View File

@ -17,58 +17,63 @@
using namespace boost::json;
class null_parser
{
struct handler
{
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
bool on_string( string_view, std::size_t, error_code& ) { return true; }
bool on_number_part( string_view, error_code& ) { return true; }
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
bool on_double( double, string_view, error_code& ) { return true; }
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part(string_view, error_code&) { return true; }
bool on_comment(string_view, error_code&) { return true; }
};
basic_parser<handler> p_;
public:
null_parser()
: p_(parse_options())
{
}
~null_parser()
{
}
std::size_t
write(
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write( false, data, size, ec );
if(! ec && n < size)
ec = error::extra_data;
return n;
}
};
bool
validate( string_view s )
{
class null_parser
{
struct handler
{
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
bool on_string( string_view, std::size_t, error_code& ) { return true; }
bool on_number_part( string_view, error_code& ) { return true; }
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
bool on_double( double, string_view, error_code& ) { return true; }
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part(string_view, error_code&) { return true; }
bool on_comment(string_view, error_code&) { return true; }
};
basic_parser<handler> p_;
public:
null_parser()
: p_(parse_options())
{
}
~null_parser()
{
}
std::size_t
write(
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write( false, data, size, ec );
if(! ec && n < size)
ec = error::extra_data;
return n;
}
};
// Parse with the null parser and return false on error
null_parser p;
error_code ec;

View File

@ -1022,7 +1022,7 @@ public:
std::size_t
max_size() noexcept
{
return BOOST_JSON_MAX_STRUCTURED_SIZE;
return array_impl::max_size();
}
/** Return the number of elements that can be held in currently allocated memory.

View File

@ -965,10 +965,22 @@ parse_unescaped(const char* p)
cs = detail::count_valid<AllowBadUTF8>(
cs.begin(), cs.end());
std::size_t size = cs.used(start);
if(BOOST_JSON_UNLIKELY(size >
BOOST_JSON_MAX_STRING_SIZE - total))
return fail(cs.begin(), IsKey ?
error::key_too_large : error::string_too_large);
if(IsKey)
{
BOOST_ASSERT(total <= Handler::max_key_size);
if(BOOST_JSON_UNLIKELY(size >
Handler::max_key_size - total))
return fail(cs.begin(),
error::key_too_large);
}
else
{
BOOST_ASSERT(total <= Handler::max_string_size);
if(BOOST_JSON_UNLIKELY(size >
Handler::max_string_size - total))
return fail(cs.begin(),
error::string_too_large);
}
total += size;
if(BOOST_JSON_UNLIKELY(! cs))
{
@ -1049,6 +1061,8 @@ parse_escaped(
&Handler::on_key_part : &Handler::on_string_part;
constexpr auto ev_too_large = IsKey ?
error::key_too_large : error::string_too_large;
constexpr auto max_size = IsKey ?
Handler::max_key_size : Handler::max_string_size;
detail::clipped_const_stream cs(p, end_);
detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
int digit;
@ -1089,8 +1103,9 @@ do_str3:
{
if(BOOST_JSON_LIKELY(! temp.empty()))
{
if(BOOST_JSON_UNLIKELY(temp.size() >
BOOST_JSON_MAX_STRING_SIZE - total))
BOOST_ASSERT(total <= max_size);
if(BOOST_JSON_UNLIKELY(
temp.size() > max_size - total))
return fail(cs.begin(), ev_too_large);
total += temp.size();
if(BOOST_JSON_UNLIKELY(
@ -1238,8 +1253,9 @@ do_str3:
// flush
if(BOOST_JSON_LIKELY(! temp.empty()))
{
if(BOOST_JSON_UNLIKELY(temp.size() >
BOOST_JSON_MAX_STRING_SIZE - total))
BOOST_ASSERT(total <= max_size);
if(BOOST_JSON_UNLIKELY(
temp.size() > max_size - total))
return fail(cs.begin(), ev_too_large);
total += temp.size();
if(BOOST_JSON_UNLIKELY(
@ -1367,8 +1383,9 @@ do_str2:
// flush
if(BOOST_JSON_LIKELY(! temp.empty()))
{
if(BOOST_JSON_UNLIKELY(temp.size() >
BOOST_JSON_MAX_STRING_SIZE - total))
BOOST_ASSERT(total <= max_size);
if(BOOST_JSON_UNLIKELY(
temp.size() > max_size - total))
return fail(cs.begin(), ev_too_large);
total += temp.size();
if(BOOST_JSON_UNLIKELY(
@ -1383,8 +1400,9 @@ do_str2:
c = *cs;
if(BOOST_JSON_LIKELY(c == '\x22')) // '"'
{
if(BOOST_JSON_UNLIKELY(temp.size() >
BOOST_JSON_MAX_STRING_SIZE - total))
BOOST_ASSERT(total <= max_size);
if(BOOST_JSON_UNLIKELY(
temp.size() > max_size - total))
return fail(cs.begin(), ev_too_large);
total += temp.size();
if(BOOST_JSON_UNLIKELY(
@ -1400,8 +1418,9 @@ do_str2:
{
if(BOOST_JSON_LIKELY(! temp.empty()))
{
if(BOOST_JSON_UNLIKELY(temp.size() >
BOOST_JSON_MAX_STRING_SIZE - total))
BOOST_ASSERT(total <= max_size);
if(BOOST_JSON_UNLIKELY(
temp.size() > max_size - total))
return fail(cs.begin(), ev_too_large);
total += temp.size();
if(BOOST_JSON_UNLIKELY(
@ -1512,7 +1531,7 @@ do_obj2:
}
loop:
if(BOOST_JSON_UNLIKELY(++size >
BOOST_JSON_MAX_STRUCTURED_SIZE))
Handler::max_object_size))
return fail(cs.begin(), error::object_too_large);
do_obj3:
cs = parse_string<StackEmpty, true,
@ -1658,7 +1677,7 @@ do_arr2:
}
loop:
if(BOOST_JSON_UNLIKELY(++size >
BOOST_JSON_MAX_STRUCTURED_SIZE))
Handler::max_array_size))
return fail(cs.begin(), error::array_too_large);
do_arr3:
// array is not empty, value required

View File

@ -54,10 +54,7 @@ public:
static
constexpr
std::size_t
max_size() noexcept
{
return BOOST_JSON_MAX_STRUCTURED_SIZE;
}
max_size() noexcept;
value*
data() const noexcept

View File

@ -83,6 +83,24 @@ BOOST_JSON_NS_BEGIN
the error code to a suitable value. This error
code will be returned by the write function to
the caller.
\n
Handlers must also define the following
static data members:
@li `max_object_size`, the maximum number
of elements an object can contain,
@li `max_array_size`, the maximum number
of elements an array can contain,
@li `max_key_size`, the maximum length
for object keys, and
@li `max_string_size`, the maximum
length for strings.
If a value exceeding these limits
is encountered, parsing fails.
\n
The following declaration meets the parser's
handler requirements:
@ -90,6 +108,12 @@ BOOST_JSON_NS_BEGIN
@code
struct handler
{
/// Value size limits
constexpr static std::size_t max_object_size = -1;
constexpr static std::size_t max_array_size = -1;
constexpr static std::size_t max_key_size = -1;
constexpr static std::size_t max_string_size = -1;
/// Called once when the JSON parsing begins.
///
/// @return `true` on success.

View File

@ -13,6 +13,18 @@
BOOST_JSON_NS_BEGIN
namespace detail {
constexpr
std::size_t
array_impl::
max_size() noexcept
{
// max_size depends on the address model
using min = std::integral_constant<std::size_t,
(std::size_t(-1) - sizeof(table)) / sizeof(value)>;
return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
}
auto
array_impl::
index_of(value const* pos) const noexcept ->

View File

@ -21,16 +21,14 @@ array_impl(
std::size_t capacity,
storage_ptr const& sp)
{
auto constexpr soft_limit =
(std::size_t(-1) - sizeof(table)) /
sizeof(value);
if( capacity > soft_limit ||
capacity > max_size())
if(capacity > max_size())
detail::throw_length_error(
"array too large",
"capacity > max_size()",
BOOST_CURRENT_LOCATION);
if(capacity > 0)
{
// make sure to update max_size
// if this is changed
tab_ = ::new(sp->allocate(
(sizeof(table) +
capacity * sizeof(value) +

View File

@ -16,6 +16,19 @@
BOOST_JSON_NS_BEGIN
namespace detail {
constexpr
std::size_t
object_impl::
max_size() noexcept
{
// max_size depends on the address model
using min = std::integral_constant<std::size_t,
(std::size_t(-1) - sizeof(table)) /
(sizeof(value_type) + sizeof(index_t))>;
return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
}
void
object_impl::
remove(
@ -41,7 +54,7 @@ bucket_sizes() noexcept ->
{
// Taken from Boost.Intrusive and Boost.MultiIndex code,
// thanks to Ion Gaztanaga and Joaquin M Lopez Munoz.
static constexpr std::size_t list[33] =
static constexpr std::size_t list[34] =
{
0,
@ -61,7 +74,9 @@ bucket_sizes() noexcept ->
100663319, 201326611,
402653189, 805306457,
1610612741,
BOOST_JSON_MAX_STRUCTURED_SIZE // 3221225473
BOOST_JSON_MAX_STRUCTURED_SIZE,
// catch anything that exceeds max_size
std::size_t(-1)
};
return list;
}

View File

@ -37,14 +37,12 @@ object_impl(
std::uintptr_t salt,
storage_ptr const& sp)
{
// max capacity based on address model
auto constexpr soft_limit =
(std::size_t(-1) - sizeof(table)) / (
sizeof(value_type) + sizeof(index_t));
if(capacity > soft_limit)
if(capacity > max_size())
throw_length_error(
"capacity > soft_limit",
"capacity > max_size()",
BOOST_CURRENT_LOCATION);
// make sure to update max_size
// if this is changed
const auto n =
sizeof(table) +
capacity *

View File

@ -31,7 +31,7 @@ class object_impl
using index_t = std::uint32_t;
static index_t const null_index =
std::uint32_t(-1);
using bucket_size_array = const std::size_t [33];
using bucket_size_array = const std::size_t[34];
BOOST_JSON_DECL
void
@ -62,6 +62,11 @@ public:
do_destroy(sp);
}
static
constexpr
std::size_t
max_size() noexcept;
std::size_t
size() const noexcept
{

View File

@ -97,7 +97,11 @@ public:
std::size_t
max_size() noexcept
{
return BOOST_JSON_MAX_STRING_SIZE;
// max_size depends on the address model
using min = std::integral_constant<std::size_t,
std::size_t(-1) - sizeof(table)>;
return min::value < BOOST_JSON_MAX_STRING_SIZE ?
min::value : BOOST_JSON_MAX_STRING_SIZE;
}
BOOST_JSON_DECL

View File

@ -212,10 +212,6 @@ reserve(std::size_t new_capacity)
{
if(new_capacity <= capacity())
return;
if(new_capacity > max_size())
detail::throw_length_error(
"new_capacity > max_size()",
BOOST_CURRENT_LOCATION);
rehash(new_capacity);
}

View File

@ -509,12 +509,12 @@ rehash(std::size_t new_capacity)
BOOST_ASSERT(new_capacity > capacity());
std::size_t const* prime =
object_impl::bucket_sizes();
while(new_capacity > *prime)
while(*prime < new_capacity)
++prime;
new_capacity = *prime;
if(new_capacity > max_size())
detail::throw_length_error(
"object too large",
"new_capacity > max_size()",
BOOST_CURRENT_LOCATION);
object_impl impl(
new_capacity,

View File

@ -860,7 +860,7 @@ public:
std::size_t
max_size() noexcept
{
return BOOST_JSON_MAX_STRUCTURED_SIZE;
return object_impl::max_size();
}
/** Return the number of elements that can be held in currently allocated memory

View File

@ -104,6 +104,18 @@ class parser
{
struct handler
{
constexpr static std::size_t
max_object_size = object::max_size();
constexpr static std::size_t
max_array_size = array::max_size();
constexpr static std::size_t
max_key_size = string::max_size();
constexpr static std::size_t
max_string_size = string::max_size();
value_stack st;
template<class... Args>

View File

@ -62,6 +62,8 @@ class string
friend struct detail::value_access;
#endif
using string_impl = detail::string_impl;
inline
string(
char** key,
@ -130,7 +132,7 @@ private:
char>::value>::type;
storage_ptr sp_; // must come first
detail::string_impl impl_;
string_impl impl_;
public:
/** Destructor.
@ -190,7 +192,7 @@ public:
: sp_(std::move(other.get().sp_))
, impl_(other.get().impl_)
{
::new(&other.get().impl_) detail::string_impl();
::new(&other.get().impl_) string_impl();
}
/** Constructor.
@ -437,7 +439,7 @@ public:
: sp_(other.sp_)
, impl_(other.impl_)
{
::new(&other.impl_) detail::string_impl();
::new(&other.impl_) string_impl();
}
/** Constructor.
@ -1433,7 +1435,7 @@ public:
std::size_t
max_size() noexcept
{
return BOOST_JSON_MAX_STRING_SIZE;
return string_impl::max_size();
}
/** Return the number of characters that can be held without a reallocation.

View File

@ -872,6 +872,72 @@ public:
good_one(s);
}
class comment_parser
{
struct handler
{
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
std::string captured = "";
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
bool on_string( string_view, std::size_t, error_code& ) { return true; }
bool on_number_part( string_view, error_code&) { return true; }
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
bool on_double( double, string_view, error_code& ) { return true; }
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part( string_view s, error_code& )
{
captured.append(s.data(), s.size());
return true;
}
bool on_comment( string_view s, error_code& )
{
captured.append(s.data(), s.size());
return true;
}
};
basic_parser<handler> p_;
public:
comment_parser()
: p_(make_options(true, false, false))
{
}
std::size_t
write(
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write(
false, data, size, ec);
if(! ec && n < size)
ec = error::extra_data;
return n;
}
string_view
captured() const noexcept
{
return p_.handler().captured;
}
};
void
testComments()
{
@ -899,67 +965,6 @@ public:
"/*** aaaa***/"
};
class comment_parser
{
struct handler
{
std::string captured = "";
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
bool on_string( string_view, std::size_t, error_code& ) { return true; }
bool on_number_part( string_view, error_code&) { return true; }
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
bool on_double( double, string_view, error_code& ) { return true; }
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part( string_view s, error_code& )
{
captured.append(s.data(), s.size());
return true;
}
bool on_comment( string_view s, error_code& )
{
captured.append(s.data(), s.size());
return true;
}
};
basic_parser<handler> p_;
public:
comment_parser()
: p_(make_options(true, false, false))
{
}
std::size_t
write(
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write(
false, data, size, ec);
if(! ec && n < size)
ec = error::extra_data;
return n;
}
string_view
captured() const noexcept
{
return p_.handler().captured;
}
};
std::string formatted = "";
std::string just_comments = "";
std::size_t guess = std::count(
@ -1064,6 +1069,73 @@ public:
good("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{},},},},},},}", enabled);
}
class utf8_parser
{
struct handler
{
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
std::string captured = "";
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view sv, std::size_t, error_code& )
{
captured.append(sv.data(), sv.size());
return true;
}
bool on_string( string_view sv, std::size_t, error_code& )
{
captured.append(sv.data(), sv.size());
return true;
}
bool on_number_part( string_view, error_code&) { return true; }
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
bool on_double( double, string_view, error_code& ) { return true; }
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part( string_view, error_code& ) { return true; }
bool on_comment( string_view, error_code& ) { return true; }
};
basic_parser<handler> p_;
public:
utf8_parser()
: p_(parse_options())
{
}
std::size_t
write(
bool more,
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write(
more, data, size, ec);
if(! ec && n < size)
ec = error::extra_data;
return n;
}
string_view
captured() const noexcept
{
return p_.handler().captured;
}
};
void
testUTF8Validation()
{
@ -1228,68 +1300,6 @@ public:
bad("\"\\n\xf4\x80\x70\x80----------\"");
bad("\"\\n\xf4\x80\xbf\x70-\\n\xf4\x80\xbf\x70\"");
class utf8_parser
{
struct handler
{
std::string captured = "";
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view sv, std::size_t, error_code& )
{
captured.append(sv.data(), sv.size());
return true;
}
bool on_string( string_view sv, std::size_t, error_code& )
{
captured.append(sv.data(), sv.size());
return true;
}
bool on_number_part( string_view, error_code&) { return true; }
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
bool on_double( double, string_view, error_code& ) { return true; }
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part( string_view, error_code& ) { return true; }
bool on_comment( string_view, error_code& ) { return true; }
};
basic_parser<handler> p_;
public:
utf8_parser()
: p_(parse_options())
{
}
std::size_t
write(
bool more,
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write(
more, data, size, ec);
if(! ec && n < size)
ec = error::extra_data;
return n;
}
string_view
captured() const noexcept
{
return p_.handler().captured;
}
};
const auto check =
[this](string_view expected)
{
@ -1360,85 +1370,89 @@ public:
}
}
class literal_parser
{
struct handler
{
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
std::string captured = "";
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
bool on_string( string_view, std::size_t, error_code& ) { return true; }
bool on_number_part( string_view sv, error_code&)
{
captured.append(sv.data(), sv.size());
return true;
}
bool on_int64( std::int64_t, string_view sv, error_code& )
{
captured.append(sv.data(), sv.size());
captured += 's';
return true;
}
bool on_uint64( std::uint64_t, string_view sv, error_code& )
{
captured.append(sv.data(), sv.size());
captured += 'u';
return true;
}
bool on_double( double, string_view sv, error_code& )
{
captured.append(sv.data(), sv.size());
captured += 'd';
return true;
}
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part( string_view, error_code& ) { return true; }
bool on_comment( string_view, error_code& ) { return true; }
};
basic_parser<handler> p_;
public:
literal_parser()
: p_(make_options(true, false, false))
{
}
std::size_t
write(
bool more,
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write(
more, data, size, ec);
if(! ec && n < size)
ec = error::extra_data;
return n;
}
string_view
captured()
{
return p_.handler().captured;
}
};
void
testNumberLiteral()
{
class literal_parser
{
struct handler
{
std::string captured = "";
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
bool on_object_end( std::size_t, error_code& ) { return true; }
bool on_array_begin( error_code& ) { return true; }
bool on_array_end( std::size_t, error_code& ) { return true; }
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
bool on_key( string_view, std::size_t, error_code& ) { return true; }
bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
bool on_string( string_view, std::size_t, error_code& ) { return true; }
bool on_number_part( string_view sv, error_code&)
{
captured.append(sv.data(), sv.size());
return true;
}
bool on_int64( std::int64_t, string_view sv, error_code& )
{
captured.append(sv.data(), sv.size());
captured += 's';
return true;
}
bool on_uint64( std::uint64_t, string_view sv, error_code& )
{
captured.append(sv.data(), sv.size());
captured += 'u';
return true;
}
bool on_double( double, string_view sv, error_code& )
{
captured.append(sv.data(), sv.size());
captured += 'd';
return true;
}
bool on_bool( bool, error_code& ) { return true; }
bool on_null( error_code& ) { return true; }
bool on_comment_part( string_view, error_code& ) { return true; }
bool on_comment( string_view, error_code& ) { return true; }
};
basic_parser<handler> p_;
public:
literal_parser()
: p_(make_options(true, false, false))
{
}
std::size_t
write(
bool more,
char const* data,
std::size_t size,
error_code& ec)
{
auto const n = p_.write(
more, data, size, ec);
if(! ec && n < size)
ec = error::extra_data;
return n;
}
string_view
captured()
{
return p_.handler().captured;
}
};
const auto check =
[](string_view expected)
[](string_view expected)
{
string_view sv = expected;
sv.remove_suffix(1);

View File

@ -286,14 +286,8 @@ public:
auto jv = parse(s, ec);
BOOST_TEST(! ec);
}
}
void
testBasicParser()
{
// overflow in on_key_part
{
null_parser p;
error_code ec;
std::string big;
big = "\\b";
@ -301,13 +295,12 @@ public:
string::max_size()*2, '*');
auto const js =
"{\"" + big + "\":null}";
p.write(js.data(), js.size(), ec);
auto jv = parse(js, ec);
BOOST_TEST(ec == error::key_too_large);
}
// overflow in on_key
{
null_parser p;
error_code ec;
std::string big;
big = "\\b";
@ -315,13 +308,12 @@ public:
(string::max_size()*3)/2, '*');
auto const js =
"{\"" + big + "\":null}";
p.write(js.data(), js.size(), ec);
auto jv = parse(js, ec);
BOOST_TEST(ec == error::key_too_large);
}
// overflow in on_string_part
{
null_parser p;
error_code ec;
std::string big;
big = "\\b";
@ -329,13 +321,12 @@ public:
string::max_size()*2, '*');
auto const js =
"\"" + big + "\"";
p.write(js.data(), js.size(), ec);
auto jv = parse(js, ec);
BOOST_TEST(ec == error::string_too_large);
}
// overflow in on_string
{
null_parser p;
error_code ec;
std::string big;
big = "\\b";
@ -343,14 +334,13 @@ public:
(string::max_size()*3)/2, '*');
auto const js =
"\"" + big + "\"";
p.write(js.data(), js.size(), ec);
auto jv = parse(js, ec);
BOOST_TEST(ec == error::string_too_large);
}
// object overflow
{
null_parser p;
error_code ec;
string_view s = R"({
"00":0,"01":0,"02":0,"03":0,"04":0,"05":0,"06":0,"07":0,"08":0,"09":0,
@ -358,20 +348,19 @@ public:
"20":0
})";
p.write(s.data(), s.size(), ec);
auto jv = parse(s, ec);
BOOST_TEST(ec == error::object_too_large);
}
// array overflow
{
null_parser p;
error_code ec;
string_view s = "["
"0,0,0,0,0,0,0,0,0,0,"
"0,0,0,0,0,0,0,0,0,0,"
"0"
"]";
p.write(s.data(), s.size(), ec);
auto jv = parse(s, ec);
BOOST_TEST(ec == error::array_too_large);
}
}
@ -390,7 +379,6 @@ public:
testString();
testStack();
testParser();
testBasicParser();
#else
BOOST_TEST_PASS();

View File

@ -145,6 +145,11 @@ class null_parser
{
struct handler
{
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
bool on_document_begin( error_code& ) { return true; }
bool on_document_end( error_code& ) { return true; }
bool on_object_begin( error_code& ) { return true; }
@ -205,6 +210,11 @@ class fail_parser
{
struct handler
{
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
std::size_t n;
handler()
@ -445,6 +455,11 @@ class throw_parser
{
struct handler
{
constexpr static std::size_t max_object_size = std::size_t(-1);
constexpr static std::size_t max_array_size = std::size_t(-1);
constexpr static std::size_t max_key_size = std::size_t(-1);
constexpr static std::size_t max_string_size = std::size_t(-1);
std::size_t n;
handler()

View File

@ -1640,13 +1640,7 @@ public:
check_array(value{false,2}, false, 2);
check_array(value{false,2,"3",nullptr}, false, 2, "3", nullptr);
check_array(value{2,false,"3"}, 2, false, "3");
check_array(value{true,2,"3"}, true, 2, "3"); }
void
testMaxSize()
{
// The implementation requires these equal
BOOST_TEST(object::max_size() == array::max_size());
check_array(value{true,2,"3"}, true, 2, "3");
}
//------------------------------------------------------
@ -1667,7 +1661,6 @@ public:
testKeyValuePair();
testStdConstruction();
testInitList();
testMaxSize();
}
};