2121
2222#include < chrono>
2323#include < cstdint>
24+ #include < memory>
2425#include < string>
2526
2627#include " src/request_body_processor/json_adapter.h"
@@ -34,10 +35,44 @@ static const char* json_depth_limit_exceeded_msg = ". Parsing depth limit exceed
3435
3536namespace {
3637
37- JsonSinkStatus startContainer (std::deque<JSONContainer *> *containers,
38- JSONContainer *container, int64_t *current_depth, double max_depth,
39- bool *depth_limit_exceeded) {
40- containers->push_back (container);
38+ void assignJsonErrorMessage (std::string *err, JsonParseStatus parse_status,
39+ const std::string &detail) {
40+ if (err == nullptr ) {
41+ return ;
42+ }
43+
44+ if (!detail.empty ()) {
45+ err->assign (detail);
46+ return ;
47+ }
48+
49+ switch (parse_status) {
50+ case JsonParseStatus::ParseError:
51+ err->assign (" Invalid JSON body." );
52+ break ;
53+ case JsonParseStatus::TruncatedInput:
54+ err->assign (" Incomplete JSON body." );
55+ break ;
56+ case JsonParseStatus::Utf8Error:
57+ err->assign (" Invalid UTF-8 in JSON body." );
58+ break ;
59+ case JsonParseStatus::EngineAbort:
60+ err->assign (" JSON traversal aborted by ModSecurity." );
61+ break ;
62+ case JsonParseStatus::InternalError:
63+ err->assign (" Internal JSON backend failure." );
64+ break ;
65+ case JsonParseStatus::Ok:
66+ err->clear ();
67+ break ;
68+ }
69+ }
70+
71+ JsonSinkStatus startContainer (
72+ std::deque<std::unique_ptr<JSONContainer>> *containers,
73+ std::unique_ptr<JSONContainer> container, int64_t *current_depth,
74+ double max_depth, bool *depth_limit_exceeded) {
75+ containers->push_back (std::move (container));
4176 (*current_depth)++;
4277 if (*current_depth > max_depth) {
4378 *depth_limit_exceeded = true ;
@@ -46,18 +81,17 @@ JsonSinkStatus startContainer(std::deque<JSONContainer *> *containers,
4681 return JsonSinkStatus::Continue;
4782}
4883
49- JsonSinkStatus endContainer (std::deque<JSONContainer *> *containers,
84+ JsonSinkStatus endContainer (
85+ std::deque<std::unique_ptr<JSONContainer>> *containers,
5086 int64_t *current_depth) {
5187 if (containers->empty ()) {
5288 return JsonSinkStatus::InternalError;
5389 }
5490
55- JSONContainer *container = containers->back ();
5691 containers->pop_back ();
57- delete container;
5892
59- if (containers->empty () == false ) {
60- auto *array = dynamic_cast <JSONContainerArray *>(containers->back ());
93+ if (! containers->empty ()) {
94+ auto *array = dynamic_cast <JSONContainerArray *>(containers->back (). get () );
6195 if (array != nullptr ) {
6296 array->m_elementCounter ++;
6397 }
@@ -72,6 +106,16 @@ JsonSinkStatus endContainer(std::deque<JSONContainer *> *containers,
72106 return JsonSinkStatus::Continue;
73107}
74108
109+ JsonSinkStatus addArgumentAsSinkStatus (JSON *json,
110+ const std::string &argument_value) {
111+ return json->addArgument (argument_value) != 0 ? JsonSinkStatus::Continue
112+ : JsonSinkStatus::EngineAbort;
113+ }
114+
115+ JsonSinkStatus addStringViewAsSinkStatus (JSON *json, std::string_view value) {
116+ return addArgumentAsSinkStatus (json, std::string (value.data (), value.size ()));
117+ }
118+
75119} // namespace
76120
77121JSON::JSON (Transaction *transaction) : m_transaction(transaction),
@@ -129,48 +173,7 @@ bool JSON::complete(std::string *err) {
129173 if (result.sink_status == JsonSinkStatus::DepthLimitExceeded) {
130174 m_depth_limit_exceeded = true ;
131175 }
132- if (err != nullptr ) {
133- switch (result.parse_status ) {
134- case JsonParseStatus::ParseError:
135- if (result.detail .empty ()) {
136- err->assign (" Invalid JSON body." );
137- } else {
138- err->assign (result.detail );
139- }
140- break ;
141- case JsonParseStatus::TruncatedInput:
142- if (result.detail .empty ()) {
143- err->assign (" Incomplete JSON body." );
144- } else {
145- err->assign (result.detail );
146- }
147- break ;
148- case JsonParseStatus::Utf8Error:
149- if (result.detail .empty ()) {
150- err->assign (" Invalid UTF-8 in JSON body." );
151- } else {
152- err->assign (result.detail );
153- }
154- break ;
155- case JsonParseStatus::EngineAbort:
156- if (result.detail .empty ()) {
157- err->assign (" JSON traversal aborted by ModSecurity." );
158- } else {
159- err->assign (result.detail );
160- }
161- break ;
162- case JsonParseStatus::InternalError:
163- if (result.detail .empty ()) {
164- err->assign (" Internal JSON backend failure." );
165- } else {
166- err->assign (result.detail );
167- }
168- break ;
169- case JsonParseStatus::Ok:
170- err->clear ();
171- break ;
172- }
173- }
176+ assignJsonErrorMessage (err, result.parse_status , result.detail );
174177 if (m_depth_limit_exceeded && err != nullptr ) {
175178 err->append (json_depth_limit_exceeded_msg);
176179 }
@@ -187,9 +190,9 @@ int JSON::addArgument(const std::string& value) {
187190
188191 for (size_t i = 0 ; i < m_containers.size (); i++) {
189192 const JSONContainerArray *a = dynamic_cast <JSONContainerArray *>(
190- m_containers[i]);
193+ m_containers[i]. get () );
191194 path = path + m_containers[i]->m_name ;
192- if (a != NULL ) {
195+ if (a != nullptr ) {
193196 path = path + " .array_" + std::to_string (a->m_elementCounter );
194197 } else {
195198 path = path + " ." ;
@@ -198,7 +201,7 @@ int JSON::addArgument(const std::string& value) {
198201
199202 if (m_containers.size () > 0 ) {
200203 JSONContainerArray *a = dynamic_cast <JSONContainerArray *>(
201- m_containers.back ());
204+ m_containers.back (). get () );
202205 if (a) {
203206 a->m_elementCounter ++;
204207 } else {
@@ -225,35 +228,28 @@ JsonSinkStatus JSON::on_key(std::string_view value) {
225228
226229
227230JsonSinkStatus JSON::on_null () {
228- return addArgument (" " ) != 0 ? JsonSinkStatus::Continue
229- : JsonSinkStatus::EngineAbort;
231+ return addArgumentAsSinkStatus (this , " " );
230232}
231233
232234
233235JsonSinkStatus JSON::on_boolean (bool value) {
234- if (value) {
235- return addArgument (" true" ) != 0 ? JsonSinkStatus::Continue
236- : JsonSinkStatus::EngineAbort;
237- }
238- return addArgument (" false" ) != 0 ? JsonSinkStatus::Continue
239- : JsonSinkStatus::EngineAbort;
236+ return addArgumentAsSinkStatus (this , value ? " true" : " false" );
240237}
241238
242239
243240JsonSinkStatus JSON::on_string (std::string_view value) {
244- return addArgument (std::string (value.data (), value.size ())) != 0
245- ? JsonSinkStatus::Continue : JsonSinkStatus::EngineAbort;
241+ return addStringViewAsSinkStatus (this , value);
246242}
247243
248244
249245JsonSinkStatus JSON::on_number (std::string_view value) {
250- return addArgument (std::string (value.data (), value.size ())) != 0
251- ? JsonSinkStatus::Continue : JsonSinkStatus::EngineAbort;
246+ return addStringViewAsSinkStatus (this , value);
252247}
253248
254249
255250JsonSinkStatus JSON::on_start_array () {
256- return startContainer (&m_containers, new JSONContainerArray (getCurrentKey ()),
251+ return startContainer (&m_containers,
252+ std::make_unique<JSONContainerArray>(getCurrentKey ()),
257253 &m_current_depth, m_max_depth, &m_depth_limit_exceeded);
258254}
259255
@@ -264,7 +260,8 @@ JsonSinkStatus JSON::on_end_array() {
264260
265261
266262JsonSinkStatus JSON::on_start_object () {
267- return startContainer (&m_containers, new JSONContainerMap (getCurrentKey ()),
263+ return startContainer (&m_containers,
264+ std::make_unique<JSONContainerMap>(getCurrentKey ()),
268265 &m_current_depth, m_max_depth, &m_depth_limit_exceeded);
269266}
270267
@@ -274,11 +271,7 @@ JsonSinkStatus JSON::on_end_object() {
274271}
275272
276273void JSON::clearContainers () {
277- while (m_containers.size () > 0 ) {
278- JSONContainer *a = m_containers.back ();
279- m_containers.pop_back ();
280- delete a;
281- }
274+ m_containers.clear ();
282275}
283276
284277} // namespace modsecurity::RequestBodyProcessor
0 commit comments