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.
11 Replies
- 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 VARIABLEand 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.
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)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
