revision-id: 294d9bf2484abfd3409d4ac25a3b3b695d66b0ec (mariadb-10.4.1-93-g294d9bf) parent(s): edba0470803bf2277b5509af3b978f042c0b7204 committer: Alexey Botchkov timestamp: 2019-01-17 03:52:52 +0400 message: MDEV-5313 Improving audit api. JSON api implementations and tests pushed. sql_acl.cc fixed with the new function names. --- include/json_lib.h | 4 - include/mysql/plugin_audit.h.pp | 20 ++-- include/mysql/plugin_auth.h.pp | 20 ++-- include/mysql/plugin_encryption.h.pp | 20 ++-- include/mysql/plugin_ftparser.h.pp | 20 ++-- include/mysql/plugin_password_validation.h.pp | 20 ++-- include/mysql/service_json.h | 20 ++-- sql/sql_acl.cc | 30 +++--- strings/json_lib.c | 145 +++++++++++++++++--------- unittest/strings/CMakeLists.txt | 2 +- 10 files changed, 174 insertions(+), 127 deletions(-) diff --git a/include/json_lib.h b/include/json_lib.h index 0f8cff7..a347538 100644 --- a/include/json_lib.h +++ b/include/json_lib.h @@ -425,10 +425,6 @@ int json_path_compare(const json_path_t *a, const json_path_t *b, int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs); -int json_get_object_by_key(const char *js, size_t js_len, - const char *key, size_t key_len, - enum json_value_types *value_type, - const char **value_start, size_t *value_len); #ifdef __cplusplus } #endif diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 0588b21..47f07ae 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -388,33 +388,33 @@ enum json_types }; extern struct json_service_st { enum json_types (*json_type)(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_array_item)(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_object_key)(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int (*json_escape_string)(const char *str,const char *str_end, char *json, char *json_end); int (*json_unescape_json)(const char *json_str, const char *json_end, char *res, char *res_end); } *json_service; enum json_types json_type(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_object_key(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int json_escape_string(const char *str,const char *str_end, char *json, char *json_end); int json_unescape_json(const char *json_str, const char *json_end, diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index cfb9201..f9d01a8 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -388,33 +388,33 @@ enum json_types }; extern struct json_service_st { enum json_types (*json_type)(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_array_item)(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_object_key)(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int (*json_escape_string)(const char *str,const char *str_end, char *json, char *json_end); int (*json_unescape_json)(const char *json_str, const char *json_end, char *res, char *res_end); } *json_service; enum json_types json_type(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_object_key(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int json_escape_string(const char *str,const char *str_end, char *json, char *json_end); int json_unescape_json(const char *json_str, const char *json_end, diff --git a/include/mysql/plugin_encryption.h.pp b/include/mysql/plugin_encryption.h.pp index 7761a3e..e55a034 100644 --- a/include/mysql/plugin_encryption.h.pp +++ b/include/mysql/plugin_encryption.h.pp @@ -388,33 +388,33 @@ enum json_types }; extern struct json_service_st { enum json_types (*json_type)(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_array_item)(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_object_key)(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int (*json_escape_string)(const char *str,const char *str_end, char *json, char *json_end); int (*json_unescape_json)(const char *json_str, const char *json_end, char *res, char *res_end); } *json_service; enum json_types json_type(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_object_key(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int json_escape_string(const char *str,const char *str_end, char *json, char *json_end); int json_unescape_json(const char *json_str, const char *json_end, diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index 2e77597..f9d9844 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -388,33 +388,33 @@ enum json_types }; extern struct json_service_st { enum json_types (*json_type)(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_array_item)(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_object_key)(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int (*json_escape_string)(const char *str,const char *str_end, char *json, char *json_end); int (*json_unescape_json)(const char *json_str, const char *json_end, char *res, char *res_end); } *json_service; enum json_types json_type(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_object_key(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int json_escape_string(const char *str,const char *str_end, char *json, char *json_end); int json_unescape_json(const char *json_str, const char *json_end, diff --git a/include/mysql/plugin_password_validation.h.pp b/include/mysql/plugin_password_validation.h.pp index 7492642..b672db6 100644 --- a/include/mysql/plugin_password_validation.h.pp +++ b/include/mysql/plugin_password_validation.h.pp @@ -388,33 +388,33 @@ enum json_types }; extern struct json_service_st { enum json_types (*json_type)(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_array_item)(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_object_key)(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int (*json_escape_string)(const char *str,const char *str_end, char *json, char *json_end); int (*json_unescape_json)(const char *json_str, const char *json_end, char *res, char *res_end); } *json_service; enum json_types json_type(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_object_key(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int json_escape_string(const char *str,const char *str_end, char *json, char *json_end); int json_unescape_json(const char *json_str, const char *json_end, diff --git a/include/mysql/service_json.h b/include/mysql/service_json.h index 2044172..734787a 100644 --- a/include/mysql/service_json.h +++ b/include/mysql/service_json.h @@ -61,17 +61,17 @@ enum json_types extern struct json_service_st { enum json_types (*json_type)(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_array_item)(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types (*json_get_object_key)(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int (*json_escape_string)(const char *str,const char *str_end, char *json, char *json_end); int (*json_unescape_json)(const char *json_str, const char *json_end, @@ -90,16 +90,16 @@ extern struct json_service_st { #else enum json_types json_type(const char *js, const char *js_end, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, - const char **v, int *vlen); + const char **value, int *value_len); enum json_types json_get_object_key(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen); + const char *key, const char *key_end, + const char **value, int *value_len); enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, - const char **v, int *vlen); + const char **value, int *value_len); int json_escape_string(const char *str,const char *str_end, char *json, char *json_end); int json_unescape_json(const char *json_str, const char *json_end, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b2840c3..61d6812 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1291,20 +1291,23 @@ class User_table_json: public User_table return 0; } bool get_value(const char *key, size_t klen, - enum json_value_types vt, const char **v, size_t *vl) const + enum json_types vt, const char **v, size_t *vl) const { - enum json_value_types value_type; + enum json_types value_type; + int int_vl; String str, *res= m_table->field[2]->val_str(&str); - if (!res || json_get_object_by_key(res->ptr(), res->length(), key, klen, - &value_type, v, vl)) + if (!res || + (value_type= json_get_object_key(res->ptr(), res->end(), + key, key+klen, v, &int_vl)) == JSV_BAD_JSON) return 1; // invalid + *vl= int_vl; return value_type != vt; } const char *get_str_value(MEM_ROOT *root, const char *key, size_t klen) const { size_t value_len; const char *value_start; - if (get_value(key, klen, JSON_VALUE_STRING, &value_start, &value_len)) + if (get_value(key, klen, JSV_STRING, &value_start, &value_len)) return ""; char *ptr= (char*)alloca(value_len); int len= json_unescape(m_table->field[2]->charset(), @@ -1321,7 +1324,7 @@ class User_table_json: public User_table int err; size_t value_len; const char *value_start; - if (get_value(key, klen, JSON_VALUE_NUMBER, &value_start, &value_len)) + if (get_value(key, klen, JSV_NUMBER, &value_start, &value_len)) return 0; const char *value_end= value_start + value_len; return my_strtoll10(value_start, (char**)&value_end, &err); @@ -1331,7 +1334,7 @@ class User_table_json: public User_table int err; size_t value_len; const char *value_start; - if (get_value(key, klen, JSON_VALUE_NUMBER, &value_start, &value_len)) + if (get_value(key, klen, JSV_NUMBER, &value_start, &value_len)) return 0; const char *value_end= value_start + value_len; return my_strtod(value_start, (char**)&value_end, &err); @@ -1340,25 +1343,26 @@ class User_table_json: public User_table { size_t value_len; const char *value_start; - if (get_value(key, klen, JSON_VALUE_TRUE, &value_start, &value_len)) + if (get_value(key, klen, JSV_TRUE, &value_start, &value_len)) return false; return true; } bool set_value(const char *key, size_t klen, const char *val, size_t vlen, bool string) const { - size_t value_len; + int value_len; const char *value_start; - enum json_value_types value_type; + enum json_types value_type; String str, *res= m_table->field[2]->val_str(&str); if (!res || !res->length()) (res= &str)->set(STRING_WITH_LEN("{}"), m_table->field[2]->charset()); - if (json_get_object_by_key(res->ptr(), res->length(), key, klen, - &value_type, &value_start, &value_len)) + value_type= json_get_object_key(res->ptr(), res->end(), key, key+klen, + &value_start, &value_len); + if (value_type == JSV_BAD_JSON) return 1; // invalid StringBuffer<JSON_SIZE> json(res->charset()); json.copy(res->ptr(), value_start - res->ptr(), res->charset()); - if (!value_type) + if (value_type == JSV_NOTHING) { if (value_len) json.append(','); diff --git a/strings/json_lib.c b/strings/json_lib.c index bc93601..8930581 100644 --- a/strings/json_lib.c +++ b/strings/json_lib.c @@ -1847,57 +1847,104 @@ int json_path_compare(const json_path_t *a, const json_path_t *b, } +static enum json_types smart_read_value(json_engine_t *je, + const char **value, int *value_len) +{ + if (json_read_value(je)) + goto err_return; + + *value= (char *) je->value; + + if (json_value_scalar(je)) + *value_len= je->value_len; + else + { + if (json_skip_level(je)) + goto err_return; + + *value_len= (char *) je->s.c_str - *value; + } + + return je->value_type; + +err_return: + return JSV_BAD_JSON; +} + + enum json_types json_type(const char *js, const char *js_end, - const char **v, int *vlen) + const char **value, int *value_len) { - return JSV_NOTHING; + json_engine_t je; + + json_scan_start(&je, &my_charset_utf8mb4_bin,(const uchar *) js, + (const uchar *) js_end); + + return smart_read_value(&je, value, value_len); } enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, - const char **v, int *vlen) + const char **value, int *value_len) { - return JSV_NOTHING; -} + json_engine_t je; + int c_item= 0; + json_scan_start(&je, &my_charset_utf8mb4_bin,(const uchar *) js, + (const uchar *) js_end); -enum json_types json_get_object_key(const char *js, const char *js_end, - const char *key, - const char **v, int *vlen) -{ - return JSV_NOTHING; -} + if (json_read_value(&je) || + je.value_type != JSON_VALUE_ARRAY) + goto err_return; + while (!json_scan_next(&je)) + { + switch (je.state) + { + case JST_VALUE: + if (c_item == n_item) + return smart_read_value(&je, value, value_len); -enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey, - const char **keyname, const char **keyname_end, - const char **v, int *vlen) -{ - return JSV_NOTHING; + if (json_skip_key(&je)) + goto err_return; + + c_item++; + break; + + case JST_ARRAY_END: + *value= (const char *) (je.s.c_str - je.sav_c_len); + *value_len= c_item; + return JSV_NOTHING; + } + } + +err_return: + return JSV_BAD_JSON; } + /** Simple json lookup for a value by the key. - Only supports flat json objects. - Does not look inside nested objects. - Does not process complex path expressions. + Expects JSON object. + Only scans the 'first level' of the object, not + the nested structures. - @param js [in] json to search in - @param js_len [in] - " - + @param js [in] json object to search in + @param js_end [in] end of json string @param key [in] key to search for - @param key_len [in] - " - - @param value_type [out] type of the value found or 0 if not found + @param key_end [in] - " - @param value_start [out] pointer into js (value or closing }) @param value_len [out] length of the value found or number of keys - @retval 0 - success - @retval 1 - error (invalid json) + @retval the type of the key value + @retval JSV_BAD_JSON - syntax error found reading JSON. + or not JSON object. + @retval JSV_NOTHING - no such key found. */ -int json_get_object_by_key(const char *js, size_t js_len, - const char *key, size_t key_len, - enum json_value_types *value_type, - const char **value_start, size_t *value_len) +enum json_types json_get_object_key(const char *js, const char *js_end, + const char *key, const char *key_end, + const char **value, int *value_len) { json_engine_t je; json_string_t key_name; @@ -1906,7 +1953,7 @@ int json_get_object_by_key(const char *js, size_t js_len, json_string_set_cs(&key_name, &my_charset_utf8mb4_bin); json_scan_start(&je, &my_charset_utf8mb4_bin,(const uchar *) js, - (const uchar *) js + js_len); + (const uchar *) js_end); if (json_read_value(&je) || je.value_type != JSON_VALUE_OBJECT) @@ -1919,35 +1966,35 @@ int json_get_object_by_key(const char *js, size_t js_len, case JST_KEY: n_keys++; json_string_set_str(&key_name, (const uchar *) key, - (const uchar *) key + key_len); - if (!json_key_matches(&je, &key_name)) - { - if (json_skip_key(&je)) - goto err_return; - } - else - { - if (json_read_value(&je)) - goto err_return; - *value_type= je.value_type; - *value_start= (const char *) je.value; - *value_len= je.value_len; - return 0; - } + (const uchar *) key_end); + if (json_key_matches(&je, &key_name)) + return smart_read_value(&je, value, value_len); + + if (json_skip_key(&je)) + goto err_return; + break; case JST_OBJ_END: - *value_type= (enum json_value_types) 0; - *value_start= (const char *) (je.s.c_str - je.sav_c_len); + *value= (const char *) (je.s.c_str - je.sav_c_len); *value_len= n_keys; - return 0; + return JSV_NOTHING; } } err_return: - return 1; + return JSV_BAD_JSON; } + +enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey, + const char **keyname, const char **keyname_end, + const char **value, int *value_len) +{ + return JSV_NOTHING; +} + + /** Check if json is valid (well-formed) @retval 0 - success, json is well-formed diff --git a/unittest/strings/CMakeLists.txt b/unittest/strings/CMakeLists.txt index 2457475..0896e13 100644 --- a/unittest/strings/CMakeLists.txt +++ b/unittest/strings/CMakeLists.txt @@ -1,3 +1,3 @@ -MY_ADD_TESTS(strings LINK_LIBRARIES strings mysys) +MY_ADD_TESTS(strings json LINK_LIBRARIES strings mysys)