]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
hoist tmpls
authorAlan T. DeKok <aland@freeradius.org>
Fri, 18 Apr 2025 12:40:11 +0000 (08:40 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 18 Apr 2025 14:15:31 +0000 (10:15 -0400)
if a tmpl is asked to parse %{...}. then the result is TMPL_TYPE_XLAT.

However, if the contents of that xlat are identically a tmpl, e.g.
User-Name, then there is no reason to keep the xlat.  Instead, we
hoist the tmpl we really want, and discard the intermediate xlat

this simplifies the internal data structures, and allows for
additional optimizations.  It also means that we do less work
at run-time in order to expand the tmpl.

src/lib/server/tmpl_tokenize.c
src/tests/unit/xlat/base.txt

index 7f4b38d643842a8c4d7e2804c76add869365ef48..00d58aff514e728d3e9a9f593b729cbd06b4b837 100644 (file)
@@ -3207,10 +3207,34 @@ fr_slen_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out,
                        slen = xlat_tokenize(vpt, &head, &our_in, p_rules, t_rules);
                        if (slen <= 0) FR_SBUFF_ERROR_RETURN(&our_in);
 
-                       if (xlat_needs_resolving(head)) UNRESOLVED_SET(&type);
+                       if (xlat_needs_resolving(head)) {
+                               UNRESOLVED_SET(&type);
+                               goto set_tmpl;
 
-                       tmpl_init(vpt, type, quote, fr_sbuff_start(&our_in), slen, t_rules);
-                       vpt->data.xlat.ex = head;
+                       } else if (fr_dlist_num_elements(&head->dlist) == 1) {
+                               xlat_exp_t *node = xlat_exp_head(head);
+                               tmpl_t *hoisted;
+
+                               if (node->type != XLAT_TMPL) goto set_tmpl;
+
+                               /*
+                                *      We were asked to parse a tmpl.  But it turned out to be an xlat %{...}
+                                *
+                                *      If that xlat is identically a tmpl such as %{User-Name}, then we just
+                                *      hoist the tmpl to this node.  Otherwise at run time, we will have an
+                                *      extra bounce through the xlat code, for no real reason.
+                                */
+                               hoisted = node->vpt;
+
+                               (void) talloc_steal(ctx, hoisted);
+                               talloc_free(vpt);
+                               vpt = hoisted;
+
+                       } else {
+                       set_tmpl:
+                               tmpl_init(vpt, type, quote, fr_sbuff_start(&our_in), slen, t_rules);
+                               vpt->data.xlat.ex = head;
+                       }
 
                        *out = vpt;
 
index 746395a3744638505886ef944a91a5e5638073b0..426475120714112c4e9c3e721ac9f2f123b4eafc 100644 (file)
@@ -73,6 +73,13 @@ match ERROR offset 14: Too many arguments, expected 0, got 1
 xlat %test('bar')
 match %test('bar')
 
+#
+#  @todo - we now hoist the tmpl -> xlat -> tmpl to just a tmpl.  But
+#  we don't change the name of the parent group.  We may want to do that.
+#
+xlat %test(%{User-Name})
+match %test(%{User-Name})
+
 xlat %test()
 match ERROR offset 6: Missing required arg 1
 
@@ -297,4 +304,4 @@ xlat %md5('arg"')
 match %md5(0x61726722)
 
 count
-match 159
+match 161