From 81c8d89341c1e58c31c4666a79218c5324f22044 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Sun, 11 Mar 2018 10:11:14 +0100 Subject: [PATCH] Added max_depth parameter to variant conversions --- include/fc/array.hpp | 8 +- include/fc/crypto/elliptic.hpp | 8 +- include/fc/crypto/ripemd160.hpp | 4 +- include/fc/crypto/sha1.hpp | 4 +- include/fc/crypto/sha224.hpp | 4 +- include/fc/crypto/sha256.hpp | 4 +- include/fc/crypto/sha512.hpp | 4 +- include/fc/exception/exception.hpp | 8 +- include/fc/filesystem.hpp | 4 +- include/fc/io/json.hpp | 10 +- include/fc/io/raw.hpp | 8 +- include/fc/log/console_appender.hpp | 5 +- include/fc/log/file_appender.hpp | 3 +- include/fc/log/gelf_appender.hpp | 3 +- include/fc/log/log_message.hpp | 24 +- include/fc/log/logger.hpp | 2 +- include/fc/reflect/variant.hpp | 45 +-- include/fc/rpc/api_connection.hpp | 9 +- include/fc/rpc/http_api.hpp | 2 +- include/fc/rpc/json_connection.hpp | 7 +- include/fc/rpc/websocket_api.hpp | 2 +- include/fc/string.hpp | 2 +- include/fc/variant.hpp | 464 ++++++++++++++------------ include/fc/variant_object.hpp | 28 +- src/crypto/elliptic_common.cpp | 16 +- src/crypto/ripemd160.cpp | 26 +- src/crypto/sha1.cpp | 15 +- src/crypto/sha224.cpp | 25 +- src/crypto/sha256.cpp | 24 +- src/crypto/sha512.cpp | 23 +- src/exception.cpp | 28 +- src/filesystem.cpp | 8 +- src/log/console_appender.cpp | 9 +- src/log/file_appender.cpp | 4 +- src/log/gelf_appender.cpp | 4 +- src/log/log_message.cpp | 47 +-- src/log/logger_config.cpp | 1 - src/rpc/http_api.cpp | 15 +- src/rpc/json_connection.cpp | 24 +- src/rpc/websocket_api.cpp | 24 +- src/string.cpp | 4 +- src/time.cpp | 16 +- src/variant.cpp | 115 ++++--- src/variant_object.cpp | 9 +- tests/crypto/sha_tests.cpp | 4 +- tests/io/json_tests.cpp | 20 +- tests/network/http/websocket_test.cpp | 4 + 47 files changed, 602 insertions(+), 525 deletions(-) diff --git a/include/fc/array.hpp b/include/fc/array.hpp index 8453447..541cd69 100644 --- a/include/fc/array.hpp +++ b/include/fc/array.hpp @@ -102,14 +102,14 @@ namespace fc { { return 0 != memcmp( a.data, b.data, N*sizeof(T) ); } template - void to_variant( const array& bi, variant& v ) + void to_variant( const array& bi, variant& v, uint32_t max_depth = 1 ) { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, 1 ); } template - void from_variant( const variant& v, array& bi ) + void from_variant( const variant& v, array& bi, uint32_t max_depth = 1 ) { - std::vector ve = v.as< std::vector >(); + std::vector ve = v.as< std::vector >( 1 ); if( ve.size() ) { memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); diff --git a/include/fc/crypto/elliptic.hpp b/include/fc/crypto/elliptic.hpp index 971ae3d..954fc89 100644 --- a/include/fc/crypto/elliptic.hpp +++ b/include/fc/crypto/elliptic.hpp @@ -252,10 +252,10 @@ namespace fc { } // namespace ecc - void to_variant( const ecc::private_key& var, variant& vo ); - void from_variant( const variant& var, ecc::private_key& vo ); - void to_variant( const ecc::public_key& var, variant& vo ); - void from_variant( const variant& var, ecc::public_key& vo ); + void to_variant( const ecc::private_key& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, ecc::private_key& vo, uint32_t max_depth ); + void to_variant( const ecc::public_key& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, ecc::public_key& vo, uint32_t max_depth ); namespace raw { diff --git a/include/fc/crypto/ripemd160.hpp b/include/fc/crypto/ripemd160.hpp index 912c392..1982e43 100644 --- a/include/fc/crypto/ripemd160.hpp +++ b/include/fc/crypto/ripemd160.hpp @@ -72,8 +72,8 @@ class ripemd160 }; class variant; - void to_variant( const ripemd160& bi, variant& v ); - void from_variant( const variant& v, ripemd160& bi ); + void to_variant( const ripemd160& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, ripemd160& bi, uint32_t max_depth ); typedef ripemd160 uint160_t; typedef ripemd160 uint160; diff --git a/include/fc/crypto/sha1.hpp b/include/fc/crypto/sha1.hpp index 32fc2e4..a269797 100644 --- a/include/fc/crypto/sha1.hpp +++ b/include/fc/crypto/sha1.hpp @@ -66,8 +66,8 @@ class sha1 }; class variant; - void to_variant( const sha1& bi, variant& v ); - void from_variant( const variant& v, sha1& bi ); + void to_variant( const sha1& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, sha1& bi, uint32_t max_depth ); } // namespace fc diff --git a/include/fc/crypto/sha224.hpp b/include/fc/crypto/sha224.hpp index a621208..311e24f 100644 --- a/include/fc/crypto/sha224.hpp +++ b/include/fc/crypto/sha224.hpp @@ -71,8 +71,8 @@ class sha224 }; class variant; - void to_variant( const sha224& bi, variant& v ); - void from_variant( const variant& v, sha224& bi ); + void to_variant( const sha224& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, sha224& bi, uint32_t max_depth ); } // fc namespace std diff --git a/include/fc/crypto/sha256.hpp b/include/fc/crypto/sha256.hpp index 58bba9e..03a2080 100644 --- a/include/fc/crypto/sha256.hpp +++ b/include/fc/crypto/sha256.hpp @@ -101,8 +101,8 @@ class sha256 typedef sha256 uint256; class variant; - void to_variant( const sha256& bi, variant& v ); - void from_variant( const variant& v, sha256& bi ); + void to_variant( const sha256& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, sha256& bi, uint32_t max_depth ); uint64_t hash64(const char* buf, size_t len); diff --git a/include/fc/crypto/sha512.hpp b/include/fc/crypto/sha512.hpp index ef10887..2f77b21 100644 --- a/include/fc/crypto/sha512.hpp +++ b/include/fc/crypto/sha512.hpp @@ -69,8 +69,8 @@ class sha512 typedef fc::sha512 uint512; class variant; - void to_variant( const sha512& bi, variant& v ); - void from_variant( const variant& v, sha512& bi ); + void to_variant( const sha512& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, sha512& bi, uint32_t max_depth ); } // fc diff --git a/include/fc/exception/exception.hpp b/include/fc/exception/exception.hpp index 9fa7b54..1c1e7dc 100644 --- a/include/fc/exception/exception.hpp +++ b/include/fc/exception/exception.hpp @@ -116,8 +116,8 @@ namespace fc */ virtual std::shared_ptr dynamic_copy_exception()const; - friend void to_variant( const exception& e, variant& v ); - friend void from_variant( const variant& e, exception& ll ); + friend void to_variant( const exception& e, variant& v, uint32_t max_depth ); + friend void from_variant( const variant& e, exception& ll, uint32_t max_depth ); exception& operator=( const exception& copy ); exception& operator=( exception&& copy ); @@ -125,8 +125,8 @@ namespace fc std::unique_ptr my; }; - void to_variant( const exception& e, variant& v ); - void from_variant( const variant& e, exception& ll ); + void to_variant( const exception& e, variant& v, uint32_t max_depth ); + void from_variant( const variant& e, exception& ll, uint32_t max_depth ); typedef std::shared_ptr exception_ptr; typedef optional oexception; diff --git a/include/fc/filesystem.hpp b/include/fc/filesystem.hpp index 7484f2a..38fb74a 100644 --- a/include/fc/filesystem.hpp +++ b/include/fc/filesystem.hpp @@ -182,8 +182,8 @@ namespace fc { const fc::path& current_path(); class variant; - void to_variant( const fc::path&, fc::variant& ); - void from_variant( const fc::variant& , fc::path& ); + void to_variant( const fc::path&, fc::variant&, uint32_t max_depth = 1 ); + void from_variant( const fc::variant&, fc::path&, uint32_t max_depth = 1 ); template<> struct get_typename { static const char* name() { return "path"; } }; diff --git a/include/fc/io/json.hpp b/include/fc/io/json.hpp index 21d07c4..1980f74 100644 --- a/include/fc/io/json.hpp +++ b/include/fc/io/json.hpp @@ -52,7 +52,7 @@ namespace fc template static void save_to_file( const T& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ) { - save_to_file( variant(v), fi, pretty, format, max_depth ); + save_to_file( variant(v, max_depth), fi, pretty, format, max_depth ); } static void save_to_file( const variant& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); @@ -61,25 +61,25 @@ namespace fc template static T from_file( const fc::path& p, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ) { - return json::from_file(p, ptype, max_depth).as(); + return json::from_file(p, ptype, max_depth).as(max_depth); } template static string to_string( const T& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ) { - return to_string( variant(v), format, max_depth ); + return to_string( variant(v, max_depth), format, max_depth ); } template static string to_pretty_string( const T& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ) { - return to_pretty_string( variant(v), format, max_depth ); + return to_pretty_string( variant(v, max_depth), format, max_depth ); } template static void save_to_file( const T& v, const std::string& p, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ) { - save_to_file( variant(v), fc::path(p), pretty, format, max_depth ); + save_to_file( variant(v, max_depth), fc::path(p), pretty, format, max_depth ); } }; diff --git a/include/fc/io/raw.hpp b/include/fc/io/raw.hpp index d7e8bcd..30f9456 100644 --- a/include/fc/io/raw.hpp +++ b/include/fc/io/raw.hpp @@ -57,15 +57,17 @@ namespace fc { inline void pack( Stream& s, const fc::log_message& msg, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); - fc::raw::pack( s, variant(msg), _max_depth - 1 ); // TODO check variant depth? + --_max_depth; + fc::raw::pack( s, variant( msg, _max_depth ), _max_depth ); } template inline void unpack( Stream& s, fc::log_message& msg, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); fc::variant vmsg; - fc::raw::unpack( s, vmsg, _max_depth - 1 ); - msg = vmsg.as(); // TODO check depth? + --_max_depth; + fc::raw::unpack( s, vmsg, _max_depth ); + msg = vmsg.as( _max_depth ); } template diff --git a/include/fc/log/console_appender.hpp b/include/fc/log/console_appender.hpp index c15fcf0..2ed96fb 100644 --- a/include/fc/log/console_appender.hpp +++ b/include/fc/log/console_appender.hpp @@ -38,11 +38,12 @@ namespace fc { config() :format( "${timestamp} ${thread_name} ${context} ${file}:${line} ${method} ${level}] ${message}" ), - stream(console_appender::stream::std_error),flush(true){} + stream(console_appender::stream::std_error),max_object_depth(LOG_MAX_OBJECT_DEPTH),flush(true){} fc::string format; console_appender::stream::type stream; std::vector level_colors; + uint32_t max_object_depth; bool flush; }; @@ -69,4 +70,4 @@ namespace fc FC_REFLECT_ENUM( fc::console_appender::stream::type, (std_out)(std_error) ) FC_REFLECT_ENUM( fc::console_appender::color::type, (red)(green)(brown)(blue)(magenta)(cyan)(white)(console_default) ) FC_REFLECT( fc::console_appender::level_color, (level)(color) ) -FC_REFLECT( fc::console_appender::config, (format)(stream)(level_colors)(flush) ) +FC_REFLECT( fc::console_appender::config, (format)(stream)(level_colors)(max_object_depth)(flush) ) diff --git a/include/fc/log/file_appender.hpp b/include/fc/log/file_appender.hpp index a05fcd3..dca0d6a 100644 --- a/include/fc/log/file_appender.hpp +++ b/include/fc/log/file_appender.hpp @@ -18,6 +18,7 @@ class file_appender : public appender { bool rotate = false; microseconds rotation_interval; microseconds rotation_limit; + uint32_t max_object_depth; }; file_appender( const variant& args ); ~file_appender(); @@ -31,4 +32,4 @@ class file_appender : public appender { #include FC_REFLECT( fc::file_appender::config, - (format)(filename)(flush)(rotate)(rotation_interval)(rotation_limit) ) + (format)(filename)(flush)(rotate)(rotation_interval)(rotation_limit)(max_object_depth) ) diff --git a/include/fc/log/gelf_appender.hpp b/include/fc/log/gelf_appender.hpp index 2228313..ba81c3d 100644 --- a/include/fc/log/gelf_appender.hpp +++ b/include/fc/log/gelf_appender.hpp @@ -15,6 +15,7 @@ namespace fc { string endpoint = "127.0.0.1:12201"; string host = "fc"; // the name of the host, source or application that sent this message (just passed through to GELF server) + uint32_t max_object_depth; }; gelf_appender(const variant& args); @@ -29,4 +30,4 @@ namespace fc #include FC_REFLECT(fc::gelf_appender::config, - (endpoint)(host)) + (endpoint)(host)(max_object_depth)) diff --git a/include/fc/log/log_message.hpp b/include/fc/log/log_message.hpp index 1928a98..f297688 100644 --- a/include/fc/log/log_message.hpp +++ b/include/fc/log/log_message.hpp @@ -43,8 +43,8 @@ namespace fc values value; }; - void to_variant( log_level e, variant& v ); - void from_variant( const variant& e, log_level& ll ); + void to_variant( log_level e, variant& v, uint32_t max_depth = 1 ); + void from_variant( const variant& e, log_level& ll, uint32_t max_depth = 1 ); /** * @brief provides information about where and when a log message was generated. @@ -61,8 +61,8 @@ namespace fc uint64_t line, const char* method ); ~log_context(); - explicit log_context( const variant& v ); - variant to_variant()const; + explicit log_context( const variant& v, uint32_t max_depth ); + variant to_variant( uint32_t max_depth )const; string get_file()const; uint64_t get_line_number()const; @@ -81,8 +81,8 @@ namespace fc std::shared_ptr my; }; - void to_variant( const log_context& l, variant& v ); - void from_variant( const variant& l, log_context& c ); + void to_variant( const log_context& l, variant& v, uint32_t max_depth ); + void from_variant( const variant& l, log_context& c, uint32_t max_depth ); /** * @brief aggregates a message along with the context and associated meta-information. @@ -112,8 +112,8 @@ namespace fc log_message( log_context ctx, std::string format, variant_object args = variant_object() ); ~log_message(); - log_message( const variant& v ); - variant to_variant()const; + log_message( const variant& v, uint32_t max_depth ); + variant to_variant(uint32_t max_depth)const; string get_message()const; @@ -125,8 +125,8 @@ namespace fc std::shared_ptr my; }; - void to_variant( const log_message& l, variant& v ); - void from_variant( const variant& l, log_message& c ); + void to_variant( const log_message& l, variant& v, uint32_t max_depth ); + void from_variant( const variant& l, log_message& c, uint32_t max_depth ); typedef std::vector log_messages; @@ -139,6 +139,8 @@ FC_REFLECT_TYPENAME( fc::log_message ); #define __func__ __FUNCTION__ #endif +#define LOG_MAX_OBJECT_DEPTH 210 + /** * @def FC_LOG_CONTEXT(LOG_LEVEL) * @brief Automatically captures the File, Line, and Method names and passes them to @@ -158,5 +160,5 @@ FC_REFLECT_TYPENAME( fc::log_message ); * @param ... A set of key/value pairs denoted as ("key",val)("key2",val2)... */ #define FC_LOG_MESSAGE( LOG_LEVEL, FORMAT, ... ) \ - fc::log_message( FC_LOG_CONTEXT(LOG_LEVEL), FORMAT, fc::mutable_variant_object()__VA_ARGS__ ) + fc::log_message( FC_LOG_CONTEXT(LOG_LEVEL), FORMAT, fc::limited_mutable_variant_object(LOG_MAX_OBJECT_DEPTH)__VA_ARGS__ ) diff --git a/include/fc/log/logger.hpp b/include/fc/log/logger.hpp index 9005d75..a2868f4 100644 --- a/include/fc/log/logger.hpp +++ b/include/fc/log/logger.hpp @@ -145,7 +145,7 @@ namespace fc BOOST_PP_STRINGIZE(base) ": ${" BOOST_PP_STRINGIZE( base ) "} " #define FC_FORMAT_ARGS(r, unused, base) \ - BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(base),fc::variant(base) BOOST_PP_RPAREN() + BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(base),fc::variant(base,LOG_MAX_OBJECT_DEPTH) BOOST_PP_RPAREN() #define FC_FORMAT( SEQ )\ BOOST_PP_SEQ_FOR_EACH( FC_FORMAT_ARG, v, SEQ ) diff --git a/include/fc/reflect/variant.hpp b/include/fc/reflect/variant.hpp index 31bbbdf..907b20e 100644 --- a/include/fc/reflect/variant.hpp +++ b/include/fc/reflect/variant.hpp @@ -5,17 +5,19 @@ namespace fc { template - void to_variant( const T& o, variant& v ); + void to_variant( const T& o, variant& v, uint32_t max_depth ); template - void from_variant( const variant& v, T& o ); + void from_variant( const variant& v, T& o, uint32_t max_depth ); template class to_variant_visitor { public: - to_variant_visitor( mutable_variant_object& mvo, const T& v ) - :vo(mvo),val(v){} + to_variant_visitor( mutable_variant_object& mvo, const T& v, uint32_t max_depth ) + :vo(mvo),val(v),_max_depth(max_depth - 1) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + } template void operator()( const char* name )const @@ -28,50 +30,54 @@ namespace fc void add( mutable_variant_object& vo, const char* name, const optional& v )const { if( v.valid() ) - vo(name,*v); + vo(name, variant( *v, _max_depth )); } template void add( mutable_variant_object& vo, const char* name, const M& v )const - { vo(name,v); } + { vo(name, variant( v, _max_depth )); } mutable_variant_object& vo; const T& val; + const uint32_t _max_depth; }; template class from_variant_visitor { public: - from_variant_visitor( const variant_object& _vo, T& v ) - :vo(_vo),val(v){} + from_variant_visitor( const variant_object& _vo, T& v, uint32_t max_depth ) + :vo(_vo),val(v),_max_depth(max_depth - 1) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + } template void operator()( const char* name )const { auto itr = vo.find(name); if( itr != vo.end() ) - from_variant( itr->value(), val.*member ); + from_variant( itr->value(), val.*member, _max_depth ); } const variant_object& vo; T& val; + const uint32_t _max_depth; }; template struct if_enum { template - static inline void to_variant( const T& v, fc::variant& vo ) + static inline void to_variant( const T& v, fc::variant& vo, uint32_t max_depth ) { mutable_variant_object mvo; - fc::reflector::visit( to_variant_visitor( mvo, v ) ); + fc::reflector::visit( to_variant_visitor( mvo, v, max_depth ) ); vo = fc::move(mvo); } template - static inline void from_variant( const fc::variant& v, T& o ) + static inline void from_variant( const fc::variant& v, T& o, uint32_t max_depth ) { const variant_object& vo = v.get_object(); - fc::reflector::visit( from_variant_visitor( vo, o ) ); + fc::reflector::visit( from_variant_visitor( vo, o, max_depth ) ); } }; @@ -79,12 +85,12 @@ namespace fc struct if_enum { template - static inline void to_variant( const T& o, fc::variant& v ) + static inline void to_variant( const T& o, fc::variant& v, uint32_t max_depth = 1 ) { v = fc::reflector::to_fc_string(o); } template - static inline void from_variant( const fc::variant& v, T& o ) + static inline void from_variant( const fc::variant& v, T& o, uint32_t max_depth = 1 ) { if( v.is_string() ) o = fc::reflector::from_string( v.get_string().c_str() ); @@ -95,15 +101,14 @@ namespace fc template - void to_variant( const T& o, variant& v ) + void to_variant( const T& o, variant& v, uint32_t max_depth ) { - if_enum::is_enum>::to_variant( o, v ); + if_enum::is_enum>::to_variant( o, v, max_depth ); } template - void from_variant( const variant& v, T& o ) + void from_variant( const variant& v, T& o, uint32_t max_depth ) { - if_enum::is_enum>::from_variant( v, o ); + if_enum::is_enum>::from_variant( v, o, max_depth ); } - } diff --git a/include/fc/rpc/api_connection.hpp b/include/fc/rpc/api_connection.hpp index 1cd5561..05f93ca 100644 --- a/include/fc/rpc/api_connection.hpp +++ b/include/fc/rpc/api_connection.hpp @@ -8,7 +8,6 @@ #include #include #include -//#include namespace fc { class api_connection; @@ -148,14 +147,14 @@ namespace fc { R call_generic( const std::function,Args...)>& f, variants::const_iterator a0, variants::const_iterator e ) { FC_ASSERT( a0 != e, "too few arguments passed to method" ); - detail::callback_functor arg0( get_connection(), a0->as() ); + detail::callback_functor arg0( get_connection(), a0->as(1) ); return call_generic( this->bind_first_arg,Args...>( f, std::function(arg0) ), a0+1, e ); } template R call_generic( const std::function&,Args...)>& f, variants::const_iterator a0, variants::const_iterator e ) { FC_ASSERT( a0 != e, "too few arguments passed to method" ); - detail::callback_functor arg0( get_connection(), a0->as() ); + detail::callback_functor arg0( get_connection(), a0->as(1) ); return call_generic( this->bind_first_arg&,Args...>( f, arg0 ), a0+1, e ); } @@ -207,7 +206,7 @@ namespace fc { class api_connection : public std::enable_shared_from_this { public: - api_connection(){} + api_connection(uint32_t max_depth):_max_conversion_depth(max_depth){} virtual ~api_connection(){}; @@ -262,6 +261,8 @@ namespace fc { std::vector get_method_names( api_id_type local_api_id = 0 )const { return _local_apis[local_api_id]->get_method_names(); } fc::signal closed; + protected: + const uint32_t _max_conversion_depth = 200; // for nested structures, json, variant etc. private: std::vector< std::unique_ptr > _local_apis; std::map< uint64_t, api_id_type > _handle_to_id; diff --git a/include/fc/rpc/http_api.hpp b/include/fc/rpc/http_api.hpp index 47eb289..a693655 100644 --- a/include/fc/rpc/http_api.hpp +++ b/include/fc/rpc/http_api.hpp @@ -11,7 +11,7 @@ namespace fc { namespace rpc { class http_api_connection : public api_connection { public: - http_api_connection(); + http_api_connection(uint32_t max_conversion_depth); ~http_api_connection(); virtual variant send_call( diff --git a/include/fc/rpc/json_connection.hpp b/include/fc/rpc/json_connection.hpp index 04cd041..af76e89 100644 --- a/include/fc/rpc/json_connection.hpp +++ b/include/fc/rpc/json_connection.hpp @@ -21,7 +21,7 @@ namespace fc { namespace rpc { typedef std::function method; typedef std::function named_param_method; - json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out ); + json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out, uint32_t max_depth ); ~json_connection(); /** @@ -303,7 +303,10 @@ namespace fc { namespace rpc { /// Sending in a variant_object will be issued as named parameters variant call( const fc::string& method, const variant_object& named_args ); ///@} - + + protected: + const uint32_t _max_conversion_depth; // for nested structures, json, variant etc. + private: std::unique_ptr my; }; diff --git a/include/fc/rpc/websocket_api.hpp b/include/fc/rpc/websocket_api.hpp index 92d7f2e..ebb6fe7 100644 --- a/include/fc/rpc/websocket_api.hpp +++ b/include/fc/rpc/websocket_api.hpp @@ -10,7 +10,7 @@ namespace fc { namespace rpc { class websocket_api_connection : public api_connection { public: - websocket_api_connection( fc::http::websocket_connection& c ); + websocket_api_connection( fc::http::websocket_connection& c, uint32_t max_conversion_depth ); ~websocket_api_connection(); virtual variant send_call( diff --git a/include/fc/string.hpp b/include/fc/string.hpp index dc942b9..13e10da 100644 --- a/include/fc/string.hpp +++ b/include/fc/string.hpp @@ -25,7 +25,7 @@ namespace fc typedef fc::optional ostring; class variant_object; - fc::string format_string( const fc::string&, const variant_object& ); + fc::string format_string( const fc::string&, const variant_object&, uint32_t max_object_depth = 200 ); fc::string trim( const fc::string& ); fc::string to_lower( const fc::string& ); string trim_and_normalize_spaces( const string& s ); diff --git a/include/fc/variant.hpp b/include/fc/variant.hpp index c5ddf0d..48de3af 100644 --- a/include/fc/variant.hpp +++ b/include/fc/variant.hpp @@ -17,6 +17,17 @@ #include #include +#ifdef FC_ASSERT +#define _FC_ASSERT(...) FC_ASSERT( __VA_ARGS__ ) +#else +// poor man's FC_ASSERT, want to avoid recursive inclusion of exception.hpp +namespace fc +{ +void throw_assertion_failure( const std::string& message ); +} +#define _FC_ASSERT( cond, msg ) { if( !(cond) ) { fc::throw_assertion_failure( #cond ": " msg ); } } +#endif + namespace fc { /** @@ -44,115 +55,115 @@ namespace fc struct blob { std::vector data; }; - void to_variant( const blob& var, variant& vo ); - void from_variant( const variant& var, blob& vo ); + void to_variant( const blob& var, variant& vo, uint32_t max_depth = 1); + void from_variant( const variant& var, blob& vo, uint32_t max_depth = 1 ); - template void to_variant( const boost::multi_index_container& s, variant& v ); - template void from_variant( const variant& v, boost::multi_index_container& s ); + template void to_variant( const boost::multi_index_container& s, variant& v, uint32_t max_depth ); + template void from_variant( const variant& v, boost::multi_index_container& s, uint32_t max_depth ); - template void to_variant( const smart_ref& s, variant& v ); - template void from_variant( const variant& v, smart_ref& s ); - template void to_variant( const safe& s, variant& v ); - template void from_variant( const variant& v, safe& s ); - template void to_variant( const std::unique_ptr& s, variant& v ); - template void from_variant( const variant& v, std::unique_ptr& s ); + template void to_variant( const smart_ref& s, variant& v, uint32_t max_depth ); + template void from_variant( const variant& v, smart_ref& s, uint32_t max_depth ); + template void to_variant( const safe& s, variant& v, uint32_t max_depth ); + template void from_variant( const variant& v, safe& s, uint32_t max_depth ); + template void to_variant( const std::unique_ptr& s, variant& v, uint32_t max_depth ); + template void from_variant( const variant& v, std::unique_ptr& s, uint32_t max_depth ); - template void to_variant( const static_variant& s, variant& v ); - template void from_variant( const variant& v, static_variant& s ); + template void to_variant( const static_variant& s, variant& v, uint32_t max_depth ); + template void from_variant( const variant& v, static_variant& s, uint32_t max_depth ); - void to_variant( const uint8_t& var, variant& vo ); - void from_variant( const variant& var, uint8_t& vo ); - void to_variant( const int8_t& var, variant& vo ); - void from_variant( const variant& var, int8_t& vo ); + void to_variant( const uint8_t& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, uint8_t& vo, uint32_t max_depth = 1 ); + void to_variant( const int8_t& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, int8_t& vo, uint32_t max_depth = 1 ); - void to_variant( const uint16_t& var, variant& vo ); - void from_variant( const variant& var, uint16_t& vo ); - void to_variant( const int16_t& var, variant& vo ); - void from_variant( const variant& var, int16_t& vo ); + void to_variant( const uint16_t& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, uint16_t& vo, uint32_t max_depth = 1 ); + void to_variant( const int16_t& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, int16_t& vo, uint32_t max_depth = 1 ); - void to_variant( const uint32_t& var, variant& vo ); - void from_variant( const variant& var, uint32_t& vo ); - void to_variant( const int32_t& var, variant& vo ); - void from_variant( const variant& var, int32_t& vo ); + void to_variant( const uint32_t& var, variant& vo, uint32_t max_depth = 1 ); + /** @ingroup Serializable */ + void from_variant( const variant& var, uint32_t& vo, uint32_t max_depth = 1 ); + void to_variant( const int32_t& var, variant& vo, uint32_t max_depth = 1 ); + /** @ingroup Serializable */ + void from_variant( const variant& var, int32_t& vo, uint32_t max_depth = 1 ); - void to_variant( const variant_object& var, variant& vo ); - void from_variant( const variant& var, variant_object& vo ); - void to_variant( const mutable_variant_object& var, variant& vo ); - void from_variant( const variant& var, mutable_variant_object& vo ); - void to_variant( const std::vector& var, variant& vo ); - void from_variant( const variant& var, std::vector& vo ); + void to_variant( const variant_object& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, variant_object& vo, uint32_t max_depth ); + void to_variant( const mutable_variant_object& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, mutable_variant_object& vo, uint32_t max_depth ); + void to_variant( const std::vector& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, std::vector& vo, uint32_t max_depth = 1 ); template - void to_variant( const std::unordered_map& var, variant& vo ); + void to_variant( const std::unordered_map& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::unordered_map& vo ); + void from_variant( const variant& var, std::unordered_map& vo, uint32_t max_depth ); template - void to_variant( const fc::flat_map& var, variant& vo ); + void to_variant( const fc::flat_map& var, variant& vo, uint32_t max_depth ); template - void from_variant(const variant& var, flat_map& vo); + void from_variant(const variant& var, flat_map& vo, uint32_t max_depth ); template - void to_variant( const std::map& var, variant& vo ); + void to_variant( const std::map& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::map& vo ); + void from_variant( const variant& var, std::map& vo, uint32_t max_depth ); template - void to_variant( const std::multimap& var, variant& vo ); + void to_variant( const std::multimap& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::multimap& vo ); + void from_variant( const variant& var, std::multimap& vo, uint32_t max_depth ); template - void to_variant( const std::unordered_set& var, variant& vo ); + void to_variant( const std::unordered_set& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::unordered_set& vo ); + void from_variant( const variant& var, std::unordered_set& vo, uint32_t max_depth ); template - void to_variant( const std::deque& var, variant& vo ); + void to_variant( const std::deque& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::deque& vo ); + void from_variant( const variant& var, std::deque& vo, uint32_t max_depth ); template - void to_variant( const fc::flat_set& var, variant& vo ); + void to_variant( const fc::flat_set& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, fc::flat_set& vo ); + void from_variant( const variant& var, fc::flat_set& vo, uint32_t max_depth ); template - void to_variant( const std::set& var, variant& vo ); + void to_variant( const std::set& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::set& vo ); + void from_variant( const variant& var, std::set& vo, uint32_t max_depth ); - void to_variant( const time_point& var, variant& vo ); - void from_variant( const variant& var, time_point& vo ); + void to_variant( const time_point& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, time_point& vo, uint32_t max_depth ); - void to_variant( const time_point_sec& var, variant& vo ); - void from_variant( const variant& var, time_point_sec& vo ); + void to_variant( const time_point_sec& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, time_point_sec& vo, uint32_t max_depth ); - void to_variant( const microseconds& input_microseconds, variant& output_variant ); - void from_variant( const variant& input_variant, microseconds& output_microseconds ); + void to_variant( const microseconds& input_microseconds, variant& output_variant, uint32_t max_depth ); + void from_variant( const variant& input_variant, microseconds& output_microseconds, uint32_t max_depth ); #ifdef __APPLE__ void to_variant( size_t s, variant& v ); #elif !defined(_MSC_VER) - void to_variant( long long int s, variant& v ); - void to_variant( unsigned long long int s, variant& v ); + void to_variant( long long int s, variant& v, uint32_t max_depth = 1 ); + void to_variant( unsigned long long int s, variant& v, uint32_t max_depth = 1 ); #endif - void to_variant( const std::string& s, variant& v ); + void to_variant( const std::string& s, variant& v, uint32_t max_depth = 1 ); template - void to_variant( const std::shared_ptr& var, variant& vo ); + void to_variant( const std::shared_ptr& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::shared_ptr& vo ); + void from_variant( const variant& var, std::shared_ptr& vo, uint32_t max_depth ); typedef std::vector variants; template - void to_variant( const std::pair& t, variant& v ); + void to_variant( const std::pair& t, variant& v, uint32_t max_depth ); template - void from_variant( const variant& v, std::pair& p ); - - + void from_variant( const variant& v, std::pair& p, uint32_t max_depth ); /** * @brief stores null, int64, uint64, double, bool, string, std::vector, @@ -182,31 +193,31 @@ namespace fc /// Constructs a null_type variant variant(); /// Constructs a null_type variant - variant( nullptr_t ); + variant( nullptr_t, uint32_t max_depth = 1 ); /// @param str - UTF8 string - variant( const char* str ); - variant( char* str ); - variant( wchar_t* str ); - variant( const wchar_t* str ); - variant( float val ); - variant( uint8_t val ); - variant( int8_t val ); - variant( uint16_t val ); - variant( int16_t val ); - variant( uint32_t val ); - variant( int32_t val ); - variant( uint64_t val ); - variant( int64_t val ); - variant( double val ); - variant( bool val ); - variant( blob val ); - variant( fc::string val ); - variant( variant_object ); - variant( mutable_variant_object ); - variant( variants ); - variant( const variant& ); - variant( variant&& ); + variant( const char* str, uint32_t max_depth = 1 ); + variant( char* str, uint32_t max_depth = 1 ); + variant( wchar_t* str, uint32_t max_depth = 1 ); + variant( const wchar_t* str, uint32_t max_depth = 1 ); + variant( float val, uint32_t max_depth = 1 ); + variant( uint8_t val, uint32_t max_depth = 1 ); + variant( int8_t val, uint32_t max_depth = 1 ); + variant( uint16_t val, uint32_t max_depth = 1 ); + variant( int16_t val, uint32_t max_depth = 1 ); + variant( uint32_t val, uint32_t max_depth = 1 ); + variant( int32_t val, uint32_t max_depth = 1 ); + variant( uint64_t val, uint32_t max_depth = 1 ); + variant( int64_t val, uint32_t max_depth = 1 ); + variant( double val, uint32_t max_depth = 1 ); + variant( bool val, uint32_t max_depth = 1 ); + variant( blob val, uint32_t max_depth = 1 ); + variant( fc::string val, uint32_t max_depth = 1 ); + variant( variant_object, uint32_t max_depth = 1 ); + variant( mutable_variant_object, uint32_t max_depth = 1 ); + variant( variants, uint32_t max_depth = 1 ); + variant( const variant&, uint32_t max_depth = 1 ); + variant( variant&&, uint32_t max_depth = 1 ); ~variant(); /** @@ -298,17 +309,17 @@ namespace fc * types. */ template - T as()const + T as( uint32_t max_depth )const { T tmp; - from_variant( *this, tmp ); + from_variant( *this, tmp, max_depth ); return tmp; } template - void as( T& v )const + void as( T& v, uint32_t max_depth )const { - from_variant( *this, v ); + from_variant( *this, v, max_depth ); } variant& operator=( variant&& v ); @@ -321,14 +332,15 @@ namespace fc } template - variant( const optional& v ) + variant( const optional& v, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); memset( this, 0, sizeof(*this) ); - if( v.valid() ) *this = variant(*v); + if( v.valid() ) *this = variant( *v, max_depth - 1 ); } template - explicit variant( const T& val ); + variant( const T& val, uint32_t max_depth ); void clear(); @@ -340,264 +352,298 @@ namespace fc typedef optional ovariant; /** @ingroup Serializable */ - void from_variant( const variant& var, string& vo ); + void from_variant( const variant& var, string& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, variants& vo ); - void from_variant( const variant& var, variant& vo ); + void from_variant( const variant& var, variants& vo, uint32_t max_depth ); + void from_variant( const variant& var, variant& vo, uint32_t max_depth ); /** @ingroup Serializable */ - void from_variant( const variant& var, int64_t& vo ); + void from_variant( const variant& var, int64_t& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, uint64_t& vo ); + void from_variant( const variant& var, uint64_t& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, bool& vo ); + void from_variant( const variant& var, bool& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, double& vo ); + void from_variant( const variant& var, double& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, float& vo ); - /** @ingroup Serializable */ - void from_variant( const variant& var, int32_t& vo ); - /** @ingroup Serializable */ - void from_variant( const variant& var, uint32_t& vo ); + void from_variant( const variant& var, float& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ template - void from_variant( const variant& var, optional& vo ) + void from_variant( const variant& var, optional& vo, uint32_t max_depth ) { if( var.is_null() ) vo = optional(); else { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); vo = T(); - from_variant( var, *vo ); + from_variant( var, *vo, max_depth - 1 ); } } template - void to_variant( const std::unordered_set& var, variant& vo ) + void to_variant( const std::unordered_set& var, variant& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); std::vector vars(var.size()); size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = variant(*itr); + for( const auto& item : var ) + vars[i++] = variant( item, max_depth - 1 ); vo = vars; } template - void from_variant( const variant& var, std::unordered_set& vo ) + void from_variant( const variant& var, std::unordered_set& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); vo.clear(); vo.reserve( vars.size() ); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as() ); + for( const auto& item : vars ) + vo.insert( item.as( max_depth - 1 ) ); } template - void to_variant( const std::unordered_map& var, variant& vo ) + void to_variant( const std::unordered_map& var, variant& vo, uint32_t max_depth ) { - std::vector< variant > vars(var.size()); - size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = fc::variant(*itr); - vo = vars; + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector< variant > vars(var.size()); + size_t i = 0; + for( const auto& key_value : var ) + vars[i++] = fc::variant( key_value, max_depth - 1 ); + vo = vars; } template - void from_variant( const variant& var, std::unordered_map& vo ) + void from_variant( const variant& var, std::unordered_map& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); vo.clear(); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as< std::pair >() ); - + vo.reserve( vars.size() ); + for( const auto& item : vars ) + vo.insert( item.as< std::pair >( max_depth - 1 ) ); } template - void to_variant( const std::map& var, variant& vo ) + void to_variant( const std::map& var, variant& vo, uint32_t max_depth ) { - std::vector< variant > vars(var.size()); - size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = fc::variant(*itr); - vo = vars; + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector< variant > vars(var.size()); + size_t i = 0; + for( const auto& key_value : var ) + vars[i++] = fc::variant( key_value, max_depth - 1 ); + vo = vars; } template - void from_variant( const variant& var, std::map& vo ) + void from_variant( const variant& var, std::map& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); vo.clear(); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as< std::pair >() ); + for( auto item : vars ) + vo.insert( item.as< std::pair >( max_depth - 1 ) ); } template - void to_variant( const std::multimap& var, variant& vo ) + void to_variant( const std::multimap& var, variant& vo, uint32_t max_depth ) { - std::vector< variant > vars(var.size()); - size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = fc::variant(*itr); - vo = vars; + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector< variant > vars(var.size()); + size_t i = 0; + for( const auto& key_value : var ) + vars[i++] = fc::variant( key_value, max_depth - 1 ); + vo = vars; } template - void from_variant( const variant& var, std::multimap& vo ) + void from_variant( const variant& var, std::multimap& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); vo.clear(); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as< std::pair >() ); + for( auto item : vars ) + vo.insert( item.as< std::pair >( max_depth - 1 ) ); } template - void to_variant( const std::set& var, variant& vo ) + void to_variant( const std::set& var, variant& vo, uint32_t max_depth ) { - std::vector vars(var.size()); - size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = variant(*itr); - vo = vars; + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector vars(var.size()); + size_t i = 0; + for( const auto& item : var ) + vars[i++] = fc::variant( item, max_depth - 1 ); + vo = vars; } template - void from_variant( const variant& var, std::set& vo ) + void from_variant( const variant& var, std::set& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); vo.clear(); - //vo.reserve( vars.size() ); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as() ); + for( const auto& item : vars ) + vo.insert( item.as( max_depth - 1 ) ); } /** @ingroup Serializable */ template - void from_variant( const variant& var, std::deque& tmp ) + void from_variant( const variant& var, std::deque& dest, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); - tmp.clear(); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - tmp.push_back( itr->as() ); + dest.clear(); + dest.resize( vars.size() ); + for( const auto& item : vars ) + dest.push_back( item.as( max_depth - 1 ) ); } /** @ingroup Serializable */ template - void to_variant( const std::deque& t, variant& v ) + void to_variant( const std::deque& src, variant& v, uint32_t max_depth ) { - std::vector vars(t.size()); - for( size_t i = 0; i < t.size(); ++i ) - vars[i] = variant(t[i]); + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector vars(src.size()); + for( size_t i = 0; i < src.size(); ++i ) + vars[i] = variant( src[i], max_depth - 1 ); v = std::move(vars); } /** @ingroup Serializable */ template - void from_variant( const variant& var, std::vector& tmp ) + void from_variant( const variant& var, std::vector& dest, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); - tmp.clear(); - tmp.reserve( vars.size() ); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - tmp.push_back( itr->as() ); + dest.clear(); + dest.reserve( vars.size() ); + for( const auto& item : vars ) + dest.push_back( item.as( max_depth - 1 ) ); } /** @ingroup Serializable */ template - void to_variant( const std::vector& t, variant& v ) + void to_variant( const std::vector& t, variant& v, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); std::vector vars(t.size()); - for( size_t i = 0; i < t.size(); ++i ) - vars[i] = variant(t[i]); - v = std::move(vars); + for( size_t i = 0; i < t.size(); ++i ) + vars[i] = variant( t[i], max_depth - 1 ); + v = std::move(vars); } /** @ingroup Serializable */ template - void to_variant( const std::pair& t, variant& v ) + void to_variant( const std::pair& t, variant& v, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); std::vector vars(2); - vars[0] = variant(t.first); - vars[1] = variant(t.second); - v = vars; + vars[0] = variant( t.first, max_depth - 1 ); + vars[1] = variant( t.second, max_depth - 1 ); + v = vars; } template - void from_variant( const variant& v, std::pair& p ) + void from_variant( const variant& v, std::pair& p, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = v.get_array(); if( vars.size() > 0 ) - p.first = vars[0].as(); + p.first = vars[0].as( max_depth - 1 ); if( vars.size() > 1 ) - p.second = vars[1].as(); + p.second = vars[1].as( max_depth - 1 ); } template - variant::variant( const T& val ) + variant::variant( const T& val, uint32_t max_depth ) { memset( this, 0, sizeof(*this) ); - to_variant( val, *this ); + to_variant( val, *this, max_depth ); } #ifdef __APPLE__ inline void to_variant( size_t s, variant& v ) { v = variant(uint64_t(s)); } #endif template - void to_variant( const std::shared_ptr& var, variant& vo ) + void to_variant( const std::shared_ptr& var, variant& vo, uint32_t max_depth ) { - if( var ) to_variant( *var, vo ); + if( var ) + { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + to_variant( *var, vo, max_depth - 1 ); + } else vo = nullptr; } template - void from_variant( const variant& var, std::shared_ptr& vo ) + void from_variant( const variant& var, std::shared_ptr& vo, uint32_t max_depth ) { if( var.is_null() ) vo = nullptr; - else if( vo ) from_variant( var, *vo ); - else { - vo = std::make_shared(); - from_variant( var, *vo ); + else + { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + if( !vo ) vo = std::make_shared(); + from_variant( var, *vo, max_depth - 1 ); } } template - void to_variant( const std::unique_ptr& var, variant& vo ) + void to_variant( const std::unique_ptr& var, variant& vo, uint32_t max_depth ) { - if( var ) to_variant( *var, vo ); + if( var ) + { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + to_variant( *var, vo, max_depth - 1 ); + } else vo = nullptr; } template - void from_variant( const variant& var, std::unique_ptr& vo ) + void from_variant( const variant& var, std::unique_ptr& vo, uint32_t max_depth ) { if( var.is_null() ) vo.reset(); - else if( vo ) from_variant( var, *vo ); - else { - vo.reset( new T() ); - from_variant( var, *vo ); + else + { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + if( !vo ) vo.reset( new T() ); + from_variant( var, *vo, max_depth - 1 ); } } template - void to_variant( const safe& s, variant& v ) { v = s.value; } - - template - void from_variant( const variant& v, safe& s ) { s.value = v.as_uint64(); } - - template - void to_variant( const smart_ref& s, variant& v ) { v = *s; } - - template - void from_variant( const variant& v, smart_ref& s ) { from_variant( v, *s ); } - - template void to_variant( const boost::multi_index_container& c, variant& v ) - { - std::vector vars; - vars.reserve( c.size() ); - for( const auto& item : c ) - vars.emplace_back( variant(item) ); - v = std::move(vars); + void to_variant( const safe& s, variant& v, uint32_t max_depth ) { + to_variant( s.value, v, max_depth ); } - template void from_variant( const variant& v, boost::multi_index_container& c ) + template + void from_variant( const variant& v, safe& s, uint32_t max_depth ) { + s.value = v.as( max_depth ); + } + + template + void to_variant( const smart_ref& s, variant& v, uint32_t max_depth ) { + to_variant( *s, v, max_depth ); + } + + template + void from_variant( const variant& v, smart_ref& s, uint32_t max_depth ) { + from_variant( v, *s, max_depth ); + } + + template + void to_variant( const boost::multi_index_container& c, variant& v, uint32_t max_depth ) + { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector vars; + vars.reserve( c.size() ); + for( const auto& item : c ) + vars.emplace_back( variant( item, max_depth - 1 ) ); + v = std::move(vars); + } + + template + void from_variant( const variant& v, boost::multi_index_container& c, uint32_t max_depth ) { const variants& vars = v.get_array(); c.clear(); for( const auto& item : vars ) - c.insert( item.as() ); + c.insert( item.as( max_depth - 1 ) ); } variant operator + ( const variant& a, const variant& b ); diff --git a/include/fc/variant_object.hpp b/include/fc/variant_object.hpp index 5a39c80..dc72b9e 100644 --- a/include/fc/variant_object.hpp +++ b/include/fc/variant_object.hpp @@ -169,11 +169,12 @@ namespace fc * * @return *this; */ - mutable_variant_object& operator()( string key, variant var ); + mutable_variant_object& operator()( string key, variant var, uint32_t max_depth = 1 ); template - mutable_variant_object& operator()( string key, T&& var ) + mutable_variant_object& operator()( string key, T&& var, uint32_t max_depth ) { - set(std::move(key), variant( fc::forward(var) ) ); + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + set( std::move(key), variant( fc::forward(var), max_depth - 1 ) ); return *this; } /** @@ -216,9 +217,26 @@ namespace fc std::unique_ptr< std::vector< entry > > _key_value; friend class variant_object; }; + + class limited_mutable_variant_object : public mutable_variant_object + { + public: + limited_mutable_variant_object( uint32_t max_depth ); + + template + limited_mutable_variant_object& operator()( string key, T&& var ) + { + set( std::move(key), variant( fc::forward(var), _max_depth ) ); + return *this; + } + + private: + const uint32_t _max_depth; + }; + /** @ingroup Serializable */ - void to_variant( const mutable_variant_object& var, variant& vo ); + void to_variant( const mutable_variant_object& var, variant& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, mutable_variant_object& vo ); + void from_variant( const variant& var, mutable_variant_object& vo, uint32_t max_depth = 1 ); } // namespace fc diff --git a/src/crypto/elliptic_common.cpp b/src/crypto/elliptic_common.cpp index 9b9044c..7027179 100644 --- a/src/crypto/elliptic_common.cpp +++ b/src/crypto/elliptic_common.cpp @@ -388,27 +388,27 @@ namespace fc { namespace ecc { } } -void to_variant( const ecc::private_key& var, variant& vo ) +void to_variant( const ecc::private_key& var, variant& vo, uint32_t max_depth ) { - vo = var.get_secret(); + to_variant( var.get_secret(), vo, max_depth ); } -void from_variant( const variant& var, ecc::private_key& vo ) +void from_variant( const variant& var, ecc::private_key& vo, uint32_t max_depth ) { fc::sha256 sec; - from_variant( var, sec ); + from_variant( var, sec, max_depth ); vo = ecc::private_key::regenerate(sec); } -void to_variant( const ecc::public_key& var, variant& vo ) +void to_variant( const ecc::public_key& var, variant& vo, uint32_t max_depth ) { - vo = var.serialize(); + to_variant( var.serialize(), vo, max_depth ); } -void from_variant( const variant& var, ecc::public_key& vo ) +void from_variant( const variant& var, ecc::public_key& vo, uint32_t max_depth ) { ecc::public_key_data dat; - from_variant( var, dat ); + from_variant( var, dat, max_depth ); vo = ecc::public_key(dat); } diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp index e336b39..3e96048 100644 --- a/src/crypto/ripemd160.cpp +++ b/src/crypto/ripemd160.cpp @@ -26,7 +26,8 @@ ripemd160::operator string()const { return str(); } char* ripemd160::data()const { return (char*)&_hash[0]; } -struct ripemd160::encoder::impl { +class ripemd160::encoder::impl { +public: impl() { memset( (char*)&ctx, 0, sizeof(ctx) ); @@ -98,19 +99,16 @@ bool operator == ( const ripemd160& h1, const ripemd160& h2 ) { return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; } - void to_variant( const ripemd160& bi, variant& v ) - { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); - } - void from_variant( const variant& v, ripemd160& bi ) - { - std::vector ve = v.as< std::vector >(); - if( ve.size() ) - { - memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); - } - else - memset( &bi, char(0), sizeof(bi) ); + void to_variant( const ripemd160& bi, variant& v, uint32_t max_depth ) + { + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); + } + void from_variant( const variant& v, ripemd160& bi, uint32_t max_depth ) + { + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); + if( ve.size() ) + memcpy( &bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } } // fc diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp index 88107db..f509f00 100644 --- a/src/crypto/sha1.cpp +++ b/src/crypto/sha1.cpp @@ -83,19 +83,16 @@ bool operator == ( const sha1& h1, const sha1& h2 ) { return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; } - void to_variant( const sha1& bi, variant& v ) + void to_variant( const sha1& bi, variant& v, uint32_t max_depth ) { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); } - void from_variant( const variant& v, sha1& bi ) + void from_variant( const variant& v, sha1& bi, uint32_t max_depth ) { - std::vector ve = v.as< std::vector >(); + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); if( ve.size() ) - { - memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); - } - else - memset( &bi, char(0), sizeof(bi) ); + memcpy( &bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } } // fc diff --git a/src/crypto/sha224.cpp b/src/crypto/sha224.cpp index 0ae1707..4015f90 100644 --- a/src/crypto/sha224.cpp +++ b/src/crypto/sha224.cpp @@ -60,7 +60,7 @@ namespace fc { sha224 operator ^ ( const sha224& h1, const sha224& h2 ) { sha224 result; for( uint32_t i = 0; i < 7; ++i ) - result._hash[i] = h1._hash[i] ^ h2._hash[i]; + result._hash[i] = h1._hash[i] ^ h2._hash[i]; return result; } bool operator >= ( const sha224& h1, const sha224& h2 ) { @@ -79,19 +79,16 @@ namespace fc { return memcmp( h1._hash, h2._hash, sizeof(sha224) ) == 0; } - void to_variant( const sha224& bi, variant& v ) - { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); - } - void from_variant( const variant& v, sha224& bi ) - { - std::vector ve = v.as< std::vector >(); - if( ve.size() ) - { - memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); - } - else - memset( &bi, char(0), sizeof(bi) ); + void to_variant( const sha224& bi, variant& v, uint32_t max_depth ) + { + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); + } + void from_variant( const variant& v, sha224& bi, uint32_t max_depth ) + { + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); + if( ve.size() ) + memcpy( &bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } template<> diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index c1b8235..e27fd60 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -148,7 +148,6 @@ namespace fc { } else (*this) = (*this) << (nzbits - 0x18); - return; } double sha256::inverse_approx_log_32_double( uint32_t x ) @@ -194,19 +193,16 @@ namespace fc { return lzbits; } - void to_variant( const sha256& bi, variant& v ) - { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); - } - void from_variant( const variant& v, sha256& bi ) - { - std::vector ve = v.as< std::vector >(); - if( ve.size() ) - { - memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); - } - else - memset( &bi, char(0), sizeof(bi) ); + void to_variant( const sha256& bi, variant& v, uint32_t max_depth ) + { + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); + } + void from_variant( const variant& v, sha256& bi, uint32_t max_depth ) + { + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); + if( ve.size() ) + memcpy( &bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } uint64_t hash64(const char* buf, size_t len) diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp index 7e0315c..49bc8d9 100644 --- a/src/crypto/sha512.cpp +++ b/src/crypto/sha512.cpp @@ -85,19 +85,16 @@ namespace fc { return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; } - void to_variant( const sha512& bi, variant& v ) - { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); - } - void from_variant( const variant& v, sha512& bi ) - { - std::vector ve = v.as< std::vector >(); - if( ve.size() ) - { - memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); - } - else - memset( &bi, char(0), sizeof(bi) ); + void to_variant( const sha512& bi, variant& v, uint32_t max_depth ) + { + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); + } + void from_variant( const variant& v, sha512& bi, uint32_t max_depth ) + { + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); + if( ve.size() ) + memcpy( &bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } template<> diff --git a/src/exception.cpp b/src/exception.cpp index e173be4..1f84286 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -123,19 +123,25 @@ namespace fc exception::~exception(){} - void to_variant( const exception& e, variant& v ) + void to_variant( const exception& e, variant& v, uint32_t max_depth ) { - v = mutable_variant_object( "code", e.code() ) - ( "name", e.name() ) - ( "message", e.what() ) - ( "stack", e.get_log() ); + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + variant v_log; + to_variant( e.get_log(), v_log, max_depth - 1 ); + mutable_variant_object tmp; + tmp( "code", e.code() ) + ( "name", e.name() ) + ( "message", e.what() ) + ( "stack", v_log ); + v = variant( tmp, max_depth ); } - void from_variant( const variant& v, exception& ll ) + void from_variant( const variant& v, exception& ll, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); auto obj = v.get_object(); if( obj.contains( "stack" ) ) - ll.my->_elog = obj["stack"].as(); + ll.my->_elog = obj["stack"].as( max_depth - 1 ); if( obj.contains( "code" ) ) ll.my->_code = obj["code"].as_int64(); if( obj.contains( "name" ) ) @@ -161,7 +167,7 @@ namespace fc ss << variant(my->_code).as_string() <<" " << my->_name << ": " <_what<<"\n"; for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ) { - ss << itr->get_message() <<"\n"; //fc::format_string( itr->get_format(), itr->get_data() ) <<"\n"; + ss << itr->get_message() <<"\n"; try { ss << " " << json::to_string( itr->get_data() )<<"\n"; @@ -188,7 +194,6 @@ namespace fc { if( itr->get_format().size() ) ss << " " << fc::format_string( itr->get_format(), itr->get_data() ); - // ss << " " << itr->get_context().to_string() <<"\n"; } return ss.str(); } @@ -251,6 +256,11 @@ namespace fc return *this; } + void throw_assertion_failure( const std::string& message ) + { + FC_THROW_EXCEPTION( fc::assert_exception, message ); + } + void record_assert_trip( const char* filename, uint32_t lineno, diff --git a/src/filesystem.cpp b/src/filesystem.cpp index a7151c5..fc200bf 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -27,19 +27,15 @@ namespace fc { // when converting to and from a variant, store utf-8 in the variant - void to_variant( const fc::path& path_to_convert, variant& variant_output ) + void to_variant( const fc::path& path_to_convert, variant& variant_output, uint32_t max_depth ) { std::wstring wide_string = path_to_convert.generic_wstring(); std::string utf8_string; fc::encodeUtf8(wide_string, &utf8_string); variant_output = utf8_string; - - //std::string path = t.to_native_ansi_path(); - //std::replace(path.begin(), path.end(), '\\', '/'); - //v = path; } - void from_variant( const fc::variant& variant_to_convert, fc::path& path_output ) + void from_variant( const fc::variant& variant_to_convert, fc::path& path_output, uint32_t max_depth ) { std::wstring wide_string; fc::decodeUtf8(variant_to_convert.as_string(), &wide_string); diff --git a/src/log/console_appender.cpp b/src/log/console_appender.cpp index 9c55ff0..a02147d 100644 --- a/src/log/console_appender.cpp +++ b/src/log/console_appender.cpp @@ -31,7 +31,7 @@ namespace fc { console_appender::console_appender( const variant& args ) :my(new impl) { - configure( args.as() ); + configure( args.as(LOG_MAX_OBJECT_DEPTH) ); } console_appender::console_appender( const config& cfg ) @@ -89,12 +89,9 @@ namespace fc { } void console_appender::log( const log_message& m ) { - //fc::string message = fc::format_string( m.get_format(), m.get_data() ); - //fc::variant lmsg(m); FILE* out = stream::std_error ? stderr : stdout; - //fc::string fmt_str = fc::format_string( cfg.format, mutable_variant_object(m.get_context())( "message", message) ); std::stringstream file_line; file_line << m.get_context().get_file() <<":"<cfg.max_object_depth ); + line << message; fc::unique_lock lock(log_mutex()); diff --git a/src/log/file_appender.cpp b/src/log/file_appender.cpp index 85b69c6..3b21560 100644 --- a/src/log/file_appender.cpp +++ b/src/log/file_appender.cpp @@ -138,7 +138,7 @@ namespace fc { {} file_appender::file_appender( const variant& args ) : - my( new impl( args.as() ) ) + my( new impl( args.as(LOG_MAX_OBJECT_DEPTH) ) ) { try { @@ -180,7 +180,7 @@ namespace fc { } line << "] "; - fc::string message = fc::format_string( m.get_format(), m.get_data() ); + fc::string message = fc::format_string( m.get_format(), m.get_data(), my->cfg.max_object_depth ); line << message.c_str(); //fc::variant lmsg(m); diff --git a/src/log/gelf_appender.cpp b/src/log/gelf_appender.cpp index 2f14d78..187584a 100644 --- a/src/log/gelf_appender.cpp +++ b/src/log/gelf_appender.cpp @@ -38,7 +38,7 @@ namespace fc }; gelf_appender::gelf_appender(const variant& args) : - my(new impl(args.as())) + my(new impl(args.as(LOG_MAX_OBJECT_DEPTH))) { try { @@ -94,7 +94,7 @@ namespace fc mutable_variant_object gelf_message; gelf_message["version"] = "1.1"; gelf_message["host"] = my->cfg.host; - gelf_message["short_message"] = format_string(message.get_format(), message.get_data()); + gelf_message["short_message"] = format_string( message.get_format(), message.get_data(), my->cfg.max_object_depth ); gelf_message["timestamp"] = context.get_timestamp().time_since_epoch().count() / 1000000.; diff --git a/src/log/log_message.cpp b/src/log/log_message.cpp index 09b6815..cf8d27a 100644 --- a/src/log/log_message.cpp +++ b/src/log/log_message.cpp @@ -58,11 +58,11 @@ namespace fc my->task_name = current_task_desc ? current_task_desc : "?unnamed?"; } - log_context::log_context( const variant& v ) + log_context::log_context( const variant& v, uint32_t max_depth ) :my( std::make_shared() ) { auto obj = v.get_object(); - my->level = obj["level"].as(); + my->level = obj["level"].as(max_depth); my->file = obj["file"].as_string(); my->line = obj["line"].as_uint64(); my->method = obj["method"].as_string(); @@ -70,9 +70,9 @@ namespace fc my->thread_name = obj["thread_name"].as_string(); if (obj.contains("task_name")) my->task_name = obj["task_name"].as_string(); - my->timestamp = obj["timestamp"].as(); + my->timestamp = obj["timestamp"].as(max_depth); if( obj.contains( "context" ) ) - my->context = obj["context"].as(); + my->context = obj["context"].as(max_depth); } fc::string log_context::to_string()const @@ -91,26 +91,26 @@ namespace fc log_context::~log_context(){} - void to_variant( const log_context& l, variant& v ) + void to_variant( const log_context& l, variant& v, uint32_t max_depth ) { - v = l.to_variant(); + v = l.to_variant(max_depth); } - void from_variant( const variant& l, log_context& c ) + void from_variant( const variant& l, log_context& c, uint32_t max_depth ) { - c = log_context(l); + c = log_context(l, max_depth); } - void from_variant( const variant& l, log_message& c ) + void from_variant( const variant& l, log_message& c, uint32_t max_depth ) { - c = log_message(l); + c = log_message(l, max_depth); } - void to_variant( const log_message& m, variant& v ) + void to_variant( const log_message& m, variant& v, uint32_t max_depth ) { - v = m.to_variant(); + v = m.to_variant( max_depth ); } - void to_variant( log_level e, variant& v ) + void to_variant( log_level e, variant& v, uint32_t max_depth ) { switch( e ) { @@ -134,7 +134,7 @@ namespace fc return; } } - void from_variant( const variant& v, log_level& e ) + void from_variant( const variant& v, log_level& e, uint32_t max_depth ) { try { @@ -163,16 +163,16 @@ namespace fc string log_context::get_context()const { return my->context; } - variant log_context::to_variant()const + variant log_context::to_variant(uint32_t max_depth)const { mutable_variant_object o; - o( "level", variant(my->level) ) + o( "level", variant(my->level, max_depth) ) ( "file", my->file ) ( "line", my->line ) ( "method", my->method ) ( "hostname", my->hostname ) ( "thread_name", my->thread_name ) - ( "timestamp", variant(my->timestamp) ); + ( "timestamp", variant(my->timestamp, max_depth) ); if( my->context.size() ) o( "context", my->context ); @@ -191,22 +191,23 @@ namespace fc my->args = std::move(args); } - log_message::log_message( const variant& v ) - :my( std::make_shared( log_context( v.get_object()["context"] ) ) ) + log_message::log_message( const variant& v, uint32_t max_depth ) + :my( std::make_shared( log_context( v.get_object()["context"], max_depth ) ) ) { my->format = v.get_object()["format"].as_string(); my->args = v.get_object()["data"].get_object(); } - variant log_message::to_variant()const + variant log_message::to_variant(uint32_t max_depth)const { - return mutable_variant_object( "context", my->context ) + return limited_mutable_variant_object(max_depth) + ( "context", my->context ) ( "format", my->format ) ( "data", my->args ); } - log_context log_message::get_context()const { return my->context; } - string log_message::get_format()const { return my->format; } + log_context log_message::get_context()const { return my->context; } + string log_message::get_format()const { return my->format; } variant_object log_message::get_data()const { return my->args; } string log_message::get_message()const diff --git a/src/log/logger_config.cpp b/src/log/logger_config.cpp index 92dde24..3e35c28 100644 --- a/src/log/logger_config.cpp +++ b/src/log/logger_config.cpp @@ -27,7 +27,6 @@ namespace fc { get_logger_map().clear(); get_appender_map().clear(); - //slog( "\n%s", fc::json::to_pretty_string(cfg).c_str() ); for( size_t i = 0; i < cfg.appenders.size(); ++i ) { appender::create( cfg.appenders[i].name, cfg.appenders[i].type, cfg.appenders[i].args ); // TODO... process enabled diff --git a/src/rpc/http_api.cpp b/src/rpc/http_api.cpp index c9571a2..b8a299a 100644 --- a/src/rpc/http_api.cpp +++ b/src/rpc/http_api.cpp @@ -7,7 +7,8 @@ http_api_connection::~http_api_connection() { } -http_api_connection::http_api_connection() +http_api_connection::http_api_connection(uint32_t max_depth) +:api_connection(max_depth) { _rpc_state.add_method( "call", [this]( const variants& args ) -> variant { @@ -88,25 +89,27 @@ void http_api_connection::on_request( const fc::http::request& req, const fc::ht { resp.add_header( "Content-Type", "application/json" ); std::string req_body( req.body.begin(), req.body.end() ); - auto var = fc::json::from_string( req_body ); + auto var = fc::json::from_string( req_body, fc::json::legacy_parser, _max_conversion_depth ); const auto& var_obj = var.get_object(); if( var_obj.contains( "method" ) ) { - auto call = var.as(); + auto call = var.as(_max_conversion_depth); try { try { - auto result = _rpc_state.local_call( call.method, call.params ); - resp_body = fc::json::to_string( fc::rpc::response( *call.id, result ) ); + fc::variant result( _rpc_state.local_call( call.method, call.params ), _max_conversion_depth ); + resp_body = fc::json::to_string( fc::variant( fc::rpc::response( *call.id, result ), _max_conversion_depth), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); resp_status = http::reply::OK; } FC_CAPTURE_AND_RETHROW( (call.method)(call.params) ); } catch ( const fc::exception& e ) { - resp_body = fc::json::to_string( fc::rpc::response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e)} ) ); + resp_body = fc::json::to_string( fc::variant( fc::rpc::response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e, _max_conversion_depth)} ), _max_conversion_depth), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); resp_status = http::reply::InternalServerError; } } diff --git a/src/rpc/json_connection.cpp b/src/rpc/json_connection.cpp index bde046a..fd19f27 100644 --- a/src/rpc/json_connection.cpp +++ b/src/rpc/json_connection.cpp @@ -14,8 +14,8 @@ namespace fc { namespace rpc { class json_connection_impl { public: - json_connection_impl( fc::buffered_istream_ptr&& in, fc::buffered_ostream_ptr&& out ) - :_in(fc::move(in)),_out(fc::move(out)),_eof(false),_next_id(0),_logger("json_connection"){} + json_connection_impl( fc::buffered_istream_ptr&& in, fc::buffered_ostream_ptr&& out, uint32_t max_depth ) + :_in(fc::move(in)),_out(fc::move(out)),_eof(false),_next_id(0),_logger("json_connection"),_max_depth(max_depth){} fc::buffered_istream_ptr _in; fc::buffered_ostream_ptr _out; @@ -33,6 +33,7 @@ namespace fc { namespace rpc { std::function _on_close; logger _logger; + uint32_t _max_depth; void send_result( variant id, variant result ) { @@ -40,9 +41,9 @@ namespace fc { namespace rpc { { fc::scoped_lock lock(_write_mutex); *_out << "{\"id\":"; - json::to_stream( *_out, id ); + json::to_stream( *_out, id, json::stringify_large_ints_and_doubles, _max_depth ); *_out << ",\"result\":"; - json::to_stream( *_out, result); + json::to_stream( *_out, result, json::stringify_large_ints_and_doubles, _max_depth ); *_out << "}\n"; _out->flush(); } @@ -54,11 +55,11 @@ namespace fc { namespace rpc { { fc::scoped_lock lock(_write_mutex); *_out << "{\"id\":"; - json::to_stream( *_out, id ); + json::to_stream( *_out, id, json::stringify_large_ints_and_doubles, _max_depth ); *_out << ",\"error\":{\"message\":"; json::to_stream( *_out, fc::string(e.what()) ); *_out <<",\"code\":0,\"data\":"; - json::to_stream( *_out, variant(e)); + json::to_stream( *_out, variant(e, _max_depth), json::stringify_large_ints_and_doubles, _max_depth ); *_out << "}}\n"; _out->flush(); } @@ -165,10 +166,7 @@ namespace fc { namespace rpc { auto err = e->value().get_object(); auto data = err.find( "data" ); if( data != err.end() ) - { - //wlog( "exception: ${except}", ("except", data->value() ) ); - await->second->set_exception( data->value().as().dynamic_copy_exception() ); - } + await->second->set_exception( data->value().as(_max_depth).dynamic_copy_exception() ); else await->second->set_exception( exception_ptr(new FC_EXCEPTION( exception, "${error}", ("error",e->value()) ) ) ); } @@ -207,7 +205,7 @@ namespace fc { namespace rpc { fc::string line; while( !_done.canceled() ) { - variant v = json::from_stream(*_in); + variant v = json::from_stream( *_in, json::legacy_parser, _max_depth ); ///ilog( "input: ${in}", ("in", v ) ); //wlog( "recv: ${line}", ("line", line) ); _handle_message_future = fc::async([=](){ handle_message(v.get_object()); }, "json_connection handle_message"); @@ -242,8 +240,8 @@ namespace fc { namespace rpc { }; }//namespace detail - json_connection::json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out ) - :my( new detail::json_connection_impl(fc::move(in),fc::move(out)) ) + json_connection::json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out, uint32_t max_depth ) + :_max_conversion_depth(max_depth),my( new detail::json_connection_impl(fc::move(in),fc::move(out),max_depth) ) {} json_connection::~json_connection() diff --git a/src/rpc/websocket_api.cpp b/src/rpc/websocket_api.cpp index 8c60614..ae4e26e 100644 --- a/src/rpc/websocket_api.cpp +++ b/src/rpc/websocket_api.cpp @@ -7,8 +7,8 @@ websocket_api_connection::~websocket_api_connection() { } -websocket_api_connection::websocket_api_connection( fc::http::websocket_connection& c ) - : _connection(c) +websocket_api_connection::websocket_api_connection( fc::http::websocket_connection& c, uint32_t max_depth ) + : api_connection(max_depth),_connection(c) { _rpc_state.add_method( "call", [this]( const variants& args ) -> variant { @@ -58,7 +58,8 @@ variant websocket_api_connection::send_call( variants args /* = variants() */ ) { auto request = _rpc_state.start_remote_call( "call", {api_id, std::move(method_name), std::move(args) } ); - _connection.send_message( fc::json::to_string(request) ); + _connection.send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); return _rpc_state.wait_for_response( *request.id ); } @@ -67,7 +68,8 @@ variant websocket_api_connection::send_callback( variants args /* = variants() */ ) { auto request = _rpc_state.start_remote_call( "callback", {callback_id, std::move(args) } ); - _connection.send_message( fc::json::to_string(request) ); + _connection.send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); return _rpc_state.wait_for_response( *request.id ); } @@ -76,7 +78,8 @@ void websocket_api_connection::send_notice( variants args /* = variants() */ ) { fc::rpc::request req{ optional(), "notice", {callback_id, std::move(args)}}; - _connection.send_message( fc::json::to_string(req) ); + _connection.send_message( fc::json::to_string(fc::variant(req, _max_conversion_depth), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); } std::string websocket_api_connection::on_message( @@ -85,12 +88,12 @@ std::string websocket_api_connection::on_message( { try { - auto var = fc::json::from_string(message); + auto var = fc::json::from_string(message, fc::json::legacy_parser, _max_conversion_depth); const auto& var_obj = var.get_object(); if( var_obj.contains( "method" ) ) { - auto call = var.as(); + auto call = var.as(_max_conversion_depth); exception_ptr optexcept; try { @@ -113,7 +116,7 @@ std::string websocket_api_connection::on_message( if( call.id ) { - auto reply = fc::json::to_string( response( *call.id, result, "2.0" ) ); + auto reply = fc::json::to_string( response( *call.id, result, "2.0" ), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); if( send_message ) _connection.send_message( reply ); return reply; @@ -130,7 +133,8 @@ std::string websocket_api_connection::on_message( } if( optexcept ) { - auto reply = fc::json::to_string( response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept)}, "2.0" ) ); + auto reply = fc::json::to_string( variant(response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept, _max_conversion_depth)}, "2.0" ), _max_conversion_depth ), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); if( send_message ) _connection.send_message( reply ); @@ -139,7 +143,7 @@ std::string websocket_api_connection::on_message( } else { - auto reply = var.as(); + auto reply = var.as(_max_conversion_depth); _rpc_state.handle_reply( reply ); } } diff --git a/src/string.cpp b/src/string.cpp index e04f439..2432360 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -258,7 +258,7 @@ namespace fc { } } - string format_string( const string& format, const variant_object& args ) + string format_string( const string& format, const variant_object& args, uint32_t max_object_depth ) { stringstream ss; size_t prev = 0; @@ -291,7 +291,7 @@ namespace fc { { try { - ss << json::to_string( val->value() ); + ss << json::to_string( val->value(), json::stringify_large_ints_and_doubles, max_object_depth ); } catch( const fc::assert_exception& e ) { diff --git a/src/time.cpp b/src/time.cpp index 27dd848..bf8857f 100644 --- a/src/time.cpp +++ b/src/time.cpp @@ -54,16 +54,16 @@ namespace fc { return time_point( time_point_sec::from_iso_string( s ) ); } FC_RETHROW_EXCEPTIONS( warn, "unable to convert ISO-formatted string to fc::time_point" ) } - void to_variant( const fc::time_point& t, variant& v ) { - v = fc::string( t ); + void to_variant( const fc::time_point& t, variant& v, uint32_t max_depth ) { + to_variant( fc::string( t ), v, max_depth ); } - void from_variant( const fc::variant& v, fc::time_point& t ) { + void from_variant( const fc::variant& v, fc::time_point& t, uint32_t max_depth ) { t = fc::time_point::from_iso_string( v.as_string() ); } - void to_variant( const fc::time_point_sec& t, variant& v ) { - v = fc::string( t ); + void to_variant( const fc::time_point_sec& t, variant& v, uint32_t max_depth ) { + to_variant( fc::string( t ), v, max_depth ); } - void from_variant( const fc::variant& v, fc::time_point_sec& t ) { + void from_variant( const fc::variant& v, fc::time_point_sec& t, uint32_t max_depth ) { t = fc::time_point_sec::from_iso_string( v.as_string() ); } @@ -134,11 +134,11 @@ namespace fc { return get_approximate_relative_time_string(time_point_sec(event_time), time_point_sec(relative_to_time), ago); } - void to_variant( const microseconds& input_microseconds, variant& output_variant ) + void to_variant( const microseconds& input_microseconds, variant& output_variant, uint32_t max_depth ) { output_variant = input_microseconds.count(); } - void from_variant( const variant& input_variant, microseconds& output_microseconds ) + void from_variant( const variant& input_variant, microseconds& output_microseconds, uint32_t max_depth ) { output_microseconds = microseconds(input_variant.as_int64()); } diff --git a/src/variant.cpp b/src/variant.cpp index 5d9416a..c8e0493 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -27,140 +27,139 @@ variant::variant() set_variant_type( this, null_type ); } -variant::variant( fc::nullptr_t ) +variant::variant( fc::nullptr_t, uint32_t max_depth ) { set_variant_type( this, null_type ); } -variant::variant( uint8_t val ) +variant::variant( uint8_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } -variant::variant( int8_t val ) +variant::variant( int8_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } -variant::variant( uint16_t val ) +variant::variant( uint16_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } -variant::variant( int16_t val ) +variant::variant( int16_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } -variant::variant( uint32_t val ) +variant::variant( uint32_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } -variant::variant( int32_t val ) +variant::variant( int32_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } -variant::variant( uint64_t val ) +variant::variant( uint64_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } -variant::variant( int64_t val ) +variant::variant( int64_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } -variant::variant( float val ) +variant::variant( float val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, double_type ); } -variant::variant( double val ) +variant::variant( double val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, double_type ); } -variant::variant( bool val ) +variant::variant( bool val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, bool_type ); } -variant::variant( char* str ) +variant::variant( char* str, uint32_t max_depth ) { *reinterpret_cast(this) = new string( str ); set_variant_type( this, string_type ); } -variant::variant( const char* str ) +variant::variant( const char* str, uint32_t max_depth ) { *reinterpret_cast(this) = new string( str ); set_variant_type( this, string_type ); } // TODO: do a proper conversion to utf8 -variant::variant( wchar_t* str ) +variant::variant( wchar_t* str, uint32_t max_depth ) { size_t len = wcslen(str); boost::scoped_array buffer(new char[len]); for (unsigned i = 0; i < len; ++i) - buffer[i] = (char)str[i]; + buffer[i] = (char)str[i]; *reinterpret_cast(this) = new string(buffer.get(), len); set_variant_type( this, string_type ); } // TODO: do a proper conversion to utf8 -variant::variant( const wchar_t* str ) +variant::variant( const wchar_t* str, uint32_t max_depth ) { size_t len = wcslen(str); boost::scoped_array buffer(new char[len]); for (unsigned i = 0; i < len; ++i) - buffer[i] = (char)str[i]; + buffer[i] = (char)str[i]; *reinterpret_cast(this) = new string(buffer.get(), len); set_variant_type( this, string_type ); } -variant::variant( fc::string val ) +variant::variant( fc::string val, uint32_t max_depth ) { *reinterpret_cast(this) = new string( fc::move(val) ); set_variant_type( this, string_type ); } -variant::variant( blob val ) +variant::variant( blob val, uint32_t max_depth ) { *reinterpret_cast(this) = new blob( fc::move(val) ); set_variant_type( this, blob_type ); } -variant::variant( variant_object obj) +variant::variant( variant_object obj, uint32_t max_depth ) { - *reinterpret_cast(this) = new variant_object(fc::move(obj)); + *reinterpret_cast(this) = new variant_object(fc::move(obj)); set_variant_type(this, object_type ); } -variant::variant( mutable_variant_object obj) +variant::variant( mutable_variant_object obj, uint32_t max_depth ) { - *reinterpret_cast(this) = new variant_object(fc::move(obj)); + *reinterpret_cast(this) = new variant_object(fc::move(obj)); set_variant_type(this, object_type ); } -variant::variant( variants arr ) +variant::variant( variants arr, uint32_t max_depth ) { *reinterpret_cast(this) = new variants(fc::move(arr)); set_variant_type(this, array_type ); } - typedef const variant_object* const_variant_object_ptr; typedef const variants* const_variants_ptr; typedef const blob* const_blob_ptr; @@ -185,7 +184,7 @@ void variant::clear() set_variant_type( this, null_type ); } -variant::variant( const variant& v ) +variant::variant( const variant& v, uint32_t max_depth ) { switch( v.get_type() ) { @@ -209,7 +208,7 @@ variant::variant( const variant& v ) } } -variant::variant( variant&& v ) +variant::variant( variant&& v, uint32_t max_depth ) { memcpy( this, &v, sizeof(v) ); set_variant_type( &v, null_type ); @@ -575,7 +574,7 @@ const variant_object& variant::get_object()const FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from type '${type}' to Object", ("type",get_type()) ); } -void from_variant( const variant& var, variants& vo ) +void from_variant( const variant& var, variants& vo, uint32_t max_depth ) { vo = var.get_array(); } @@ -585,78 +584,78 @@ void from_variant( const variant& var, variants& vo ) // vo = var.get_object(); //} -void from_variant( const variant& var, variant& vo ) { vo = var; } +void from_variant( const variant& var, variant& vo, uint32_t max_depth ) { vo = var; } -void to_variant( const uint8_t& var, variant& vo ) { vo = uint64_t(var); } +void to_variant( const uint8_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); } // TODO: warn on overflow? -void from_variant( const variant& var, uint8_t& vo ){ vo = static_cast(var.as_uint64()); } +void from_variant( const variant& var, uint8_t& vo, uint32_t max_depth ){ vo = static_cast(var.as_uint64()); } -void to_variant( const int8_t& var, variant& vo ) { vo = int64_t(var); } +void to_variant( const int8_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); } // TODO: warn on overflow? -void from_variant( const variant& var, int8_t& vo ){ vo = static_cast(var.as_int64()); } +void from_variant( const variant& var, int8_t& vo, uint32_t max_depth ) { vo = static_cast(var.as_int64()); } -void to_variant( const uint16_t& var, variant& vo ) { vo = uint64_t(var); } +void to_variant( const uint16_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); } // TODO: warn on overflow? -void from_variant( const variant& var, uint16_t& vo ){ vo = static_cast(var.as_uint64()); } +void from_variant( const variant& var, uint16_t& vo, uint32_t max_depth ){ vo = static_cast(var.as_uint64()); } -void to_variant( const int16_t& var, variant& vo ) { vo = int64_t(var); } +void to_variant( const int16_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); } // TODO: warn on overflow? -void from_variant( const variant& var, int16_t& vo ){ vo = static_cast(var.as_int64()); } +void from_variant( const variant& var, int16_t& vo, uint32_t max_depth ){ vo = static_cast(var.as_int64()); } -void to_variant( const uint32_t& var, variant& vo ) { vo = uint64_t(var); } -void from_variant( const variant& var, uint32_t& vo ) +void to_variant( const uint32_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); } +void from_variant( const variant& var, uint32_t& vo, uint32_t max_depth ) { vo = static_cast(var.as_uint64()); } -void to_variant( const int32_t& var, variant& vo ) { vo = int64_t(var); } -void from_variant( const variant& var, int32_t& vo ) +void to_variant( const int32_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); } +void from_variant( const variant& var,int32_t& vo, uint32_t max_depth ) { vo = static_cast(var.as_int64()); } -void from_variant( const variant& var, int64_t& vo ) +void from_variant( const variant& var, int64_t& vo, uint32_t max_depth ) { vo = var.as_int64(); } -void from_variant( const variant& var, uint64_t& vo ) +void from_variant( const variant& var, uint64_t& vo, uint32_t max_depth ) { vo = var.as_uint64(); } -void from_variant( const variant& var, bool& vo ) +void from_variant( const variant& var, bool& vo, uint32_t max_depth ) { vo = var.as_bool(); } -void from_variant( const variant& var, double& vo ) +void from_variant( const variant& var, double& vo, uint32_t max_depth ) { vo = var.as_double(); } -void from_variant( const variant& var, float& vo ) +void from_variant( const variant& var, float& vo, uint32_t max_depth ) { vo = static_cast(var.as_double()); } -void to_variant( const std::string& s, variant& v ) +void to_variant( const std::string& s, variant& v, uint32_t max_depth ) { - v = variant( fc::string(s) ); + v = variant( fc::string(s), max_depth ); } -void from_variant( const variant& var, string& vo ) +void from_variant( const variant& var, string& vo, uint32_t max_depth ) { vo = var.as_string(); } -void to_variant( const std::vector& var, variant& vo ) +void to_variant( const std::vector& var, variant& vo, uint32_t max_depth ) { if( var.size() ) vo = variant(to_hex(var.data(),var.size())); else vo = ""; } -void from_variant( const variant& var, std::vector& vo ) +void from_variant( const variant& var, std::vector& vo, uint32_t max_depth ) { auto str = var.as_string(); vo.resize( str.size() / 2 ); @@ -665,15 +664,13 @@ void from_variant( const variant& var, std::vector& vo ) size_t r = from_hex( str, vo.data(), vo.size() ); FC_ASSERT( r == vo.size() ); } -// std::string b64 = base64_decode( var.as_string() ); -// vo = std::vector( b64.c_str(), b64.c_str() + b64.size() ); } - #ifdef __APPLE__ - #elif !defined(_MSC_VER) - void to_variant( long long int s, variant& v ) { v = variant( int64_t(s) ); } - void to_variant( unsigned long long int s, variant& v ) { v = variant( uint64_t(s)); } - #endif +#ifdef __APPLE__ +#elif !defined(_MSC_VER) + void to_variant( long long int s, variant& v, uint32_t max_depth ) { v = variant( int64_t(s) ); } + void to_variant( unsigned long long int s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s)); } +#endif variant operator == ( const variant& a, const variant& b ) { diff --git a/src/variant_object.cpp b/src/variant_object.cpp index 6f3b1dc..95b3118 100644 --- a/src/variant_object.cpp +++ b/src/variant_object.cpp @@ -163,12 +163,12 @@ namespace fc return *this; } - void to_variant( const variant_object& var, variant& vo ) + void to_variant( const variant_object& var, variant& vo, uint32_t max_depth ) { vo = variant(var); } - void from_variant( const variant& var, variant_object& vo ) + void from_variant( const variant& var, variant_object& vo, uint32_t max_depth ) { vo = var.get_object(); } @@ -344,7 +344,7 @@ namespace fc /** Appends \a key and \a var without checking for duplicates, designed to * simplify construction of dictionaries using (key,val)(key2,val2) syntax */ - mutable_variant_object& mutable_variant_object::operator()( string key, variant var ) + mutable_variant_object& mutable_variant_object::operator()( string key, variant var, uint32_t max_depth ) { _key_value->push_back( entry( fc::move(key), fc::move(var) ) ); return *this; @@ -366,6 +366,9 @@ namespace fc return *this; } + limited_mutable_variant_object::limited_mutable_variant_object( uint32_t m ) + : mutable_variant_object(), _max_depth(m) {} + void to_variant( const mutable_variant_object& var, variant& vo ) { vo = variant(var); diff --git a/tests/crypto/sha_tests.cpp b/tests/crypto/sha_tests.cpp index 104f0c2..9a5665c 100644 --- a/tests/crypto/sha_tests.cpp +++ b/tests/crypto/sha_tests.cpp @@ -65,8 +65,8 @@ void test_big( const std::string& expected ) { H hash2( expected ); fc::variant v; - to_variant( hash2, v ); - from_variant( v, hash ); + to_variant( hash2, v, 5 ); + from_variant( v, hash, 5 ); BOOST_CHECK( hash == hash2 ); H hash3( expected.substr(15) + "000000000000000" ); diff --git a/tests/io/json_tests.cpp b/tests/io/json_tests.cpp index 42af936..e06f51b 100644 --- a/tests/io/json_tests.cpp +++ b/tests/io/json_tests.cpp @@ -128,9 +128,9 @@ static bool equal( const fc::variant& a, const fc::variant& b ) { auto a_type = a.get_type(); auto b_type = b.get_type(); - if( a_type == fc::variant::type_id::int64_type && a.as() > 0 ) + if( a_type == fc::variant::type_id::int64_type && a.as(1) > 0 ) a_type = fc::variant::type_id::uint64_type; - if( b_type == fc::variant::type_id::int64_type && b.as() > 0 ) + if( b_type == fc::variant::type_id::int64_type && b.as(1) > 0 ) b_type = fc::variant::type_id::uint64_type; if( a_type != b_type ) { @@ -138,17 +138,17 @@ static bool equal( const fc::variant& a, const fc::variant& b ) && b_type == fc::variant::type_id::string_type ) || ( a_type == fc::variant::type_id::string_type && b_type == fc::variant::type_id::double_type ) ) - return a.as() == b.as(); + return a.as(1) == b.as(1); return false; } switch( a_type ) { case fc::variant::type_id::null_type: return true; - case fc::variant::type_id::int64_type: return a.as() == b.as(); - case fc::variant::type_id::uint64_type: return a.as() == b.as(); - case fc::variant::type_id::double_type: return a.as() == b.as(); - case fc::variant::type_id::bool_type: return a.as() == b.as(); - case fc::variant::type_id::string_type: return a.as() == b.as(); + case fc::variant::type_id::int64_type: return a.as(1) == b.as(1); + case fc::variant::type_id::uint64_type: return a.as(1) == b.as(1); + case fc::variant::type_id::double_type: return a.as(1) == b.as(1); + case fc::variant::type_id::bool_type: return a.as(1) == b.as(1); + case fc::variant::type_id::string_type: return a.as(1) == b.as(1); case fc::variant::type_id::array_type: if( a.get_array().size() != b.get_array().size() ) return false; else @@ -311,8 +311,8 @@ BOOST_AUTO_TEST_CASE(structured_test) BOOST_AUTO_TEST_CASE(precision_test) { - BOOST_CHECK_EQUAL( "\"4294967296\"", fc::json::to_string( fc::variant( 0x100000000LL ) ) ); - BOOST_CHECK_EQUAL( "\"-4294967296\"", fc::json::to_string( fc::variant( -0x100000000LL ) ) ); + BOOST_CHECK_EQUAL( "\"4294967296\"", fc::json::to_string( fc::variant( int64_t(0x100000000LL) ) ) ); + BOOST_CHECK_EQUAL( "\"-4294967296\"", fc::json::to_string( fc::variant( int64_t(-0x100000000LL) ) ) ); std::string half = fc::json::to_string( fc::variant( 0.5 ) ); BOOST_CHECK_EQUAL( '"', half.front() ); BOOST_CHECK_EQUAL( '"', half.back() ); diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp index 83fcba9..deb6bbe 100644 --- a/tests/network/http/websocket_test.cpp +++ b/tests/network/http/websocket_test.cpp @@ -64,6 +64,10 @@ BOOST_AUTO_TEST_CASE(websocket_test) BOOST_FAIL("expected assertion failure"); } catch (const fc::exception& e) { std::cerr << e.to_string() << "\n"; + } catch (const fc::exception& e) { + BOOST_FAIL("Unexpected exception: " + e.to_string()); + } catch (const std::exception& e) { + BOOST_FAIL("Unexpected exception: " + std::string(e.what())); } }