From 888bda7ab91208e99693f08fea6e9368fdd754b5 Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Fri, 22 Nov 2024 10:38:33 -0500 Subject: [PATCH] add and document support for tripled-quoted strings secret = """foo " bar " baz ! """ --- .../reference/pages/type/all_types.adoc | 2 +- .../modules/reference/pages/type/index.adoc | 2 +- .../reference/pages/type/string/double.adoc | 9 +++++++ .../reference/pages/type/string/single.adoc | 13 +++++++-- src/lib/server/tmpl_tokenize.c | 27 +++++++++++++++++-- src/lib/util/token.c | 27 ++++++++++++++++--- 6 files changed, 71 insertions(+), 9 deletions(-) diff --git a/doc/antora/modules/reference/pages/type/all_types.adoc b/doc/antora/modules/reference/pages/type/all_types.adoc index ec772f7db128..3e5392870d2d 100644 --- a/doc/antora/modules/reference/pages/type/all_types.adoc +++ b/doc/antora/modules/reference/pages/type/all_types.adoc @@ -36,7 +36,7 @@ possible to write values in the format you expect, The server will do | ipv4prefix | IPv4 network with address and prefix length | ipv6prefix | IPv6 network with address and prefix length | octets | raw binary, printed as hex strings -| string | printable strings +| xref:type/string/index.adoc[string] | printable strings | time_delta | difference between two calendar dates | uint8 | 8-bit unsigned integer | uint16 | 16-bit unsigned integer diff --git a/doc/antora/modules/reference/pages/type/index.adoc b/doc/antora/modules/reference/pages/type/index.adoc index cfdbd7faf33c..0f66ce4918ff 100644 --- a/doc/antora/modules/reference/pages/type/index.adoc +++ b/doc/antora/modules/reference/pages/type/index.adoc @@ -1,7 +1,7 @@ = Data Types Unlang supports a number of data types. These data types are used in -conditional expressions or when assigning a value to an attribute. +dictionaries, expressions or when assigning a value to an attribute. == Using Data Types diff --git a/doc/antora/modules/reference/pages/type/string/double.adoc b/doc/antora/modules/reference/pages/type/string/double.adoc index 8df6661da8e2..fafcd2b0119a 100644 --- a/doc/antora/modules/reference/pages/type/string/double.adoc +++ b/doc/antora/modules/reference/pages/type/string/double.adoc @@ -8,6 +8,14 @@ xref:xlat/index.adoc[dynamic expansions]. As with xref:type/string/single.adoc[single-quoted strings], text within double quotes can include spaces. +For normally quoted strings, the quotation character can be placed inside of +the string by escaping it with a backslash. + +For triple quoted strings, the quotation character does not need to be +escaped. However, if the string does contain an escaped quotation +character, the quotation character is unescaped, as with normally +quoted strings. + The main difference between the single and double quoted strings is that the double quoted strings can be dynamically expanded. The syntax `${...}` is used for parse-time expansion and `%{...}` is used for @@ -133,6 +141,7 @@ string is being used. `"this has embedded\ncharacters"` + `"attribute\tvalue\nusername\t%{User-Name}\nreply-message\t%{reply.Reply-Message}"` `"The result of 'SELECT * FROM foo WHERE 1' is: %sql(SELECT * FROM foo WHERE 1)"` +`"""this string has a "double quoted" string in the middle of it"""` // Licenced under CC-by-NC 4.0. // Copyright (C) 2019 Arran Cudbard-Bell diff --git a/doc/antora/modules/reference/pages/type/string/single.adoc b/doc/antora/modules/reference/pages/type/string/single.adoc index fb4b9a4b208c..2a91f325163e 100644 --- a/doc/antora/modules/reference/pages/type/string/single.adoc +++ b/doc/antora/modules/reference/pages/type/string/single.adoc @@ -2,11 +2,19 @@ .Syntax `'string'` +`'''string with 'quote' embedded'''` A single-quoted string is interpreted without any dynamic string expansion. The quotes allow the string to contain spaces, among other -special characters. The single quote character can be placed in such a -string by escaping it with a backslash. +special characters. + +For normally quoted strings, the quotation character can be placed inside of +the string by escaping it with a backslash. + +For triple quoted strings, the quotation character does not need to be +escaped. However, if the string does contain an escaped quotation +character, the quotation character is unescaped, as with normally +quoted strings. .Examples @@ -14,6 +22,7 @@ string by escaping it with a backslash. `'foo bar`' + `'foo\\'bar'` + `'this is a long string'` +`'''This is a string with 'embedded' quotes'''` // Copyright (C) 2021 Network RADIUS SAS. Licenced under CC-by-NC 4.0. // This documentation was developed by Network RADIUS SAS. diff --git a/src/lib/server/tmpl_tokenize.c b/src/lib/server/tmpl_tokenize.c index 9a9e88e54d65..b8c6088f9d9f 100644 --- a/src/lib/server/tmpl_tokenize.c +++ b/src/lib/server/tmpl_tokenize.c @@ -5352,6 +5352,7 @@ ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *in, size_t i char quote; char close; int depth; + bool triple; *type = T_INVALID; @@ -5496,8 +5497,17 @@ ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *in, size_t i * more rigorous check. */ skip_string: + if ((inlen > 3) && (p[0] == quote) && (p[1] == quote)) { + triple = true; + p += 2; + } else { + triple = false; + } *out = p; + while (*p) { + if (p >= end) goto unterminated; + /* * End of string. Tell the caller the * length of the data inside of the @@ -5505,9 +5515,21 @@ ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *in, size_t i * characters to skip. */ if (*p == quote) { - *outlen = p - (*out); + if (!triple) { + *outlen = p - (*out); + p++; + return p - in; + + } + + if (((end - p) >= 3) && (p[1] == quote) && (p[2] == quote)) { + *outlen = p - (*out); + p += 3; + return p - in; + } + p++; - return p - in; + continue; } if (*p == '\\') { @@ -5523,6 +5545,7 @@ ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *in, size_t i * End of input without end of string. * Point the error to the start of the string. */ + unterminated: p = *out; return_P("Unterminated string"); diff --git a/src/lib/util/token.c b/src/lib/util/token.c index c7fa61e9893d..3c063dda7a7c 100644 --- a/src/lib/util/token.c +++ b/src/lib/util/token.c @@ -256,6 +256,7 @@ static fr_token_t getthing(char const **ptr, char *buf, int buflen, bool tok, char *s; char const *p; char quote; + bool triple = false; unsigned int x; size_t i; fr_token_t token; @@ -315,6 +316,14 @@ static fr_token_t getthing(char const **ptr, char *buf, int buflen, bool tok, if (token != T_BARE_WORD) { quote = *p; + + /* + * Triple-quoted strings are copied over verbatim, without escapes. + */ + if ((buflen >= 3) && (p[1] == quote) && (p[2] == quote)) { + p += 3; + } + p++; } s = buf; @@ -350,9 +359,21 @@ static fr_token_t getthing(char const **ptr, char *buf, int buflen, bool tok, * Un-escaped quote character. We're done. */ if (*p == quote) { - p++; - *s++ = 0; - goto done; + if (!triple) { + p++; + *s++ = 0; + goto done; + + } + + if ((buflen >= 3) && (p[1] == quote) && (p[2] == quote)) { + p += 3; + *s++ = 0; + goto done; + } + + *s++ = *p++; + continue; } /*