master
c 558 lines 15.1 KB
Raw
1 #include "libnetdata/libnetdata.h"
2 #include "json.h"
3
4 #ifndef ENABLE_JSONC
5 #include "jsmn.h"
6 #endif
7
8 #define JSON_TOKENS 1024
9
10 int json_tokens = JSON_TOKENS;
11
12 /**
13 * Json Tokenise
14 *
15 * Map the string given inside tokens.
16 *
17 * @param js is the string used to create the tokens
18 * @param len is the string length
19 * @param count the number of tokens present in the string
20 *
21 * @return it returns the json parsed in tokens
22 */
23 #ifdef ENABLE_JSONC
24 json_object *json_tokenise(char *js) {
25 if(!js) {
26 netdata_log_error("JSON: json string is empty.");
27 return NULL;
28 }
29
30 json_object *token = json_tokener_parse(js);
31 if(!token) {
32 netdata_log_error("JSON: Invalid json string.");
33 return NULL;
34 }
35
36 return token;
37 }
38 #else
39 jsmntok_t *json_tokenise(char *js, size_t len, size_t *count)
40 {
41 int n = json_tokens;
42 if(!js || !len) {
43 netdata_log_error("JSON: json string is empty.");
44 return NULL;
45 }
46
47 jsmn_parser parser;
48 jsmn_init(&parser);
49
50 jsmntok_t *tokens = mallocz(sizeof(jsmntok_t) * n);
51 if(!tokens) return NULL;
52
53 int ret = jsmn_parse(&parser, js, len, tokens, n);
54 while (ret == JSMN_ERROR_NOMEM) {
55 n *= 2;
56 jsmntok_t *new = reallocz(tokens, sizeof(jsmntok_t) * n);
57 if(!new) {
58 freez(tokens);
59 return NULL;
60 }
61 tokens = new;
62 ret = jsmn_parse(&parser, js, len, tokens, n);
63 }
64
65 if (ret == JSMN_ERROR_INVAL) {
66 netdata_log_error("JSON: Invalid json string.");
67 freez(tokens);
68 return NULL;
69 }
70 else if (ret == JSMN_ERROR_PART) {
71 netdata_log_error("JSON: Truncated JSON string.");
72 freez(tokens);
73 return NULL;
74 }
75
76 if(count) *count = (size_t)ret;
77
78 if(json_tokens < n) json_tokens = n;
79 return tokens;
80 }
81 #endif
82
83 /**
84 * Callback Print
85 *
86 * Set callback print case necessary and wrinte an information inside a buffer to write in the log.
87 *
88 * @param e a pointer for a structure that has the complete information about json structure.
89 *
90 * @return It always return 0
91 */
92 int json_callback_print(JSON_ENTRY *e)
93 {
94 BUFFER *wb=buffer_create(300, NULL);
95
96 buffer_sprintf(wb,"%s = ", e->name);
97 char txt[50];
98 switch(e->type) {
99 case JSON_OBJECT:
100 e->callback_function = json_callback_print;
101 buffer_strcat(wb,"OBJECT");
102 break;
103
104 case JSON_ARRAY:
105 e->callback_function = json_callback_print;
106 snprintfz(txt, sizeof(txt), "ARRAY[%lu]", (long unsigned int) e->data.items);
107 buffer_strcat(wb, txt);
108 break;
109
110 case JSON_STRING:
111 buffer_strcat(wb, e->data.string);
112 break;
113
114 case JSON_NUMBER:
115 buffer_print_netdata_double(wb, e->data.number);
116 break;
117
118 case JSON_BOOLEAN:
119 buffer_strcat(wb, e->data.boolean?"TRUE":"FALSE");
120 break;
121
122 case JSON_NULL:
123 buffer_strcat(wb,"NULL");
124 break;
125 }
126 netdata_log_info("JSON: %s", buffer_tostring(wb));
127 buffer_free(wb);
128 return 0;
129 }
130
131 /**
132 * JSONC Set String
133 *
134 * Set the string value of the structure JSON_ENTRY.
135 *
136 * @param e the output structure
137 */
138 static inline void json_jsonc_set_string(JSON_ENTRY *e,char *key,const char *value) {
139 size_t len = strlen(key);
140 if(len > JSON_NAME_LEN)
141 len = JSON_NAME_LEN;
142 e->type = JSON_STRING;
143 memcpy(e->name,key,len);
144 e->name[len] = 0x00;
145 e->data.string = (char *) value;
146 }
147
148
149 #ifdef ENABLE_JSONC
150 /**
151 * JSONC set Boolean
152 *
153 * Set the boolean value of the structure JSON_ENTRY
154 *
155 * @param e the output structure
156 * @param value the input value
157 */
158 static inline void json_jsonc_set_boolean(JSON_ENTRY *e,int value) {
159 e->type = JSON_BOOLEAN;
160 e->data.boolean = value;
161 }
162
163 static inline void json_jsonc_set_integer(JSON_ENTRY *e, char *key, int64_t value) {
164 size_t len = strlen(key);
165 if(len > JSON_NAME_LEN)
166 len = JSON_NAME_LEN;
167 e->type = JSON_NUMBER;
168 memcpy(e->name, key, len);
169 e->name[len] = 0;
170 e->data.number = (NETDATA_DOUBLE)value;
171 }
172
173 /**
174 * Parse Array
175 *
176 * Parse the array object.
177 *
178 * @param ptr the pointer for the object that we will parse.
179 * @param callback_data additional data to be used together the callback function
180 * @param callback_function function used to create a silencer.
181 */
182 static inline void json_jsonc_parse_array(json_object *ptr, void *callback_data,int (*callback_function)(struct json_entry *)) {
183 int end = json_object_array_length(ptr);
184 JSON_ENTRY e;
185
186 if(end) {
187 int i;
188 i = 0;
189
190 enum json_type type;
191 do {
192 json_object *jvalue = json_object_array_get_idx(ptr, i);
193 if(jvalue) {
194 e.callback_data = callback_data;
195 e.type = JSON_OBJECT;
196 callback_function(&e);
197 json_object_object_foreach(jvalue, key, val) {
198 type = json_object_get_type(val);
199 if (type == json_type_array) {
200 e.type = JSON_ARRAY;
201 json_jsonc_parse_array(val, callback_data, callback_function);
202 } else if (type == json_type_object) {
203 json_walk(val,callback_data,callback_function);
204 } else if (type == json_type_string) {
205 json_jsonc_set_string(&e,key,json_object_get_string(val));
206 callback_function(&e);
207 } else if (type == json_type_boolean) {
208 json_jsonc_set_boolean(&e,json_object_get_boolean(val));
209 callback_function(&e);
210 }
211 }
212 }
213
214 } while (++i < end);
215 }
216 }
217 #else
218
219 /**
220 * Walk string
221 *
222 * Set JSON_ENTRY to string and map the values from jsmntok_t.
223 *
224 * @param js the original string
225 * @param t the tokens
226 * @param start the first position
227 * @param e the output structure.
228 *
229 * @return It always return 1
230 */
231 size_t json_walk_string(char *js, jsmntok_t *t, size_t start, JSON_ENTRY *e)
232 {
233 char old = js[t[start].end];
234 js[t[start].end] = '\0';
235 e->original_string = &js[t[start].start];
236
237 e->type = JSON_STRING;
238 e->data.string = e->original_string;
239 if(e->callback_function) e->callback_function(e);
240 js[t[start].end] = old;
241 return 1;
242 }
243
244 /**
245 * Walk Primitive
246 *
247 * Define the data type of the string
248 *
249 * @param js the original string
250 * @param t the tokens
251 * @param start the first position
252 * @param e the output structure.
253 *
254 * @return It always return 1
255 */
256 size_t json_walk_primitive(char *js, jsmntok_t *t, size_t start, JSON_ENTRY *e)
257 {
258 char old = js[t[start].end];
259 js[t[start].end] = '\0';
260 e->original_string = &js[t[start].start];
261
262 switch(e->original_string[0]) {
263 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
264 case '8': case '9': case '-': case '.':
265 e->type = JSON_NUMBER;
266 e->data.number = strtold(e->original_string, NULL);
267 break;
268
269 case 't': case 'T':
270 e->type = JSON_BOOLEAN;
271 e->data.boolean = 1;
272 break;
273
274 case 'f': case 'F':
275 e->type = JSON_BOOLEAN;
276 e->data.boolean = 0;
277 break;
278
279 case 'n': case 'N':
280 default:
281 e->type = JSON_NULL;
282 break;
283 }
284 if(e->callback_function) e->callback_function(e);
285 js[t[start].end] = old;
286 return 1;
287 }
288
289 /**
290 * Array
291 *
292 * Measure the array length
293 *
294 * @param js the original string
295 * @param t the tokens
296 * @param nest the length of structure t
297 * @param start the first position
298 * @param e the structure with values and callback to be used inside the function.
299 *
300 * @return It returns the array length
301 */
302 size_t json_walk_array(char *js, jsmntok_t *t, size_t nest, size_t start, JSON_ENTRY *e)
303 {
304 JSON_ENTRY ne;
305
306 char old = js[t[start].end];
307 js[t[start].end] = '\0';
308 ne.original_string = &js[t[start].start];
309
310 memcpy(&ne, e, sizeof(JSON_ENTRY));
311 ne.type = JSON_ARRAY;
312 ne.data.items = t[start].size;
313 ne.callback_function = e->callback_function;
314 ne.name[0]='\0';
315 ne.fullname[0]='\0';
316 if(e->callback_function) e->callback_function(&ne);
317 js[t[start].end] = old;
318
319 size_t i, init = start, size = t[start].size;
320
321 start++;
322 for(i = 0; i < size ; i++) {
323 ne.pos = i;
324 if (strlen(e->name) > JSON_NAME_LEN - 24 || strlen(e->fullname) > JSON_FULLNAME_LEN -24) {
325 netdata_log_info("JSON: JSON walk_array ignoring element with name:%s fullname:%s",e->name, e->fullname);
326 continue;
327 }
328 snprintfz(ne.name, JSON_NAME_LEN, "%s[%lu]", e->name, i);
329 snprintfz(ne.fullname, JSON_FULLNAME_LEN, "%s[%lu]", e->fullname, i);
330
331 switch(t[start].type) {
332 case JSMN_PRIMITIVE:
333 start += json_walk_primitive(js, t, start, &ne);
334 break;
335
336 case JSMN_OBJECT:
337 start += json_walk_object(js, t, nest + 1, start, &ne);
338 break;
339
340 case JSMN_ARRAY:
341 start += json_walk_array(js, t, nest + 1, start, &ne);
342 break;
343
344 case JSMN_STRING:
345 start += json_walk_string(js, t, start, &ne);
346 break;
347 }
348 }
349 return start - init;
350 }
351
352 /**
353 * Object
354 *
355 * Measure the Object length
356 *
357 * @param js the original string
358 * @param t the tokens
359 * @param nest the length of structure t
360 * @param start the first position
361 * @param e the output structure.
362 *
363 * @return It returns the Object length
364 */
365 size_t json_walk_object(char *js, jsmntok_t *t, size_t nest, size_t start, JSON_ENTRY *e)
366 {
367 JSON_ENTRY ne = {
368 .name = "",
369 .fullname = "",
370 .callback_data = NULL,
371 .callback_function = NULL
372 };
373
374 char old = js[t[start].end];
375 js[t[start].end] = '\0';
376 ne.original_string = &js[t[start].start];
377 memcpy(&ne, e, sizeof(JSON_ENTRY));
378 ne.type = JSON_OBJECT;
379 ne.callback_function = e->callback_function;
380 if(e->callback_function) e->callback_function(&ne);
381 js[t[start].end] = old;
382
383 int key = 1;
384 size_t i, init = start, size = t[start].size;
385
386 start++;
387 for(i = 0; i < size ; i++) {
388 switch(t[start].type) {
389 case JSMN_PRIMITIVE:
390 start += json_walk_primitive(js, t, start, &ne);
391 key = 1;
392 break;
393
394 case JSMN_OBJECT:
395 start += json_walk_object(js, t, nest + 1, start, &ne);
396 key = 1;
397 break;
398
399 case JSMN_ARRAY:
400 start += json_walk_array(js, t, nest + 1, start, &ne);
401 key = 1;
402 break;
403
404 case JSMN_STRING:
405 default:
406 if(key) {
407 int len = t[start].end - t[start].start;
408 if (unlikely(len>JSON_NAME_LEN)) len=JSON_NAME_LEN;
409 strncpy(ne.name, &js[t[start].start], len);
410 ne.name[len] = '\0';
411 len=strlen(e->fullname) + strlen(e->fullname[0]?".":"") + strlen(ne.name);
412 char *c = mallocz((len+1)*sizeof(char));
413 sprintf(c,"%s%s%s", e->fullname, e->fullname[0]?".":"", ne.name);
414 if (unlikely(len>JSON_FULLNAME_LEN)) len=JSON_FULLNAME_LEN;
415 strncpy(ne.fullname, c, len);
416 freez(c);
417 start++;
418 key = 0;
419 }
420 else {
421 start += json_walk_string(js, t, start, &ne);
422 key = 1;
423 }
424 break;
425 }
426 }
427 return start - init;
428 }
429 #endif
430
431 /**
432 * Tree
433 *
434 * Call the correct walk function according its type.
435 *
436 * @param t the json object to work
437 * @param callback_data additional data to be used together the callback function
438 * @param callback_function function used to create a silencer.
439 *
440 * @return It always return 1
441 */
442 #ifdef ENABLE_JSONC
443 size_t json_walk(json_object *t, void *callback_data, int (*callback_function)(struct json_entry *)) {
444 if (!t || json_object_get_type(t) != json_type_object)
445 return 0;
446
447 JSON_ENTRY e = { 0 };
448 e.callback_data = callback_data;
449 enum json_type type;
450 json_object_object_foreach(t, key, val) {
451 type = json_object_get_type(val);
452 if (type == json_type_array) {
453 e.type = JSON_ARRAY;
454 json_jsonc_parse_array(val,NULL,callback_function);
455 } else if (type == json_type_object) {
456 e.type = JSON_OBJECT;
457 } else if (type == json_type_string) {
458 json_jsonc_set_string(&e,key,json_object_get_string(val));
459 callback_function(&e);
460 } else if (type == json_type_boolean) {
461 json_jsonc_set_boolean(&e,json_object_get_boolean(val));
462 callback_function(&e);
463 } else if (type == json_type_int) {
464 json_jsonc_set_integer(&e,key,json_object_get_int64(val));
465 callback_function(&e);
466 }
467 }
468
469 return 1;
470 }
471 #else
472 /**
473 * Tree
474 *
475 * Call the correct walk function according its type.
476 *
477 * @param js the original string
478 * @param t the tokens
479 * @param callback_data additional data to be used together the callback function
480 * @param callback_function function used to create a silencer.
481 *
482 * @return It always return 1
483 */
484 size_t json_walk_tree(char *js, jsmntok_t *t, void *callback_data, int (*callback_function)(struct json_entry *))
485 {
486 JSON_ENTRY e = {
487 .name = "",
488 .fullname = "",
489 .callback_data = callback_data,
490 .callback_function = callback_function
491 };
492
493 switch (t[0].type) {
494 case JSMN_OBJECT:
495 e.type = JSON_OBJECT;
496 json_walk_object(js, t, 0, 0, &e);
497 break;
498
499 case JSMN_ARRAY:
500 e.type = JSON_ARRAY;
501 json_walk_array(js, t, 0, 0, &e);
502 break;
503
504 case JSMN_PRIMITIVE:
505 case JSMN_STRING:
506 break;
507 }
508
509 return 1;
510 }
511 #endif
512
513 /**
514 * JSON Parse
515 *
516 * Parse the json message with the callback function
517 *
518 * @param js the string that the callback function will parse
519 * @param callback_data additional data to be used together the callback function
520 * @param callback_function function used to create a silencer.
521 *
522 * @return JSON_OK case everything happened as expected, JSON_CANNOT_PARSE case there were errors in the
523 * parsing process and JSON_CANNOT_DOWNLOAD case the string given(js) is NULL.
524 */
525 int json_parse(char *js, void *callback_data, int (*callback_function)(JSON_ENTRY *))
526 {
527 if(js) {
528 #ifdef ENABLE_JSONC
529 json_object *tokens = json_tokenise(js);
530 #else
531 size_t count;
532 jsmntok_t *tokens = json_tokenise(js, strlen(js), &count);
533 #endif
534
535 if(tokens) {
536 #ifdef ENABLE_JSONC
537 json_walk(tokens, callback_data, callback_function);
538 json_object_put(tokens);
539 #else
540 json_walk_tree(js, tokens, callback_data, callback_function);
541 freez(tokens);
542 #endif
543 return JSON_OK;
544 }
545
546 return JSON_CANNOT_PARSE;
547 }
548
549 return JSON_CANNOT_DOWNLOAD;
550 }
551
552 /*
553 int json_test(char *str)
554 {
555 return json_parse(str, NULL, json_callback_print);
556 }
557 */
558