Forum Discussion
dubdub
Nimbostratus
Jun 15, 2011iRule to intercept traffic and then send on to original pool
Hi all,
I refuse to believe this is impossible, so I just need some advice on how to make it happen!
I am trying to create an iRule to intercept certain requests for additional processing before ultimately sending them on to their original target. The main application server tier is a data warehouse application. Users of the data warehouse app must be in a specific AD security group in order to access it. A separate web application (on a completely different environment) has been created that will handle this group processing - it will check if the user is already in the security group, and if not, it will add them. Once the user has established a session with the data warehouse, I can bypass sending any requests to the web application because I'll know that user has already been added. The session can be verified by looking for the jsessionid value.
So, this is the general flow I need:
if the jsessionid exists {
send to original pool, no special handling required
} else {
if the pool for the web application is up {
preserve the original URL somehow
invoke the web application
} else {
send to the original pool; the user may already be a member of the group and have access - we don't want to prevent them getting through just because the web app may be unavailable
}
}
I've tried a number of combinations of HTTP headers, cookies, redirects, responds, etc. in an attempt to get the intercept working. It seems that getting the flow back from the web application and sent onto the data warehouse within the same connection is not likely to happen, so I was hoping to send the original URL along to the web app, and have the web app actually do the redirection to the original data warehouse URL. However, the URLs can be unbelievably long, and I could seriously run into the URL limit boundary if I try to pass the original URL as a query parameter to the web application. I tried passing the URL as an HTTP header and as a cookie - neither seems to survive its transit into the web app (where right now we are dumping all header variables, cookies, etc. to the browser just as a gut check).
Any other suggestions on how I can get this URL down to the web app? Or is there a completely better way to approach this?
Thanks,
Jen
6 Replies
- hoolio
Cirrostratus
Hi Jen,
Can you post the actual rule you've tested and debug logs showing the issue? If you need to save the original request you should be able to save the original request headers, send the first request to the pool for requests with no JSESSIONID and then use HTTP::retry to retry the original request once the prerequisite request is done.
You can check the HTTP::retry wiki page and this article for details:
http://devcentral.f5.com/wiki/default.aspx/iRules/http__retry
Conditioning iRule Logic on External Information - 01 - HTTP::retry
http://devcentral.f5.com/Default.aspx?tabid=63&articleType=ArticleView&articleId=105
Aaron - dubdub
Nimbostratus
Hi Aaron,
Thanks much for the tip on HTTP::retry, here is my latest effort:
--------
when RULE_INIT {
set static::debug 1
}
when CLIENT_ACCEPTED {
if { $static::debug != 0 } {
log local0. "setting lookup to 1"
}
set lookup 1
}
when HTTP_REQUEST {
if { [HTTP::cookie "JSESSIONID"] ne "" } {
if { $static::debug != 0 } {
log local0. "got jsession id, sending to DW"
}
pool pool_DW
} else {
if { $static::debug != 0 } {
log local0. "no session id, sending to WF for url [HTTP::host][HTTP::uri]"
}
if { [active_members pool_WF] > 0 and ($lookup == 1) } {
if { $static::debug != 0 } {
log local0. "lookup is $lookup"
log local0. "redirecting to WF, saving request first"
}
set myRequest [HTTP::request]
HTTP::uri "/DW_add_user_app"
pool pool_WF
} else {
if { $static::debug != 0 } {
log local0. "WF pool unavailable or lookup is $lookup, sending to DW"
}
pool pool_DW
}
}
}
when HTTP_RESPONSE {
if {[HTTP::header exists Content-Length] && \
([HTTP::header Content-Length] < 1048576)}{
set clength [HTTP::header Content-Length]
} else {
set clength 1048576
}
if { $static::debug != 0 } {
log local0. "collecting clength $clength"
}
HTTP::collect $clength
}
when HTTP_RESPONSE_DATA {
if { $static::debug != 0 } {
log local0. "got a reply back from web app, retrying request"
}
pool pool_DW
HTTP::retry $myRequest
set lookup 0
}
-----------
And the output:
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : setting lookup to 1
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : no session id, sending to WF for url dwtestvip/
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : lookup is 1
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : redirecting to WF, saving request first
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : collecting clength 153
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : got a reply back from web app, retrying request
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : no session id, sending to WF for url dwtestvip/
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : WF pool unavailable or lookup is 0, sending to DW
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : collecting clength 1048576
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : no session id, sending to WF for url dwtestvip/InfoApp
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : WF pool unavailable or lookup is 0, sending to DW
Jun 15 20:38:25 local/tmm1 info tmm1[6449]: Rule DWIntercept : collecting clength 1048576
At this point the browser is just spinning. I'm not sure if it's waiting on collecting more data, maybe 1MB isn't enough? I tried increasing it to 10MB but I saw the documentation on HTTP::collect cautioned about stalling the connection. Hitting the root VIP normally results in a redirect to VIP/InfoApp, so there's some redirection going on at the data warehouse app as well, just to make things more interesting.
Thanks,
Jen - dubdub
Nimbostratus
Just to follow up... finally got this working, this is the final iRule, which is a variation on the excellent ideas suggested in http://devcentral.f5.com/Community/GroupDetails/tabid/1082223/asg/50/aft/14001/showtab/groupforums/Default.aspx.
when RULE_INIT {
set static::debug 1
}
when CLIENT_ACCEPTED {
if { $static::debug != 0 } {
log local0. "setting addingUser to 1"
}
set addingUser 1
}
when HTTP_REQUEST {
save original request
if { $addingUser == 1 } {
if { $static::debug != 0 } {
log local0. "saving request, redirecting to WebFarm"
}
set req [HTTP::request]
inject lookup URI in place of original request
HTTP::uri "/addDWUser"
set pool to webfarm pool
pool pool_WebFarm
}
}
when HTTP_RESPONSE {
if {$addingUser == 1 } {
collect first response (from lookup server) only
if {[HTTP::header exists Content-Length] && ([HTTP::header Content-Length] < 1048576) } {
set clength [HTTP::header Content-Length]
} else {
set clength 1048576
}
if { $static::debug != 0 } {
log local0. "collecting response presumably from WebFarm, length is $clength"
}
HTTP::collect $clength
}
}
when HTTP_RESPONSE_DATA {
Get poolname from server response
Response would ideally be in the form of a pool name only.
Otherwise parse or derive the poolname here
set myPool pool_DataWarehouse
verify pool exists and has members
if { ![catch [pool $myPool]] }{
if { $static::debug != 0 } {
log local0. "retrying request"
}
pool pool_DataWarehouse
HTTP::retry $req
} else {
insert dead/non-existent pool logic here
}
re-set flag so that subsequent response to re-tried
request from real server is not processed as a lookup
if { $static::debug != 0 } {
log local0. "setting addingUser to 0"
}
set addingUser 0
}
Thanks!
Jen - hoolio
Cirrostratus
Nice work in figuring that out. Thanks for posting your rule.
Aaron - JRahm
Admin
Just a note on optimizations...I was curious about the efficiency of $static::debug != 0 versus $static::debug == 1 versus just $static::debug...here's how it worked out in my testing:1. 37166 cycles on average over 5000 requests from (ab -n 5000 -c 25 http://172.16.101.85/) if { $static::debug != 0 } {} 2. 34341 cycles on average over 5000 requests from (ab -n 5000 -c 25 http://172.16.101.85/) if { $static::debug == 1 } {} 3. 29034 cycles on average over 5000 requests from (ab -n 5000 -c 25 http://172.16.101.85/): if { $static::debug } {}A 21.9% savings by using the 3rd option as opposed to the 1st!
- hoolio
Cirrostratus
The last one is the simplest, but it's great to hear that it's also the most efficient. Thanks for testing this.
Aaron
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