Forum Discussion
irule executes twice when refreshing a website
Hello.. I have a really odd problem, my irule script works exactly every second time. I'm working with APIs and on the backend, they are setup to use apiName.example.com/api/id. For the real world, We want to use api.example.com/api/apiName/id. I know this can be done with tools like TYK, however, at the moment we need a workaround using irules... My iRule:
when HTTP_REQUEST {
log local0. "-------------------------------------------------------------"
log local0. "Path [HTTP::path]"
if { not ([HTTP::path] starts_with "/api/") } { return }
set apiType [lindex [split [HTTP::path] "/"] 2]
log local0. "api type $apiType"
append newSubdomain $apiType .uat.
log local0. "New Subdomain $newSubdomain"
HTTP::header replace "Host" [string map [list "api-uat." $newSubdomain ] [HTTP::host]]
log local0. "-------True"
HTTP::path [string map [list "/api/$apiType" "/api"] [HTTP::path]]
log local0. "New Path [HTTP::host][HTTP::path]"
return
}
The above code works every second time... in the browser, I'm going to https://api-uat.example.com/api/inventory/demo and it should change into inventory.uat.example.com/api/demo which it does in the first request, but not the second one.. and every time I refresh it goes bad, good, bad, good.... no idea what I'm doing wrong, please help.
Path /api/inventory/demo
api type inventory
New Subdomain inventory.uat.
-------True
New Path inventory.uat.example.com/api/demo
-------------------------------------------------------------
Path /api/inventory/demo
api type inventory
New Subdomain inventory.uat.inventory.uat.
-------True
New Path inventory.uat.inventory.uat.example.com/api/demo
Try unsetting your variables at the end of the iRule? Specifically...
unset $newSubdomain
- ekaleidoCirrus
Try unsetting your variables at the end of the iRule? Specifically...
unset $newSubdomain
- Lukasz_01_15307Nimbostratus
Hi ekaleido, this actually made my website unavailable for some reason...
error "connection reset" in chrome...
- ekaleidoCirrus
Using the following modifications? What is being logged?
when HTTP_REQUEST { log local0. "-------------------------------------------------------------" log local0. "Path [HTTP::path]" if { not ([HTTP::path] starts_with "/api/") } { return } set apiType [lindex [split [HTTP::path] "/"] 2] log local0. "api type $apiType" append newSubdomain $apiType .uat. log local0. "New Subdomain $newSubdomain" HTTP::header replace "Host" [string map [list "api-uat." $newSubdomain ] [HTTP::host]] log local0. "-------True" HTTP::path [string map [list "/api/$apiType" "/api"] [HTTP::path]] log local0. "New Path [HTTP::host][HTTP::path]" unset $newSubdomain }
- Lukasz_01_15307Nimbostratus
the error was
warning: [variable reference used where variable name expected][$newSubdomain]
so I changed
unset $newSubdomain
to
unset newSubdomain
and it seems to be working.
Thanks! 🙂
a question... Why would irule require a variable to be unset? shouldn't all local variable be unset at the end of the script? as far as I know this is a local variable...
Hi Lukasz,
the best approach to fix your iRule be to change the append newSubdomain $apiType .uat. syntax to set newSubdomain "${apiType}.uat.". In this case you don't need to manally issue a unset newSubdomain after each single web request. And no, this is not a bug. Its more a very important feature to have persistent session variables for the duration of an existing TCP connection.
As a general guideline I always recommend to use as little $variables in iRules as possibile. Try to set $variables only in the case you have to parse something more or less complex - but only if you need the results a second time or if you need those data in other (incompatible) iRule events.
Below is an example how you could improve the syntax of your code to use as little CPU overhead as possible. Its a combination of well selected commands and a consequent avoidance of unneccessary variables.
when HTTP_REQUEST { log local0.debug "-------------------------------------------------------------" log local0.debug "Incomming Request for: [HTTP::host][HTTP::path]" if { ( [HTTP::path] starts_with "/api/" ) and ( [set apiType [getfield [HTTP::path] "/" 3]] ne "" ) } then { log local0.debug "Set Host-Header to: ${apiType}.uat.[domain [HTTP::host] 2]" HTTP::header replace "Host" "${apiType}.uat.[domain [HTTP::host] 2]" log local0.debug "Set HTTP-Path to: /api[string range [HTTP::path] [string length "/api/$apiType"] end]" HTTP::path "/api[string range [HTTP::path] [string length "/api/$apiType"] end]" } log local0.debug "Outgoing Request to: [HTTP::host][HTTP::path]" log local0.debug "-------------------------------------------------------------" }
Note: The iRule above uses a slightly different syntax which consumes much less CPU ressources (e.g. using [getfield [HTTP::path] "/" 3] instead of [lindex [split [HTTP::path] "/"] 2], using a substituted ${apiType}.uat.[domain [HTTP::host] 2] instead of [string map [list oldHost newHost] [HTTP::host]] and using a substituted /newpath[string range [HTTP::path] [string length /somepath] end] instead of [string map [list /somepath /newpath] [HTTP::path]]).
Cheers, Kai
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