endpoints_ruleset.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/common/array_list.h>
  6. #include <aws/common/hash_table.h>
  7. #include <aws/common/json.h>
  8. #include <aws/common/ref_count.h>
  9. #include <aws/common/string.h>
  10. #include <aws/sdkutils/private/endpoints_types_impl.h>
  11. #include <aws/sdkutils/private/endpoints_util.h>
  12. /* parameter types */
  13. static struct aws_byte_cursor s_string_type_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("string");
  14. static struct aws_byte_cursor s_boolean_type_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("boolean");
  15. /* rule types */
  16. static struct aws_byte_cursor s_endpoint_type_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("endpoint");
  17. static struct aws_byte_cursor s_error_type_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("error");
  18. static struct aws_byte_cursor s_tree_type_cur = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("tree");
  19. static struct aws_byte_cursor s_supported_version = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("1.0");
  20. static struct aws_byte_cursor s_empty_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("");
  21. /* TODO: improve error messages. Include json line num? or dump json node? */
  22. struct aws_byte_cursor aws_endpoints_get_supported_ruleset_version(void) {
  23. return s_supported_version;
  24. }
  25. /*
  26. ******************************
  27. * Parameter Getters.
  28. ******************************
  29. */
  30. enum aws_endpoints_parameter_type aws_endpoints_parameter_get_type(const struct aws_endpoints_parameter *parameter) {
  31. AWS_PRECONDITION(parameter);
  32. return parameter->type;
  33. }
  34. struct aws_byte_cursor aws_endpoints_parameter_get_built_in(const struct aws_endpoints_parameter *parameter) {
  35. AWS_PRECONDITION(parameter);
  36. return parameter->built_in;
  37. }
  38. int aws_endpoints_parameter_get_default_string(
  39. const struct aws_endpoints_parameter *parameter,
  40. struct aws_byte_cursor *out_cursor) {
  41. AWS_PRECONDITION(parameter);
  42. AWS_PRECONDITION(out_cursor);
  43. if (parameter->type == AWS_ENDPOINTS_PARAMETER_STRING) {
  44. *out_cursor = parameter->default_value.string;
  45. return AWS_OP_SUCCESS;
  46. };
  47. *out_cursor = s_empty_cursor;
  48. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  49. }
  50. int aws_endpoints_parameter_get_default_boolean(
  51. const struct aws_endpoints_parameter *parameter,
  52. const bool **out_bool) {
  53. AWS_PRECONDITION(parameter);
  54. AWS_PRECONDITION(out_bool);
  55. if (parameter->type == AWS_ENDPOINTS_PARAMETER_BOOLEAN) {
  56. *out_bool = &parameter->default_value.boolean;
  57. return AWS_OP_SUCCESS;
  58. };
  59. *out_bool = NULL;
  60. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  61. }
  62. bool aws_endpoints_parameters_get_is_required(const struct aws_endpoints_parameter *parameter) {
  63. AWS_PRECONDITION(parameter);
  64. return parameter->is_required;
  65. }
  66. struct aws_byte_cursor aws_endpoints_parameter_get_documentation(const struct aws_endpoints_parameter *parameter) {
  67. AWS_PRECONDITION(parameter);
  68. return parameter->documentation;
  69. }
  70. bool aws_endpoints_parameters_get_is_deprecated(const struct aws_endpoints_parameter *parameter) {
  71. AWS_PRECONDITION(parameter);
  72. return parameter->is_deprecated;
  73. }
  74. struct aws_byte_cursor aws_endpoints_parameter_get_deprecated_message(const struct aws_endpoints_parameter *parameter) {
  75. AWS_PRECONDITION(parameter);
  76. return parameter->deprecated_message;
  77. }
  78. struct aws_byte_cursor aws_endpoints_parameter_get_deprecated_since(const struct aws_endpoints_parameter *parameter) {
  79. AWS_PRECONDITION(parameter);
  80. return parameter->deprecated_since;
  81. }
  82. /*
  83. ******************************
  84. * Parser getters.
  85. ******************************
  86. */
  87. const struct aws_hash_table *aws_endpoints_ruleset_get_parameters(struct aws_endpoints_ruleset *ruleset) {
  88. AWS_PRECONDITION(ruleset);
  89. return &ruleset->parameters;
  90. }
  91. struct aws_byte_cursor aws_endpoints_ruleset_get_version(const struct aws_endpoints_ruleset *ruleset) {
  92. AWS_PRECONDITION(ruleset);
  93. return ruleset->version;
  94. }
  95. struct aws_byte_cursor aws_endpoints_ruleset_get_service_id(const struct aws_endpoints_ruleset *ruleset) {
  96. AWS_PRECONDITION(ruleset);
  97. return ruleset->service_id;
  98. }
  99. /*
  100. ******************************
  101. * Parser helpers.
  102. ******************************
  103. */
  104. static void s_on_rule_array_element_clean_up(void *element) {
  105. struct aws_endpoints_rule *rule = element;
  106. aws_endpoints_rule_clean_up(rule);
  107. }
  108. static void s_on_expr_element_clean_up(void *data) {
  109. struct aws_endpoints_expr *expr = data;
  110. aws_endpoints_expr_clean_up(expr);
  111. }
  112. static void s_callback_endpoints_parameter_destroy(void *data) {
  113. struct aws_endpoints_parameter *parameter = data;
  114. aws_endpoints_parameter_destroy(parameter);
  115. }
  116. static void s_callback_headers_destroy(void *data) {
  117. struct aws_array_list *array = data;
  118. struct aws_allocator *alloc = array->alloc;
  119. aws_array_list_deep_clean_up(array, s_on_expr_element_clean_up);
  120. aws_array_list_clean_up(array);
  121. aws_mem_release(alloc, array);
  122. }
  123. struct array_parser_wrapper {
  124. struct aws_allocator *allocator;
  125. struct aws_array_list *array;
  126. };
  127. static int s_init_array_from_json(
  128. struct aws_allocator *allocator,
  129. const struct aws_json_value *value_node,
  130. struct aws_array_list *values,
  131. aws_json_on_value_encountered_const_fn *value_fn) {
  132. AWS_PRECONDITION(allocator);
  133. AWS_PRECONDITION(values);
  134. AWS_PRECONDITION(value_node);
  135. AWS_PRECONDITION(value_fn);
  136. struct array_parser_wrapper wrapper = {
  137. .allocator = allocator,
  138. .array = values,
  139. };
  140. if (aws_json_const_iterate_array(value_node, value_fn, &wrapper)) {
  141. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to iterate through array.");
  142. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  143. }
  144. return AWS_OP_SUCCESS;
  145. }
  146. struct member_parser_wrapper {
  147. struct aws_allocator *allocator;
  148. struct aws_hash_table *table;
  149. };
  150. static int s_init_members_from_json(
  151. struct aws_allocator *allocator,
  152. struct aws_json_value *node,
  153. struct aws_hash_table *table,
  154. aws_json_on_member_encountered_const_fn *member_fn) {
  155. AWS_PRECONDITION(allocator);
  156. AWS_PRECONDITION(node);
  157. AWS_PRECONDITION(table);
  158. struct member_parser_wrapper wrapper = {
  159. .allocator = allocator,
  160. .table = table,
  161. };
  162. if (aws_json_const_iterate_object(node, member_fn, &wrapper)) {
  163. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to iterate through member fields.");
  164. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  165. }
  166. return AWS_OP_SUCCESS;
  167. }
  168. /*
  169. ******************************
  170. * Parser functions.
  171. ******************************
  172. */
  173. static int s_parse_function(
  174. struct aws_allocator *allocator,
  175. const struct aws_json_value *node,
  176. struct aws_endpoints_function *function);
  177. /*
  178. * Note: this function only fails in cases where node is a ref (ie object with a
  179. * ref field), but cannot be parsed completely.
  180. */
  181. static int s_try_parse_reference(const struct aws_json_value *node, struct aws_byte_cursor *out_reference) {
  182. AWS_PRECONDITION(node);
  183. AWS_ZERO_STRUCT(*out_reference);
  184. struct aws_json_value *ref_node = aws_json_value_get_from_object(node, aws_byte_cursor_from_c_str("ref"));
  185. if (ref_node != NULL && aws_json_value_get_string(ref_node, out_reference)) {
  186. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to parse ref.");
  187. AWS_ZERO_STRUCT(*out_reference);
  188. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  189. }
  190. return AWS_OP_SUCCESS;
  191. }
  192. static int s_parse_expr(
  193. struct aws_allocator *allocator,
  194. const struct aws_json_value *node,
  195. struct aws_endpoints_expr *expr);
  196. static int s_on_expr_element(
  197. size_t idx,
  198. const struct aws_json_value *value_node,
  199. bool *out_should_continue,
  200. void *user_data) {
  201. (void)idx;
  202. (void)out_should_continue;
  203. AWS_PRECONDITION(value_node);
  204. AWS_PRECONDITION(user_data);
  205. struct array_parser_wrapper *wrapper = user_data;
  206. struct aws_endpoints_expr expr;
  207. if (s_parse_expr(wrapper->allocator, value_node, &expr)) {
  208. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to parse expr.");
  209. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  210. }
  211. aws_array_list_push_back(wrapper->array, &expr);
  212. return AWS_OP_SUCCESS;
  213. }
  214. static int s_parse_expr(
  215. struct aws_allocator *allocator,
  216. const struct aws_json_value *node,
  217. struct aws_endpoints_expr *expr) {
  218. AWS_PRECONDITION(allocator);
  219. AWS_PRECONDITION(node);
  220. AWS_PRECONDITION(expr);
  221. AWS_ZERO_STRUCT(*expr);
  222. /* TODO: this recurses. in practical circumstances depth will never be high,
  223. but we should still consider doing iterative approach */
  224. if (aws_json_value_is_string(node) && !aws_json_value_get_string(node, &expr->e.string)) {
  225. expr->type = AWS_ENDPOINTS_EXPR_STRING;
  226. return AWS_OP_SUCCESS;
  227. } else if (aws_json_value_is_number(node) && !aws_json_value_get_number(node, &expr->e.number)) {
  228. expr->type = AWS_ENDPOINTS_EXPR_NUMBER;
  229. return AWS_OP_SUCCESS;
  230. } else if (aws_json_value_is_boolean(node) && !aws_json_value_get_boolean(node, &expr->e.boolean)) {
  231. expr->type = AWS_ENDPOINTS_EXPR_BOOLEAN;
  232. return AWS_OP_SUCCESS;
  233. } else if (aws_json_value_is_array(node)) {
  234. expr->type = AWS_ENDPOINTS_EXPR_ARRAY;
  235. size_t num_elements = aws_json_get_array_size(node);
  236. aws_array_list_init_dynamic(&expr->e.array, allocator, num_elements, sizeof(struct aws_endpoints_expr));
  237. if (s_init_array_from_json(allocator, node, &expr->e.array, s_on_expr_element)) {
  238. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to parse array value type.");
  239. goto on_error;
  240. }
  241. return AWS_OP_SUCCESS;
  242. }
  243. struct aws_byte_cursor reference;
  244. if (s_try_parse_reference(node, &reference)) {
  245. goto on_error;
  246. }
  247. if (reference.len > 0) {
  248. expr->type = AWS_ENDPOINTS_EXPR_REFERENCE;
  249. expr->e.reference = reference;
  250. return AWS_OP_SUCCESS;
  251. }
  252. expr->type = AWS_ENDPOINTS_EXPR_FUNCTION;
  253. if (s_parse_function(allocator, node, &expr->e.function)) {
  254. goto on_error;
  255. }
  256. return AWS_OP_SUCCESS;
  257. on_error:
  258. aws_endpoints_expr_clean_up(expr);
  259. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to parse expr type");
  260. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  261. }
  262. static int s_parse_function(
  263. struct aws_allocator *allocator,
  264. const struct aws_json_value *node,
  265. struct aws_endpoints_function *function) {
  266. AWS_PRECONDITION(allocator);
  267. AWS_PRECONDITION(node);
  268. AWS_ZERO_STRUCT(*function);
  269. struct aws_json_value *fn_node = aws_json_value_get_from_object(node, aws_byte_cursor_from_c_str("fn"));
  270. if (fn_node == NULL) {
  271. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Node is not a function.");
  272. goto on_error;
  273. }
  274. struct aws_byte_cursor fn_cur;
  275. if (aws_json_value_get_string(fn_node, &fn_cur)) {
  276. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract fn name.");
  277. goto on_error;
  278. }
  279. function->fn = AWS_ENDPOINTS_FN_LAST;
  280. uint64_t hash = aws_hash_byte_cursor_ptr(&fn_cur);
  281. for (int idx = AWS_ENDPOINTS_FN_FIRST; idx < AWS_ENDPOINTS_FN_LAST; ++idx) {
  282. if (aws_endpoints_fn_name_hash[idx] == hash) {
  283. function->fn = idx;
  284. break;
  285. }
  286. }
  287. if (function->fn == AWS_ENDPOINTS_FN_LAST) {
  288. AWS_LOGF_ERROR(
  289. AWS_LS_SDKUTILS_ENDPOINTS_PARSING,
  290. "Could not map function name to function type: " PRInSTR,
  291. AWS_BYTE_CURSOR_PRI(fn_cur));
  292. goto on_error;
  293. }
  294. struct aws_json_value *argv_node = aws_json_value_get_from_object(node, aws_byte_cursor_from_c_str("argv"));
  295. if (argv_node == NULL || !aws_json_value_is_array(argv_node)) {
  296. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "No argv or unexpected type.");
  297. goto on_error;
  298. }
  299. size_t num_args = aws_json_get_array_size(argv_node);
  300. aws_array_list_init_dynamic(&function->argv, allocator, num_args, sizeof(struct aws_endpoints_expr));
  301. if (s_init_array_from_json(allocator, argv_node, &function->argv, s_on_expr_element)) {
  302. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to parse argv.");
  303. goto on_error;
  304. }
  305. return AWS_OP_SUCCESS;
  306. on_error:
  307. aws_endpoints_function_clean_up(function);
  308. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  309. }
  310. static int s_on_parameter_key(
  311. const struct aws_byte_cursor *key,
  312. const struct aws_json_value *value,
  313. bool *out_should_continue,
  314. void *user_data) {
  315. (void)out_should_continue;
  316. AWS_PRECONDITION(key);
  317. AWS_PRECONDITION(value);
  318. AWS_PRECONDITION(user_data);
  319. struct member_parser_wrapper *wrapper = user_data;
  320. struct aws_endpoints_parameter *parameter = aws_endpoints_parameter_new(wrapper->allocator, *key);
  321. /* required fields */
  322. struct aws_byte_cursor type_cur;
  323. struct aws_json_value *type_node = aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("type"));
  324. if (type_node == NULL || aws_json_value_get_string(type_node, &type_cur)) {
  325. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract parameter type.");
  326. goto on_error;
  327. }
  328. enum aws_endpoints_parameter_type type;
  329. if (aws_byte_cursor_eq_ignore_case(&type_cur, &s_string_type_cur)) {
  330. type = AWS_ENDPOINTS_PARAMETER_STRING;
  331. } else if (aws_byte_cursor_eq_ignore_case(&type_cur, &s_boolean_type_cur)) {
  332. type = AWS_ENDPOINTS_PARAMETER_BOOLEAN;
  333. } else {
  334. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected type for parameter.");
  335. goto on_error;
  336. }
  337. parameter->type = type;
  338. struct aws_json_value *documentation_node =
  339. aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("documentation"));
  340. /* TODO: spec calls for documentation to be required, but several test-cases
  341. are missing docs on parameters */
  342. if (documentation_node != NULL) {
  343. if (aws_json_value_get_string(documentation_node, &parameter->documentation)) {
  344. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract parameter documentation.");
  345. goto on_error;
  346. }
  347. }
  348. /* optional fields */
  349. struct aws_json_value *built_in_node = aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("builtIn"));
  350. if (built_in_node != NULL) {
  351. if (aws_json_value_get_string(built_in_node, &parameter->built_in)) {
  352. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected type for built-in parameter field.");
  353. goto on_error;
  354. }
  355. }
  356. struct aws_json_value *required_node =
  357. aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("required"));
  358. if (required_node != NULL) {
  359. if (!aws_json_value_is_boolean(required_node)) {
  360. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected type for required parameter field.");
  361. goto on_error;
  362. }
  363. aws_json_value_get_boolean(required_node, &parameter->is_required);
  364. }
  365. struct aws_json_value *default_node = aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("default"));
  366. parameter->has_default_value = default_node != NULL;
  367. if (default_node != NULL) {
  368. if (type == AWS_ENDPOINTS_PARAMETER_STRING &&
  369. aws_json_value_get_string(default_node, &parameter->default_value.string)) {
  370. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected type for default parameter value.");
  371. goto on_error;
  372. } else if (
  373. type == AWS_ENDPOINTS_PARAMETER_BOOLEAN &&
  374. aws_json_value_get_boolean(default_node, &parameter->default_value.boolean)) {
  375. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected type for default parameter value.");
  376. goto on_error;
  377. }
  378. }
  379. struct aws_json_value *deprecated_node =
  380. aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("deprecated"));
  381. if (deprecated_node != NULL) {
  382. struct aws_json_value *deprecated_message_node =
  383. aws_json_value_get_from_object(deprecated_node, aws_byte_cursor_from_c_str("message"));
  384. if (deprecated_message_node != NULL &&
  385. aws_json_value_get_string(deprecated_message_node, &parameter->deprecated_message)) {
  386. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected value for deprecated message.");
  387. goto on_error;
  388. }
  389. struct aws_json_value *deprecated_since_node =
  390. aws_json_value_get_from_object(deprecated_node, aws_byte_cursor_from_c_str("since"));
  391. if (deprecated_since_node != NULL &&
  392. aws_json_value_get_string(deprecated_since_node, &parameter->deprecated_since)) {
  393. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected value for deprecated since.");
  394. goto on_error;
  395. }
  396. }
  397. if (aws_hash_table_put(wrapper->table, &parameter->name, parameter, NULL)) {
  398. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to add parameter.");
  399. goto on_error;
  400. }
  401. return AWS_OP_SUCCESS;
  402. on_error:
  403. aws_endpoints_parameter_destroy(parameter);
  404. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  405. }
  406. static int s_on_condition_element(
  407. size_t idx,
  408. const struct aws_json_value *condition_node,
  409. bool *out_should_continue,
  410. void *user_data) {
  411. (void)idx;
  412. (void)out_should_continue;
  413. AWS_PRECONDITION(condition_node);
  414. AWS_PRECONDITION(user_data);
  415. struct array_parser_wrapper *wrapper = user_data;
  416. struct aws_endpoints_condition condition;
  417. AWS_ZERO_STRUCT(condition);
  418. condition.expr.type = AWS_ENDPOINTS_EXPR_FUNCTION;
  419. if (s_parse_function(wrapper->allocator, condition_node, &condition.expr.e.function)) {
  420. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to parse function.");
  421. goto on_error;
  422. }
  423. struct aws_json_value *assign_node =
  424. aws_json_value_get_from_object(condition_node, aws_byte_cursor_from_c_str("assign"));
  425. if (assign_node != NULL && aws_json_value_get_string(assign_node, &condition.assign)) {
  426. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected value for assign.");
  427. goto on_error;
  428. }
  429. aws_array_list_push_back(wrapper->array, &condition);
  430. return AWS_OP_SUCCESS;
  431. on_error:
  432. aws_endpoints_condition_clean_up(&condition);
  433. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  434. }
  435. static int s_on_header_element(
  436. size_t idx,
  437. const struct aws_json_value *value,
  438. bool *out_should_continue,
  439. void *user_data) {
  440. (void)idx;
  441. (void)out_should_continue;
  442. AWS_PRECONDITION(value);
  443. AWS_PRECONDITION(user_data);
  444. struct array_parser_wrapper *wrapper = user_data;
  445. struct aws_endpoints_expr expr;
  446. if (s_parse_expr(wrapper->allocator, value, &expr)) {
  447. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected format for header element.");
  448. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  449. }
  450. aws_array_list_push_back(wrapper->array, &expr);
  451. return AWS_OP_SUCCESS;
  452. }
  453. static int s_on_headers_key(
  454. const struct aws_byte_cursor *key,
  455. const struct aws_json_value *value,
  456. bool *out_should_continue,
  457. void *user_data) {
  458. (void)out_should_continue;
  459. AWS_PRECONDITION(key);
  460. AWS_PRECONDITION(value);
  461. AWS_PRECONDITION(user_data);
  462. struct member_parser_wrapper *wrapper = user_data;
  463. if (!aws_json_value_is_array(value)) {
  464. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected format for header value.");
  465. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  466. }
  467. size_t num_elements = aws_json_get_array_size(value);
  468. struct aws_array_list *headers = aws_mem_calloc(wrapper->allocator, 1, sizeof(struct aws_array_list));
  469. aws_array_list_init_dynamic(headers, wrapper->allocator, num_elements, sizeof(struct aws_endpoints_expr));
  470. if (s_init_array_from_json(wrapper->allocator, value, headers, s_on_header_element)) {
  471. goto on_error;
  472. }
  473. aws_hash_table_put(wrapper->table, aws_string_new_from_cursor(wrapper->allocator, key), headers, NULL);
  474. return AWS_OP_SUCCESS;
  475. on_error:
  476. if (headers) {
  477. s_callback_headers_destroy(headers);
  478. }
  479. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  480. }
  481. static int s_parse_endpoints_rule_data_endpoint(
  482. struct aws_allocator *allocator,
  483. const struct aws_json_value *rule_node,
  484. struct aws_endpoints_rule_data_endpoint *data_rule) {
  485. AWS_PRECONDITION(allocator);
  486. AWS_PRECONDITION(rule_node);
  487. AWS_PRECONDITION(data_rule);
  488. data_rule->allocator = allocator;
  489. struct aws_json_value *url_node = aws_json_value_get_from_object(rule_node, aws_byte_cursor_from_c_str("url"));
  490. if (url_node == NULL || aws_json_value_is_string(url_node)) {
  491. data_rule->url.type = AWS_ENDPOINTS_EXPR_STRING;
  492. aws_json_value_get_string(url_node, &data_rule->url.e.string);
  493. } else {
  494. struct aws_byte_cursor reference;
  495. if (s_try_parse_reference(url_node, &reference)) {
  496. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to parse reference.");
  497. goto on_error;
  498. }
  499. if (reference.len > 0) {
  500. data_rule->url.type = AWS_ENDPOINTS_EXPR_REFERENCE;
  501. data_rule->url.e.reference = reference;
  502. } else {
  503. data_rule->url.type = AWS_ENDPOINTS_EXPR_FUNCTION;
  504. if (s_parse_function(allocator, url_node, &data_rule->url.e.function)) {
  505. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to function.");
  506. goto on_error;
  507. }
  508. }
  509. }
  510. struct aws_json_value *properties_node =
  511. aws_json_value_get_from_object(rule_node, aws_byte_cursor_from_c_str("properties"));
  512. if (properties_node != NULL) {
  513. aws_byte_buf_init(&data_rule->properties, allocator, 0);
  514. if (aws_byte_buf_append_json_string(properties_node, &data_rule->properties)) {
  515. aws_byte_buf_clean_up(&data_rule->properties);
  516. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract properties.");
  517. goto on_error;
  518. }
  519. }
  520. /* TODO: this is currently aws_string* to aws_array_list*
  521. * We cannot use same trick as for params to use aws_byte_cursor as key,
  522. * since value is a generic type. We can wrap list into a struct, but
  523. * seems ugly. Anything cleaner?
  524. */
  525. aws_hash_table_init(
  526. &data_rule->headers,
  527. allocator,
  528. 20,
  529. aws_hash_string,
  530. aws_hash_callback_string_eq,
  531. aws_hash_callback_string_destroy,
  532. s_callback_headers_destroy);
  533. struct aws_json_value *headers_node =
  534. aws_json_value_get_from_object(rule_node, aws_byte_cursor_from_c_str("headers"));
  535. if (headers_node != NULL) {
  536. if (s_init_members_from_json(allocator, headers_node, &data_rule->headers, s_on_headers_key)) {
  537. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract parameters.");
  538. goto on_error;
  539. }
  540. }
  541. return AWS_OP_SUCCESS;
  542. on_error:
  543. aws_endpoints_rule_data_endpoint_clean_up(data_rule);
  544. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  545. }
  546. static int s_parse_endpoints_rule_data_error(
  547. struct aws_allocator *allocator,
  548. const struct aws_json_value *error_node,
  549. struct aws_endpoints_rule_data_error *data_rule) {
  550. AWS_PRECONDITION(allocator);
  551. AWS_PRECONDITION(error_node);
  552. AWS_PRECONDITION(data_rule);
  553. if (aws_json_value_is_string(error_node)) {
  554. data_rule->error.type = AWS_ENDPOINTS_EXPR_STRING;
  555. aws_json_value_get_string(error_node, &data_rule->error.e.string);
  556. return AWS_OP_SUCCESS;
  557. }
  558. struct aws_byte_cursor reference;
  559. if (s_try_parse_reference(error_node, &reference)) {
  560. goto on_error;
  561. }
  562. if (reference.len > 0) {
  563. data_rule->error.type = AWS_ENDPOINTS_EXPR_REFERENCE;
  564. data_rule->error.e.reference = reference;
  565. return AWS_OP_SUCCESS;
  566. }
  567. data_rule->error.type = AWS_ENDPOINTS_EXPR_FUNCTION;
  568. if (s_parse_function(allocator, error_node, &data_rule->error.e.function)) {
  569. goto on_error;
  570. }
  571. return AWS_OP_SUCCESS;
  572. on_error:
  573. aws_endpoints_rule_data_error_clean_up(data_rule);
  574. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to parse error rule.");
  575. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  576. }
  577. static int s_on_rule_element(
  578. size_t idx,
  579. const struct aws_json_value *value,
  580. bool *out_should_continue,
  581. void *user_data);
  582. static int s_parse_endpoints_rule_data_tree(
  583. struct aws_allocator *allocator,
  584. const struct aws_json_value *rule_node,
  585. struct aws_endpoints_rule_data_tree *rule_data) {
  586. AWS_PRECONDITION(allocator);
  587. AWS_PRECONDITION(rule_node);
  588. AWS_PRECONDITION(rule_data);
  589. struct aws_json_value *rules_node = aws_json_value_get_from_object(rule_node, aws_byte_cursor_from_c_str("rules"));
  590. if (rules_node == NULL || !aws_json_value_is_array(rules_node)) {
  591. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Rules node is missing or unexpected type.");
  592. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  593. }
  594. size_t num_rules = aws_json_get_array_size(rules_node);
  595. aws_array_list_init_dynamic(&rule_data->rules, allocator, num_rules, sizeof(struct aws_endpoints_rule));
  596. if (s_init_array_from_json(allocator, rules_node, &rule_data->rules, s_on_rule_element)) {
  597. aws_endpoints_rule_data_tree_clean_up(rule_data);
  598. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to parse rules.");
  599. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  600. }
  601. return AWS_OP_SUCCESS;
  602. }
  603. static int s_on_rule_element(
  604. size_t idx,
  605. const struct aws_json_value *value,
  606. bool *out_should_continue,
  607. void *user_data) {
  608. (void)idx;
  609. (void)out_should_continue;
  610. AWS_PRECONDITION(value);
  611. AWS_PRECONDITION(user_data);
  612. struct array_parser_wrapper *wrapper = user_data;
  613. /* Required fields */
  614. struct aws_byte_cursor type_cur;
  615. struct aws_json_value *type_node = aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("type"));
  616. if (type_node == NULL || aws_json_value_get_string(type_node, &type_cur)) {
  617. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract rule type.");
  618. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  619. }
  620. enum aws_endpoints_rule_type type;
  621. if (aws_byte_cursor_eq_ignore_case(&type_cur, &s_endpoint_type_cur)) {
  622. type = AWS_ENDPOINTS_RULE_ENDPOINT;
  623. } else if (aws_byte_cursor_eq_ignore_case(&type_cur, &s_error_type_cur)) {
  624. type = AWS_ENDPOINTS_RULE_ERROR;
  625. } else if (aws_byte_cursor_eq_ignore_case(&type_cur, &s_tree_type_cur)) {
  626. type = AWS_ENDPOINTS_RULE_TREE;
  627. } else {
  628. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected rule type.");
  629. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  630. }
  631. struct aws_endpoints_rule rule;
  632. AWS_ZERO_STRUCT(rule);
  633. rule.type = type;
  634. struct aws_json_value *conditions_node =
  635. aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("conditions"));
  636. if (conditions_node == NULL || !aws_json_value_is_array(conditions_node)) {
  637. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Conditions node missing.");
  638. goto on_error;
  639. }
  640. size_t num_conditions = aws_json_get_array_size(conditions_node);
  641. aws_array_list_init_dynamic(
  642. &rule.conditions, wrapper->allocator, num_conditions, sizeof(struct aws_endpoints_condition));
  643. if (s_init_array_from_json(wrapper->allocator, conditions_node, &rule.conditions, s_on_condition_element)) {
  644. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract conditions.");
  645. goto on_error;
  646. }
  647. switch (type) {
  648. case AWS_ENDPOINTS_RULE_ENDPOINT: {
  649. struct aws_json_value *endpoint_node =
  650. aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("endpoint"));
  651. if (endpoint_node == NULL ||
  652. s_parse_endpoints_rule_data_endpoint(wrapper->allocator, endpoint_node, &rule.rule_data.endpoint)) {
  653. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract endpoint rule data.");
  654. goto on_error;
  655. }
  656. break;
  657. }
  658. case AWS_ENDPOINTS_RULE_ERROR: {
  659. struct aws_json_value *error_node =
  660. aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("error"));
  661. if (error_node == NULL ||
  662. s_parse_endpoints_rule_data_error(wrapper->allocator, error_node, &rule.rule_data.error)) {
  663. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract error rule data.");
  664. goto on_error;
  665. }
  666. break;
  667. }
  668. case AWS_ENDPOINTS_RULE_TREE: {
  669. if (s_parse_endpoints_rule_data_tree(wrapper->allocator, value, &rule.rule_data.tree)) {
  670. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract tree rule data.");
  671. goto on_error;
  672. }
  673. break;
  674. }
  675. default:
  676. AWS_FATAL_ASSERT(false);
  677. }
  678. /* Optional fields */
  679. struct aws_json_value *documentation_node =
  680. aws_json_value_get_from_object(value, aws_byte_cursor_from_c_str("documentation"));
  681. if (documentation_node != NULL) {
  682. if (aws_json_value_get_string(documentation_node, &rule.documentation)) {
  683. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract parameter documentation.");
  684. goto on_error;
  685. }
  686. }
  687. aws_array_list_push_back(wrapper->array, &rule);
  688. return AWS_OP_SUCCESS;
  689. on_error:
  690. aws_endpoints_rule_clean_up(&rule);
  691. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  692. }
  693. static int s_init_ruleset_from_json(
  694. struct aws_allocator *allocator,
  695. struct aws_endpoints_ruleset *ruleset,
  696. struct aws_byte_cursor json) {
  697. AWS_PRECONDITION(allocator);
  698. AWS_PRECONDITION(ruleset);
  699. AWS_PRECONDITION(aws_byte_cursor_is_valid(&json));
  700. struct aws_json_value *root = aws_json_value_new_from_string(allocator, json);
  701. if (root == NULL) {
  702. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to parse provided string as json.");
  703. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  704. }
  705. ruleset->json_root = root;
  706. struct aws_json_value *version_node = aws_json_value_get_from_object(root, aws_byte_cursor_from_c_str("version"));
  707. if (version_node == NULL || aws_json_value_get_string(version_node, &ruleset->version)) {
  708. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract version.");
  709. aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_UNSUPPORTED_RULESET);
  710. goto on_error;
  711. }
  712. #ifdef ENDPOINTS_VERSION_CHECK /* TODO: samples are currently inconsistent with versions. skip check for now */
  713. if (!aws_byte_cursor_eq_c_str(&ruleset->version, &s_supported_version)) {
  714. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unsupported ruleset version.");
  715. aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_UNSUPPORTED_RULESET);
  716. goto on_error;
  717. }
  718. #endif
  719. struct aws_json_value *service_id_node =
  720. aws_json_value_get_from_object(root, aws_byte_cursor_from_c_str("serviceId"));
  721. if (service_id_node != NULL && aws_json_value_get_string(service_id_node, &ruleset->service_id)) {
  722. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract serviceId.");
  723. aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_UNSUPPORTED_RULESET);
  724. goto on_error;
  725. }
  726. aws_hash_table_init(
  727. &ruleset->parameters,
  728. allocator,
  729. 20,
  730. aws_hash_byte_cursor_ptr,
  731. aws_endpoints_byte_cursor_eq,
  732. NULL,
  733. s_callback_endpoints_parameter_destroy);
  734. struct aws_json_value *parameters_node =
  735. aws_json_value_get_from_object(root, aws_byte_cursor_from_c_str("parameters"));
  736. if (parameters_node == NULL ||
  737. s_init_members_from_json(allocator, parameters_node, &ruleset->parameters, s_on_parameter_key)) {
  738. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract parameters.");
  739. aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  740. goto on_error;
  741. }
  742. struct aws_json_value *rules_node = aws_json_value_get_from_object(root, aws_byte_cursor_from_c_str("rules"));
  743. if (rules_node == NULL || !aws_json_value_is_array(rules_node)) {
  744. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Unexpected type for rules node.");
  745. aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  746. goto on_error;
  747. }
  748. size_t num_rules = aws_json_get_array_size(rules_node);
  749. aws_array_list_init_dynamic(&ruleset->rules, allocator, num_rules, sizeof(struct aws_endpoints_rule));
  750. if (s_init_array_from_json(allocator, rules_node, &ruleset->rules, s_on_rule_element)) {
  751. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_PARSING, "Failed to extract rules.");
  752. aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_PARSE_FAILED);
  753. goto on_error;
  754. }
  755. return AWS_OP_SUCCESS;
  756. on_error:
  757. return AWS_OP_ERR;
  758. }
  759. static void s_endpoints_ruleset_destroy(void *data) {
  760. if (data == NULL) {
  761. return;
  762. }
  763. struct aws_endpoints_ruleset *ruleset = data;
  764. aws_json_value_destroy(ruleset->json_root);
  765. aws_hash_table_clean_up(&ruleset->parameters);
  766. aws_array_list_deep_clean_up(&ruleset->rules, s_on_rule_array_element_clean_up);
  767. aws_mem_release(ruleset->allocator, ruleset);
  768. }
  769. struct aws_endpoints_ruleset *aws_endpoints_ruleset_new_from_string(
  770. struct aws_allocator *allocator,
  771. struct aws_byte_cursor ruleset_json) {
  772. AWS_PRECONDITION(allocator);
  773. AWS_PRECONDITION(aws_byte_cursor_is_valid(&ruleset_json));
  774. struct aws_endpoints_ruleset *ruleset = aws_mem_calloc(allocator, 1, sizeof(struct aws_endpoints_ruleset));
  775. ruleset->allocator = allocator;
  776. if (s_init_ruleset_from_json(allocator, ruleset, ruleset_json)) {
  777. s_endpoints_ruleset_destroy(ruleset);
  778. return NULL;
  779. }
  780. aws_ref_count_init(&ruleset->ref_count, ruleset, s_endpoints_ruleset_destroy);
  781. return ruleset;
  782. }
  783. struct aws_endpoints_ruleset *aws_endpoints_ruleset_acquire(struct aws_endpoints_ruleset *ruleset) {
  784. AWS_PRECONDITION(ruleset);
  785. if (ruleset) {
  786. aws_ref_count_acquire(&ruleset->ref_count);
  787. }
  788. return ruleset;
  789. }
  790. struct aws_endpoints_ruleset *aws_endpoints_ruleset_release(struct aws_endpoints_ruleset *ruleset) {
  791. if (ruleset) {
  792. aws_ref_count_release(&ruleset->ref_count);
  793. }
  794. return NULL;
  795. }