Forum Discussion
The EVAL command
I am testing the eval command and want to generate an error if my input script contains an error. My test code is as follows:
set cmd "if { \[HTTP::uri\] starts_with \"/hello\" }{ log local0.alert \"match!!!\" }"
if { [catch {
[eval $cmd]
} myresult] != 0 } {
log local0. "My rule failed: $myresult"
}
The output to this is as follows:
Rule : match!!!
Rule : My rule failed: invalid command name ""
So the "match!!!" output clearly shows the command was run successfully, but the catch command is returning an error.
Any ideas as to why?
9 Replies
- hoolio
Cirrostratus
Hi,
The catch command already executes the wrapped expression. So you could use [catch { eval $cmd } myresult]. Wrapping eval $cmd in square braces executes the output of eval again resulting in the invalid command name. Here's a version which should work and not require escaping the characters in the command:when HTTP_REQUEST { set cmd {if { [HTTP:uri] starts_with "/hello" }{ log local0.alert "match!!!" }} if { [catch { eval $cmd } myresult] != 0 } { log local0. "My rule failed: $myresult, \$cmd: $cmd" } else { log local0. "My rule succeeded: $myresult, \$cmd: $cmd" } }
That said, why do you want to use catch for this? catch handles errors, but it's not too likely that you'd get a runtime error with that anyhow.
Aaron - ichalis_37981Historic F5 AccountThanks!
My intention is for a set of TCL commands to be stored in a data group as a set of signatures to be eval'd against each request. I want to use catch in case the admin inputs a syntax error in the datagroup..
CHeers.. - brad_11480
Nimbostratus
From what I understand the EVAL command is an old, old command and continues to exist because it is used widely. Further I understand that the preferred method is to use the {*} notation to allow safe argument expansion. That is what I wanted to do.. I had the list of arguments in a string. But the use of {*}$string resulted in a syntax error.
Wondering if it will be supported in the near future?!
( {*} - The artist formerly known as {expand}. ) - hoolio
Cirrostratus
Hi Brad,
I haven't heard of the {*} syntax before and couldn't find anything on the TCL wiki pages about it. Do you have any references for it?
Also in 8.4, the eval command has the following:
http://www.tcl.tk/man/tcl8.4/TclCmd/eval.htm
Note that the list command quotes sequences of words in such a way that they are not further expanded by the eval command.
Aaron - spark_86682Historic F5 AccountIt's more that eval and {*} do different things. Eval takes a string and executes it as a command. {*} is used to expand a Tcl list into separate arguments ("stringifying" it, essentially), typically for use in calling a command.
For example, if you had a variable called $headers which was a Tcl list of header names and values, which looked like:{ Set-Cookie "foo=bar" Set-Cookie "baz=quux" X-Server "BIG-IP iRule" }
you might want to do something like:HTTP::respond 302 Location http://new.example.com $headers
to craft an HTTP response with all of those headers. But that wouldn't work, because Tcl would pass in those headers as one big parameter, confusing the HTTP::respond command. With {*}, you could make it work:HTTP::respond 302 Location http://new.example.com {*}$headers
which would be the same as:HTTP::respond 302 Location http://new.example.com Set-Cookie "foo=bar" Set-Cookie "baz=quux" X-Server "BIG-IP iRule"
However, the {*} syntax was introduced in Tcl 8.5, and BIG-IP is still using Tcl 8.4. So you need to use eval as a workaround:eval "HTTP::respond 302 Location http://new.example.com $headers"
This will expand the $headers variable as a string, and parse the contents as separate arguments to the HTTP::respond command.
So eval is an old command, but no more than the rest of Tcl. 🙂 - nitass
Employee
nice explanation Spark! - Andrew_Le_12873
Nimbostratus
Yup, great explanation with examples, Spark!
- hoolio
Cirrostratus
There's more info on {*} here: http://wiki.tcl.tk/17158
- Simon_Mittelber
Nimbostratus
is there any news on this one?
using eval for this, as spark suggests, is dangerous in my eyes:
eval "HTTP::respond 302 Location http://new.example.com $headers"what if headers contain user input? someone could inject commands...
or what if anyone would use it for a response including content:
eval "HTTP::respond 200 content $content"what if the content contains user input?
i think introducing the {*}-command is the only way to enable safe argument expansion.
i did a
on big ip 13.0.0. tcl version is still 8.4.6.[info patchlevel]is big ip expected to move to 8.5 in the near future?
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
