Forum Discussion
iRule Variables and Connection Re-Use
I have an iRule that does 301 redirects within the same site, and have noticed when the client reuses the connection the variables seem to not be re-initialized.
when HTTP_REQUEST {
set HOST [HTTP::host]
set PATH [HTTP::path]
if { [class match $PATH eq www_redirects] } {
set ACTION "redirect"
set VALUE [class match -value $PATH equals www_redirects]
}
if { [info exists ACTION] } {
if { $ACTION eq "redirect" } {
HTTP::respond 301 "Location" "https://$HOST$VALUE"
}
}
}
The browser does a wget to https://mysite.com/old it gets redirect to https://mysite.com/new as expected. But then gets redirect to https://mysite.com/new, https://mysite.com/new, https://mysite.com/new etc
Logging shows that $ACTION is still being set to "redirect" on the subsequent requests, so it's as if it's not being re-initialized when the new HTTP request comes in.
- John_Heyer_1508
Cirrostratus
I found a work-around was to initialize the variable with an empty string:
when HTTP_REQUEST { set ACTION "" if { $ACTION ne "" } { // do something } }
Still seems like odd behavior though. Even when re-using the connection, it should be seen by the LTM as a different request.
- ekaleido
Cirrus
Be very careful with variables the way you are using them. Immediatey after acting on them, unset them or they will persist as-is. This might work better for you...
when HTTP_REQUEST { if { [class match [HTTP::path] eq www_redirects] } { set value [class match -value [HTTP::path] eq www_redirects] HTTP::respond 301 "Location" "https://[HTTP::host]$value" unset value } }
- cjunior
Nacreous
Hi, I think it's a normal behavior when connections keeps alive. You may try to unset the variable and/or set connections to close on redirect.
if { [info exists ACTION] } { if { $ACTION eq "redirect" } { HTTP::respond 301 "Location" "https://$HOST$VALUE" Connection close } unset ACTION }
Regards
Hi John,
TCL session variables will be keept during the duration of the underlying TCP connection. So if you [set variable 1] conditionally and laster use a [info exists variable] to handle those conditional requests, then you have to make sure that you [unset variable] after each single request or at least just within the [info exists variable] code structure.
when HTTP_REQUEST { set HOST [HTTP::host] set PATH [HTTP::path] if { [class match $PATH eq www_redirects] } { set ACTION "redirect" set VALUE [class match -value $PATH equals www_redirects] } if { [info exists ACTION] } { if { $ACTION eq "redirect" } { HTTP::respond 301 "Location" "https://$HOST$VALUE" } unset $ACTION } }
But the most effective way to support your scenario would be:
- Reduce $variable usage to an absolute minimum (each of them is eating your CPU and RAM).
- Avoid [info exists] since it has a somewhat high overhead. You may use [set] on the very beginning of a request to always set/overwrite $variable to a default value (e.g. "") and then check if $variable has a non-default value to handle the conditioal requests.
- Try to use nested control structures to speed up the execution. Repetive code blocks may look slow, but they are much faster compared to setting variables and then evaluate a variable to trigger additional code blocks.
- Reduce the [class match] executions to a minimum by skipping the initial data-group entry exist checks. Its far more effective to directly pull the -value for a given data-group entry and then just check if a value could be retrived or not (aka. value not equal ""). While doing so, you may store the output into a $variable for further usage.
Based on the recommendations the most effective code for you scenario would look like that:
when HTTP_REQUEST { if { [set class_uri [class lookup -value [HTTP::path] equals www_redirects]] ne "" } then { HTTP::respond 301 "Location" "https://[HTTP::host]$class_uri" } }
Note: The iRule will query the data-group www_redirects a single time per request and saves the output to $class_uri. If the data-group query got some data back (aka. $class_uri not equal ""), it will directly throw a 301 redirect to the location https://[HTTP::host]$class_uri.
Cheers, Kai
- John_Heyer_1508
Cirrostratus
Funny, this did work on 11.6.1 but we just upgraded to 12.1.2 and now neither unsetting or setting to "" is working. Going to have to open a support case
- cjunior
Nacreous
Man, I don't like any v12.x, but it's sounds weird to me.
Are you doing set ACTION "" / unset ACTION or set $ACTION "" / unset $ACTION?
The first one is the right way.
Regards.
- John_Heyer_1508
Cirrostratus
I've tried both this:
if { [info exists VARIABLE] } { do ... unset VARIABLE
and this
set VARIABLE "" if { $VARIABLE ne "" } { do ...
In both cases, VARIABLE gets cached from the previous HTTP request.
- cjunior
Nacreous
OK, I believe in you. So I'll not shot on script logical, CMP, etc. I really don't like this v12.x, but this case still sounds weird to me. When you get some conclusion, please post here. Good lucky on case, friend!
- John_Heyer_1508
Cirrostratus
Found a work-around: enable oneconnect but NOT http2.
Really seems like http2 exacerbates the problem. This is why we noticed it after upgrading from 11.6 to 12.1
- Stanislas_Piro2
Cumulonimbus
Hi,
There is an issue with HTTP/2 with HTTP::path command in version 12.X. this command returns the full URI instead of path part of the URI.
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