endpoints_rule_engine.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/common/byte_buf.h>
  6. #include <aws/common/json.h>
  7. #include <aws/common/macros.h>
  8. #include <aws/common/string.h>
  9. #include <aws/sdkutils/partitions.h>
  10. #include <aws/sdkutils/private/endpoints_types_impl.h>
  11. #include <aws/sdkutils/private/endpoints_util.h>
  12. #include <inttypes.h>
  13. #include <stdio.h>
  14. /* TODO: checking for unknown enum values is annoying and is brittle. compile
  15. time assert on enum size or members would make it a lot simpler. */
  16. /*
  17. * How rule resolution works.
  18. * Note: read comments in endpoint_types_impl.h first to understand type system.
  19. *
  20. * Initial scope is created from parameters defined in request context and
  21. * default values defined in ruleset (s_init_top_level_scope). Validation that
  22. * all required parameters have values is done at this point as well.
  23. *
  24. * Rules are then resolved sequentially against scope.
  25. * First list of conditions associated with the rule is resolved
  26. * (s_resolve_conditions). Final result of conditions resolution is an AND of
  27. * truthiness of resolved values (as defined in is_value_truthy) for each
  28. * condition. If resolution is true then rule is selected.
  29. * - For endpoint and error rules that means terminal state is reached and rule
  30. * data is returned
  31. * - For tree rule, the engine starts resolving rules associated with tree rule.
  32. * Note: tree rules are terminal and once engine jumps into tree rule
  33. * resolution there is no way to jump back out.
  34. *
  35. * Conditions can add values to scope. Those values are valid for the duration of
  36. * rule resolution. Note: for tree rules, any values added in tree conditions are
  37. * valid for all rules within the tree.
  38. * Scope can be though of as a 'leveled' structure. Top level or 0 level
  39. * represents all values from context and defaults. Levels 1 and up represent
  40. * values added by rules. Ex. if we start at level 0, all values added by rule
  41. * can be though of as level 1.
  42. * Since tree rule cannot be exited from, engine is simplified by making all
  43. * values in scope top level whenever tree is jumped into. So in practice engine
  44. * goes back between top level and first level as resolving rules. If that
  45. * changes in future, scope can add explicit level number and cleanup only values
  46. * at that level when going to next rule.
  47. *
  48. * Overall flow is as follows:
  49. * - Start with any values provided in context as scope
  50. * - Add any default values provided in ruleset and validate all required
  51. * params are specified.
  52. * - Iterate through rules and resolve each rule:
  53. * -- resolve conditions with side effects
  54. * -- if conditions are truthy return rule result
  55. * -- if conditions are truthy and rule is tree, jump down a level and
  56. * restart resolution with tree rules
  57. * -- if conditions are falsy, rollback level and go to next rule
  58. * - if no rules match, resolution fails with exhausted error.
  59. */
  60. struct resolve_template_callback_data {
  61. struct aws_allocator *allocator;
  62. struct aws_endpoints_resolution_scope *scope;
  63. };
  64. AWS_STATIC_ASSERT(AWS_ENDPOINTS_VALUE_SIZE == 7);
  65. static bool is_value_truthy(const struct aws_endpoints_value *value) {
  66. switch (value->type) {
  67. case AWS_ENDPOINTS_VALUE_NONE:
  68. return false;
  69. case AWS_ENDPOINTS_VALUE_BOOLEAN:
  70. return value->v.boolean;
  71. case AWS_ENDPOINTS_VALUE_ARRAY:
  72. case AWS_ENDPOINTS_VALUE_STRING:
  73. case AWS_ENDPOINTS_VALUE_OBJECT:
  74. return true;
  75. case AWS_ENDPOINTS_VALUE_NUMBER:
  76. return value->v.number != 0;
  77. default:
  78. AWS_ASSERT(false);
  79. return false;
  80. }
  81. }
  82. void s_scope_value_destroy_cb(void *data) {
  83. struct aws_endpoints_scope_value *value = data;
  84. aws_endpoints_scope_value_destroy(value);
  85. }
  86. static int s_deep_copy_context_to_scope(
  87. struct aws_allocator *allocator,
  88. const struct aws_endpoints_request_context *context,
  89. struct aws_endpoints_resolution_scope *scope) {
  90. struct aws_endpoints_scope_value *new_value = NULL;
  91. for (struct aws_hash_iter iter = aws_hash_iter_begin(&context->values); !aws_hash_iter_done(&iter);
  92. aws_hash_iter_next(&iter)) {
  93. struct aws_endpoints_scope_value *context_value = (struct aws_endpoints_scope_value *)iter.element.value;
  94. new_value = aws_endpoints_scope_value_new(allocator, context_value->name.cur);
  95. if (aws_endpoints_deep_copy_parameter_value(allocator, &context_value->value, &new_value->value)) {
  96. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to deep copy value.");
  97. goto on_error;
  98. }
  99. if (aws_hash_table_put(&scope->values, &new_value->name.cur, new_value, NULL)) {
  100. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to add deep copy to scope.");
  101. goto on_error;
  102. }
  103. }
  104. return AWS_OP_SUCCESS;
  105. on_error:
  106. aws_endpoints_scope_value_destroy(new_value);
  107. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_INIT_FAILED);
  108. }
  109. static int s_init_top_level_scope(
  110. struct aws_allocator *allocator,
  111. const struct aws_endpoints_request_context *context,
  112. const struct aws_endpoints_ruleset *ruleset,
  113. const struct aws_partitions_config *partitions,
  114. struct aws_endpoints_resolution_scope *scope) {
  115. AWS_PRECONDITION(allocator);
  116. AWS_PRECONDITION(context);
  117. AWS_PRECONDITION(ruleset);
  118. AWS_PRECONDITION(scope);
  119. struct aws_endpoints_scope_value *val = NULL;
  120. scope->rule_idx = 0;
  121. scope->rules = &ruleset->rules;
  122. scope->partitions = partitions;
  123. if (aws_hash_table_init(
  124. &scope->values,
  125. allocator,
  126. 0,
  127. aws_hash_byte_cursor_ptr,
  128. aws_endpoints_byte_cursor_eq,
  129. NULL,
  130. s_scope_value_destroy_cb)) {
  131. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to init request context values.");
  132. goto on_error;
  133. }
  134. if (s_deep_copy_context_to_scope(allocator, context, scope)) {
  135. goto on_error;
  136. }
  137. if (aws_array_list_init_dynamic(&scope->added_keys, allocator, 10, sizeof(struct aws_byte_cursor))) {
  138. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to init added keys.");
  139. goto on_error;
  140. }
  141. /* Add defaults to the top level scope. */
  142. for (struct aws_hash_iter iter = aws_hash_iter_begin(&ruleset->parameters); !aws_hash_iter_done(&iter);
  143. aws_hash_iter_next(&iter)) {
  144. const struct aws_byte_cursor key = *(const struct aws_byte_cursor *)iter.element.key;
  145. struct aws_endpoints_parameter *value = (struct aws_endpoints_parameter *)iter.element.value;
  146. /* Skip non-required values, since they cannot have default values. */
  147. if (!value->is_required) {
  148. continue;
  149. }
  150. struct aws_hash_element *existing = NULL;
  151. if (aws_hash_table_find(&scope->values, &key, &existing)) {
  152. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to init request context values.");
  153. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_INIT_FAILED);
  154. }
  155. if (existing == NULL) {
  156. if (!value->has_default_value) {
  157. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "No value or default for required parameter.");
  158. goto on_error;
  159. }
  160. val = aws_endpoints_scope_value_new(allocator, key);
  161. AWS_ASSERT(val);
  162. switch (value->type) {
  163. case AWS_ENDPOINTS_PARAMETER_STRING:
  164. val->value.type = AWS_ENDPOINTS_VALUE_STRING;
  165. val->value.v.owning_cursor_string =
  166. aws_endpoints_non_owning_cursor_create(value->default_value.string);
  167. break;
  168. case AWS_ENDPOINTS_PARAMETER_BOOLEAN:
  169. val->value.type = AWS_ENDPOINTS_VALUE_BOOLEAN;
  170. val->value.v.boolean = value->default_value.boolean;
  171. break;
  172. default:
  173. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Unexpected parameter type.");
  174. goto on_error;
  175. }
  176. if (aws_hash_table_put(&scope->values, &val->name.cur, val, NULL)) {
  177. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to add value to top level scope.");
  178. goto on_error;
  179. }
  180. }
  181. }
  182. return AWS_OP_SUCCESS;
  183. on_error:
  184. aws_endpoints_scope_value_destroy(val);
  185. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_INIT_FAILED);
  186. }
  187. static void s_scope_clean_up(struct aws_endpoints_resolution_scope *scope) {
  188. AWS_PRECONDITION(scope);
  189. aws_hash_table_clean_up(&scope->values);
  190. aws_array_list_clean_up(&scope->added_keys);
  191. }
  192. static int s_resolve_expr(
  193. struct aws_allocator *allocator,
  194. struct aws_endpoints_expr *expr,
  195. struct aws_endpoints_resolution_scope *scope,
  196. struct aws_endpoints_value *out_value);
  197. static int s_resolve_template(
  198. struct aws_byte_cursor template,
  199. void *user_data,
  200. struct aws_owning_cursor *out_owning_cursor);
  201. int aws_endpoints_argv_expect(
  202. struct aws_allocator *allocator,
  203. struct aws_endpoints_resolution_scope *scope,
  204. struct aws_array_list *argv,
  205. size_t idx,
  206. enum aws_endpoints_value_type expected_type,
  207. struct aws_endpoints_value *out_value) {
  208. AWS_ZERO_STRUCT(*out_value);
  209. struct aws_endpoints_value argv_value = {0};
  210. struct aws_endpoints_expr argv_expr;
  211. if (aws_array_list_get_at(argv, &argv_expr, idx)) {
  212. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to parse argv");
  213. goto on_error;
  214. }
  215. if (s_resolve_expr(allocator, &argv_expr, scope, &argv_value)) {
  216. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve argv.");
  217. goto on_error;
  218. }
  219. if (expected_type != AWS_ENDPOINTS_VALUE_ANY && argv_value.type != expected_type) {
  220. AWS_LOGF_ERROR(
  221. AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE,
  222. "Unexpected arg type actual: %u expected %u.",
  223. argv_value.type,
  224. expected_type);
  225. goto on_error;
  226. }
  227. *out_value = argv_value;
  228. return AWS_OP_SUCCESS;
  229. on_error:
  230. aws_endpoints_value_clean_up(&argv_value);
  231. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  232. }
  233. /*
  234. ******************************
  235. * Expr/String resolve
  236. ******************************
  237. */
  238. static int s_resolve_expr(
  239. struct aws_allocator *allocator,
  240. struct aws_endpoints_expr *expr,
  241. struct aws_endpoints_resolution_scope *scope,
  242. struct aws_endpoints_value *out_value) {
  243. AWS_ZERO_STRUCT(*out_value);
  244. switch (expr->type) {
  245. case AWS_ENDPOINTS_EXPR_STRING: {
  246. struct aws_byte_buf buf;
  247. struct resolve_template_callback_data data = {.allocator = allocator, .scope = scope};
  248. if (aws_byte_buf_init_from_resolved_templated_string(
  249. allocator, &buf, expr->e.string, s_resolve_template, &data, false)) {
  250. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve templated string.");
  251. goto on_error;
  252. }
  253. out_value->type = AWS_ENDPOINTS_VALUE_STRING;
  254. out_value->v.owning_cursor_string =
  255. aws_endpoints_owning_cursor_from_string(aws_string_new_from_buf(allocator, &buf));
  256. aws_byte_buf_clean_up(&buf);
  257. break;
  258. }
  259. case AWS_ENDPOINTS_EXPR_BOOLEAN: {
  260. out_value->type = AWS_ENDPOINTS_VALUE_BOOLEAN;
  261. out_value->v.boolean = expr->e.boolean;
  262. break;
  263. }
  264. case AWS_ENDPOINTS_EXPR_NUMBER: {
  265. out_value->type = AWS_ENDPOINTS_VALUE_NUMBER;
  266. out_value->v.number = expr->e.number;
  267. break;
  268. }
  269. case AWS_ENDPOINTS_EXPR_ARRAY: {
  270. out_value->type = AWS_ENDPOINTS_VALUE_ARRAY;
  271. /* TODO: deep copy */
  272. out_value->v.array = expr->e.array;
  273. break;
  274. }
  275. case AWS_ENDPOINTS_EXPR_REFERENCE: {
  276. struct aws_hash_element *element;
  277. if (aws_hash_table_find(&scope->values, &expr->e.reference, &element)) {
  278. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to deref.");
  279. goto on_error;
  280. }
  281. if (element == NULL) {
  282. out_value->type = AWS_ENDPOINTS_VALUE_NONE;
  283. } else {
  284. struct aws_endpoints_scope_value *aws_endpoints_scope_value = element->value;
  285. *out_value = aws_endpoints_scope_value->value;
  286. if (aws_endpoints_scope_value->value.type == AWS_ENDPOINTS_VALUE_STRING) {
  287. /* Value will not own underlying mem and instead its owned
  288. by the scope, so set it to NULL. */
  289. out_value->v.owning_cursor_string.string = NULL;
  290. } else if (aws_endpoints_scope_value->value.type == AWS_ENDPOINTS_VALUE_OBJECT) {
  291. out_value->v.owning_cursor_object.string = NULL;
  292. }
  293. }
  294. break;
  295. }
  296. case AWS_ENDPOINTS_EXPR_FUNCTION: {
  297. if (aws_endpoints_dispatch_standard_lib_fn_resolve(
  298. expr->e.function.fn, allocator, &expr->e.function.argv, scope, out_value)) {
  299. goto on_error;
  300. }
  301. break;
  302. }
  303. }
  304. return AWS_OP_SUCCESS;
  305. on_error:
  306. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  307. }
  308. static int s_resolve_one_condition(
  309. struct aws_allocator *allocator,
  310. struct aws_endpoints_condition *condition,
  311. struct aws_endpoints_resolution_scope *scope,
  312. bool *out_is_truthy) {
  313. struct aws_endpoints_scope_value *scope_value = NULL;
  314. struct aws_endpoints_value val;
  315. if (s_resolve_expr(allocator, &condition->expr, scope, &val)) {
  316. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve expr.");
  317. goto on_error;
  318. }
  319. *out_is_truthy = is_value_truthy(&val);
  320. /* Note: assigning value is skipped if condition is falsy, since nothing can
  321. use it and that avoids adding value and then removing it from scope right away. */
  322. if (*out_is_truthy && condition->assign.len > 0) {
  323. /* If condition assigns a value, push it to scope and let scope
  324. handle value memory. */
  325. scope_value = aws_endpoints_scope_value_new(allocator, condition->assign);
  326. scope_value->value = val;
  327. if (aws_array_list_push_back(&scope->added_keys, &scope_value->name.cur)) {
  328. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to update key at given scope.");
  329. goto on_error;
  330. }
  331. int was_created = 1;
  332. if (aws_hash_table_put(&scope->values, &scope_value->name.cur, scope_value, &was_created)) {
  333. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to set assigned variable.");
  334. goto on_error;
  335. }
  336. /* Shadowing existing values is prohibited. */
  337. if (!was_created) {
  338. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Assigned variable shadows existing one.");
  339. goto on_error;
  340. }
  341. } else {
  342. /* Otherwise clean up temp value */
  343. aws_endpoints_value_clean_up(&val);
  344. }
  345. return AWS_OP_SUCCESS;
  346. on_error:
  347. aws_endpoints_scope_value_destroy(scope_value);
  348. /* Only cleanup value if mem ownership was not transferred to scope value. */
  349. if (scope_value == NULL) {
  350. aws_endpoints_value_clean_up(&val);
  351. }
  352. *out_is_truthy = false;
  353. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  354. }
  355. static int s_resolve_conditions(
  356. struct aws_allocator *allocator,
  357. const struct aws_array_list *conditions,
  358. struct aws_endpoints_resolution_scope *scope,
  359. bool *out_is_truthy) {
  360. /* Note: spec defines empty conditions list as truthy. */
  361. *out_is_truthy = true;
  362. for (size_t idx = 0; idx < aws_array_list_length(conditions); ++idx) {
  363. struct aws_endpoints_condition *condition = NULL;
  364. if (aws_array_list_get_at_ptr(conditions, (void **)&condition, idx)) {
  365. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to retrieve condition.");
  366. goto on_error;
  367. }
  368. if (s_resolve_one_condition(allocator, condition, scope, out_is_truthy)) {
  369. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve condition.");
  370. goto on_error;
  371. }
  372. /* truthiness of all conditions is an AND of truthiness for each condition,
  373. hence first false one short circuits resolution */
  374. if (!*out_is_truthy) {
  375. break;
  376. }
  377. }
  378. return AWS_OP_SUCCESS;
  379. on_error:
  380. *out_is_truthy = false;
  381. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  382. }
  383. int aws_endpoints_path_through_array(
  384. struct aws_allocator *allocator,
  385. struct aws_endpoints_resolution_scope *scope,
  386. struct aws_endpoints_value *value,
  387. struct aws_byte_cursor path_cur,
  388. struct aws_endpoints_value *out_value) {
  389. AWS_PRECONDITION(value->type == AWS_ENDPOINTS_VALUE_ARRAY);
  390. uint64_t index;
  391. struct aws_byte_cursor split = {0};
  392. if ((!aws_byte_cursor_next_split(&path_cur, '[', &split) || split.len > 0) ||
  393. !aws_byte_cursor_next_split(&path_cur, ']', &split) || aws_byte_cursor_utf8_parse_u64(split, &index)) {
  394. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Could not parse index from template string.");
  395. goto on_error;
  396. }
  397. if (index < aws_array_list_length(&value->v.array)) {
  398. out_value->type = AWS_ENDPOINTS_VALUE_NONE;
  399. return AWS_OP_SUCCESS;
  400. }
  401. struct aws_endpoints_expr *expr = NULL;
  402. if (aws_array_list_get_at_ptr(&value->v.array, (void **)&expr, (size_t)index)) {
  403. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to index into resolved value");
  404. goto on_error;
  405. }
  406. struct aws_endpoints_value val;
  407. if (s_resolve_expr(allocator, expr, scope, &val)) {
  408. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve val.");
  409. aws_endpoints_value_clean_up(&val);
  410. goto on_error;
  411. }
  412. *out_value = val;
  413. return AWS_OP_SUCCESS;
  414. on_error:
  415. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  416. }
  417. int aws_endpoints_path_through_object(
  418. struct aws_allocator *allocator,
  419. struct aws_endpoints_value *value,
  420. struct aws_byte_cursor path_cur,
  421. struct aws_endpoints_value *out_value) {
  422. AWS_ZERO_STRUCT(*out_value);
  423. struct aws_json_value *root_node = NULL;
  424. struct aws_byte_cursor value_cur = value->type != AWS_ENDPOINTS_VALUE_STRING ? value->v.owning_cursor_string.cur
  425. : value->v.owning_cursor_object.cur;
  426. root_node = aws_json_value_new_from_string(allocator, value_cur);
  427. const struct aws_json_value *result;
  428. if (aws_path_through_json(allocator, root_node, path_cur, &result)) {
  429. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to path through json.");
  430. goto on_error;
  431. }
  432. if (result == NULL) {
  433. out_value->type = AWS_ENDPOINTS_VALUE_NONE;
  434. } else if (aws_json_value_is_string(result)) {
  435. struct aws_byte_cursor final;
  436. if (aws_json_value_get_string(result, &final)) {
  437. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Could not parse string from node.");
  438. goto on_error;
  439. }
  440. out_value->type = AWS_ENDPOINTS_VALUE_STRING;
  441. out_value->v.owning_cursor_string = aws_endpoints_owning_cursor_from_cursor(allocator, final);
  442. } else if (aws_json_value_is_array(result) || aws_json_value_is_object(result)) {
  443. struct aws_byte_buf json_blob;
  444. aws_byte_buf_init(&json_blob, allocator, 0);
  445. if (aws_byte_buf_append_json_string(result, &json_blob)) {
  446. aws_byte_buf_clean_up(&json_blob);
  447. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to extract properties.");
  448. goto on_error;
  449. }
  450. aws_byte_buf_clean_up(&json_blob);
  451. out_value->type = AWS_ENDPOINTS_VALUE_OBJECT;
  452. out_value->v.owning_cursor_object =
  453. aws_endpoints_owning_cursor_from_string(aws_string_new_from_buf(allocator, &json_blob));
  454. } else if (aws_json_value_is_boolean(result)) {
  455. if (aws_json_value_get_boolean(result, &out_value->v.boolean)) {
  456. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Could not parse boolean from node.");
  457. goto on_error;
  458. }
  459. out_value->type = AWS_ENDPOINTS_VALUE_BOOLEAN;
  460. } else if (aws_json_value_is_number(result)) {
  461. if (aws_json_value_get_number(result, &out_value->v.number)) {
  462. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Could not parse number from node.");
  463. goto on_error;
  464. }
  465. out_value->type = AWS_ENDPOINTS_VALUE_NUMBER;
  466. }
  467. aws_json_value_destroy(root_node);
  468. return AWS_OP_SUCCESS;
  469. on_error:
  470. aws_json_value_destroy(root_node);
  471. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  472. }
  473. static int s_resolve_templated_value_with_pathing(
  474. struct aws_allocator *allocator,
  475. struct aws_endpoints_resolution_scope *scope,
  476. struct aws_byte_cursor template_cur,
  477. struct aws_owning_cursor *out_owning_cursor) {
  478. struct aws_endpoints_value resolved_value = {0};
  479. struct aws_byte_cursor split = {0};
  480. if (!aws_byte_cursor_next_split(&template_cur, '#', &split) || split.len == 0) {
  481. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Invalid value in template string.");
  482. goto on_error;
  483. }
  484. struct aws_hash_element *elem = NULL;
  485. if (aws_hash_table_find(&scope->values, &split, &elem) || elem == NULL) {
  486. AWS_LOGF_ERROR(
  487. AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Templated value does not exist: " PRInSTR, AWS_BYTE_CURSOR_PRI(split));
  488. goto on_error;
  489. }
  490. struct aws_endpoints_scope_value *scope_value = elem->value;
  491. if (!aws_byte_cursor_next_split(&template_cur, '#', &split)) {
  492. if (scope_value->value.type != AWS_ENDPOINTS_VALUE_STRING) {
  493. AWS_LOGF_ERROR(
  494. AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Unexpected type: must be string if pathing is not provided");
  495. goto on_error;
  496. }
  497. *out_owning_cursor = aws_endpoints_non_owning_cursor_create(scope_value->value.v.owning_cursor_string.cur);
  498. return AWS_OP_SUCCESS;
  499. }
  500. if (scope_value->value.type == AWS_ENDPOINTS_VALUE_OBJECT) {
  501. if (aws_endpoints_path_through_object(allocator, &scope_value->value, split, &resolved_value)) {
  502. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to path through object.");
  503. goto on_error;
  504. }
  505. } else if (scope_value->value.type == AWS_ENDPOINTS_VALUE_ARRAY) {
  506. if (aws_endpoints_path_through_array(allocator, scope, &scope_value->value, split, &resolved_value)) {
  507. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to path through array.");
  508. goto on_error;
  509. }
  510. } else {
  511. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Invalid value type for pathing through.");
  512. goto on_error;
  513. }
  514. if (resolved_value.type != AWS_ENDPOINTS_VALUE_STRING) {
  515. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Templated string didn't resolve to string");
  516. goto on_error;
  517. }
  518. if (resolved_value.v.owning_cursor_string.string != NULL) {
  519. /* Transfer ownership of the underlying string. */
  520. *out_owning_cursor = aws_endpoints_owning_cursor_from_string(resolved_value.v.owning_cursor_string.string);
  521. resolved_value.v.owning_cursor_string.string = NULL;
  522. } else {
  523. /* Unlikely to get here since current pathing always return new string. */
  524. *out_owning_cursor = aws_endpoints_non_owning_cursor_create(resolved_value.v.owning_cursor_string.cur);
  525. }
  526. aws_endpoints_value_clean_up(&resolved_value);
  527. return AWS_OP_SUCCESS;
  528. on_error:
  529. aws_endpoints_value_clean_up(&resolved_value);
  530. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  531. }
  532. static int s_resolve_template(struct aws_byte_cursor template, void *user_data, struct aws_owning_cursor *out_cursor) {
  533. struct resolve_template_callback_data *data = user_data;
  534. if (s_resolve_templated_value_with_pathing(data->allocator, data->scope, template, out_cursor)) {
  535. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve template value.");
  536. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  537. ;
  538. }
  539. return AWS_OP_SUCCESS;
  540. }
  541. /*
  542. ******************************
  543. * Request Context
  544. ******************************
  545. */
  546. static void s_endpoints_request_context_destroy(void *data) {
  547. if (data == NULL) {
  548. return;
  549. }
  550. struct aws_endpoints_request_context *context = data;
  551. aws_hash_table_clean_up(&context->values);
  552. aws_mem_release(context->allocator, context);
  553. }
  554. struct aws_endpoints_request_context *aws_endpoints_request_context_new(struct aws_allocator *allocator) {
  555. AWS_PRECONDITION(allocator);
  556. struct aws_endpoints_request_context *context =
  557. aws_mem_calloc(allocator, 1, sizeof(struct aws_endpoints_request_context));
  558. context->allocator = allocator;
  559. aws_ref_count_init(&context->ref_count, context, s_endpoints_request_context_destroy);
  560. if (aws_hash_table_init(
  561. &context->values,
  562. allocator,
  563. 0,
  564. aws_hash_byte_cursor_ptr,
  565. aws_endpoints_byte_cursor_eq,
  566. NULL,
  567. s_scope_value_destroy_cb)) {
  568. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to init request context values.");
  569. goto on_error;
  570. }
  571. return context;
  572. on_error:
  573. s_endpoints_request_context_destroy(context);
  574. return NULL;
  575. }
  576. struct aws_endpoints_request_context *aws_endpoints_request_context_acquire(
  577. struct aws_endpoints_request_context *request_context) {
  578. AWS_PRECONDITION(request_context);
  579. if (request_context) {
  580. aws_ref_count_acquire(&request_context->ref_count);
  581. }
  582. return request_context;
  583. }
  584. struct aws_endpoints_request_context *aws_endpoints_request_context_release(
  585. struct aws_endpoints_request_context *request_context) {
  586. if (request_context) {
  587. aws_ref_count_release(&request_context->ref_count);
  588. }
  589. return NULL;
  590. }
  591. int aws_endpoints_request_context_add_string(
  592. struct aws_allocator *allocator,
  593. struct aws_endpoints_request_context *context,
  594. struct aws_byte_cursor name,
  595. struct aws_byte_cursor value) {
  596. AWS_PRECONDITION(allocator);
  597. struct aws_endpoints_scope_value *val = aws_endpoints_scope_value_new(allocator, name);
  598. val->value.type = AWS_ENDPOINTS_VALUE_STRING;
  599. val->value.v.owning_cursor_string = aws_endpoints_owning_cursor_from_cursor(allocator, value);
  600. if (aws_hash_table_put(&context->values, &val->name.cur, val, NULL)) {
  601. aws_endpoints_scope_value_destroy(val);
  602. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_INIT_FAILED);
  603. };
  604. return AWS_OP_SUCCESS;
  605. }
  606. int aws_endpoints_request_context_add_boolean(
  607. struct aws_allocator *allocator,
  608. struct aws_endpoints_request_context *context,
  609. struct aws_byte_cursor name,
  610. bool value) {
  611. AWS_PRECONDITION(allocator);
  612. struct aws_endpoints_scope_value *val = aws_endpoints_scope_value_new(allocator, name);
  613. val->value.type = AWS_ENDPOINTS_VALUE_BOOLEAN;
  614. val->value.v.boolean = value;
  615. if (aws_hash_table_put(&context->values, &val->name.cur, val, NULL)) {
  616. aws_endpoints_scope_value_destroy(val);
  617. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_INIT_FAILED);
  618. };
  619. return AWS_OP_SUCCESS;
  620. }
  621. /*
  622. ******************************
  623. * Rule engine.
  624. ******************************
  625. */
  626. struct aws_endpoints_resolved_endpoint {
  627. struct aws_allocator *allocator;
  628. struct aws_ref_count ref_count;
  629. enum aws_endpoints_resolved_endpoint_type type;
  630. union {
  631. struct resolved_endpoint {
  632. struct aws_byte_buf url;
  633. struct aws_byte_buf properties;
  634. struct aws_hash_table headers;
  635. } endpoint;
  636. struct aws_byte_buf error;
  637. } r;
  638. };
  639. static void s_endpoints_resolved_endpoint_destroy(void *data) {
  640. if (data == NULL) {
  641. return;
  642. }
  643. struct aws_endpoints_resolved_endpoint *resolved = data;
  644. if (resolved->type == AWS_ENDPOINTS_RESOLVED_ENDPOINT) {
  645. aws_byte_buf_clean_up(&resolved->r.endpoint.url);
  646. aws_byte_buf_clean_up(&resolved->r.endpoint.properties);
  647. aws_hash_table_clean_up(&resolved->r.endpoint.headers);
  648. } else if (resolved->type == AWS_ENDPOINTS_RESOLVED_ERROR) {
  649. aws_byte_buf_clean_up(&resolved->r.error);
  650. }
  651. aws_mem_release(resolved->allocator, resolved);
  652. }
  653. struct aws_endpoints_resolved_endpoint *s_endpoints_resolved_endpoint_new(struct aws_allocator *allocator) {
  654. AWS_PRECONDITION(allocator);
  655. struct aws_endpoints_resolved_endpoint *resolved =
  656. aws_mem_calloc(allocator, 1, sizeof(struct aws_endpoints_resolved_endpoint));
  657. resolved->allocator = allocator;
  658. aws_ref_count_init(&resolved->ref_count, resolved, s_endpoints_resolved_endpoint_destroy);
  659. return resolved;
  660. }
  661. struct aws_endpoints_resolved_endpoint *aws_endpoints_resolved_endpoint_acquire(
  662. struct aws_endpoints_resolved_endpoint *resolved_endpoint) {
  663. AWS_PRECONDITION(resolved_endpoint);
  664. if (resolved_endpoint) {
  665. aws_ref_count_acquire(&resolved_endpoint->ref_count);
  666. }
  667. return resolved_endpoint;
  668. }
  669. struct aws_endpoints_resolved_endpoint *aws_endpoints_resolved_endpoint_release(
  670. struct aws_endpoints_resolved_endpoint *resolved_endpoint) {
  671. if (resolved_endpoint) {
  672. aws_ref_count_release(&resolved_endpoint->ref_count);
  673. }
  674. return NULL;
  675. }
  676. enum aws_endpoints_resolved_endpoint_type aws_endpoints_resolved_endpoint_get_type(
  677. const struct aws_endpoints_resolved_endpoint *resolved_endpoint) {
  678. AWS_PRECONDITION(resolved_endpoint);
  679. return resolved_endpoint->type;
  680. }
  681. int aws_endpoints_resolved_endpoint_get_url(
  682. const struct aws_endpoints_resolved_endpoint *resolved_endpoint,
  683. struct aws_byte_cursor *out_url) {
  684. AWS_PRECONDITION(resolved_endpoint);
  685. AWS_PRECONDITION(out_url);
  686. if (resolved_endpoint->type != AWS_ENDPOINTS_RESOLVED_ENDPOINT) {
  687. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  688. }
  689. *out_url = aws_byte_cursor_from_buf(&resolved_endpoint->r.endpoint.url);
  690. return AWS_OP_SUCCESS;
  691. }
  692. int aws_endpoints_resolved_endpoint_get_properties(
  693. const struct aws_endpoints_resolved_endpoint *resolved_endpoint,
  694. struct aws_byte_cursor *out_properties) {
  695. AWS_PRECONDITION(resolved_endpoint);
  696. AWS_PRECONDITION(out_properties);
  697. if (resolved_endpoint->type != AWS_ENDPOINTS_RESOLVED_ENDPOINT) {
  698. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  699. }
  700. *out_properties = aws_byte_cursor_from_buf(&resolved_endpoint->r.endpoint.properties);
  701. return AWS_OP_SUCCESS;
  702. }
  703. int aws_endpoints_resolved_endpoint_get_headers(
  704. const struct aws_endpoints_resolved_endpoint *resolved_endpoint,
  705. const struct aws_hash_table **out_headers) {
  706. AWS_PRECONDITION(resolved_endpoint);
  707. AWS_PRECONDITION(out_headers);
  708. if (resolved_endpoint->type != AWS_ENDPOINTS_RESOLVED_ENDPOINT) {
  709. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  710. }
  711. *out_headers = &resolved_endpoint->r.endpoint.headers;
  712. return AWS_OP_SUCCESS;
  713. }
  714. int aws_endpoints_resolved_endpoint_get_error(
  715. const struct aws_endpoints_resolved_endpoint *resolved_endpoint,
  716. struct aws_byte_cursor *out_error) {
  717. AWS_PRECONDITION(resolved_endpoint);
  718. AWS_PRECONDITION(out_error);
  719. if (resolved_endpoint->type != AWS_ENDPOINTS_RESOLVED_ERROR) {
  720. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  721. }
  722. *out_error = aws_byte_cursor_from_buf(&resolved_endpoint->r.error);
  723. return AWS_OP_SUCCESS;
  724. }
  725. struct aws_endpoints_rule_engine {
  726. struct aws_allocator *allocator;
  727. struct aws_ref_count ref_count;
  728. struct aws_endpoints_ruleset *ruleset;
  729. struct aws_partitions_config *partitions_config;
  730. };
  731. static void s_endpoints_rule_engine_destroy(void *data) {
  732. if (data == NULL) {
  733. return;
  734. }
  735. struct aws_endpoints_rule_engine *engine = data;
  736. aws_endpoints_ruleset_release(engine->ruleset);
  737. aws_partitions_config_release(engine->partitions_config);
  738. aws_mem_release(engine->allocator, engine);
  739. }
  740. struct aws_endpoints_rule_engine *aws_endpoints_rule_engine_new(
  741. struct aws_allocator *allocator,
  742. struct aws_endpoints_ruleset *ruleset,
  743. struct aws_partitions_config *partitions_config) {
  744. AWS_PRECONDITION(allocator);
  745. AWS_PRECONDITION(ruleset);
  746. struct aws_endpoints_rule_engine *engine = aws_mem_calloc(allocator, 1, sizeof(struct aws_endpoints_rule_engine));
  747. engine->allocator = allocator;
  748. engine->ruleset = ruleset;
  749. engine->partitions_config = partitions_config;
  750. aws_endpoints_ruleset_acquire(ruleset);
  751. aws_partitions_config_acquire(partitions_config);
  752. aws_ref_count_init(&engine->ref_count, engine, s_endpoints_rule_engine_destroy);
  753. return engine;
  754. }
  755. struct aws_endpoints_rule_engine *aws_endpoints_rule_engine_acquire(struct aws_endpoints_rule_engine *rule_engine) {
  756. AWS_PRECONDITION(rule_engine);
  757. if (rule_engine) {
  758. aws_ref_count_acquire(&rule_engine->ref_count);
  759. }
  760. return rule_engine;
  761. }
  762. struct aws_endpoints_rule_engine *aws_endpoints_rule_engine_release(struct aws_endpoints_rule_engine *rule_engine) {
  763. if (rule_engine) {
  764. aws_ref_count_release(&rule_engine->ref_count);
  765. }
  766. return NULL;
  767. }
  768. int s_revert_scope(struct aws_endpoints_resolution_scope *scope) {
  769. for (size_t idx = 0; idx < aws_array_list_length(&scope->added_keys); ++idx) {
  770. struct aws_byte_cursor *cur = NULL;
  771. if (aws_array_list_get_at_ptr(&scope->added_keys, (void **)&cur, idx)) {
  772. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to retrieve value.");
  773. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  774. }
  775. aws_hash_table_remove(&scope->values, cur, NULL, NULL);
  776. }
  777. aws_array_list_clear(&scope->added_keys);
  778. return AWS_OP_SUCCESS;
  779. }
  780. static void s_on_string_array_element_destroy(void *element) {
  781. struct aws_string *str = *(struct aws_string **)element;
  782. aws_string_destroy(str);
  783. }
  784. static void s_callback_headers_destroy(void *data) {
  785. struct aws_array_list *array = data;
  786. struct aws_allocator *alloc = array->alloc;
  787. aws_array_list_deep_clean_up(array, s_on_string_array_element_destroy);
  788. aws_mem_release(alloc, array);
  789. }
  790. static int s_resolve_headers(
  791. struct aws_allocator *allocator,
  792. struct aws_endpoints_resolution_scope *scope,
  793. struct aws_hash_table *headers,
  794. struct aws_hash_table *out_headers) {
  795. struct aws_endpoints_value value;
  796. struct aws_array_list *resolved_headers = NULL;
  797. if (aws_hash_table_init(
  798. out_headers,
  799. allocator,
  800. aws_hash_table_get_entry_count(headers),
  801. aws_hash_string,
  802. aws_hash_callback_string_eq,
  803. aws_hash_callback_string_destroy,
  804. s_callback_headers_destroy)) {
  805. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to init table for resolved headers");
  806. goto on_error;
  807. }
  808. for (struct aws_hash_iter iter = aws_hash_iter_begin(headers); !aws_hash_iter_done(&iter);
  809. aws_hash_iter_next(&iter)) {
  810. struct aws_string *key = (struct aws_string *)iter.element.key;
  811. struct aws_array_list *header_list = (struct aws_array_list *)iter.element.value;
  812. resolved_headers = aws_mem_calloc(allocator, 1, sizeof(struct aws_array_list));
  813. aws_array_list_init_dynamic(
  814. resolved_headers, allocator, aws_array_list_length(header_list), sizeof(struct aws_string *));
  815. for (size_t i = 0; i < aws_array_list_length(header_list); ++i) {
  816. struct aws_endpoints_expr *expr = NULL;
  817. if (aws_array_list_get_at_ptr(header_list, (void **)&expr, i)) {
  818. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to get header.");
  819. goto on_error;
  820. }
  821. if (s_resolve_expr(allocator, expr, scope, &value) || value.type != AWS_ENDPOINTS_VALUE_STRING) {
  822. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve header expr.");
  823. goto on_error;
  824. }
  825. struct aws_string *str = aws_string_new_from_cursor(allocator, &value.v.owning_cursor_string.cur);
  826. if (aws_array_list_push_back(resolved_headers, &str)) {
  827. aws_string_destroy(str);
  828. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to add resolved header to result.");
  829. goto on_error;
  830. }
  831. aws_endpoints_value_clean_up(&value);
  832. }
  833. if (aws_hash_table_put(out_headers, aws_string_clone_or_reuse(allocator, key), resolved_headers, NULL)) {
  834. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to add resolved header to result.");
  835. goto on_error;
  836. }
  837. }
  838. return AWS_OP_SUCCESS;
  839. on_error:
  840. aws_endpoints_value_clean_up(&value);
  841. if (resolved_headers != NULL) {
  842. s_callback_headers_destroy(resolved_headers);
  843. }
  844. aws_hash_table_clean_up(out_headers);
  845. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  846. }
  847. int aws_endpoints_rule_engine_resolve(
  848. struct aws_endpoints_rule_engine *engine,
  849. const struct aws_endpoints_request_context *context,
  850. struct aws_endpoints_resolved_endpoint **out_resolved_endpoint) {
  851. if (aws_array_list_length(&engine->ruleset->rules) == 0) {
  852. return aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_EMPTY_RULESET);
  853. }
  854. int result = AWS_OP_SUCCESS;
  855. struct aws_endpoints_resolution_scope scope;
  856. if (s_init_top_level_scope(engine->allocator, context, engine->ruleset, engine->partitions_config, &scope)) {
  857. result = AWS_OP_ERR;
  858. goto on_done;
  859. }
  860. while (scope.rule_idx < aws_array_list_length(scope.rules)) {
  861. struct aws_endpoints_rule *rule = NULL;
  862. if (aws_array_list_get_at_ptr(scope.rules, (void **)&rule, scope.rule_idx)) {
  863. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to get rule.");
  864. result = AWS_OP_ERR;
  865. goto on_done;
  866. }
  867. bool is_truthy = false;
  868. if (s_resolve_conditions(engine->allocator, &rule->conditions, &scope, &is_truthy)) {
  869. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve conditions.");
  870. result = AWS_OP_ERR;
  871. goto on_done;
  872. }
  873. if (!is_truthy) {
  874. s_revert_scope(&scope);
  875. ++scope.rule_idx;
  876. continue;
  877. }
  878. switch (rule->type) {
  879. case AWS_ENDPOINTS_RULE_ENDPOINT: {
  880. struct aws_endpoints_resolved_endpoint *endpoint = s_endpoints_resolved_endpoint_new(engine->allocator);
  881. endpoint->type = AWS_ENDPOINTS_RESOLVED_ENDPOINT;
  882. struct aws_endpoints_value val;
  883. if (s_resolve_expr(engine->allocator, &rule->rule_data.endpoint.url, &scope, &val) ||
  884. val.type != AWS_ENDPOINTS_VALUE_STRING ||
  885. aws_byte_buf_init_copy_from_cursor(
  886. &endpoint->r.endpoint.url, engine->allocator, val.v.owning_cursor_string.cur)) {
  887. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve templated url.");
  888. result = AWS_OP_ERR;
  889. goto on_done;
  890. }
  891. aws_endpoints_value_clean_up(&val);
  892. struct resolve_template_callback_data data = {.allocator = engine->allocator, .scope = &scope};
  893. if (rule->rule_data.endpoint.properties.len > 0 &&
  894. aws_byte_buf_init_from_resolved_templated_string(
  895. engine->allocator,
  896. &endpoint->r.endpoint.properties,
  897. aws_byte_cursor_from_buf(&rule->rule_data.endpoint.properties),
  898. s_resolve_template,
  899. &data,
  900. true)) {
  901. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve templated properties.");
  902. result = AWS_OP_ERR;
  903. goto on_done;
  904. }
  905. if (s_resolve_headers(
  906. engine->allocator, &scope, &rule->rule_data.endpoint.headers, &endpoint->r.endpoint.headers)) {
  907. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve templated headers.");
  908. result = AWS_OP_ERR;
  909. goto on_done;
  910. }
  911. *out_resolved_endpoint = endpoint;
  912. goto on_done;
  913. }
  914. case AWS_ENDPOINTS_RULE_ERROR: {
  915. struct aws_endpoints_resolved_endpoint *error = s_endpoints_resolved_endpoint_new(engine->allocator);
  916. error->type = AWS_ENDPOINTS_RESOLVED_ERROR;
  917. struct aws_endpoints_value val;
  918. if (s_resolve_expr(engine->allocator, &rule->rule_data.error.error, &scope, &val) ||
  919. val.type != AWS_ENDPOINTS_VALUE_STRING ||
  920. aws_byte_buf_init_copy_from_cursor(
  921. &error->r.error, engine->allocator, val.v.owning_cursor_string.cur)) {
  922. aws_endpoints_value_clean_up(&val);
  923. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Failed to resolve templated url.");
  924. result = AWS_OP_ERR;
  925. goto on_done;
  926. }
  927. aws_endpoints_value_clean_up(&val);
  928. *out_resolved_endpoint = error;
  929. goto on_done;
  930. }
  931. case AWS_ENDPOINTS_RULE_TREE: {
  932. /* jumping down a level */
  933. aws_array_list_clear(&scope.added_keys);
  934. scope.rule_idx = 0;
  935. scope.rules = &rule->rule_data.tree.rules;
  936. continue;
  937. }
  938. default: {
  939. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Unexpected rule type.");
  940. result = aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RESOLVE_FAILED);
  941. goto on_done;
  942. }
  943. }
  944. }
  945. AWS_LOGF_ERROR(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "All rules have been exhausted.");
  946. result = aws_raise_error(AWS_ERROR_SDKUTILS_ENDPOINTS_RULESET_EXHAUSTED);
  947. on_done:
  948. AWS_LOGF_DEBUG(AWS_LS_SDKUTILS_ENDPOINTS_RESOLVE, "Resolved endpoint with status %d", result);
  949. s_scope_clean_up(&scope);
  950. return result;
  951. }