revision-id: cc18a5db9bce667c9b8722cdf6f51ee83b55a4b0 (mariadb-10.4.1-98-gcc18a5d) parent(s): dd03cb3776e6d25dc1dd2c3a83473a1b78ae99f9 committer: Alexey Botchkov timestamp: 2019-01-18 03:18:02 +0400 message: MDEV-5313 Improving audit API. json_locate_key() implemented. get rid of 'key_len' argument in functions. --- include/json_lib.h | 5 ++ include/mysql/plugin_audit.h.pp | 4 +- include/mysql/plugin_auth.h.pp | 4 +- include/mysql/plugin_encryption.h.pp | 4 +- include/mysql/plugin_ftparser.h.pp | 4 +- include/mysql/plugin_password_validation.h.pp | 4 +- include/mysql/service_json.h | 4 +- sql/sql_acl.cc | 100 +++++++++++++------------- strings/json_lib.c | 94 +++++++++++++++++++++++- unittest/strings/json-t.c | 28 +++++++- 10 files changed, 185 insertions(+), 66 deletions(-) diff --git a/include/json_lib.h b/include/json_lib.h index a347538..b6add6d 100644 --- a/include/json_lib.h +++ b/include/json_lib.h @@ -425,6 +425,11 @@ 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_locate_key(const char *js, const char *js_end, + const char *kname, + const char **key_start, const char **key_end, + int *comma_pos); + #ifdef __cplusplus } #endif diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 47f07ae..c5ae678 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -393,7 +393,7 @@ extern struct json_service_st { int n_item, 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 *key_end, + const char *key, const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, @@ -410,7 +410,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, 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 *key_end, + const char *key, 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, diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index f9d01a8..41cb7d07 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -393,7 +393,7 @@ extern struct json_service_st { int n_item, 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 *key_end, + const char *key, const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, @@ -410,7 +410,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, 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 *key_end, + const char *key, 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, diff --git a/include/mysql/plugin_encryption.h.pp b/include/mysql/plugin_encryption.h.pp index e55a034..6597dec 100644 --- a/include/mysql/plugin_encryption.h.pp +++ b/include/mysql/plugin_encryption.h.pp @@ -393,7 +393,7 @@ extern struct json_service_st { int n_item, 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 *key_end, + const char *key, const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, @@ -410,7 +410,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, 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 *key_end, + const char *key, 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, diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index f9d9844..bd1cfc7 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -393,7 +393,7 @@ extern struct json_service_st { int n_item, 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 *key_end, + const char *key, const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, @@ -410,7 +410,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, 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 *key_end, + const char *key, 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, diff --git a/include/mysql/plugin_password_validation.h.pp b/include/mysql/plugin_password_validation.h.pp index b672db6..2f9d229 100644 --- a/include/mysql/plugin_password_validation.h.pp +++ b/include/mysql/plugin_password_validation.h.pp @@ -393,7 +393,7 @@ extern struct json_service_st { int n_item, 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 *key_end, + const char *key, const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, @@ -410,7 +410,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, 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 *key_end, + const char *key, 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, diff --git a/include/mysql/service_json.h b/include/mysql/service_json.h index 734787a..141b762 100644 --- a/include/mysql/service_json.h +++ b/include/mysql/service_json.h @@ -66,7 +66,7 @@ extern struct json_service_st { int n_item, 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 *key_end, + const char *key, const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, @@ -95,7 +95,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, 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 *key_end, + const char *key, 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, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 61d6812..bb5a397 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1204,16 +1204,16 @@ class User_table_json: public User_table int get_auth(THD *thd, MEM_ROOT *root, const char **plugin, const char **authstr) const { - *plugin= get_str_value(root, STRING_WITH_LEN("plugin")); + *plugin= get_str_value(root, "plugin"); if (!**plugin) *plugin= native_password_plugin_name.str; - *authstr= get_str_value(root, STRING_WITH_LEN("authentication_string")); + *authstr= get_str_value(root, "authentication_string"); return *plugin == NULL || *authstr == NULL; } void set_auth(const char *p, size_t pl, const char *as, size_t asl) const { - set_str_value(STRING_WITH_LEN("plugin"), p, pl); - set_str_value(STRING_WITH_LEN("authentication_string"), as, asl); + set_str_value("plugin", p, pl); + set_str_value("authentication_string", as, asl); } ulong get_access() const { @@ -1222,7 +1222,7 @@ class User_table_json: public User_table (or, for example, my_count_bits(GLOBAL_ACLS)) in the json too, and it'll allow us to do privilege upgrades */ - return get_int_value(STRING_WITH_LEN("access")) & GLOBAL_ACLS; + return get_int_value("access") & GLOBAL_ACLS; } void set_access(ulong rights, bool revoke) const { @@ -1231,53 +1231,53 @@ class User_table_json: public User_table access&= ~rights; else access|= rights; - set_int_value(STRING_WITH_LEN("access"), access & GLOBAL_ACLS); + set_int_value("access", access & GLOBAL_ACLS); } SSL_type get_ssl_type () const - { return (SSL_type)get_int_value(STRING_WITH_LEN("ssl_type")); } + { return (SSL_type)get_int_value("ssl_type"); } int set_ssl_type (SSL_type x) const - { return set_int_value(STRING_WITH_LEN("ssl_type"), x); } + { return set_int_value("ssl_type", x); } const char* get_ssl_cipher (MEM_ROOT *root) const - { return get_str_value(root, STRING_WITH_LEN("ssl_cipher")); } + { return get_str_value(root, "ssl_cipher"); } int set_ssl_cipher (const char *s, size_t l) const - { return set_str_value(STRING_WITH_LEN("ssl_cipher"), s, l); } + { return set_str_value("ssl_cipher", s, l); } const char* get_x509_issuer (MEM_ROOT *root) const - { return get_str_value(root, STRING_WITH_LEN("x509_issuer")); } + { return get_str_value(root, "x509_issuer"); } int set_x509_issuer (const char *s, size_t l) const - { return set_str_value(STRING_WITH_LEN("x509_issuer"), s, l); } + { return set_str_value("x509_issuer", s, l); } const char* get_x509_subject (MEM_ROOT *root) const - { return get_str_value(root, STRING_WITH_LEN("x509_subject")); } + { return get_str_value(root, "x509_subject"); } int set_x509_subject (const char *s, size_t l) const - { return set_str_value(STRING_WITH_LEN("x509_subject"), s, l); } + { return set_str_value("x509_subject", s, l); } longlong get_max_questions () const - { return get_int_value(STRING_WITH_LEN("max_questions")); } + { return get_int_value("max_questions"); } int set_max_questions (longlong x) const - { return set_int_value(STRING_WITH_LEN("max_questions"), x); } + { return set_int_value("max_questions", x); } longlong get_max_updates () const - { return get_int_value(STRING_WITH_LEN("max_updates")); } + { return get_int_value("max_updates"); } int set_max_updates (longlong x) const - { return set_int_value(STRING_WITH_LEN("max_updates"), x); } + { return set_int_value("max_updates", x); } longlong get_max_connections () const - { return get_int_value(STRING_WITH_LEN("max_connections")); } + { return get_int_value("max_connections"); } int set_max_connections (longlong x) const - { return set_int_value(STRING_WITH_LEN("max_connections"), x); } + { return set_int_value("max_connections", x); } longlong get_max_user_connections () const - { return get_int_value(STRING_WITH_LEN("max_user_connections")); } + { return get_int_value("max_user_connections"); } int set_max_user_connections (longlong x) const - { return set_int_value(STRING_WITH_LEN("max_user_connections"), x); } + { return set_int_value("max_user_connections", x); } double get_max_statement_time () const - { return get_double_value(STRING_WITH_LEN("max_statement_time")); } + { return get_double_value("max_statement_time"); } int set_max_statement_time (double x) const - { return set_double_value(STRING_WITH_LEN("max_statement_time"), x); } + { return set_double_value("max_statement_time", x); } bool get_is_role () const - { return get_bool_value(STRING_WITH_LEN("is_role")); } + { return get_bool_value("is_role"); } int set_is_role (bool x) const - { return set_bool_value(STRING_WITH_LEN("is_role"), x); } + { return set_bool_value("is_role", x); } const char* get_default_role (MEM_ROOT *root) const - { return get_str_value(root, STRING_WITH_LEN("default_role")); } + { return get_str_value(root, "default_role"); } int set_default_role (const char *s, size_t l) const - { return set_str_value(STRING_WITH_LEN("default_role"), s, l); } + { return set_str_value("default_role", s, l); } ~User_table_json() {} private: @@ -1290,24 +1290,24 @@ class User_table_json: public User_table USERNAME_CHAR_LENGTH); return 0; } - bool get_value(const char *key, size_t klen, + bool get_value(const char *key, enum json_types vt, const char **v, size_t *vl) const { enum json_types value_type; int int_vl; String str, *res= m_table->field[2]->val_str(&str); if (!res || - (value_type= json_get_object_key(res->ptr(), res->end(), - key, key+klen, v, &int_vl)) == JSV_BAD_JSON) + (value_type= json_get_object_key(res->ptr(), res->end(), key, + 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 + const char *get_str_value(MEM_ROOT *root, const char *key) const { size_t value_len; const char *value_start; - if (get_value(key, klen, JSV_STRING, &value_start, &value_len)) + if (get_value(key, JSV_STRING, &value_start, &value_len)) return ""; char *ptr= (char*)alloca(value_len); int len= json_unescape(m_table->field[2]->charset(), @@ -1319,35 +1319,35 @@ class User_table_json: public User_table return NULL; return strmake_root(root, ptr, len); } - longlong get_int_value(const char *key, size_t klen) const + longlong get_int_value(const char *key) const { int err; size_t value_len; const char *value_start; - if (get_value(key, klen, JSV_NUMBER, &value_start, &value_len)) + if (get_value(key, 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); } - double get_double_value(const char *key, size_t klen) const + double get_double_value(const char *key) const { int err; size_t value_len; const char *value_start; - if (get_value(key, klen, JSV_NUMBER, &value_start, &value_len)) + if (get_value(key, 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); } - bool get_bool_value(const char *key, size_t klen) const + bool get_bool_value(const char *key) const { size_t value_len; const char *value_start; - if (get_value(key, klen, JSV_TRUE, &value_start, &value_len)) + if (get_value(key, JSV_TRUE, &value_start, &value_len)) return false; return true; } - bool set_value(const char *key, size_t klen, + bool set_value(const char *key, const char *val, size_t vlen, bool string) const { int value_len; @@ -1356,7 +1356,7 @@ class User_table_json: public User_table 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()); - value_type= json_get_object_key(res->ptr(), res->end(), key, key+klen, + value_type= json_get_object_key(res->ptr(), res->end(), key, &value_start, &value_len); if (value_type == JSV_BAD_JSON) return 1; // invalid @@ -1367,7 +1367,7 @@ class User_table_json: public User_table if (value_len) json.append(','); json.append('"'); - json.append(key, klen); + json.append(STRING_WITH_LEN(key)); json.append(STRING_WITH_LEN("\":")); if (string) json.append('"'); @@ -1382,7 +1382,7 @@ class User_table_json: public User_table m_table->field[2]->store(json.ptr(), json.length(), json.charset()); return 0; } - bool set_str_value(const char *key, size_t klen, const char *val, size_t vlen) const + bool set_str_value(const char *key, const char *val, size_t vlen) const { char buf[JSON_SIZE]; int blen= json_escape(system_charset_info, @@ -1391,22 +1391,22 @@ class User_table_json: public User_table (uchar*)buf, (uchar*)buf+sizeof(buf)); if (blen < 0) return 1; - return set_value(key, klen, buf, blen, true); + return set_value(key, buf, blen, true); } - bool set_int_value(const char *key, size_t klen, longlong val) const + bool set_int_value(const char *key, longlong val) const { char v[MY_INT64_NUM_DECIMAL_DIGITS+1]; size_t vlen= longlong10_to_str(val, v, -10) - v; - return set_value(key, klen, v, vlen, false); + return set_value(key, v, vlen, false); } - bool set_double_value(const char *key, size_t klen, double val) const + bool set_double_value(const char *key, double val) const { char v[FLOATING_POINT_BUFFER+1]; size_t vlen= my_fcvt(val, TIME_SECOND_PART_DIGITS, v, NULL); - return set_value(key, klen, v, vlen, false); + return set_value(key, v, vlen, false); } - bool set_bool_value(const char *key, size_t klen, bool val) const - { return set_value(key, klen, val ? "true" : "false", val ? 4 : 5, false); } + bool set_bool_value(const char *key, bool val) const + { return set_value(key, val ? "true" : "false", val ? 4 : 5, false); } }; class Db_table: public Grant_table_base diff --git a/strings/json_lib.c b/strings/json_lib.c index e28ec3c..6c94ce2 100644 --- a/strings/json_lib.c +++ b/strings/json_lib.c @@ -1943,9 +1943,10 @@ enum json_types json_get_array_item(const char *js, const char *js_end, @retval JSV_NOTHING - no such key found. */ enum json_types json_get_object_key(const char *js, const char *js_end, - const char *key, const char *key_end, + const char *key, const char **value, int *value_len) { + const char *key_end= key + strlen(key); json_engine_t je; json_string_t key_name; int n_keys= 0; @@ -1999,10 +2000,99 @@ enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey @retval 0 - success, json is well-formed @retval 1 - error, json is invalid -*/int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs) +*/ +int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs) { json_engine_t je; json_scan_start(&je, cs, (const uchar *) js, (const uchar *) js + js_len); while (json_scan_next(&je) == 0) /* no-op */ ; return je.s.error == 0; } + + +/* + Expects the JSON object as an js argument, and the key name. + Looks for this key in the object and returns + the location of all the text related to it. + The text includes the comma, separating this key. + + comma_pos - the hint where the comma is. It is important + if you plan to replace the key rather than just cut. + 1 - comma is on the left + 2 - comma is on the right. + 0 - no comma at all (the object has just this single key) + + if no such key found *key_start is set to NULL. +*/ +int json_locate_key(const char *js, const char *js_end, + const char *kname, + const char **key_start, const char **key_end, + int *comma_pos) +{ + const char *kname_end= kname + strlen(kname); + json_engine_t je; + json_string_t key_name; + int t_next, c_len, match_result; + + json_string_set_cs(&key_name, &my_charset_utf8mb4_bin); + + json_scan_start(&je, &my_charset_utf8mb4_bin,(const uchar *) js, + (const uchar *) js_end); + + if (json_read_value(&je) || + je.value_type != JSON_VALUE_OBJECT) + goto err_return; + + *key_start= (const char *) je.s.c_str; + *comma_pos= 0; + + while (!json_scan_next(&je)) + { + switch (je.state) + { + case JST_KEY: + json_string_set_str(&key_name, (const uchar *) kname, + (const uchar *) kname_end); + match_result= json_key_matches(&je, &key_name); + if (json_skip_key(&je)) + goto err_return; + get_first_nonspace(&je.s, &t_next, &c_len); + je.s.c_str-= c_len; + + if (match_result) + { + *key_end= (const char *) je.s.c_str; + + if (*comma_pos == 1) + return 0; + + DBUG_ASSERT(*comma_pos == 0); + + if (t_next == C_COMMA) + { + *key_end+= c_len; + *comma_pos= 2; + } + else if (t_next == C_RCURB) + *comma_pos= 0; + else + goto err_return; + return 0; + } + + *key_start= (const char *) je.s.c_str; + *comma_pos= 1; + break; + + case JST_OBJ_END: + *key_start= NULL; + return 0; + } + } + +err_return: + return 1; + +} + + diff --git a/unittest/strings/json-t.c b/unittest/strings/json-t.c index 8af8636..ce0f04d 100644 --- a/unittest/strings/json-t.c +++ b/unittest/strings/json-t.c @@ -17,21 +17,29 @@ #include <my_sys.h> #include <json_lib.h> +int json_locate_key(const char *js, const char *js_end, const char *kname, + const char **key_start, const char **key_end, + int *comma_pos); int main() { const char *json="{\"int\":1, \"str\":\"foo bar\", " "\"array\":[10,20,{\"c\":\"d\"}],\"bool\":false}"; const char *json_ar="[1, \"foo bar\", " "[10,20,{\"c\":\"d\"}], false]"; + const char *json_w="{\"int\" : 1 , \"str\" : \"foo bar\" , " + "\"array\" : [10,20,{\"c\":\"d\"}] , \"bool\" : false }"; + const char *json_1="{ \"str\" : \"foo bar\" }"; enum json_types value_type; const char *value_start; int value_len; + const char *key_start, *key_end; + int result, comma_pos; - plan(10); + plan(15); #define do_json(V) \ do { \ value_type= json_get_object_key(json, json+strlen(json), \ - V, V + (sizeof(V) - 1),&value_start, &value_len); \ + V, &value_start, &value_len); \ ok(value_type != JSV_BAD_JSON, V); \ diag("type=%d, value=\"%.*s\"", value_type, (int)value_len, value_start); \ } while(0) @@ -42,6 +50,16 @@ int main() ok(value_type != JSV_BAD_JSON, #N); \ diag("type=%d, value=\"%.*s\"", value_type, (int)value_len, value_start); \ } while(0) +#define do_json_locate(J, V) \ + do { \ + result= json_locate_key(J, J+strlen(J), \ + V, &key_start, &key_end, &comma_pos); \ + ok(result == 0, V); \ + if (key_start) \ + diag("key_str=\"%.*s\" comma_pos= %d", (int)(key_end - key_start), key_start, comma_pos); \ + else \ + diag("no key found"); \ + } while(0) do_json("int"); do_json("str"); @@ -54,5 +72,11 @@ int main() do_json_ar(2); do_json_ar(3); do_json_ar(4); + + do_json_locate(json_w, "bool"); + do_json_locate(json_w, "int"); + do_json_locate(json_w, "array"); + do_json_locate(json_1, "str"); + do_json_locate(json_w, "c"); return exit_status(); }