Forum Discussion

Demonio_21719's avatar
Demonio_21719
Icon for Nimbostratus rankNimbostratus
Oct 09, 2015

Can't use non-numeric string as operand of "&&" in rule

Hello. When this irule runs the following error occurs:

 

/Common/SSL_Test - can't use non-numeric string as operand of "&&" while executing "if { $renegtried == 0 and [SSL::cert count] == 0 and ( ([HTTP::uri] matches_regex {^/test1$}) or ([HTTP::uri] matches_reg..."

 

when HTTP_REQUEST { set uri [string tolower [HTTP::uri] ] /_hst name and ?_hst=1 parameter triggers client cert renegotiation if { $renegtried == 0 and [SSL::cert count] == 0 and ( ([HTTP::uri] matches_regex {^/test1$}) or ([HTTP::uri] matches_regex {^/prob$}) or ([HTTP::uri] matches_regex {^/Register$}) ) } {

 

How I can fix it? Thank you.

 

10 Replies

  • Hi,

    First, Regex is useless in your irule. it will generate performance issues.

    • use ([HTTP::uri] starts_with /test1) instead of ([HTTP::uri] matches_regex {^/test1})
    • use ([HTTP::uri] ends_with /test1) instead of ([HTTP::uri] matches_regex {/test1$})
    • use ([HTTP::uri] equals /test1) instead of ([HTTP::uri] matches_regex {^/test1$})

    Your issue is your 2 first conditions do not have parenthesis.

     

    ($renegtried == 0) and ([SSL::cert count] == 0)
    

     

    and you can replace ($renegtried == 0) by !($renegtried)

  • Thanks for your help. I've applied but does not work:

    • when HTTP_REQUEST {
    • set uri [string tolower [HTTP::uri] ]
    • /_hst name and ?_hst=1 parameter triggers client cert renegotiation
    • if { !($renegtried) and ([SSL::cert count] == 0)
    • and (([HTTP::uri] equals "/extern/test.jsp") or ([HTTP::uri] equal "/SO/services/dat") or * ([HTTP::uri] equal "/test/services/Tasacion") or [(HTTP::uri] equal "/Ex/services/pay"))
    • } {
    • log local0. "[IP::client_addr]:[TCP::client_port]: A log entry"
    • HTTP::collect
    • SSL::cert mode request
    • SSL::renegotiate
    • }
    • }
    • The error is this:
    • :01070151:3: Rule [/Common/SSL_Test] error: /Common/Common/SSL_Test:12: error: [parse error: PARSE syntax 465 {syntax error in expression "!($renegtried)and ([SSL::cert count] == 0)and ...": variable references require preceding $}][{!($renegtried)and ([SSL::cert count] == 0)and (([HTTP::uri] equals "/extern/test.jsp") or ([HTTP::uri] equal "/SO/services/dat") or ([HTTP::uri] equal "/test/services/Tasacion") or [(HTTP::uri] equal "/Ex/services/pay"))}]
  • Here is your code formatted:

     

    when HTTP_REQUEST {
        set uri [string tolower [HTTP::uri] ]
        /_hst name and ?_hst=1 parameter triggers client cert renegotiation
        if { !($renegtried) and ([SSL::cert count] == 0) and (([HTTP::uri] equals "/extern/test.jsp") or ([HTTP::uri] equal "/SO/services/dat") or ([HTTP::uri] equal "/test/services/Tasacion") or [(HTTP::uri] equal "/Ex/services/pay")) } {
            log local0. "[IP::client_addr]:[TCP::client_port]: A log entry"
            HTTP::collect
            SSL::cert mode request
            SSL::renegotiate
        }
    }
    

     

    You have some oddly placed characters (for example, "[(" and sometimes you put "equal" rather than "equals"). In any case, a switch for equality will be easier to read:

     

    when HTTP_REQUEST {
        switch [HTTP::uri] {
            "/extern/test.jsp" -
            "/SO/services/dat" -
            "/Ex/services/pay" {
                if { !$renegtried && [SSL::cert count] == 0 } {
                    log local0. "[IP::client_addr]:[TCP::client_port]: A log entry"
                    HTTP::collect
                    SSL::cert mode request
                    SSL::renegotiate
                }
            }
            
        }
    }
    

     

    Note that I removed the string tolower. Ordinarily, URI paths are case-sensitive (assuming your server and filesystem are) so the conversion is of no real value. Indeed, you perform the conversion, assign the value to $uri then never reference that variable. If you really do care, you can simply substitute that back in.

  • * tHANK YOU!! * And if I want to add any condition in the HTTP_REQUEST?, for example (SOME "ELSE IF and * ELSE"): * Do I have to put an if before the switch? * For example:

    • when HTTP_REQUEST {
    • switch [HTTP::uri] {
    • "/extern/test.jsp" -
    • "/SO/services/dat" -
    • "/Ex/services/pay" {
    • if { !$renegtried && [SSL::cert count] == 0 } {
    • log local0. "[IP::client_addr]:[TCP::client_port]: A log entry"
    • HTTP::collect
    • SSL::cert mode request
    • SSL::renegotiate
    • pool TEST-BACKUP <---- PRIORITY POOL
    • }
    • }
    •  
    • }
    • }

    TO ADD:

    • } elseif {
    • ([HTTP::host] equals www.test.es } {
    • pool SECOND_POOL_SSL <---- SECOND POOL
    • SSL::enable serverside
    • log local0. "WITH SECOND POOL"
    • } else {
    • pool THIRD-POOL-SSL <---- THIRD POOL
    • SSL::disable serverside
    • log local0. "WITH THIRD POOL POOL"
    • }
  • Depends on to what the elseif is attached. Does it apply only when one of the three URI paths are matched? If not, you could place a return in the existing match clause, then put your if...else outside the switch, like so:

     

    when HTTP_REQUEST {
        switch [HTTP::uri] {
            "/extern/test.jsp" -
            "/SO/services/dat" -
            "/Ex/services/pay" {
                if { !$renegtried && [SSL::cert count] == 0 } {
                    log local0. "[IP::client_addr]:[TCP::client_port]: A log entry"
                    HTTP::collect
                    SSL::cert mode request
                    SSL::renegotiate
                    return
                }
            }
        }
    
         end up here if none of the three URI paths above match, or if one of them does match
         but either $renegtried or SSL::cert count != 0
        if { [string tolower [HTTP::host]] equals "www.test.es" } {
            pool SECOND_POOL_SSL
            SSL::enable serverside
            log local0. "WITH SECOND POOL"
        } else {
            pool THIRD-POOL-SSL
            SSL::disable serverside
            log local0. "WITH THIRD POOL POOL"
        }
    }
    

     

    For test of HTTP::host using string tolower is important, because the client may submit the Host: header in any case, and DNS is case indifferent.

  • Hello, Now, it works correctly, but the elseif and else, returns to give the error "can not use non-numeric string as operand of" && "Definitely, how it could be better?

     

    when CLIENT_ACCEPTED {
        set collecting 0
        set renegtried 0
        set default_pool [LB::server pool]
    } 
     when HTTP_REQUEST {
            set uri [string tolower [HTTP::uri] ]
            /_hst name and ?_hst=1 parameter triggers client cert renegotiation
            switch [HTTP::uri] {
                "/extern/test.jsp" -
                "/SO/services/dat" -
                "/Ex/services/pay" {
         if { !$renegtried && [SSL::cert count] == 0 } {    
            log local0. "[IP::client_addr]:[TCP::client_port]: A log entry"
                Collecting means buffering the request. The collection goes on
                until SSL::renegotiate occurs, which happens after the HTTP
                request has been received. The maximum data buffered by collect
                is 1-4 MB.
                HTTP::collect
                set collecting 1
                SSL::cert mode request
                SSL::renegotiate
                pool FIRST_POOL_SSL
                SSL::enable serverside
                log local0. "WITH FIRST POOL"
                return
                }
               }
                } 
               if { $uri equals "/extern/test.jsp" } { 
                pool FIRST_POOL_SSL
                SSL::enable serverside
                log local0. "WITH FIRST POOL"
              } elseif { ([string tolower [HTTP::host]] eq "www.test.es") && ($uri eq "/abc") }{
                HTTP::redirect "https://www.test.es/test1/"
              } elseif { ([string tolower [HTTP::host]] eq "www.test.es") && ($uri contains "/") && ($uri) }{
                HTTP::redirect "https://www.test.es[HTTP::uri]"
               } else { 
                pool $default_pool
                    SSL::disable serverside
                log local0. "WITH SECOND POOL"
            } 
        }
    

     

  • It almost certainly is what @stanislas pointed out.

    As an extended note, however, since your are testing the URI path in the additional branches, it makes sense to fold those into the switch, as well. I don't really understand the last branch because a URI path will always contain a slash (/), so that conditional match is always true. Therefore, I pushed it to the switch default condition.

     

    when CLIENT_ACCEPTED {
        set collecting 0
        set renegtried 0
    } 
     when HTTP_REQUEST {
            set uri [string tolower [HTTP::uri] ]
            /_hst name and ?_hst=1 parameter triggers client cert renegotiation
            switch [HTTP::uri] {
                "/extern/test.jsp" -
                "/SO/services/dat" -
                "/Ex/services/pay" {
                    if { !$renegtried && [SSL::cert count] == 0 } {    
                        log local0. "[IP::client_addr]:[TCP::client_port]: A log entry"
                         Collecting means buffering the request. The collection goes on
                         until SSL::renegotiate occurs, which happens after the HTTP
                         request has been received. The maximum data buffered by collect
                         is 1-4 MB.
                        HTTP::collect
                        set collecting 1
                        SSL::cert mode request
                        SSL::renegotiate
                        pool FIRST_POOL_SSL
                        SSL::enable serverside
                        log local0. "WITH FIRST POOL"
                    }
                    
                    "/extern/test.jsp" {
                        pool FIRST_POOL_SSL
                        SSL::enable serverside
                        log local0. "WITH FIRST POOL"
                    }
                    
                    "/abc" {
                        if { [string tolower [HTTP::host]] eq "www.test.es"] } {
                            HTTP::redirect "https://www.test.es/test1/"
                        }
                    }
                    
                    default {
                        if { [string tolower [HTTP::host]] eq "www.test.es" } {
                            HTTP::redirect "https://www.test.es[HTTP::uri]"
                        }
                        else {
                            SSL::disable serverside
                            log local0. "WITH SECOND POOL"
                        }
                    }
                }
            } 
        }
    

     

    Since everything is in the switch now, there is no need for the return in the first condition.

    Incidentally, in the last condition, you set the pool to LB::server pool. There is no reason to do this. If you don't invoke pool in your iRule, that is already the pool that will be selected. So, I removed that.

    Also, I assume this is not the entire iRule. When you use HTTP::collect in HTTP_REQUEST, if you don't attach a listener to the HTTP_REQUEST_DATA event and invoke HTTP::release somewhere in there, the iRule will stall (and, more importantly, there would be no value in calling HTTP::collect unless you do something with the data).

  • Thank you very much for your help. Good morning, we have implemented the irule to HTTP_REQUEST, and works perfectly. The problem appears many errors like this:

     

    TCL error: /Common/Common/SSL_Test:12 - command returned bad code: 24 while executing " /_hst name and ?_hst=1 parameter triggers client cert renegotiation switch [HTTP::uri] { "/extern/test.jsp" - "/SO/..."

     

    It could be a bug in version 11.6.0 HF5?

     

    Gretting

     

  • Perhaps, but Tcl is finicky about where comments end up. Have you tried removing the comment line

     

    /_hst name and ?_hst=1 parameter triggers client cert renegotiation
    

     

    to see if the errors go away?