Forum Discussion
Festus_50639
Nimbostratus
Oct 29, 2008legal 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
- hoolio
Cirrostratus
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 - hoolio
Cirrostratus
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 - Festus_50639
Nimbostratus
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
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
DevCentral Quicklinks
* 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
Discover DevCentral Connects
