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/libucl/ucl_schema.c | |
parent | 4ce549ad001660aaf60b3804921a70f2bd8c503a (diff) | |
download | rspamd-2275d0b9ebeda6a1edffb3f1f38d3b3af7c9c8a3.tar.gz rspamd-2275d0b9ebeda6a1edffb3f1f38d3b3af7c9c8a3.zip |
Sync with libucl
Diffstat (limited to 'contrib/libucl/ucl_schema.c')
-rw-r--r-- | contrib/libucl/ucl_schema.c | 277 |
1 files changed, 169 insertions, 108 deletions
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; } |