Forum Discussion
How to use Or/And correctly
- Apr 06, 2016
As with most languages, Tcl employs short-circuiting for logical operators, including the sugar operators ("and", "or" and "not") provided to iRules. As a consequence, when the following statement is evaluated:
if { [HTTP::host] contains "foo" or "bar" }
and it turns out that
evaluates to True, then the second part does not evaluate. If it evaluates to False, then the[HTTP::host] contains "foo"
evaluates the literal string "bar", which isn't a boolean and will cause a run-time error. To test this, I use the trivial iRule:if
when HTTP_REQUEST { if { [HTTP::host] contains "example.com" or "foo.com" } { log local0. "Yes: [HTTP::host]" } }
I then submit two requests. The first sets the Host header to "www.example.com" and the second sets it to "www.foo.com". Here is what ends up in /var/log/ltm:
Apr 5 17:06:48 b201 info tmm3[25219]: Rule /Common/test-or : Yes: www.example.com Apr 5 17:07:01 b201 err tmm[25219]: 01220001:3: TCL error: /Common/test-or - can't use non-numeric string as operand of "||" while executing "if { [HTTP::host] contains "example.com" or "foo.com" } { log local0. "Yes: [HTTP::host]" }"
So, just as I say, when the first condition matches, it's fine, but if does not, and the second condition is evaluated, a run-time error is raised.
Your second conditional is fine, and the run-time error is probably being raised in the body. I tested the following:
when HTTP_REQUEST { if { [HTTP::host] contains "example.com" or [HTTP::host] contains "foo.com" } { log local0. "Yes: [HTTP::host]" } }
with the Host header set to "www.example.com" and "www.foo.com". /var/log/ltm shows the following:
Apr 5 17:09:59 b201 info tmm1[25219]: Rule /Common/test-or : Yes: www.example.com Apr 5 17:10:01 b201 info tmm2[25219]: Rule /Common/test-or : Yes: www.foo.com
The problem likely arises because you did not quote the parameter passed to
:HTTP::redirect
HTTP::redirect www.url.com[HTTP:uri]
In this case
could contain characters that Tcl won't accept in a statement. Remember that, when you employ the substitution operator (that is, [...]), the substitution occurs first, then the statement is evaluated. Imagine that[HTTP::uri]
contains the (admittedly illegal) character ' ' (i.e., a space). It would result in a statement that looks like this:[HTTP::uri]
HTTP::redirect www.url.com/foo bar/baz
Because of the space,
is passed two parameters, but it only accepts one. There are other character combinations that can cause Tcl to hiccough. Anyhow, your best bet is to do this:HTTP::redirect
HTTP::redirect "www.url.com[HTTP::uri]"
If that doesn't solve your problem, you should pass along the log message (/var/log/ltm) associated with the failure.
In your case, there is no difference between Method 2 and Method 3. They will result in the same outcome. However, as you mention, parenthesis can be useful if you need to force order-of-evaluation. They don't hurt, in this case, and for longish conditional statements, they can make things clearer.
As with most languages, Tcl employs short-circuiting for logical operators, including the sugar operators ("and", "or" and "not") provided to iRules. As a consequence, when the following statement is evaluated:
if { [HTTP::host] contains "foo" or "bar" }
and it turns out that
[HTTP::host] contains "foo"
evaluates to True, then the second part does not evaluate. If it evaluates to False, then the if
evaluates the literal string "bar", which isn't a boolean and will cause a run-time error. To test this, I use the trivial iRule:
when HTTP_REQUEST {
if { [HTTP::host] contains "example.com" or "foo.com" } {
log local0. "Yes: [HTTP::host]"
}
}
I then submit two requests. The first sets the Host header to "www.example.com" and the second sets it to "www.foo.com". Here is what ends up in /var/log/ltm:
Apr 5 17:06:48 b201 info tmm3[25219]: Rule /Common/test-or : Yes: www.example.com
Apr 5 17:07:01 b201 err tmm[25219]: 01220001:3: TCL error: /Common/test-or - can't use non-numeric string as operand of "||" while executing "if { [HTTP::host] contains "example.com" or "foo.com" } { log local0. "Yes: [HTTP::host]" }"
So, just as I say, when the first condition matches, it's fine, but if does not, and the second condition is evaluated, a run-time error is raised.
Your second conditional is fine, and the run-time error is probably being raised in the body. I tested the following:
when HTTP_REQUEST {
if { [HTTP::host] contains "example.com" or [HTTP::host] contains "foo.com" } {
log local0. "Yes: [HTTP::host]"
}
}
with the Host header set to "www.example.com" and "www.foo.com". /var/log/ltm shows the following:
Apr 5 17:09:59 b201 info tmm1[25219]: Rule /Common/test-or : Yes: www.example.com
Apr 5 17:10:01 b201 info tmm2[25219]: Rule /Common/test-or : Yes: www.foo.com
The problem likely arises because you did not quote the parameter passed to
HTTP::redirect
:
HTTP::redirect www.url.com[HTTP:uri]
In this case
[HTTP::uri]
could contain characters that Tcl won't accept in a statement. Remember that, when you employ the substitution operator (that is, [...]), the substitution occurs first, then the statement is evaluated. Imagine that [HTTP::uri]
contains the (admittedly illegal) character ' ' (i.e., a space). It would result in a statement that looks like this:
HTTP::redirect www.url.com/foo bar/baz
Because of the space,
HTTP::redirect
is passed two parameters, but it only accepts one. There are other character combinations that can cause Tcl to hiccough. Anyhow, your best bet is to do this:
HTTP::redirect "www.url.com[HTTP::uri]"
If that doesn't solve your problem, you should pass along the log message (/var/log/ltm) associated with the failure.
In your case, there is no difference between Method 2 and Method 3. They will result in the same outcome. However, as you mention, parenthesis can be useful if you need to force order-of-evaluation. They don't hurt, in this case, and for longish conditional statements, they can make things clearer.
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