]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add xlat_tokenize_ephemeral_expression() and tests
authorAlan T. DeKok <aland@freeradius.org>
Wed, 9 Feb 2022 20:03:52 +0000 (15:03 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 9 Feb 2022 20:03:52 +0000 (15:03 -0500)
so that the new xlat expressions can be tested with something
more than just parsing

src/bin/unit_test_module.c
src/lib/unlang/xlat.h
src/lib/unlang/xlat_expr.c

index ce78013a5f85a7cec275440a63d8d6bf37649873..378e594dada6e2be800ac7bf8b3b2a59ca479422 100644 (file)
@@ -412,6 +412,50 @@ static bool do_xlats(fr_event_list_t *el, char const *filename, FILE *fp)
                        continue;
                }
 
+               /*
+                *      Look for "xlat_expr"
+                */
+               if (strncmp(input, "xlat_expr ", 10) == 0) {
+                       ssize_t                 slen;
+                       TALLOC_CTX              *xlat_ctx = talloc_init_const("xlat");
+                       char                    *fmt = talloc_typed_strdup(xlat_ctx, input + 10);
+                       xlat_exp_t              *head = NULL;
+
+                       slen = xlat_tokenize_ephemeral_expression(xlat_ctx, &head, el, NULL,
+                                                                 &FR_SBUFF_IN(fmt, talloc_array_length(fmt) - 1),
+                                                                 NULL,
+                                                                 &(tmpl_rules_t) {
+                                                                         .attr = {
+                                                                                 .dict_def = dict_protocol,
+                                                                                 .allow_unresolved = true,
+                                                                         }
+                                                                                 }
+                                                               );
+                       if (slen <= 0) {
+                               talloc_free(xlat_ctx);
+                               snprintf(output, sizeof(output), "ERROR offset %d '%s'", (int) -slen,
+                                        fr_strerror());
+                               continue;
+                       }
+
+                       if (input[slen + 10] != '\0') {
+                               talloc_free(xlat_ctx);
+                               snprintf(output, sizeof(output), "ERROR offset %d Unexpected text '%s' after parsing",
+                                        (int) slen, input + slen + 10);
+                               continue;
+                       }
+
+                       len = xlat_eval_compiled(output, sizeof(output), request, head, NULL, NULL);
+                       if (len < 0) {
+                               talloc_free(xlat_ctx);
+                               snprintf(output, sizeof(output), "ERROR expanding xlat: %s", fr_strerror());
+                               continue;
+                       }
+
+                       TALLOC_FREE(xlat_ctx); /* also frees 'head' */
+                       continue;
+               }
+
                /*
                 *      Look for "data".
                 */
index a8217bd5593a6d7a615b502d82e577020935ddae..0fa7cd0263514afcbb0e02308707fec4f5946a2a 100644 (file)
@@ -295,6 +295,11 @@ bool               xlat_async_required(xlat_exp_t const *xlat);
 ssize_t                xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_t *flags, fr_sbuff_t *in,
                                         fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules);
 
