diff options
author | Yehuda Sadeh <yehuda@inktank.com> | 2013-02-06 12:36:18 -0800 |
---|---|---|
committer | Yehuda Sadeh <yehuda@inktank.com> | 2013-02-11 17:05:06 -0800 |
commit | bfb35d3275803c1e22f740d5b2687de2cf617044 (patch) | |
tree | 402771ef19ab805605ddb1bb2114ea9c48389abc | |
parent | 70532d198539f94067e53ef48dd7d1f5114fa27d (diff) | |
download | ceph-bfb35d3275803c1e22f740d5b2687de2cf617044.tar.gz |
rgw: introduce decode_json to easily decode json structures
Introducing a new way to define the json structure of an
object, similar to what we do with bufferlist encode/decode.
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
-rw-r--r-- | src/rgw/rgw_json.cc | 97 | ||||
-rw-r--r-- | src/rgw/rgw_json.h | 100 |
2 files changed, 193 insertions, 4 deletions
diff --git a/src/rgw/rgw_json.cc b/src/rgw/rgw_json.cc index 0f91c2279e1..3cff30aa37b 100644 --- a/src/rgw/rgw_json.cc +++ b/src/rgw/rgw_json.cc @@ -268,4 +268,101 @@ bool RGWJSONParser::parse(const char *file_name) } +void decode_json_obj(long& val, JSONObj *obj) +{ + string s = obj->get_data(); + const char *start = s.c_str(); + char *p; + + errno = 0; + val = strtol(start, &p, 10); + + /* Check for various possible errors */ + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || + (errno != 0 && val == 0)) { + throw JSONDecoder::err("failed to parse number"); + } + + if (p == start) { + throw JSONDecoder::err("failed to parse number"); + } + + while (*p != '\0') { + if (!isspace(*p)) { + throw JSONDecoder::err("failed to parse number"); + } + p++; + } +} + +void decode_json_obj(unsigned long& val, JSONObj *obj) +{ + string s = obj->get_data(); + const char *start = s.c_str(); + char *p; + + errno = 0; + val = strtoul(start, &p, 10); + + /* Check for various possible errors */ + + if ((errno == ERANGE && val == ULONG_MAX) || + (errno != 0 && val == 0)) { + throw JSONDecoder::err("failed to number"); + } + + if (p == start) { + throw JSONDecoder::err("failed to parse number"); + } + + while (*p != '\0') { + if (!isspace(*p)) { + throw JSONDecoder::err("failed to parse number"); + } + p++; + } +} + +void decode_json_obj(int& val, JSONObj *obj) +{ + long l; + decode_json_obj(l, obj); +#if LONG_MAX > INT_MAX + if (l > INT_MAX || l < INT_MIN) { + throw JSONDecoder::err("integer out of range"); + } +#endif + + val = (int)l; +} + +void decode_json_obj(unsigned& val, JSONObj *obj) +{ + unsigned long l; + decode_json_obj(l, obj); +#if ULONG_MAX > UINT_MAX + if (l > UINT_MAX) { + throw JSONDecoder::err("unsigned integer out of range"); + } +#endif + + val = (unsigned)l; +} + +void decode_json_obj(bool& val, JSONObj *obj) +{ + string s = obj->get_data(); + if (strcasecmp(s.c_str(), "true") == 0) { + val = true; + return; + } + if (strcasecmp(s.c_str(), "false") == 0) { + val = true; + return; + } + int i; + decode_json_obj(i, obj); + val = (bool)i; +} diff --git a/src/rgw/rgw_json.h b/src/rgw/rgw_json.h index d0dec397c28..4b6f00d9286 100644 --- a/src/rgw/rgw_json.h +++ b/src/rgw/rgw_json.h @@ -4,13 +4,9 @@ #include <iostream> #include <include/types.h> -// for testing DELETE ME -#include <fstream> - #include "json_spirit/json_spirit.h" -using namespace std; using namespace json_spirit; @@ -91,4 +87,100 @@ public: }; +class JSONDecoder { +public: + struct err { + string message; + + err(const string& m) : message(m) {} + }; + + RGWJSONParser parser; + + JSONDecoder(bufferlist& bl) { + if (!parser.parse(bl.c_str(), bl.length())) { + cout << "JSONDecoder::err()" << std::endl; + throw JSONDecoder::err("failed to parse JSON input"); + } + } + + template<class T> + static bool decode_json(const string& name, T& val, JSONObj *obj, bool mandatory = false); + + template<class T> + static void decode_json(const string& name, T& val, T& default_val, JSONObj *obj); +}; + +template<class T> +void decode_json_obj(T& val, JSONObj *obj) +{ + val.decode_json(obj); +} + +static inline void decode_json_obj(string& val, JSONObj *obj) +{ + val = obj->get_data(); +} + +void decode_json_obj(unsigned long& val, JSONObj *obj); +void decode_json_obj(long& val, JSONObj *obj); +void decode_json_obj(unsigned& val, JSONObj *obj); +void decode_json_obj(int& val, JSONObj *obj); +void decode_json_obj(bool& val, JSONObj *obj); + +template<class T> +void decode_json_obj(list<T>& l, JSONObj *obj) +{ + JSONObjIter iter = obj->find_first(); + + for (; !iter.end(); ++iter) { + T val; + JSONObj *o = *iter; + decode_json_obj(val, o); + l.push_back(val); + } +} + +template<class T> +bool JSONDecoder::decode_json(const string& name, T& val, JSONObj *obj, bool mandatory) +{ + JSONObjIter iter = obj->find_first(name); + if (iter.end()) { + if (mandatory) { + string s = "missing mandatory field " + name; + throw err(s); + } + return false; + } + + try { + decode_json_obj(val, *iter); + } catch (err& e) { + string s = name + ": "; + s.append(e.message); + throw err(s); + } + + return true; +} + +template<class T> +void JSONDecoder::decode_json(const string& name, T& val, T& default_val, JSONObj *obj) +{ + JSONObjIter iter = obj->find_first(name); + if (iter.end()) { + val = default_val; + return; + } + + try { + decode_json_obj(val, *iter); + } catch (err& e) { + val = default_val; + string s = name + ": "; + s.append(e.message); + throw err(s); + } +} + #endif |