From 394f9bd0d445a7d0ea02dc60caf8626aae0575a1 Mon Sep 17 00:00:00 2001 From: An Tao Date: Wed, 1 Mar 2023 10:49:25 +0800 Subject: [PATCH] Add the stackLimit option for jsoncpp (#1518) --- .gitignore | 1 + config.example.json | 2 ++ drogon_ctl/templates/config.csp | 2 ++ lib/inc/drogon/HttpAppFramework.h | 17 ++++++++++++++++- lib/src/ConfigLoader.cc | 2 ++ lib/src/HttpAppFrameworkImpl.h | 12 ++++++++++++ lib/src/HttpRequestImpl.cc | 6 +++++- lib/src/HttpResponseImpl.cc | 6 +++++- 8 files changed, 45 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 6e1ca8b5..6f29d6bf 100755 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ build/ cmake-build-debug/ +cmake-build-debug-visual-studio/ .idea/ lib/inc/drogon/version.h html/ diff --git a/config.example.json b/config.example.json index 75770051..8c98b3da 100644 --- a/config.example.json +++ b/config.example.json @@ -193,6 +193,8 @@ //files is the path where the csp files locate. If the path isn't prefixed with /, it is relative //path of the current working directory. "dynamic_views_output_path": "", + //json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library. + "json_parser_stack_limit": 1000, //enable_unicode_escaping_in_json: true by default, enable unicode escaping in json. "enable_unicode_escaping_in_json": true, //float_precision_in_json: set precision of float number in json. diff --git a/drogon_ctl/templates/config.csp b/drogon_ctl/templates/config.csp index 655c099f..b5429950 100644 --- a/drogon_ctl/templates/config.csp +++ b/drogon_ctl/templates/config.csp @@ -193,6 +193,8 @@ //files is the path where the csp files locate. If the path isn't prefixed with /, it is relative //path of the current working directory. "dynamic_views_output_path": "", + //json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library. + "json_parser_stack_limit": 1000, //enable_unicode_escaping_in_json: true by default, enable unicode escaping in json. "enable_unicode_escaping_in_json": true, //float_precision_in_json: set precision of float number in json. diff --git a/lib/inc/drogon/HttpAppFramework.h b/lib/inc/drogon/HttpAppFramework.h index 499415e9..72c624f9 100644 --- a/lib/inc/drogon/HttpAppFramework.h +++ b/lib/inc/drogon/HttpAppFramework.h @@ -1193,7 +1193,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable /// Set the HTML file that a directory would resolve to by default, default /// is "index.html" /** - * @brief Sets the page which would the server load in if it detects that + * @brief Set the page which would the server load in if it detects that * the user requested a directory * * @note @@ -1247,6 +1247,21 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable virtual nosql::RedisClientPtr getFastRedisClient( const std::string &name = "default") = 0; + /** + * @brief Set the maximum stack depth of the json parser when reading a json + * string, the default value is 1000. + * + * @note + * This operation can be performed by an option in the configuration file. + */ + virtual HttpAppFramework &setJsonParserStackLimit( + size_t limit) noexcept = 0; + + /** + * @brief Get the maximum stack depth of the json parser when reading a json + * string. + */ + virtual size_t getJsonParserStackLimit() const noexcept = 0; /** * @brief This method is to enable or disable the unicode escaping (\u) in * the json string of HTTP responses or requests. it works (disable diff --git a/lib/src/ConfigLoader.cc b/lib/src/ConfigLoader.cc index b15f2aba..d21d9dd0 100644 --- a/lib/src/ConfigLoader.cc +++ b/lib/src/ConfigLoader.cc @@ -378,6 +378,8 @@ static void loadApp(const Json::Value &app) } } #endif + auto stackLimit = app.get("json_parser_stack_limit", 0).asUInt64(); + drogon::app().setJsonParserStackLimit(stackLimit); auto unicodeEscaping = app.get("enable_unicode_escaping_in_json", true).asBool(); drogon::app().setUnicodeEscapingInJson(unicodeEscaping); diff --git a/lib/src/HttpAppFrameworkImpl.h b/lib/src/HttpAppFrameworkImpl.h index e80a7caa..4e57b05d 100644 --- a/lib/src/HttpAppFrameworkImpl.h +++ b/lib/src/HttpAppFrameworkImpl.h @@ -431,6 +431,17 @@ class HttpAppFrameworkImpl final : public HttpAppFramework return running_; } + HttpAppFramework &setJsonParserStackLimit(size_t limit) noexcept override + { + jsonStackLimit_ = limit; + return *this; + } + + size_t getJsonParserStackLimit() const noexcept override + { + return jsonStackLimit_; + } + HttpAppFramework &setUnicodeEscapingInJson(bool enable) noexcept override { usingUnicodeEscaping_ = enable; @@ -666,6 +677,7 @@ class HttpAppFrameworkImpl final : public HttpAppFramework size_t logfileSize_{100000000}; size_t keepaliveRequestsNumber_{0}; size_t pipeliningRequestsNumber_{0}; + size_t jsonStackLimit_{1000}; bool useSendfile_{true}; bool useGzip_{true}; bool useBrotli_{false}; diff --git a/lib/src/HttpRequestImpl.cc b/lib/src/HttpRequestImpl.cc index b9f88e7c..3c4394bd 100644 --- a/lib/src/HttpRequestImpl.cc +++ b/lib/src/HttpRequestImpl.cc @@ -40,7 +40,11 @@ void HttpRequestImpl::parseJson() const { static std::once_flag once; static Json::CharReaderBuilder builder; - std::call_once(once, []() { builder["collectComments"] = false; }); + std::call_once(once, []() { + builder["collectComments"] = false; + builder["stackLimit"] = static_cast( + drogon::app().getJsonParserStackLimit()); + }); jsonPtr_ = std::make_shared(); JSONCPP_STRING errs; std::unique_ptr reader(builder.newCharReader()); diff --git a/lib/src/HttpResponseImpl.cc b/lib/src/HttpResponseImpl.cc index 76e5642e..8e1e7853 100644 --- a/lib/src/HttpResponseImpl.cc +++ b/lib/src/HttpResponseImpl.cc @@ -897,7 +897,11 @@ void HttpResponseImpl::parseJson() const { static std::once_flag once; static Json::CharReaderBuilder builder; - std::call_once(once, []() { builder["collectComments"] = false; }); + std::call_once(once, []() { + builder["collectComments"] = false; + builder["stackLimit"] = + static_cast(drogon::app().getJsonParserStackLimit()); + }); JSONCPP_STRING errs; std::unique_ptr reader(builder.newCharReader()); if (bodyPtr_)