Forum Discussion

ichalis_37981's avatar
ichalis_37981
Historic F5 Account
Dec 13, 2011

The EVAL command

Hi all,

 

 

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

  • 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_37981's avatar
    ichalis_37981
    Historic F5 Account
    Thanks!

     

     

    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..
  • 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}. )
  • 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_86682's avatar
    spark_86682
    Historic F5 Account
    It'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. 🙂
  • 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

    [info patchlevel]
    on big ip 13.0.0. tcl version is still 8.4.6.

    is big ip expected to move to 8.5 in the near future?