Forum Discussion

Festus_50639's avatar
Festus_50639
Icon for Nimbostratus rankNimbostratus
Oct 29, 2008

legal comparison operator syntax

Good morning all,

 

 

I seem to have found a logic error and my first step is to rule out or confirm that my iRule is at fault.

 

 

Here is the iRule as it was used when it "broke".

 

 

===============

 

when HTTP_REQUEST {

 

 

set curtime [clock seconds]

 

set redir_time [clock format $curtime -format {%H}]

 

 

if { [HTTP::uri] contains "site/app-folder" } {

 

if { ($redir_time >= 21) or ($redir_time <= 2) } {

 

HTTP::redirect "http://host.domain/site/Common/app-unavailable.html"

 

}

 

else {

 

if { [HTTP::uri] contains "?" } {

 

HTTP::redirect "http://host.domain/site/default.aspx?[lindex [split [HTTP::uri] "?"] 1]"

 

}

 

else { HTTP::redirect "http://host.domain/site/default.aspx" }

 

}

 

}

 

}

 

===============

 

 

Here is the background:

 

 

We put this iRule in place so that we can redirect requests during a nightly period of unavailability. We were able to test in our dev and lab environments after 10:00 AM so we didn't see any errors adjusting the $redir_time values so that we were before or after the unavailability period.

 

 

Using that testing as a benchmark that the logic of the iRule was good, we put the rule in place using the actual hours of non-availability which is from 9:00 PM - 3:00 AM, hence the 21 and 2 since we are using the top of the hour as our marker.

 

 

At 9:00 PM the rule began functioning as expected redirecting requests to the "unavailable" page. At 3:00 AM requests were being directed to the default page with or without query strings as expected.

 

 

Then, at about 8:00 AM, the iRule stopped working as expected and started redirecting requests to the unavailable page.

 

 

What seems to have fixed it:

 

 

We replaced the 'or' comparison with '&&' and the rule began functioning as expected.

 

 

The million dollar questions (or at least $75 on today's market) are these:

 

 

1. Is the logic in "if { ($redir_time >= 21) or ($redir_time <= 2) }" flawed and not evaluating the hours 00 - 09 as values of 0-9? and if so, why did it work from 3:00 AM until 8:00 AM?

 

 

or

 

 

2. Do I need to search the logs on my load balancer to see what happened at 8:00 AM to change the behavior of this iRule?

 

 

Any input is appreciated as well as links to information on why my comparison statement is or is not correct.

 

 

Thanks in advance,

 

Kevin

 

 

3 Replies

  • Hi Kevin,

    I think the issue is that TCL interprets an integer with a leading zero as an octal:

    http://phaseit.net/claird/comp.lang.tcl/fmm.htmlzero

    ZERO: a numeric representation (examples: "5", "639.42", ...) which begins with '0' (example: "04") is interpreted as octal. It surprises some, when, for example, "expr 09 + 1" is a syntax error. The standard approach to this common situation is such an expression as expr [string trimleft $month 0] + 1

    This is one of the two most common threads in common.lang.tcl (commenting is the other). The natives are sometimes grouchy on the subject.

    I think the simple fix is to use %k in the clock format string to leave off the leading 0, instead of %H:

    http://www.tcl.tk/man/tcl8.4/TclCmd/clock.htm

    %k

    Hour in 24-hour format, without leading zeros (0 - 23).

    You can then use your original OR logic. Here is a quick test demonstrating the issue:

     
     when RULE_INIT { 
      
        log local0. "=========================================================" 
        log local0. "Test OR versus AND without leading 0 in hour" 
      
        for {set redir_time 0}{$redir_time < 24}{incr redir_time}{ 
           log local0. "\$redir_time: $redir_time" 
           if {($redir_time >= 21) or ($redir_time <= 2)}{ 
              log local0. "$redir_time: OR check was true.    Redirect client to unavailable page." 
           } else { 
              log local0. "$redir_time: OR check was false.   Allow client to access app." 
           } 
           if {($redir_time >= 21) and ($redir_time <= 2)}{ 
              log local0. "$redir_time: AND check was true.    Redirect client to unavailable page." 
           } else { 
              log local0. "$redir_time: AND check was false.  Allow client to access app." 
           } 
        } 
        log local0. "---------------------------------------------------------" 
        log local0. "Test OR versus AND with leading 0 in hour" 
        for {set i 0}{$i < 24}{incr i}{ 
           set redir_time [format "%.2d" $i] 
           log local0. "\$redir_time: $redir_time " 
           if {($redir_time >= 21) or ($redir_time <= 2)}{ 
              log local0. "$redir_time: OR check was true.    Redirect client to unavailable page." 
           } else { 
              log local0. "$redir_time: OR check was false.   Allow client to access app." 
           } 
           if {($redir_time >= 21) and ($redir_time <= 2)}{ 
              log local0. "$redir_time: AND check was true.    Redirect client to unavailable page." 
           } else { 
              log local0. "$redir_time: AND check was false.  Allow client to access app." 
           } 
        } 
     } 
     

    In the log output for the second for loop, note that the OR test is incorrect:

    Rule : 08: OR check was true. Redirect client to unavailable page.

    Rule : 08: AND check was false. Allow client to access app.

    Rule : $redir_time: 09

    Rule : 09: OR check was true. Redirect client to unavailable page.

    Rule : 09: AND check was false. Allow client to access app.

    Aaron
  • Forgot to add... you can replace this:

     
     if { [HTTP::uri] contains "?" } { 
        HTTP::redirect "http://host.domain/site/default.aspx?[lindex [split [HTTP::uri] "?"] 1]" 
     } else { 
        HTTP::redirect "http://host.domain/site/default.aspx" } 
     } 
     

    With this:

     
     HTTP::redirect "http://host.domain/site/default.aspx?[HTTP::query]" 
     

    The only difference is that if the original request didn't have a query string, the redirect location will have a trailing ?. This shouldn't have any effect on the application though.

    Aaron
  • Thanks Hoolio.

     

     

    Once you mentioned the variable being treated as an octal the whole "break at 8:00" made sense. The further proof was watching the log results of the test script you provided.

     

     

    Cheers,

     

    Kevin