Forum Discussion
skunk69_85565
Nov 06, 2007Historic F5 Account
need to insert new info into HTTP query or uri
Hi everyone,
I need some advice here, please.
I am currently developing an iRule which will in the end send user requests to different pools based on IP addr, user agents, an existing cookie or on a customized percentage value.
Ok, I have an idea but struggle with the following:
This is the part where I look for the cookie, if present I want to insert it into the HTTPquery or as a part of the HTTP::uri.
elseif { [HTTP::cookie exists "AB_test"] } {
set client_id [HTTP::cookie "AB_test"]
set old_uri [HTTP::uri]
set qstring [HTTP::query]
log local0. "Cookie found= $client_id"
log local0. "old URI= $old_uri "
log local0. "old query string= $qstring "
set qstring $client_id
log local0. "new query string= $qstring "
HTTP::query "$qstring"
log local0. "new query= [HTTP::query]"
}
if { [HTTP::query] starts_with "/A"} {
pool poolA
return
}
elseif { [HTTP::query] starts_with "/B"} {
pool poolB
return
}
Not sure what I am doing wrong here, but the new HTTP:query is empty.....
Any help is appreciated.
Patrick
8 Replies
- hoolio
Cirrostratus
I think the value retrieved using HTTP::query and HTTP::uri is cached for performance reasons. So even if you set it to a new value, the command will still return the original value.
If you change your rule to check the $client_id or updated $qstring, you should get the desired result:
if { $qstring starts_with "/A"} {
Aaron - skunk69_85565Historic F5 AccountHi Aaron,
;-) Yes, thanks that works
just another small issue:
Above this elseif routine there is an if-statement, and if both (if and elseif) are not true, there is an else function.
Is my iRule correct? as requests without a cookie seams to end here
if { [HTTP::query] starts_with "/A"} {
pool poolA
return
and I get this log message:
TCL error: test HTTP_REQUEST - cant read qstring: no such variable while executing if { $qstring starts_with A} { pool poolA log local0. send to poolA return } elseif { $qstring starts_with B} { pool poolB l..
Thanks again,
Patrick - hoolio
Cirrostratus
You're setting qstring to the value of [HTTP::query] in an else block, but I would guess that block isn't always being hit. So you get an error when trying to reference $qstring when it hasn't been set. You could either set it to some default value or check that it has been set before trying to use it. Here's an example of the latter using 'info exists' (Click here๐
if { [info exists qstring] && $qstring starts_with "/A"} {
[edit: you might also want to handle the default condition if the qstring isn't set or is set, but doesn't start with /A or /B.]... if { [info exists qstring] && $qstring starts_with "/A"} { pool poolA } elseif { [info exists qstring] && $qstring starts_with "/B"} { pool poolB } else { pool default_pool }
Aaron - skunk69_85565Historic F5 AccountAaron,
good point and thanks for the hint.
Actually I have no default pool, just site A or B.
I solved the problem just by including my if { $qstring starts_with "/A"} {.... routine into the big elseif routine:
...
elseif { [HTTP::cookie exists "AB_test"] } {
not a bad ip addr and no crawler, look for existing cookie
set client_id [HTTP::cookie "AB_test"]
this is used to direct the traffic
set qstring [HTTP::query]
log local0. "Cookie found= $client_id"
log local0. "old query string= $qstring "
set qstring $client_id
log local0. "new query string= $qstring "
now the load balancing is done
if { $qstring starts_with "A"} {
pool poolA
log local0. "send to poolA"
return
}
elseif { $qstring starts_with "B"} {
pool poolB
log local0. "send to poolB"
return
}
}
else {
.....
so, now it is working and I am thinking of a good way to get my requests to persist as I do not see a unique value for each (not ip, not the cookie) maybe a hash?
Patrick - hoolio
Cirrostratus
If you're setting the pool, you will need to get the user back to the same pool in your rule in order for persistence based on the pool members to work. Based on what you've posted so far, I assume the AB_test cookie will be sent in all requests.
Once you select the correct pool, you have two options. Deb posted some good info on this (Click here).
- You can configure a cookie insert profile with a default cookie name and not do anything with persistence in your rule.
- Or you can create a custom cookie insert persistence profile for the two pools. You could then specify a separate persistence profile per pool using the persist command (Click here) inside the block where you set the pool.if { $qstring starts_with "A"} { pool poolA persist cookie insert poolA_cookie_persist log local0. "send to poolA" return } elseif { $qstring starts_with "B"} { pool poolB persist cookie insert poolB_cookie_persist log local0. "send to poolB" return }
Aaron - skunk69_85565Historic F5 AccountAaron,
you pointed me in the right way, and finally I got it working :-). Sure this is not the best way, but it seams to work - not tested with customer right now.
At the moment I am not sure how I can fulfill the requirement of setting the query parameter with the value of the cookie (e.g. &AB_test=A-3)? This is needed for analytics. Any idea here?
For your info: I have a VS with no default pool, no persistence profile, just this irule:
when RULE_INIT {
Value defines how many new requests will end up at siteA "
set ::DefaultPerc 30
Global Test ID which will manually changed "
set ::TestID 7
Reset of sample_id
set ::sample_id 0
}
look for bad ip addr and send straight to poolA
when CLIENT_ACCEPTED {
if { [matchclass [IP::remote_addr] equals $::BlackList] } {
log local0. "Client IP is [IP::remote_addr] and send to site A"
pool poolA
}
log local0. "Client IP is [IP::remote_addr]"
}
when HTTP_REQUEST {
set UA [HTTP::header User-Agent]
log local0. "User Agent is $UA "
look if user agent is a crawler and send straight to poolA
if { [matchclass [string tolower $UA] contains $::SearchEngineCrawler] } {
log local0. "Crawler found: $UA and send to site A"
pool poolA
return
}
elseif { [HTTP::cookie exists "AB_test"] } {
not a bad ip addr and no crawler, look for existing cookie
set client_id [HTTP::cookie "AB_test"]
this is used to direct the traffic
set qstring [HTTP::query]
log local0. "Cookie found= $client_id"
log local0. "old query string= $qstring "
set qstring $client_id
log local0. "new query string= $qstring "
now the load balancing is done
if { $qstring starts_with "A"} {
pool poolA
log local0. "send to poolA"
return
}
elseif { $qstring starts_with "B"} {
pool poolB
log local0. "send to poolB"
return
}
}
else {
no bad ip, no crawler and no cookie set or new request
log local0. "no cookie need to sample!"
set id [expr { int(100 * rand()) }]
log local0. "id ist $id"
this is where the decision is made where to send traffic to
if {$id <= $::DefaultPerc } {
set ::sample_id A-$::TestID
}
else {
set ::sample_id B-$::TestID
}
log local0. "sample id is= $::sample_id "
set qstring [HTTP::query]
log local0. "old query string= $qstring "
set qstring $::sample_id
log local0. "new query string= $qstring "
loadbalance new requests
if { $qstring starts_with "A"} {
pool poolA
log local0. "send to poolA "
return
}
elseif { $qstring starts_with "B"} {
pool poolB
log local0. "send to poolB "
return
}
}
log local0. "END"
}
when HTTP_RESPONSE {
HTTP::cookie insert name AB_test value $::sample_id
}
Any idea how to get the query parameter set is welcome.
Thanks for your help so far.
Patrick - hoolio
Cirrostratus
Hi Patrick,
Sorry, I didn't realize that HTTP::query only allows you to get the query string value, and not set it. HTTP::uri will allow you to get or set the URI, including the query string.
If you know there will never be a pre-existing query string in the original client request, you could just append the updated URI to the existing URI. However, I expect there would be requests with existing query strings for most apps. To handle that, you could use string map to replace the query string with the new query string within the entire URI. Here is an example:... original query string is returned by [HTTP::query] check if query string is empty if {[string length [HTTP::query]] > 0}{ query string wasn't empty, so we have to preserve what was there make a change to the query string set updated_qs "[HTTP::query]&someparameter=somevalue" update the URI by replacing the old query string with the new HTTP::uri [string map "[HTTP::query] $updated_qs" [HTTP::uri]] } else { query string wasn't set, so we can just append to the existing URI HTTP::uri "[HTTP::uri]?someparameter=somevalue" } ...
You won't be able to log the change to the URI using HTTP::uri, as the value is cached. But you could log the string map output to see the change:log local0. "Updated URI: [string map \"[HTTP::query] $updated_qs\" [HTTP::uri]]"
Aaron - skunk69_85565Historic F5 AccountAaron,
Thank you so much :-)
I will test it tomorrow, onsite!
Patrick
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
