master
c 124 lines 4.62 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "../libnetdata.h"
4
5 // "JSON parser failed: " prefix (20 chars) + json-c error string (< 60 chars) + NUL
6 #define JSON_PARSER_ERROR_MSG_MAX 256
7 #define JSON_PARSER_ERROR_PREFIX "JSON parser failed: "
8 #define JSON_PARSER_ERROR_TRUNCATION_SUFFIX "..."
9 #define JSON_PARSER_UNKNOWN_ERROR "unknown error"
10
11 static void json_parser_format_error(char *dst, size_t dst_size, const char *error_msg, size_t error_len) {
12 if(unlikely(!dst_size))
13 return;
14
15 if(!error_msg || !*error_msg) {
16 error_msg = JSON_PARSER_UNKNOWN_ERROR;
17 error_len = sizeof(JSON_PARSER_UNKNOWN_ERROR) - 1;
18 }
19
20 const size_t prefix_len = sizeof(JSON_PARSER_ERROR_PREFIX) - 1;
21 size_t available = dst_size - 1;
22 if(unlikely(available <= prefix_len)) {
23 dst[0] = '\0';
24 return;
25 }
26
27 available -= prefix_len;
28
29 bool truncated = error_len > available;
30 if(truncated) {
31 size_t suffix_len = sizeof(JSON_PARSER_ERROR_TRUNCATION_SUFFIX) - 1;
32 if(available > suffix_len)
33 available -= suffix_len;
34 }
35
36 snprintfz(dst, dst_size, "%s%.*s%s",
37 JSON_PARSER_ERROR_PREFIX,
38 (int)available,
39 error_msg,
40 truncated ? JSON_PARSER_ERROR_TRUNCATION_SUFFIX : "");
41 }
42
43 int rrd_call_function_error(BUFFER *wb, const char *msg, int code) {
44 buffer_reset(wb);
45 buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
46 buffer_json_member_add_int64(wb, "status", code);
47 buffer_json_member_add_string(wb, "errorMessage", msg);
48 buffer_json_finalize(wb);
49 wb->date = now_realtime_sec();
50 wb->expires = wb->date + 1;
51 wb->response_code = code;
52 return code;
53 }
54
55 struct json_object *json_parse_function_payload_or_error(BUFFER *output, BUFFER *payload, int *code, json_parse_function_payload_t cb, void *cb_data) {
56 if(!payload || !buffer_strlen(payload)) {
57 *code = rrd_call_function_error(output, "No payload given, but a payload is required for this feature.", HTTP_RESP_BAD_REQUEST);
58 return NULL;
59 }
60
61 struct json_tokener *tokener = json_tokener_new();
62 if (!tokener) {
63 *code = rrd_call_function_error(output, "Failed to initialize json parser.", HTTP_RESP_INTERNAL_SERVER_ERROR);
64 return NULL;
65 }
66
67 struct json_object *jobj = json_tokener_parse_ex(tokener, buffer_tostring(payload), (int)buffer_strlen(payload));
68 if (json_tokener_get_error(tokener) != json_tokener_success) {
69 const char *error_msg = json_tokener_error_desc(json_tokener_get_error(tokener));
70 char tmp[JSON_PARSER_ERROR_MSG_MAX];
71 json_parser_format_error(tmp, sizeof(tmp), error_msg, error_msg ? strnlen(error_msg, JSON_PARSER_ERROR_MSG_MAX) : 0);
72 json_tokener_free(tokener);
73 *code = rrd_call_function_error(output, tmp, HTTP_RESP_INTERNAL_SERVER_ERROR);
74 return NULL;
75 }
76 json_tokener_free(tokener);
77
78 CLEAN_BUFFER *error = buffer_create(0, NULL);
79 if(!cb(jobj, cb_data, error)) {
80 char tmp[JSON_PARSER_ERROR_MSG_MAX];
81 json_parser_format_error(tmp, sizeof(tmp), buffer_tostring(error), buffer_strlen(error));
82 *code = rrd_call_function_error(output, tmp, HTTP_RESP_BAD_REQUEST);
83 json_object_put(jobj);
84 return NULL;
85 }
86
87 *code = HTTP_RESP_OK;
88
89 return jobj;
90 }
91
92 int json_parse_payload_or_error(BUFFER *payload, BUFFER *error, json_parse_function_payload_t cb, void *cb_data) {
93 if(!payload || !buffer_strlen(payload)) {
94 buffer_strcat(error, "No payload given, but a payload is required for this feature.");
95 return HTTP_RESP_BAD_REQUEST;
96 }
97
98 struct json_tokener *tokener = json_tokener_new();
99 if (!tokener) {
100 buffer_strcat(error, "Failed to initialize json parser.");
101 return HTTP_RESP_INTERNAL_SERVER_ERROR;
102 }
103
104 struct json_object *jobj = json_tokener_parse_ex(tokener, buffer_tostring(payload), (int)buffer_strlen(payload));
105 if (json_tokener_get_error(tokener) != json_tokener_success) {
106 const char *error_msg = json_tokener_error_desc(json_tokener_get_error(tokener));
107 char tmp[JSON_PARSER_ERROR_MSG_MAX];
108 json_parser_format_error(tmp, sizeof(tmp), error_msg, error_msg ? strnlen(error_msg, JSON_PARSER_ERROR_MSG_MAX) : 0);
109 json_tokener_free(tokener);
110 buffer_strcat(error, tmp);
111 return HTTP_RESP_BAD_REQUEST;
112 }
113 json_tokener_free(tokener);
114
115 if(!cb(jobj, cb_data, error)) {
116 if(!buffer_strlen(error))
117 buffer_strcat(error, "Unknown error during parsing");
118 json_object_put(jobj);
119 return HTTP_RESP_BAD_REQUEST;
120 }
121
122 json_object_put(jobj);
123 return HTTP_RESP_OK;
124 }