diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2015-12-27 15:12:28 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2015-12-27 15:12:28 +0000 |
commit | 2275d0b9ebeda6a1edffb3f1f38d3b3af7c9c8a3 (patch) | |
tree | 31435c51aa1e9f6b7f79b5d272f367c3ef134e3a /contrib | |
parent | 4ce549ad001660aaf60b3804921a70f2bd8c503a (diff) | |
download | rspamd-2275d0b9ebeda6a1edffb3f1f38d3b3af7c9c8a3.tar.gz rspamd-2275d0b9ebeda6a1edffb3f1f38d3b3af7c9c8a3.zip |
Sync with libucl
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/libucl/ucl.h | 49 | ||||
-rw-r--r-- | contrib/libucl/ucl_schema.c | 277 | ||||
-rw-r--r-- | contrib/libucl/ucl_util.c | 90 |
3 files changed, 297 insertions, 119 deletions
diff --git a/contrib/libucl/ucl.h b/contrib/libucl/ucl.h index 82a1fd188..cfe62c081 100644 --- a/contrib/libucl/ucl.h +++ b/contrib/libucl/ucl.h @@ -306,6 +306,21 @@ UCL_EXTERN ucl_object_t * ucl_object_copy (const ucl_object_t *other) UCL_EXTERN ucl_type_t ucl_object_type (const ucl_object_t *obj); /** + * Converts ucl object type to its string representation + * @param type type of object + * @return constant string describing type + */ +UCL_EXTERN const char * ucl_object_type_to_string (ucl_type_t type); + +/** + * Converts string that represents ucl type to real ucl type enum + * @param input C string with name of type + * @param res resulting target + * @return true if `input` is a name of type stored in `res` + */ +UCL_EXTERN bool ucl_object_string_to_type (const char *input, ucl_type_t *res); + +/** * Convert any string to an ucl object making the specified transformations * @param str fixed size or NULL terminated string * @param len length (if len is zero, than str is treated as NULL terminated) @@ -1280,6 +1295,9 @@ enum ucl_schema_error_code { UCL_SCHEMA_MISSING_PROPERTY,/**< one or more missing properties */ UCL_SCHEMA_CONSTRAINT, /**< constraint found */ UCL_SCHEMA_MISSING_DEPENDENCY, /**< missing dependency */ + UCL_SCHEMA_EXTERNAL_REF_MISSING, /**< cannot fetch external ref */ + UCL_SCHEMA_EXTERNAL_REF_INVALID, /**< invalid external ref */ + UCL_SCHEMA_INTERNAL_ERROR, /**< something bad happened */ UCL_SCHEMA_UNKNOWN /**< generic error */ }; @@ -1303,6 +1321,37 @@ struct ucl_schema_error { UCL_EXTERN bool ucl_object_validate (const ucl_object_t *schema, const ucl_object_t *obj, struct ucl_schema_error *err); +/** + * Validate object `obj` using schema object `schema` and root schema at `root`. + * @param schema schema object + * @param obj object to validate + * @param root root schema object + * @param err error pointer, if this parameter is not NULL and error has been + * occured, then `err` is filled with the exact error definition. + * @return true if `obj` is valid using `schema` + */ +UCL_EXTERN bool ucl_object_validate_root (const ucl_object_t *schema, + const ucl_object_t *obj, + const ucl_object_t *root, + struct ucl_schema_error *err); + +/** + * Validate object `obj` using schema object `schema` and root schema at `root` + * using some external references provided. + * @param schema schema object + * @param obj object to validate + * @param root root schema object + * @param ext_refs external references (might be modified during validation) + * @param err error pointer, if this parameter is not NULL and error has been + * occured, then `err` is filled with the exact error definition. + * @return true if `obj` is valid using `schema` + */ +UCL_EXTERN bool ucl_object_validate_root_ext (const ucl_object_t *schema, + const ucl_object_t *obj, + const ucl_object_t *root, + ucl_object_t *ext_refs, + struct ucl_schema_error *err); + /** @} */ #ifdef __cplusplus diff --git a/contrib/libucl/ucl_schema.c b/contrib/libucl/ucl_schema.c index 834b62acc..9b96da5ef 100644 --- a/contrib/libucl/ucl_schema.c +++ b/contrib/libucl/ucl_schema.c @@ -43,72 +43,8 @@ static bool ucl_schema_validate (const ucl_object_t *schema, const ucl_object_t *obj, bool try_array, struct ucl_schema_error *err, - const ucl_object_t *root); - -static bool -ucl_string_to_type (const char *input, ucl_type_t *res) -{ - if (strcasecmp (input, "object") == 0) { - *res = UCL_OBJECT; - } - else if (strcasecmp (input, "array") == 0) { - *res = UCL_ARRAY; - } - else if (strcasecmp (input, "integer") == 0) { - *res = UCL_INT; - } - else if (strcasecmp (input, "number") == 0) { - *res = UCL_FLOAT; - } - else if (strcasecmp (input, "string") == 0) { - *res = UCL_STRING; - } - else if (strcasecmp (input, "boolean") == 0) { - *res = UCL_BOOLEAN; - } - else if (strcasecmp (input, "null") == 0) { - *res = UCL_NULL; - } - else { - return false; - } - - return true; -} - -static const char * -ucl_object_type_to_string (ucl_type_t type) -{ - const char *res = "unknown"; - - switch (type) { - case UCL_OBJECT: - res = "object"; - break; - case UCL_ARRAY: - res = "array"; - break; - case UCL_INT: - res = "integer"; - break; - case UCL_FLOAT: - case UCL_TIME: - res = "number"; - break; - case UCL_STRING: - res = "string"; - break; - case UCL_BOOLEAN: - res = "boolean"; - break; - case UCL_NULL: - case UCL_USERDATA: - res = "null"; - break; - } - - return res; -} + const ucl_object_t *root, + ucl_object_t *ext_ref); /* * Create validation error @@ -160,7 +96,8 @@ ucl_schema_test_pattern (const ucl_object_t *obj, const char *pattern) static bool ucl_schema_validate_dependencies (const ucl_object_t *deps, const ucl_object_t *obj, struct ucl_schema_error *err, - const ucl_object_t *root) + const ucl_object_t *root, + ucl_object_t *ext_ref) { const ucl_object_t *elt, *cur, *cur_dep; ucl_object_iter_t iter = NULL, piter; @@ -183,7 +120,7 @@ ucl_schema_validate_dependencies (const ucl_object_t *deps, } } else if (cur->type == UCL_OBJECT) { - ret = ucl_schema_validate (cur, obj, true, err, root); + ret = ucl_schema_validate (cur, obj, true, err, root, ext_ref); } } } @@ -197,7 +134,8 @@ ucl_schema_validate_dependencies (const ucl_object_t *deps, static bool ucl_schema_validate_object (const ucl_object_t *schema, const ucl_object_t *obj, struct ucl_schema_error *err, - const ucl_object_t *root) + const ucl_object_t *root, + ucl_object_t *ext_ref) { const ucl_object_t *elt, *prop, *found, *additional_schema = NULL, *required = NULL, *pat, *pelt; @@ -212,7 +150,8 @@ ucl_schema_validate_object (const ucl_object_t *schema, while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) { found = ucl_object_find_key (obj, ucl_object_key (prop)); if (found) { - ret = ucl_schema_validate (prop, found, true, err, root); + ret = ucl_schema_validate (prop, found, true, err, root, + ext_ref); } } } @@ -270,13 +209,15 @@ ucl_schema_validate_object (const ucl_object_t *schema, while (ret && (prop = ucl_iterate_object (elt, &piter, true)) != NULL) { found = ucl_schema_test_pattern (obj, ucl_object_key (prop)); if (found) { - ret = ucl_schema_validate (prop, found, true, err, root); + ret = ucl_schema_validate (prop, found, true, err, root, + ext_ref); } } } else if (elt->type == UCL_OBJECT && strcmp (ucl_object_key (elt), "dependencies") == 0) { - ret = ucl_schema_validate_dependencies (elt, obj, err, root); + ret = ucl_schema_validate_dependencies (elt, obj, err, root, + ext_ref); } } @@ -308,7 +249,8 @@ ucl_schema_validate_object (const ucl_object_t *schema, break; } else if (additional_schema != NULL) { - if (!ucl_schema_validate (additional_schema, elt, true, err, root)) { + if (!ucl_schema_validate (additional_schema, elt, + true, err, root, ext_ref)) { ret = false; break; } @@ -518,7 +460,8 @@ ucl_schema_array_is_unique (const ucl_object_t *obj, struct ucl_schema_error *er static bool ucl_schema_validate_array (const ucl_object_t *schema, const ucl_object_t *obj, struct ucl_schema_error *err, - const ucl_object_t *root) + const ucl_object_t *root, + ucl_object_t *ext_ref) { const ucl_object_t *elt, *it, *found, *additional_schema = NULL, *first_unvalidated = NULL; @@ -533,7 +476,8 @@ ucl_schema_validate_array (const ucl_object_t *schema, found = ucl_array_head (obj); while (ret && (it = ucl_iterate_object (elt, &piter, true)) != NULL) { if (found) { - ret = ucl_schema_validate (it, found, false, err, root); + ret = ucl_schema_validate (it, found, false, err, + root, ext_ref); found = ucl_array_find_index (obj, ++idx); } } @@ -545,7 +489,8 @@ ucl_schema_validate_array (const ucl_object_t *schema, else if (elt->type == UCL_OBJECT) { /* Validate all items using the specified schema */ while (ret && (it = ucl_iterate_object (obj, &piter, true)) != NULL) { - ret = ucl_schema_validate (elt, it, false, err, root); + ret = ucl_schema_validate (elt, it, false, err, root, + ext_ref); } } else { @@ -612,7 +557,7 @@ ucl_schema_validate_array (const ucl_object_t *schema, elt = ucl_array_find_index (obj, idx); while (elt) { if (!ucl_schema_validate (additional_schema, elt, false, - err, root)) { + err, root, ext_ref)) { ret = false; break; } @@ -657,7 +602,7 @@ ucl_schema_type_is_allowed (const ucl_object_t *type, const ucl_object_t *obj, } else if (type->type == UCL_STRING) { type_str = ucl_object_tostring (type); - if (!ucl_string_to_type (type_str, &t)) { + if (!ucl_object_string_to_type (type_str, &t)) { ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, type, "Type attribute is invalid in schema"); return false; @@ -771,31 +716,109 @@ ucl_schema_resolve_ref_component (const ucl_object_t *cur, */ static const ucl_object_t * ucl_schema_resolve_ref (const ucl_object_t *root, const char *ref, - struct ucl_schema_error *err) + struct ucl_schema_error *err, ucl_object_t *ext_ref, + ucl_object_t const ** nroot) { - const char *p, *c; - const ucl_object_t *res = NULL; - + UT_string *url_err = NULL; + struct ucl_parser *parser; + const ucl_object_t *res = NULL, *ext_obj = NULL; + ucl_object_t *url_obj; + const char *p, *c, *hash_ptr = NULL; + char *url_copy = NULL; + unsigned char *url_buf; + size_t url_buflen; if (ref[0] != '#') { - ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root, - "reference %s is invalid, not started with #", ref); - return NULL; + hash_ptr = strrchr (ref, '#'); + + if (hash_ptr) { + url_copy = malloc (hash_ptr - ref + 1); + + if (url_copy == NULL) { + ucl_schema_create_error (err, UCL_SCHEMA_INTERNAL_ERROR, root, + "cannot allocate memory"); + return NULL; + } + + ucl_strlcpy (url_copy, ref, hash_ptr - ref + 1); + p = url_copy; + } + else { + /* Full URL */ + p = ref; + } + + ext_obj = ucl_object_find_key (ext_ref, p); + + if (ext_obj == NULL) { + if (ucl_strnstr (p, "://", strlen (p)) != NULL) { + if (!ucl_fetch_url (p, &url_buf, &url_buflen, &url_err, true)) { + free (url_copy); + ucl_schema_create_error (err, + UCL_SCHEMA_INVALID_SCHEMA, + root, + "cannot fetch reference %s: %s", + p, + url_err != NULL ? utstring_body (url_err) + : "unknown"); + return NULL; + } + } + else { + if (!ucl_fetch_file (p, &url_buf, &url_buflen, &url_err, + true)) { + free (url_copy); + ucl_schema_create_error (err, + UCL_SCHEMA_INVALID_SCHEMA, + root, + "cannot fetch reference %s: %s", + p, + url_err != NULL ? utstring_body (url_err) + : "unknown"); + return NULL; + } + } + + parser = ucl_parser_new (0); + + if (!ucl_parser_add_chunk (parser, url_buf, url_buflen)) { + free (url_copy); + ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root, + "cannot fetch reference %s: %s", p, + ucl_parser_get_error (parser)); + ucl_parser_free (parser); + return NULL; + } + + url_obj = ucl_parser_get_object (parser); + ext_obj = url_obj; + ucl_object_insert_key (ext_ref, url_obj, p, 0, true); + free (url_buf); + free (url_copy); + } + + if (hash_ptr) { + p = hash_ptr + 1; + } + else { + p = ""; + } } - if (ref[1] == '/') { - p = &ref[2]; + else { + p = ref + 1; } - else if (ref[1] == '\0') { - return root; + + res = ext_obj != NULL ? ext_obj : root; + *nroot = res; + + if (*p == '/') { + p++; } - else { - ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, root, - "reference %s is invalid, not started with #/", ref); - return NULL; + else if (*p == '\0') { + return res; } c = p; - res = root; while (*p != '\0') { if (*p == '/') { @@ -878,15 +901,17 @@ static bool ucl_schema_validate (const ucl_object_t *schema, const ucl_object_t *obj, bool try_array, struct ucl_schema_error *err, - const ucl_object_t *root) + const ucl_object_t *root, + ucl_object_t *external_refs) { - const ucl_object_t *elt, *cur; + const ucl_object_t *elt, *cur, *ref_root; ucl_object_iter_t iter = NULL; bool ret; if (schema->type != UCL_OBJECT) { ucl_schema_create_error (err, UCL_SCHEMA_INVALID_SCHEMA, schema, - "schema is %s instead of object", ucl_object_type_to_string (schema->type)); + "schema is %s instead of object", + ucl_object_type_to_string (schema->type)); return false; } @@ -898,7 +923,7 @@ ucl_schema_validate (const ucl_object_t *schema, return false; } LL_FOREACH (obj, cur) { - if (!ucl_schema_validate (schema, cur, false, err, root)) { + if (!ucl_schema_validate (schema, cur, false, err, root, external_refs)) { return false; } } @@ -916,7 +941,7 @@ ucl_schema_validate (const ucl_object_t *schema, if (elt != NULL && elt->type == UCL_ARRAY) { iter = NULL; while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) { - ret = ucl_schema_validate (cur, obj, true, err, root); + ret = ucl_schema_validate (cur, obj, true, err, root, external_refs); if (!ret) { return false; } @@ -927,7 +952,7 @@ ucl_schema_validate (const ucl_object_t *schema, if (elt != NULL && elt->type == UCL_ARRAY) { iter = NULL; while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) { - ret = ucl_schema_validate (cur, obj, true, err, root); + ret = ucl_schema_validate (cur, obj, true, err, root, external_refs); if (ret) { break; } @@ -947,9 +972,9 @@ ucl_schema_validate (const ucl_object_t *schema, ret = false; while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) { if (!ret) { - ret = ucl_schema_validate (cur, obj, true, err, root); + ret = ucl_schema_validate (cur, obj, true, err, root, external_refs); } - else if (ucl_schema_validate (cur, obj, true, err, root)) { + else if (ucl_schema_validate (cur, obj, true, err, root, external_refs)) { ret = false; break; } @@ -961,7 +986,7 @@ ucl_schema_validate (const ucl_object_t *schema, elt = ucl_object_find_key (schema, "not"); if (elt != NULL && elt->type == UCL_OBJECT) { - if (ucl_schema_validate (elt, obj, true, err, root)) { + if (ucl_schema_validate (elt, obj, true, err, root, external_refs)) { return false; } else { @@ -972,11 +997,15 @@ ucl_schema_validate (const ucl_object_t *schema, elt = ucl_object_find_key (schema, "$ref"); if (elt != NULL) { - cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt), err); + ref_root = root; + cur = ucl_schema_resolve_ref (root, ucl_object_tostring (elt), + err, external_refs, &ref_root); + if (cur == NULL) { return false; } - if (!ucl_schema_validate (cur, obj, try_array, err, root)) { + if (!ucl_schema_validate (cur, obj, try_array, err, ref_root, + external_refs)) { return false; } } @@ -988,10 +1017,10 @@ ucl_schema_validate (const ucl_object_t *schema, switch (obj->type) { case UCL_OBJECT: - return ucl_schema_validate_object (schema, obj, err, root); + return ucl_schema_validate_object (schema, obj, err, root, external_refs); break; case UCL_ARRAY: - return ucl_schema_validate_array (schema, obj, err, root); + return ucl_schema_validate_array (schema, obj, err, root, external_refs); break; case UCL_INT: case UCL_FLOAT: @@ -1011,5 +1040,37 @@ bool ucl_object_validate (const ucl_object_t *schema, const ucl_object_t *obj, struct ucl_schema_error *err) { - return ucl_schema_validate (schema, obj, true, err, schema); + return ucl_object_validate_root_ext (schema, obj, schema, NULL, err); +} + +bool +ucl_object_validate_root (const ucl_object_t *schema, + const ucl_object_t *obj, + const ucl_object_t *root, + struct ucl_schema_error *err) +{ + return ucl_object_validate_root_ext (schema, obj, root, NULL, err); +} + +bool +ucl_object_validate_root_ext (const ucl_object_t *schema, + const ucl_object_t *obj, + const ucl_object_t *root, + ucl_object_t *ext_refs, + struct ucl_schema_error *err) +{ + bool ret, need_unref = false; + + if (ext_refs == NULL) { + ext_refs = ucl_object_typed_new (UCL_OBJECT); + need_unref = true; + } + + ret = ucl_schema_validate (schema, obj, true, err, root, ext_refs); + + if (need_unref) { + ucl_object_unref (ext_refs); + } + + return ret; } diff --git a/contrib/libucl/ucl_util.c b/contrib/libucl/ucl_util.c index 730a5c4af..2bd0c2a3f 100644 --- a/contrib/libucl/ucl_util.c +++ b/contrib/libucl/ucl_util.c @@ -437,7 +437,7 @@ ucl_copy_value_trash (const ucl_object_t *obj) } deconst->flags |= UCL_OBJECT_ALLOCATED_VALUE; } - + return obj->trash_stack[UCL_TRASH_VALUE]; } @@ -628,7 +628,7 @@ ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) * @param buflen target length * @return */ -static bool +bool ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, UT_string **err, bool must_exist) { @@ -690,8 +690,8 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, return false; } curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); - cbdata.buf = *buf; - cbdata.buflen = *buflen; + cbdata.buf = NULL; + cbdata.buflen = 0; curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); if ((r = curl_easy_perform (curl)) != CURLE_OK) { @@ -723,7 +723,7 @@ ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, * @param buflen target length * @return */ -static bool +bool ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, UT_string **err, bool must_exist) { @@ -739,7 +739,7 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl } if (st.st_size == 0) { /* Do not map empty files */ - *buf = ""; + *buf = NULL; *buflen = 0; } else { @@ -848,7 +848,7 @@ ucl_include_url (const unsigned char *data, size_t len, snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) { - return (!params->must_exist || false); + return !params->must_exist; } if (params->check_signature) { @@ -1232,7 +1232,7 @@ ucl_include_file (const unsigned char *data, size_t len, treat allow_glob/need_glob as a NOOP and just return */ return ucl_include_file_single (data, len, parser, params); #endif - + return true; } @@ -1252,7 +1252,7 @@ ucl_include_common (const unsigned char *data, size_t len, bool default_try, bool default_sign) { - bool allow_url, search; + bool allow_url = false, search = false; const char *duplicate; const ucl_object_t *param; ucl_object_iter_t it = NULL, ip = NULL; @@ -1271,8 +1271,6 @@ ucl_include_common (const unsigned char *data, size_t len, params.strat = UCL_DUPLICATE_APPEND; params.must_exist = !default_try; - search = false; - /* Process arguments */ if (args != NULL && args->type == UCL_OBJECT) { while ((param = ucl_iterate_object (args, &it, true)) != NULL) { @@ -3255,3 +3253,73 @@ ucl_object_set_priority (ucl_object_t *obj, obj->flags = priority; } } + +bool +ucl_object_string_to_type (const char *input, ucl_type_t *res) +{ + if (strcasecmp (input, "object") == 0) { + *res = UCL_OBJECT; + } + else if (strcasecmp (input, "array") == 0) { + *res = UCL_ARRAY; + } + else if (strcasecmp (input, "integer") == 0) { + *res = UCL_INT; + } + else if (strcasecmp (input, "number") == 0) { + *res = UCL_FLOAT; + } + else if (strcasecmp (input, "string") == 0) { + *res = UCL_STRING; + } + else if (strcasecmp (input, "boolean") == 0) { + *res = UCL_BOOLEAN; + } + else if (strcasecmp (input, "null") == 0) { + *res = UCL_NULL; + } + else if (strcasecmp (input, "userdata") == 0) { + *res = UCL_USERDATA; + } + else { + return false; + } + + return true; +} + +const char * +ucl_object_type_to_string (ucl_type_t type) +{ + const char *res = "unknown"; + + switch (type) { + case UCL_OBJECT: + res = "object"; + break; + case UCL_ARRAY: + res = "array"; + break; + case UCL_INT: + res = "integer"; + break; + case UCL_FLOAT: + case UCL_TIME: + res = "number"; + break; + case UCL_STRING: + res = "string"; + break; + case UCL_BOOLEAN: + res = "boolean"; + break; + case UCL_USERDATA: + res = "userdata"; + break; + case UCL_NULL: + res = "null"; + break; + } + + return res; +} |