+ssize_t                xlat_tokenize_ephemeral_expression(TALLOC_CTX *ctx, xlat_exp_t **head,
+                                                  fr_event_list_t *el,
+                                                  xlat_flags_t *flags, fr_sbuff_t *in,
+                                                  fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules);
+
 ssize_t                xlat_tokenize_ephemeral(TALLOC_CTX *ctx, xlat_exp_t **head,
                                        fr_event_list_t *el,
                                        xlat_flags_t *flags, fr_sbuff_t *in,
index 87c9a7e9a369a0fdf8e781b9e09838d6ce7dc5bd..bae29a012c1c08c4026d7d9e5159c53a067c1c2d 100644 (file)
@@ -1456,8 +1456,8 @@ ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_
        ssize_t slen;
        fr_sbuff_parse_rules_t *bracket_rules = NULL;
        fr_sbuff_parse_rules_t *terminal_rules = NULL;
-       xlat_flags_t my_flags = { };
-       tmpl_rules_t my_rules = { };
+       xlat_flags_t my_flags = { };
+       tmpl_rules_t my_rules = { };
 
        /*
         *      Whatever the caller passes, ensure that we have a
@@ -1495,11 +1495,21 @@ ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_
        talloc_free(bracket_rules);
        talloc_free(terminal_rules);
 
-       if (slen <= 0) return slen;
+       if (slen < 0) return slen;
+
+       /*
+        *      Zero length expansion, return a zero length node.
+        */
+       if (!*head) {
+               *head = xlat_exp_alloc(ctx, XLAT_BOX, "", 0);
+               return 0;
+       }
 
        /*
         *      Add nodes that need to be bootstrapped to
         *      the registry.
+        *
+        *      @todo - can't do this for ephemeral ones!
         */
        if (xlat_bootstrap(*head) < 0) {
                TALLOC_FREE(*head);
@@ -1508,3 +1518,93 @@ ssize_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_t **head, xlat_flags_
 
        return slen;
 }
+
+/** Tokenize an xlat expression at runtime
+ *
+ * This function is only for testing.  It should be deleted when
+ * expressions are integrated into the main xlat parser.
+ *
+ * @param[in] ctx      to allocate dynamic buffers in.
+ * @param[out] head    the head of the xlat list / tree structure.
+ * @param[in] el       for registering any I/O handlers.
+ * @param[out] flags   indicating the state of the ephemeral tree.
+ * @param[in] in       the format string to expand.
+ * @param[in] p_rules  from the encompassing grammar.
+ * @param[in] t_rules  controlling how attribute references are parsed.
+ * @return
+ *     - >0 on success.
+ *     - 0 and *head == NULL - Parse failure on first char.
+ *     - 0 and *head != NULL - Zero length expansion
+ *     - <0 the negative offset of the parse failure.
+ */
+ssize_t xlat_tokenize_ephemeral_expression(TALLOC_CTX *ctx, xlat_exp_t **head,
+                                          fr_event_list_t *el,
+                                          xlat_flags_t *flags, fr_sbuff_t *in,
+                                          fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
+{
+       ssize_t slen;
+       fr_sbuff_parse_rules_t *bracket_rules = NULL;
+       fr_sbuff_parse_rules_t *terminal_rules = NULL;
+       xlat_flags_t my_flags = { };
+       tmpl_rules_t my_rules = { };
+
+       /*
+        *      Whatever the caller passes, ensure that we have a
+        *      terminal rule which ends on operators, and a terminal
+        *      rule which ends on ')'.
+        */
+       MEM(bracket_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
+       MEM(terminal_rules = talloc_zero(ctx, fr_sbuff_parse_rules_t));
+       if (p_rules) {
+               *bracket_rules = *p_rules;
+               *terminal_rules = *p_rules;
+
+               if (p_rules->terminals) {
+                       MEM(terminal_rules->terminals = fr_sbuff_terminals_amerge(bracket_rules,
+                                                                                 p_rules->terminals,
+                                                                                 &operator_terms));
+               } else {
+                       terminal_rules->terminals = &operator_terms;
+               }
+       } else {
+               terminal_rules->terminals = &operator_terms;
+       }
+       MEM(bracket_rules->terminals = fr_sbuff_terminals_amerge(bracket_rules,
+                                                                terminal_rules->terminals,
+                                                                &bracket_terms));
+
+       if (!flags) flags = &my_flags;
+
+       if (t_rules) {
+               my_rules = *t_rules;
+       }
+       my_rules.xlat.runtime_el = el;
+
+       *head = NULL;
+
+       slen = tokenize_expression(ctx, head, flags, in, terminal_rules, t_rules, T_INVALID, FR_TYPE_NULL,
+                                  bracket_rules, NULL);
+       talloc_free(bracket_rules);
+       talloc_free(terminal_rules);
+
+       if (slen < 0) return slen;
+
+       /*
+        *      Zero length expansion, return a zero length node.
+        */
+       if (!*head) {
+               *head = xlat_exp_alloc(ctx, XLAT_BOX, "", 0);
+               return 0;
+       }
+
+       /*
+        *      Create ephemeral instance data for the xlat
+        */
+       if (xlat_instantiate_ephemeral(*head, el) < 0) {
+               fr_strerror_const("Failed performing ephemeral instantiation for xlat");
+               TALLOC_FREE(*head);
+               return 0;
+       }
+
+       return slen;
+}