]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/ceph_json.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / common / ceph_json.cc
1 #include "common/ceph_json.h"
2 #include "include/utime.h"
3
4 // for testing DELETE ME
5 #include <fstream>
6 #include <include/types.h>
7
8 #include <boost/algorithm/string.hpp>
9 #include <boost/tokenizer.hpp>
10 #include <boost/lexical_cast.hpp>
11
12 #include "json_spirit/json_spirit_writer_template.h"
13
14 using namespace json_spirit;
15
16 #define dout_subsys ceph_subsys_rgw
17
18
19 static JSONFormattable default_formattable;
20
21
22 void encode_json(const char *name, const JSONObj::data_val& v, Formatter *f)
23 {
24 if (v.quoted) {
25 encode_json(name, v.str, f);
26 } else {
27 f->dump_format_unquoted(name, "%s", v.str.c_str());
28 }
29 }
30
31 JSONObjIter::JSONObjIter()
32 {
33 }
34
35 JSONObjIter::~JSONObjIter()
36 {
37 }
38
39 void JSONObjIter::set(const JSONObjIter::map_iter_t &_cur, const JSONObjIter::map_iter_t &_last)
40 {
41 cur = _cur;
42 last = _last;
43 }
44
45 void JSONObjIter::operator++()
46 {
47 if (cur != last)
48 ++cur;
49 }
50
51 JSONObj *JSONObjIter::operator*()
52 {
53 return cur->second;
54 }
55
56 // does not work, FIXME
57 ostream& operator<<(ostream &out, const JSONObj &obj) {
58 out << obj.name << ": " << obj.val;
59 return out;
60 }
61
62 JSONObj::~JSONObj()
63 {
64 multimap<string, JSONObj *>::iterator iter;
65 for (iter = children.begin(); iter != children.end(); ++iter) {
66 JSONObj *obj = iter->second;
67 delete obj;
68 }
69 }
70
71
72 void JSONObj::add_child(string el, JSONObj *obj)
73 {
74 children.insert(pair<string, JSONObj *>(el, obj));
75 }
76
77 bool JSONObj::get_attr(string name, data_val& attr)
78 {
79 auto iter = attr_map.find(name);
80 if (iter == attr_map.end())
81 return false;
82 attr = iter->second;
83 return true;
84 }
85
86 JSONObjIter JSONObj::find(const string& name)
87 {
88 JSONObjIter iter;
89 map<string, JSONObj *>::iterator first;
90 map<string, JSONObj *>::iterator last;
91 first = children.find(name);
92 if (first != children.end()) {
93 last = children.upper_bound(name);
94 iter.set(first, last);
95 }
96 return iter;
97 }
98
99 JSONObjIter JSONObj::find_first()
100 {
101 JSONObjIter iter;
102 iter.set(children.begin(), children.end());
103 return iter;
104 }
105
106 JSONObjIter JSONObj::find_first(const string& name)
107 {
108 JSONObjIter iter;
109 map<string, JSONObj *>::iterator first;
110 first = children.find(name);
111 iter.set(first, children.end());
112 return iter;
113 }
114
115 JSONObj *JSONObj::find_obj(const string& name)
116 {
117 JSONObjIter iter = find(name);
118 if (iter.end())
119 return NULL;
120
121 return *iter;
122 }
123
124 bool JSONObj::get_data(const string& key, data_val *dest)
125 {
126 JSONObj *obj = find_obj(key);
127 if (!obj)
128 return false;
129
130 *dest = obj->get_data_val();
131
132 return true;
133 }
134
135 /* accepts a JSON Array or JSON Object contained in
136 * a JSON Spirit Value, v, and creates a JSONObj for each
137 * child contained in v
138 */
139 void JSONObj::handle_value(Value v)
140 {
141 if (v.type() == obj_type) {
142 Object temp_obj = v.get_obj();
143 for (Object::size_type i = 0; i < temp_obj.size(); i++) {
144 Pair temp_pair = temp_obj[i];
145 string temp_name = temp_pair.name_;
146 Value temp_value = temp_pair.value_;
147 JSONObj *child = new JSONObj;
148 child->init(this, temp_value, temp_name);
149 add_child(temp_name, child);
150 }
151 } else if (v.type() == array_type) {
152 Array temp_array = v.get_array();
153 Value value;
154
155 for (unsigned j = 0; j < temp_array.size(); j++) {
156 Value cur = temp_array[j];
157 string temp_name;
158
159 JSONObj *child = new JSONObj;
160 child->init(this, cur, temp_name);
161 add_child(child->get_name(), child);
162 }
163 }
164 }
165
166 void JSONObj::init(JSONObj *p, Value v, string n)
167 {
168 name = n;
169 parent = p;
170 data = v;
171
172 handle_value(v);
173 if (v.type() == str_type) {
174 val.set(v.get_str(), true);
175 } else {
176 val.set(json_spirit::write_string(v), false);
177 }
178 attr_map.insert(pair<string,data_val>(name, val));
179 }
180
181 JSONObj *JSONObj::get_parent()
182 {
183 return parent;
184 }
185
186 bool JSONObj::is_object()
187 {
188 return (data.type() == obj_type);
189 }
190
191 bool JSONObj::is_array()
192 {
193 return (data.type() == array_type);
194 }
195
196 vector<string> JSONObj::get_array_elements()
197 {
198 vector<string> elements;
199 Array temp_array;
200
201 if (data.type() == array_type)
202 temp_array = data.get_array();
203
204 int array_size = temp_array.size();
205 if (array_size > 0)
206 for (int i = 0; i < array_size; i++) {
207 Value temp_value = temp_array[i];
208 string temp_string;
209 temp_string = write(temp_value, raw_utf8);
210 elements.push_back(temp_string);
211 }
212
213 return elements;
214 }
215
216 JSONParser::JSONParser() : buf_len(0), success(true)
217 {
218 }
219
220 JSONParser::~JSONParser()
221 {
222 }
223
224
225
226 void JSONParser::handle_data(const char *s, int len)
227 {
228 json_buffer.append(s, len); // check for problems with null termination FIXME
229 buf_len += len;
230 }
231
232 // parse a supplied JSON fragment
233 bool JSONParser::parse(const char *buf_, int len)
234 {
235 if (!buf_) {
236 set_failure();
237 return false;
238 }
239
240 string json_string(buf_, len);
241 success = read(json_string, data);
242 if (success) {
243 handle_value(data);
244 if (data.type() != obj_type &&
245 data.type() != array_type) {
246 if (data.type() == str_type) {
247 val.set(data.get_str(), true);
248 } else {
249 val.set(json_spirit::write_string(data), false);
250 }
251 }
252 } else {
253 set_failure();
254 }
255
256 return success;
257 }
258
259 // parse the internal json_buffer up to len
260 bool JSONParser::parse(int len)
261 {
262 string json_string = json_buffer.substr(0, len);
263 success = read(json_string, data);
264 if (success)
265 handle_value(data);
266 else
267 set_failure();
268
269 return success;
270 }
271
272 // parse the complete internal json_buffer
273 bool JSONParser::parse()
274 {
275 success = read(json_buffer, data);
276 if (success)
277 handle_value(data);
278 else
279 set_failure();
280
281 return success;
282 }
283
284 // parse a supplied ifstream, for testing. DELETE ME
285 bool JSONParser::parse(const char *file_name)
286 {
287 ifstream is(file_name);
288 success = read(is, data);
289 if (success)
290 handle_value(data);
291 else
292 set_failure();
293
294 return success;
295 }
296
297
298 void decode_json_obj(long& val, JSONObj *obj)
299 {
300 string s = obj->get_data();
301 const char *start = s.c_str();
302 char *p;
303
304 errno = 0;
305 val = strtol(start, &p, 10);
306
307 /* Check for various possible errors */
308
309 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
310 (errno != 0 && val == 0)) {
311 throw JSONDecoder::err("failed to parse number");
312 }
313
314 if (p == start) {
315 throw JSONDecoder::err("failed to parse number");
316 }
317
318 while (*p != '\0') {
319 if (!isspace(*p)) {
320 throw JSONDecoder::err("failed to parse number");
321 }
322 p++;
323 }
324 }
325
326 void decode_json_obj(unsigned long& val, JSONObj *obj)
327 {
328 string s = obj->get_data();
329 const char *start = s.c_str();
330 char *p;
331
332 errno = 0;
333 val = strtoul(start, &p, 10);
334
335 /* Check for various possible errors */
336
337 if ((errno == ERANGE && val == ULONG_MAX) ||
338 (errno != 0 && val == 0)) {
339 throw JSONDecoder::err("failed to number");
340 }
341
342 if (p == start) {
343 throw JSONDecoder::err("failed to parse number");
344 }
345
346 while (*p != '\0') {
347 if (!isspace(*p)) {
348 throw JSONDecoder::err("failed to parse number");
349 }
350 p++;
351 }
352 }
353
354 void decode_json_obj(long long& val, JSONObj *obj)
355 {
356 string s = obj->get_data();
357 const char *start = s.c_str();
358 char *p;
359
360 errno = 0;
361 val = strtoll(start, &p, 10);
362
363 /* Check for various possible errors */
364
365 if ((errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) ||
366 (errno != 0 && val == 0)) {
367 throw JSONDecoder::err("failed to parse number");
368 }
369
370 if (p == start) {
371 throw JSONDecoder::err("failed to parse number");
372 }
373
374 while (*p != '\0') {
375 if (!isspace(*p)) {
376 throw JSONDecoder::err("failed to parse number");
377 }
378 p++;
379 }
380 }
381
382 void decode_json_obj(unsigned long long& val, JSONObj *obj)
383 {
384 string s = obj->get_data();
385 const char *start = s.c_str();
386 char *p;
387
388 errno = 0;
389 val = strtoull(start, &p, 10);
390
391 /* Check for various possible errors */
392
393 if ((errno == ERANGE && val == ULLONG_MAX) ||
394 (errno != 0 && val == 0)) {
395 throw JSONDecoder::err("failed to number");
396 }
397
398 if (p == start) {
399 throw JSONDecoder::err("failed to parse number");
400 }
401
402 while (*p != '\0') {
403 if (!isspace(*p)) {
404 throw JSONDecoder::err("failed to parse number");
405 }
406 p++;
407 }
408 }
409
410 void decode_json_obj(int& val, JSONObj *obj)
411 {
412 long l;
413 decode_json_obj(l, obj);
414 #if LONG_MAX > INT_MAX
415 if (l > INT_MAX || l < INT_MIN) {
416 throw JSONDecoder::err("integer out of range");
417 }
418 #endif
419
420 val = (int)l;
421 }
422
423 void decode_json_obj(unsigned& val, JSONObj *obj)
424 {
425 unsigned long l;
426 decode_json_obj(l, obj);
427 #if ULONG_MAX > UINT_MAX
428 if (l > UINT_MAX) {
429 throw JSONDecoder::err("unsigned integer out of range");
430 }
431 #endif
432
433 val = (unsigned)l;
434 }
435
436 void decode_json_obj(bool& val, JSONObj *obj)
437 {
438 string s = obj->get_data();
439 if (strcasecmp(s.c_str(), "true") == 0) {
440 val = true;
441 return;
442 }
443 if (strcasecmp(s.c_str(), "false") == 0) {
444 val = false;
445 return;
446 }
447 int i;
448 decode_json_obj(i, obj);
449 val = (bool)i;
450 }
451
452 void decode_json_obj(bufferlist& val, JSONObj *obj)
453 {
454 string s = obj->get_data();
455
456 bufferlist bl;
457 bl.append(s.c_str(), s.size());
458 try {
459 val.decode_base64(bl);
460 } catch (buffer::error& err) {
461 throw JSONDecoder::err("failed to decode base64");
462 }
463 }
464
465 void decode_json_obj(utime_t& val, JSONObj *obj)
466 {
467 string s = obj->get_data();
468 uint64_t epoch;
469 uint64_t nsec;
470 int r = utime_t::parse_date(s, &epoch, &nsec);
471 if (r == 0) {
472 val = utime_t(epoch, nsec);
473 } else {
474 throw JSONDecoder::err("failed to decode utime_t");
475 }
476 }
477
478 void encode_json(const char *name, const string& val, Formatter *f)
479 {
480 f->dump_string(name, val);
481 }
482
483 void encode_json(const char *name, const char *val, Formatter *f)
484 {
485 f->dump_string(name, val);
486 }
487
488 void encode_json(const char *name, bool val, Formatter *f)
489 {
490 string s;
491 if (val)
492 s = "true";
493 else
494 s = "false";
495
496 f->dump_string(name, s);
497 }
498
499 void encode_json(const char *name, int val, Formatter *f)
500 {
501 f->dump_int(name, val);
502 }
503
504 void encode_json(const char *name, long val, Formatter *f)
505 {
506 f->dump_int(name, val);
507 }
508
509 void encode_json(const char *name, unsigned val, Formatter *f)
510 {
511 f->dump_unsigned(name, val);
512 }
513
514 void encode_json(const char *name, unsigned long val, Formatter *f)
515 {
516 f->dump_unsigned(name, val);
517 }
518
519 void encode_json(const char *name, unsigned long long val, Formatter *f)
520 {
521 f->dump_unsigned(name, val);
522 }
523
524 void encode_json(const char *name, long long val, Formatter *f)
525 {
526 f->dump_int(name, val);
527 }
528
529 void encode_json(const char *name, const utime_t& val, Formatter *f)
530 {
531 val.gmtime(f->dump_stream(name));
532 }
533
534 void encode_json(const char *name, const bufferlist& bl, Formatter *f)
535 {
536 /* need to copy data from bl, as it is const bufferlist */
537 bufferlist src = bl;
538
539 bufferlist b64;
540 src.encode_base64(b64);
541
542 string s(b64.c_str(), b64.length());
543
544 encode_json(name, s, f);
545 }
546
547
548
549 /* JSONFormattable */
550
551 const JSONFormattable& JSONFormattable::operator[](const string& name) const
552 {
553 auto i = obj.find(name);
554 if (i == obj.end()) {
555 return default_formattable;
556 }
557 return i->second;
558 }
559
560 const JSONFormattable& JSONFormattable::operator[](size_t index) const
561 {
562 if (index >= arr.size()) {
563 return default_formattable;
564 }
565 return arr[index];
566 }
567
568 JSONFormattable& JSONFormattable::operator[](const string& name)
569 {
570 auto i = obj.find(name);
571 if (i == obj.end()) {
572 return default_formattable;
573 }
574 return i->second;
575 }
576
577 JSONFormattable& JSONFormattable::operator[](size_t index)
578 {
579 if (index >= arr.size()) {
580 return default_formattable;
581 }
582 return arr[index];
583 }
584
585 bool JSONFormattable::exists(const string& name) const
586 {
587 auto i = obj.find(name);
588 return (i != obj.end());
589 }
590
591 bool JSONFormattable::exists(size_t index) const
592 {
593 return (index < arr.size());
594 }
595
596 bool JSONFormattable::find(const string& name, string *val) const
597 {
598 auto i = obj.find(name);
599 if (i == obj.end()) {
600 return false;
601 }
602 *val = i->second.val();
603 return true;
604 }
605
606 int JSONFormattable::val_int() const {
607 return atoi(value.str.c_str());
608 }
609
610 long JSONFormattable::val_long() const {
611 return atol(value.str.c_str());
612 }
613
614 long long JSONFormattable::val_long_long() const {
615 return atoll(value.str.c_str());
616 }
617
618 bool JSONFormattable::val_bool() const {
619 return (boost::iequals(value.str, "true") ||
620 boost::iequals(value.str, "on") ||
621 boost::iequals(value.str, "yes") ||
622 boost::iequals(value.str, "1"));
623 }
624
625 string JSONFormattable::def(const string& def_val) const {
626 if (type == FMT_NONE) {
627 return def_val;
628 }
629 return val();
630 }
631
632 int JSONFormattable::def(int def_val) const {
633 if (type == FMT_NONE) {
634 return def_val;
635 }
636 return val_int();
637 }
638
639 bool JSONFormattable::def(bool def_val) const {
640 if (type == FMT_NONE) {
641 return def_val;
642 }
643 return val_bool();
644 }
645
646 string JSONFormattable::get(const string& name, const string& def_val) const
647 {
648 return (*this)[name].def(def_val);
649 }
650
651 int JSONFormattable::get_int(const string& name, int def_val) const
652 {
653 return (*this)[name].def(def_val);
654 }
655
656 bool JSONFormattable::get_bool(const string& name, bool def_val) const
657 {
658 return (*this)[name].def(def_val);
659 }
660
661 struct field_entity {
662 bool is_obj{false}; /* either obj field or array entity */
663 string name; /* if obj */
664 int index{0}; /* if array */
665 bool append{false};
666
667 field_entity() {}
668 explicit field_entity(const string& n) : is_obj(true), name(n) {}
669 explicit field_entity(int i) : is_obj(false), index(i) {}
670 };
671
672 static int parse_entity(const string& s, vector<field_entity> *result)
673 {
674 size_t ofs = 0;
675
676 while (ofs < s.size()) {
677 size_t next_arr = s.find('[', ofs);
678 if (next_arr == string::npos) {
679 if (ofs != 0) {
680 return -EINVAL;
681 }
682 result->push_back(field_entity(s));
683 return 0;
684 }
685 if (next_arr > ofs) {
686 string field = s.substr(ofs, next_arr - ofs);
687 result->push_back(field_entity(field));
688 ofs = next_arr;
689 }
690 size_t end_arr = s.find(']', next_arr + 1);
691 if (end_arr == string::npos) {
692 return -EINVAL;
693 }
694
695 string index_str = s.substr(next_arr + 1, end_arr - next_arr - 1);
696
697 ofs = end_arr + 1;
698
699 if (!index_str.empty()) {
700 result->push_back(field_entity(atoi(index_str.c_str())));
701 } else {
702 field_entity f;
703 f.append = true;
704 result->push_back(f);
705 }
706 }
707 return 0;
708 }
709
710 static bool is_numeric(const string& val)
711 {
712 try {
713 boost::lexical_cast<double>(val);
714 } catch (const boost::bad_lexical_cast& e) {
715 return false;
716 }
717 return true;
718 }
719
720 int JSONFormattable::set(const string& name, const string& val)
721 {
722 boost::escaped_list_separator<char> els('\\', '.', '"');
723 boost::tokenizer<boost::escaped_list_separator<char> > tok(name, els);
724
725 JSONFormattable *f = this;
726
727 JSONParser jp;
728
729 bool is_valid_json = jp.parse(val.c_str(), val.size());
730
731 for (const auto& i : tok) {
732 vector<field_entity> v;
733 int ret = parse_entity(i, &v);
734 if (ret < 0) {
735 return ret;
736 }
737 for (const auto& vi : v) {
738 if (f->type == FMT_NONE) {
739 if (vi.is_obj) {
740 f->type = FMT_OBJ;
741 } else {
742 f->type = FMT_ARRAY;
743 }
744 }
745
746 if (f->type == FMT_OBJ) {
747 if (!vi.is_obj) {
748 return -EINVAL;
749 }
750 f = &f->obj[vi.name];
751 } else if (f->type == FMT_ARRAY) {
752 if (vi.is_obj) {
753 return -EINVAL;
754 }
755 int index = vi.index;
756 if (vi.append) {
757 index = f->arr.size();
758 } else if (index < 0) {
759 index = f->arr.size() + index;
760 if (index < 0) {
761 return -EINVAL; /* out of bounds */
762 }
763 }
764 if ((size_t)index >= f->arr.size()) {
765 f->arr.resize(index + 1);
766 }
767 f = &f->arr[index];
768 }
769 }
770 }
771
772 if (is_valid_json) {
773 f->decode_json(&jp);
774 } else {
775 f->type = FMT_VALUE;
776 f->value.set(val, !is_numeric(val));
777 }
778
779 return 0;
780 }
781
782 int JSONFormattable::erase(const string& name)
783 {
784 boost::escaped_list_separator<char> els('\\', '.', '"');
785 boost::tokenizer<boost::escaped_list_separator<char> > tok(name, els);
786
787 JSONFormattable *f = this;
788 JSONFormattable *parent = nullptr;
789 field_entity last_entity;
790
791 for (auto& i : tok) {
792 vector<field_entity> v;
793 int ret = parse_entity(i, &v);
794 if (ret < 0) {
795 return ret;
796 }
797 for (const auto& vi : v) {
798 if (f->type == FMT_NONE ||
799 f->type == FMT_VALUE) {
800 if (vi.is_obj) {
801 f->type = FMT_OBJ;
802 } else {
803 f->type = FMT_ARRAY;
804 }
805 }
806
807 parent = f;
808
809 if (f->type == FMT_OBJ) {
810 if (!vi.is_obj) {
811 return -EINVAL;
812 }
813 auto iter = f->obj.find(vi.name);
814 if (iter == f->obj.end()) {
815 return 0; /* nothing to erase */
816 }
817 f = &iter->second;
818 } else if (f->type == FMT_ARRAY) {
819 if (vi.is_obj) {
820 return -EINVAL;
821 }
822 int index = vi.index;
823 if (index < 0) {
824 index = f->arr.size() + index;
825 if (index < 0) { /* out of bounds, nothing to remove */
826 return 0;
827 }
828 }
829 if ((size_t)index >= f->arr.size()) {
830 return 0; /* index beyond array boundaries */
831 }
832 f = &f->arr[index];
833 }
834 last_entity = vi;
835 }
836 }
837
838 if (!parent) {
839 *this = JSONFormattable(); /* erase everything */
840 } else {
841 if (last_entity.is_obj) {
842 parent->obj.erase(last_entity.name);
843 } else {
844 int index = (last_entity.index >= 0 ? last_entity.index : parent->arr.size() + last_entity.index);
845 if (index < 0 || (size_t)index >= parent->arr.size()) {
846 return 0;
847 }
848 parent->arr.erase(parent->arr.begin() + index);
849 }
850 }
851
852 return 0;
853 }
854
855 void JSONFormattable::derive_from(const JSONFormattable& parent)
856 {
857 for (auto& o : parent.obj) {
858 if (obj.find(o.first) == obj.end()) {
859 obj[o.first] = o.second;
860 }
861 }
862 }
863
864 void encode_json(const char *name, const JSONFormattable& v, Formatter *f)
865 {
866 v.encode_json(name, f);
867 }
868
869 void JSONFormattable::encode_json(const char *name, Formatter *f) const
870 {
871 switch (type) {
872 case JSONFormattable::FMT_VALUE:
873 ::encode_json(name, value, f);
874 break;
875 case JSONFormattable::FMT_ARRAY:
876 ::encode_json(name, arr, f);
877 break;
878 case JSONFormattable::FMT_OBJ:
879 f->open_object_section(name);
880 for (auto iter : obj) {
881 ::encode_json(iter.first.c_str(), iter.second, f);
882 }
883 f->close_section();
884 break;
885 case JSONFormattable::FMT_NONE:
886 break;
887 }
888 }
889
890 bool JSONFormattable::handle_value(std::string_view name, std::string_view s, bool quoted) {
891 JSONFormattable *new_val;
892 if (cur_enc->is_array()) {
893 cur_enc->arr.push_back(JSONFormattable());
894 new_val = &cur_enc->arr.back();
895 } else {
896 cur_enc->set_type(JSONFormattable::FMT_OBJ);
897 new_val = &cur_enc->obj[string{name}];
898 }
899 new_val->set_type(JSONFormattable::FMT_VALUE);
900 new_val->value.set(s, quoted);
901
902 return false;
903 }
904
905 bool JSONFormattable::handle_open_section(std::string_view name,
906 const char *ns,
907 bool section_is_array) {
908 if (cur_enc->is_array()) {
909 cur_enc->arr.push_back(JSONFormattable());
910 cur_enc = &cur_enc->arr.back();
911 } else if (enc_stack.size() > 1) {
912 /* only open a new section if already nested,
913 * otherwise root is the container
914 */
915 cur_enc = &cur_enc->obj[string{name}];
916 }
917 enc_stack.push_back(cur_enc);
918
919 if (section_is_array) {
920 cur_enc->set_type(JSONFormattable::FMT_ARRAY);
921 } else {
922 cur_enc->set_type(JSONFormattable::FMT_OBJ);
923 }
924
925 return false; /* continue processing */
926 }
927
928 bool JSONFormattable::handle_close_section() {
929 if (enc_stack.size() <= 1) {
930 return false;
931 }
932
933 enc_stack.pop_back();
934 cur_enc = enc_stack.back();
935 return false; /* continue processing */
936 }
937